Skip to content

Commit 17e5f99

Browse files
committed
Add StdIO module & clean up IO in TCB
This removes some derivable operations out of the TCB, e.g. `fprintln` and `fprintlnWithLabels`. At the same time, `inputLine` has been semi-generalised to be `freadln` (read a line from a file) and `stdin` is now a derivable capability similar to the one needed for printing to `stdout`. This also fixes the missing access to `stderr`. For now, there are lots of `runtime/core` tests that rely on the preamble functions, `print` and so on. In the long run, these tests should be rewritten such that they are completely independent. The tests for the preamble itself have been moved into a separate folder.
1 parent 6dd8c1b commit 17e5f99

File tree

89 files changed

+542
-226
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+542
-226
lines changed

compiler/src/AddAmbientMethods.hs

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,61 @@
11
-- 2020-05-17, AA
22

33
-- HACK
4-
-- This module add a number of standard
5-
-- ambient methods such as `print` to the
6-
-- beginning of the file. This provides some
7-
-- backward compatibility with prior test cases
8-
-- as well as minimizes some clutter
9-
10-
-- If these methods are unused they are
11-
-- eliminated by the optimization passes in
12-
-- the further passes.
13-
14-
module AddAmbientMethods(addAmbientMethods) where
4+
--
5+
-- This module add a number of standard ambient methods such as `print` to the beginning of the
6+
-- file. This provides some backward compatibility with prior test cases as well as minimizes some
7+
-- clutter.
8+
--
9+
-- If these methods are unused they are eliminated by the optimization passes in the further passes.
10+
11+
-- TODO
12+
--
13+
-- Move this into a '.trp' file of the form
14+
--
15+
-- ```
16+
-- let fun print x = fwrite (stdout authority, (toString x) ^"\n")
17+
-- ...
18+
-- in () end
19+
-- ```
20+
--
21+
-- Which, similar to below, after parsing has the `dummy` value replaced by the actual program. This
22+
-- preamble can then be specified at compile-time.
23+
24+
module AddAmbientMethods(addAmbientMethods) where
1525

1626
import Basics
17-
import Direct
27+
import Direct
1828
import TroupePositionInfo
1929

20-
printDecl :: FunDecl
21-
printDecl = FunDecl "print"
30+
printStringDecl :: FunDecl
31+
printStringDecl = FunDecl "printString"
2232
[Lambda [VarPattern "x"] $
23-
Let [ValDecl (VarPattern "out") (App (Var "getStdout") [Var "authority"]) NoPos]
24-
(App (Var "fprintln") [Tuple [Var "out", Var "x"]])
33+
Let [ ValDecl (VarPattern "fd") (App (Var "stdout") [Var "authority"]) NoPos
34+
, ValDecl (VarPattern "x'") (Bin Concat (Var "x") (Lit $ LString "\\n")) NoPos
35+
]
36+
(App (Var "fwrite") [Tuple [Var "fd", Var "x'"]])
2537
] NoPos
2638

27-
printWithLabelsDecl :: FunDecl
28-
printWithLabelsDecl = FunDecl "printWithLabels"
29-
[Lambda [VarPattern "x"] $
30-
Let [ValDecl (VarPattern "out") (App (Var "getStdout") [Var "authority"]) NoPos]
31-
(App (Var "fprintlnWithLabels") [Tuple [Var "out", Var "x"]])
39+
printDecl :: FunDecl
40+
printDecl = FunDecl "print"
41+
[Lambda [ VarPattern "x" ] $
42+
(App (Var "printString") [App (Var "toString") [Var "x"]])
3243
] NoPos
3344

34-
35-
printStringDecl :: FunDecl
36-
printStringDecl = FunDecl "printString"
37-
[Lambda [VarPattern "x"] $
38-
Let [ValDecl (VarPattern "out") (App (Var "getStdout") [Var "authority"]) NoPos]
39-
(App (Var "fwrite") [Tuple [Var "out", Bin Concat (Var "x") (Lit (LString "\\n"))]])
45+
printWithLabelsDecl :: FunDecl
46+
printWithLabelsDecl = FunDecl "printWithLabels"
47+
[Lambda [ VarPattern "x" ] $
48+
(App (Var "printString") [App (Var "toStringL") [Var "x"]])
4049
] NoPos
4150

51+
inputLineDecl :: FunDecl
52+
inputLineDecl = FunDecl "inputLine"
53+
[Lambda [ VarPattern "_" ] $
54+
Let [ValDecl (VarPattern "fd") (App (Var "stdin") [Var "authority"]) NoPos]
55+
(App (Var "freadln") [App (Var "stdin") [Var "authority"]])
56+
] NoPos
4257

43-
44-
addAmbientMethods :: Prog -> Prog
45-
addAmbientMethods (Prog imports atoms t) =
46-
let t' = Let [FunDecs [printDecl,printWithLabelsDecl,printStringDecl]] t
47-
in Prog imports atoms t'
58+
addAmbientMethods :: Prog -> Prog
59+
addAmbientMethods (Prog imports atoms t) =
60+
let t' = Let [FunDecs [printStringDecl,printDecl,printWithLabelsDecl,inputLineDecl]] t
61+
in Prog imports atoms t'

compiler/src/IR.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ instance WellFormedIRCheck IRExpr where
261261
-- code over wire. Such malformed code would result
262262
-- in a JS output returning a runtime error (which should
263263
-- generally be avoided)
264-
if fname `elem`[
264+
if fname `elem`[
265265
"$$authorityarg"
266266
, "adv"
267267
, "ladv"
@@ -285,16 +285,13 @@ instance WellFormedIRCheck IRExpr where
285285
, "endorse"
286286
, "floor"
287287
, "flowsTo"
288-
, "fprintln"
289-
, "fprintlnWithLabels"
290-
, "fwrite"
288+
, "freadln"
289+
, "fwrite"
291290
, "getTime"
292291
, "getType"
293292
, "getNanoTime"
294-
, "getStdout"
295293
, "_getSystemProcess"
296294
, "guard"
297-
, "inputLine"
298295
, "intToString"
299296
, "listToTuple"
300297
, "lowermbox"
@@ -305,13 +302,13 @@ instance WellFormedIRCheck IRExpr where
305302
, "newlabel"
306303
, "node"
307304
, "_pc"
305+
, "_bl"
308306
, "pcpop"
309307
, "peek"
310308
, "pinipush"
311309
, "pinipushto"
312310
, "pinipop"
313311
, "pcpush"
314-
, "question"
315312
, "raisembox"
316313
, "raiseTrust"
317314
, "random"
@@ -333,6 +330,9 @@ instance WellFormedIRCheck IRExpr where
333330
, "spawn"
334331
, "sqrt"
335332
, "substring"
333+
, "stdin"
334+
, "stdout"
335+
, "stderr"
336336
, "stringToInt"
337337
, "strlen"
338338
, "restore"

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ build:
66
# No dependencies
77
$(COMPILER) ./Number.trp -l
88
$(COMPILER) ./List.trp -l
9+
$(COMPILER) ./StdIO.trp -l
910
$(COMPILER) ./ThreadUtil.trp -l
1011

1112
# Dependency on `List`

lib/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ reviewed rigorously rather than depend on the monitor.
1313
- `List` : Operations for lists, i.e. `[]` and `x::xs`.
1414
- `ListPair` : Operations for list of pairs, i.e. `(x,y)::xs`.
1515
- `Number` : Operations for numbers, i.e. integer and floats.
16+
- `StdIO` : Standard input and output.
1617
- `StencilVector` : Memory-efficient implementation of small (sparse) arrays.
1718
- `String` : Operations for strings
1819
- `ThreadUtil` : Additional functions for thread management.

lib/StdIO.trp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
let (** OS.IO module with file reading and writing.
2+
*
3+
* TODO: For now, this is only used internally for the StdIO library. But, when file reading and
4+
* writing is properly added, then this needs to be moved to its own module. *)
5+
fun OS_IO authority =
6+
let (*--- File Reading ---*)
7+
(* TODO: Sub-line input access. *)
8+
9+
(** Obtain the next line from `fd`.
10+
*
11+
* This is merely reexposing the `freadln` language builtin.
12+
**)
13+
fun readln fd =
14+
freadln fd
15+
16+
(** Similar to `readln` but ensures the blocking label is not raised. *)
17+
fun readln' fd =
18+
let pini authority
19+
val ln = readln fd
20+
in ln end
21+
22+
(** Similar to `readln'` but declassifies what is read to the given level. *)
23+
fun readlnAtLevel fd level =
24+
declassify (readln' fd, authority, level)
25+
26+
(*--- File Writing ---*)
27+
fun _write fd str = fwrite (fd, str)
28+
29+
(** Write `x` to the given file descriptor. *)
30+
fun write fd x = case getType x of "string" => _write fd x
31+
| _ => _write fd (toString x)
32+
33+
(** Write `x` and its security label(s) to the given file descriptor. *)
34+
fun writeL fd x = _write fd (toStringL x)
35+
36+
(** Write `x` and a newline to the given file descriptor. *)
37+
fun writeln fd x = (write fd x; _write fd "\n")
38+
39+
(** Write `x`, its security label(s), and a newline to the given file descriptor. *)
40+
fun writelnL fd x = (writeL fd x; _write fd "\n")
41+
in
42+
{ readln
43+
, readln'
44+
, readlnAtLevel
45+
, write
46+
, writeL
47+
, writeln
48+
, writelnL
49+
}
50+
end
51+
52+
(** Standard input and output handling. *)
53+
fun StdIO authority =
54+
let val OS = OS_IO authority
55+
56+
(*--- STD File Descriptors ---*)
57+
58+
(** Capability for standard input. *)
59+
val stdin = stdin authority
60+
61+
(** Capability for standard output. *)
62+
val stdout = stdout authority
63+
64+
(** Capability for standard error. *)
65+
val stderr = stderr authority
66+
67+
(*--- Input/Output ---*)
68+
69+
(** Write the given `question` to `stdout` and returns the answer provided from
70+
* `stdin`. *)
71+
fun input question =
72+
(OS.write stdout question; OS.readln stdin)
73+
74+
(** Similar to `input` but does not raise the blocking label. *)
75+
fun input' question =
76+
(OS.write stdout question; OS.readln' stdin)
77+
78+
(** Similar to `input'` but also declassifies the result. *)
79+
fun inputAtLevel question level =
80+
(OS.write stdout question; OS.readlnAtLevel stdin level)
81+
82+
(*--- Submodule(s) ---*)
83+
84+
(** Reading from `stdin`. *)
85+
val In =
86+
{ readln = fn () => OS.readln stdin
87+
, readln' = fn () => OS.readln' stdin
88+
, readlnAtLevel = fn l => OS.readlnAtLevel stdin l
89+
}
90+
91+
(** Printing to `stdout`. *)
92+
val Out =
93+
{ print = OS.write stdout
94+
, println = OS.writeln stdout
95+
, printL = OS.writeL stdout
96+
, printlnL = OS.writelnL stdout
97+
}
98+
99+
(** Printing to `stderr`. *)
100+
val Err =
101+
{ print = OS.write stderr
102+
, println = OS.writeln stderr
103+
, printL = OS.writeL stderr
104+
, printlnL = OS.writelnL stderr
105+
}
106+
107+
in (*--- Module(s) ---*)
108+
{ stdin
109+
, In
110+
, stdout
111+
, Out
112+
, stderr
113+
, Err
114+
, input
115+
, input'
116+
, inputAtLevel
117+
}
118+
end
119+
120+
in [ ("StdIO", StdIO) ]
121+
end

lib/Unit.trp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ let
66
fun print auth indent str =
77
let fun makeIndent 0 = ""
88
| makeIndent i = " " ^ (makeIndent (i-1))
9-
in fwrite ((getStdout auth), (makeIndent indent) ^ str)
9+
in fwrite ((stdout auth), (makeIndent indent) ^ str)
1010
end
1111

12-
fun printCR auth = fwrite ((getStdout auth), "\r")
13-
fun printNL auth = fwrite ((getStdout auth), "\n")
12+
fun printCR auth = fwrite ((stdout auth), "\r")
13+
fun printNL auth = fwrite ((stdout auth), "\n")
1414

1515
(* TODO (Issue #55) Move colours into helper functions. *)
1616
val testStr = "\x1b[33m" ^ "[ TEST ]" ^ "\x1b[0m" ^ " it "

rt/src/Asserts.mts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function __stringRep (v) {
3434
}
3535

3636
let err = x => _thread().threadError(x)
37+
3738
export function assertIsAtom (x: any) {
3839
_thread().raiseBlockingThreadLev(x.tlev)
3940
if (x.val._troupeType != TroupeType.ATOM ) {
@@ -209,7 +210,6 @@ export function assertIsProcessId(x: any) {
209210
}
210211
}
211212

212-
213213
export function assertIsCapability(x: any) {
214214
_thread().raiseBlockingThreadLev(x.tlev);
215215
if (!(x.val instanceof Capability)) {
@@ -229,6 +229,7 @@ export function rawAssertIsLevel (x:any) {
229229
err("value " + __stringRep(x) + " is not a level");
230230
}
231231
}
232+
232233
export function assertIsRootAuthority(x: any) {
233234
let isTop = actsFor(x.val.authorityLevel, levels.ROOT);
234235
if (!isTop) {

rt/src/UserRuntime.mts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { BuiltinToString } from './builtins/toString.mjs'
1919
import { BuiltinSend } from './builtins/send.mjs'
2020
import { BuiltinSpawn } from './builtins/spawn.mjs'
2121
import { BuiltinReceive } from './builtins/receive.mjs'
22+
import { BuiltinThread } from './builtins/thread.mjs'
2223
import { BuiltinAttenuate } from './builtins/attenuate.mjs'
2324
import { BuiltinRegistry } from './builtins/whereis.mjs'
2425
import { BuiltinDeclassify } from './builtins/declassify.mjs'
@@ -46,6 +47,7 @@ export const UserRuntime =
4647
BuiltinRegistry(
4748
BuiltinAttenuate(
4849
BuiltSpawnSendReceive(
50+
BuiltinThread(
4951
BuiltinStringToInt(
5052
BuiltinToString(
5153
BuiltinGetTime(
@@ -64,5 +66,5 @@ export const UserRuntime =
6466
BuiltinMath(
6567
BuiltinRecordReflection(
6668
BuiltinTypeInformation(
67-
BuiltinStdIo(UserRuntimeZero)
68-
)))))))))))))))))))))))))))))
69+
BuiltinStdIo(UserRuntimeZero)
70+
))))))))))))))))))))))))))))))

rt/src/builtins/receive.mts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,6 @@ export function BuiltinReceive<TBase extends Constructor<UserRuntimeZero>>(Base:
131131
return this.runtime.__mbox.consume ( consume_l, i.val, lowb.val, highb.val )
132132
})
133133

134-
_blockThread = mkBase ((arg) => {
135-
assertIsUnit(arg)
136-
this.runtime.__sched.blockThread(this.runtime.__sched.__currentThread);
137-
return null;
138-
})
139-
140-
_pc = mkBase ((arg) => {
141-
assertIsUnit (arg)
142-
return this.runtime.ret (
143-
new LVal (this.runtime.$t.pc, this.runtime.$t.pc, BOT))
144-
})
145-
146-
147134
guard = mkBase (arg => {
148135
assertIsNTuple(arg, 3)
149136
let f = arg.val[0]

0 commit comments

Comments
 (0)