(load "mu.arc")
(reset)
(new-trace "literal")
(add-fns
'((main
((1 integer) <- copy (23 literal)))))
(run 'main)
(if (~is memory*.1 23)
(prn "F - 'copy' writes its lone 'arg' after the instruction name to its lone 'oarg' or output arg before the arrow. After this test, the value 23 is stored in memory address 1."))
(reset)
(new-trace "add")
(add-fns
'((main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
((3 integer) <- add (1 integer) (2 integer)))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4))
(prn "F - 'add' operates on two addresses"))
(reset)
(new-trace "add-literal")
(add-fns
'((main
((1 integer) <- add (2 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 5)
(prn "F - ops can take 'literal' operands (but not return them)"))
(reset)
(new-trace "sub-literal")
(add-fns
'((main
((1 integer) <- sub (1 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 -2)
(prn "F - 'sub' subtracts the second arg from the first"))
(reset)
(new-trace "mul-literal")
(add-fns
'((main
((1 integer) <- mul (2 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 6)
(prn "F - 'mul' multiplies like 'add' adds"))
(reset)
(new-trace "div-literal")
(add-fns
'((main
((1 integer) <- div (8 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 (/ real.8 3))
(prn "F - 'div' divides like 'sub' subtracts"))
(reset)
(new-trace "idiv-literal")
(add-fns
'((main
((1 integer) (2 integer) <- idiv (23 literal) (6 literal)))))
(run 'main)
(if (~iso memory* (obj 1 3 2 5))
(prn "F - 'idiv' performs integer division, returning quotient and remainder"))
(reset)
(new-trace "dummy-oarg")
(add-fns
'((main
(_ (2 integer) <- idiv (23 literal) (6 literal)))))
(run 'main)
(if (~iso memory* (obj 2 5))
(prn "F - '_' oarg can ignore some results"))
(reset)
(new-trace "and-literal")
(add-fns
'((main
((1 boolean) <- and (t literal) (t literal)))))
(run 'main)
(if (~is memory*.1 nil)
(prn "F - logical 'and' for booleans"))
(reset)
(new-trace "lt-literal")
(add-fns
'((main
((1 boolean) <- lt (4 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 nil)
(prn "F - 'lt' is the less-than inequality operator"))
(reset)
(new-trace "le-literal-false")
(add-fns
'((main
((1 boolean) <- le (4 literal) (3 literal)))))
(run 'main)
(if (~is memory*.1 nil)
(prn "F - 'le' is the <= inequality operator"))
(reset)
(new-trace "le-literal-true")
(add-fns
'((main
((1 boolean) <- le (4 literal) (4 literal)))))
(run 'main)
(if (~is memory*.1 t)
(prn "F - 'le' returns true for equal operands"))
(reset)
(new-trace "le-literal-true-2")
(add-fns
'((main
((1 boolean) <- le (4 literal) (5 literal)))))
(run 'main)
(if (~is memory*.1 t)
(prn "F - le is the <= inequality operator - 2"))
(reset)
(new-trace "jump-skip")
(add-fns
'((main
((1 integer) <- copy (8 literal))
(jump (1 offset))
((2 integer) <- copy (3 literal))
(reply))))
(run 'main)
(if (~iso memory* (obj 1 8))
(prn "F - 'jump' skips some instructions"))
(reset)
(new-trace "jump-target")
(add-fns
'((main
((1 integer) <- copy (8 literal))
(jump (1 offset))
((2 integer) <- copy (3 literal))
(reply)
((3 integer) <- copy (34 literal)))))
(run 'main)
(if (~iso memory* (obj 1 8))
(prn "F - 'jump' doesn't skip too many instructions"))
(reset)
(new-trace "jump-if-skip")
(add-fns
'((main
((2 integer) <- copy (1 literal))
((1 boolean) <- eq (1 literal) (2 integer))
(jump-if (1 boolean) (1 offset))
((2 integer) <- copy (3 literal))
(reply)
((3 integer) <- copy (34 literal)))))
(run 'main)
(if (~iso memory* (obj 1 t 2 1))
(prn "F - 'jump-if' is a conditional 'jump'"))
(reset)
(new-trace "jump-if-fallthrough")
(add-fns
'((main
((1 boolean) <- eq (1 literal) (2 literal))
(jump-if (3 boolean) (1 offset))
((2 integer) <- copy (3 literal))
(reply)
((3 integer) <- copy (34 literal)))))
(run 'main)
(if (~iso memory* (obj 1 nil 2 3))
(prn "F - if 'jump-if's first arg is false, it doesn't skip any instructions"))
(reset)
(new-trace "jump-if-backward")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (1 literal))
((2 integer) <- add (2 integer) (2 integer))
((3 boolean) <- eq (1 integer) (2 integer))
(jump-if (3 boolean) (-3 offset))
((4 integer) <- copy (3 literal))
(reply)
((3 integer) <- copy (34 literal)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 4 3 nil 4 3))
(prn "F - 'jump-if' can take a negative offset to make backward jumps"))
(reset)
(new-trace "direct-addressing")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 integer) <- copy (1 integer)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 34))
(prn "F - 'copy' performs direct addressing"))
(reset)
(new-trace "indirect-addressing")
(add-fns
'((main
((1 integer-address) <- copy (2 literal))
((2 integer) <- copy (34 literal))
((3 integer) <- copy (1 integer-address deref)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 34 3 34))
(prn "F - 'copy' performs indirect addressing"))
(reset)
(new-trace "indirect-addressing-oarg")
(add-fns
'((main
((1 integer-address) <- copy (2 literal))
((2 integer) <- copy (34 literal))
((1 integer-address deref) <- add (2 integer) (2 literal)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 36))
(prn "F - instructions can perform indirect addressing on output arg"))
(reset)
(each (typ typeinfo) types*
(when typeinfo!record
(assert (is typeinfo!size (len typeinfo!elems)))
(when typeinfo!fields
(assert (is typeinfo!size (len typeinfo!fields))))))
(reset)
(new-trace "get-record")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((3 boolean) <- get (1 integer-boolean-pair) (1 offset))
((4 integer) <- get (1 integer-boolean-pair) (0 offset)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 nil 3 nil 4 34))
(prn "F - 'get' accesses fields of records"))
(reset)
(new-trace "get-indirect")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((3 integer-boolean-pair-address) <- copy (1 literal))
((4 boolean) <- get (3 integer-boolean-pair-address deref) (1 offset))
((5 integer) <- get (3 integer-boolean-pair-address deref) (0 offset)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 nil 3 1 4 nil 5 34))
(prn "F - 'get' accesses fields of record address"))
(reset)
(new-trace "get-compound-field")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 integer) <- copy (35 literal))
((3 integer) <- copy (36 literal))
((4 integer-integer-pair) <- get (1 integer-point-pair) (1 offset)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 35 3 36 4 35 5 36))
(prn "F - 'get' accesses fields spanning multiple locations"))
(reset)
(new-trace "get-address")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((3 boolean-address) <- get-address (1 integer-boolean-pair) (1 offset)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 t 3 2))
(prn "F - 'get-address' returns address of fields of records"))
(reset)
(new-trace "get-address-indirect")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((3 integer-boolean-pair-address) <- copy (1 literal))
((4 boolean-address) <- get-address (3 integer-boolean-pair-address deref) (1 offset)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 t 3 1 4 2))
(prn "F - 'get-address' accesses fields of record address"))
(reset)
(new-trace "index-literal")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer-boolean-pair) <- index (1 integer-boolean-pair-array) (1 literal)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 24 7 t))
(prn "F - 'index' accesses indices of arrays"))
(reset)
(new-trace "index-direct")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer) <- copy (1 literal))
((7 integer-boolean-pair) <- index (1 integer-boolean-pair-array) (6 integer)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 1 7 24 8 t))
(prn "F - 'index' accesses indices of arrays"))
(reset)
(new-trace "index-indirect")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer) <- copy (1 literal))
((7 integer-boolean-pair-array-address) <- copy (1 literal))
((8 integer-boolean-pair) <- index (7 integer-boolean-pair-array-address deref) (6 integer)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 1 7 1 8 24 9 t))
(prn "F - 'index' accesses indices of array address"))
(reset)
(new-trace "index-address")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer) <- copy (1 literal))
((7 integer-boolean-pair-address) <- index-address (1 integer-boolean-pair-array) (6 integer)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 1 7 4))
(prn "F - 'index-address' returns addresses of indices of arrays"))
(reset)
(new-trace "index-address-indirect")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer) <- copy (1 literal))
((7 integer-boolean-pair-array-address) <- copy (1 literal))
((8 integer-boolean-pair-address) <- index-address (7 integer-boolean-pair-array-address deref) (6 integer)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 1 7 1 8 4))
(prn "F - 'index-address' returns addresses of indices of array addresses"))
(reset)
(new-trace "len-array")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer) <- len (1 integer-boolean-pair-array)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 2))
(prn "F - 'len' accesses length of array"))
(reset)
(new-trace "len-array-indirect")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 boolean) <- copy (t literal))
((4 integer) <- copy (24 literal))
((5 boolean) <- copy (t literal))
((6 integer-address) <- copy (1 literal))
((7 integer) <- len (6 integer-boolean-pair-array-address deref)))))
(run 'main)
(if (~iso memory* (obj 1 2 2 23 3 nil 4 24 5 t 6 1 7 2))
(prn "F - 'len' accesses length of array address"))
(reset)
(new-trace "sizeof-record")
(add-fns
'((main
((1 integer) <- sizeof (integer-boolean-pair literal)))))
(run 'main)
(if (~is memory*.1 2)
(prn "F - 'sizeof' returns space required by arg"))
(reset)
(new-trace "sizeof-record-not-len")
(add-fns
'((main
((1 integer) <- sizeof (integer-point-pair literal)))))
(run 'main)
(if (~is memory*.1 3)
(prn "F - 'sizeof' is different from number of elems"))
(reset)
(new-trace "compound-operand-copy")
(add-fns
'((main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((4 boolean) <- copy (t literal))
((3 integer-boolean-pair) <- copy (1 integer-boolean-pair)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 nil 3 34 4 nil))
(prn "F - ops can operate on records spanning multiple locations"))
(reset)
(new-trace "compound-arg")
(add-fns
'((test1
((4 integer-boolean-pair) <- arg))
(main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
(test1 (1 integer-boolean-pair)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 nil 4 34 5 nil))
(prn "F - 'arg' can copy records spanning multiple locations"))
(reset)
(new-trace "compound-arg-indirect")
(add-fns
'((test1
((4 integer-boolean-pair) <- arg))
(main
((1 integer) <- copy (34 literal))
((2 boolean) <- copy (t literal))
((3 integer-boolean-pair-address) <- copy (1 literal))
(test1 (3 integer-boolean-pair-address deref)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 nil 3 1 4 34 5 nil))
(prn "F - 'arg' can copy records spanning multiple locations in indirect mode"))
(reset)
(new-trace "tagged-value")
(add-fns
'((main
((1 type) <- copy (integer-address literal))
((2 integer-address) <- copy (34 literal))
((3 integer-address) (4 boolean) <- maybe-coerce (1 tagged-value) (integer-address literal)))))
(run 'main)
(each routine completed-routines*
(aif rep.routine!error (prn "error - " it)))
(if (or (~is memory*.3 34) (~is memory*.4 t))
(prn "F - 'maybe-coerce' copies value only if type tag matches"))
(reset)
(new-trace "tagged-value-2")
(add-fns
'((main
((1 type) <- copy (integer-address literal))
((2 integer-address) <- copy (34 literal))
((3 integer-address) (4 boolean) <- maybe-coerce (1 tagged-value) (boolean-address literal)))))
(run 'main)
(if (or (~is memory*.3 0) (~is memory*.4 nil))
(prn "F - 'maybe-coerce' doesn't copy value when type tag doesn't match"))
(reset)
(new-trace "save-type")
(add-fns
'((main
((1 integer-address) <- copy (34 literal))
((2 tagged-value) <- save-type (1 integer-address)))))
(run 'main)
(if (~iso memory* (obj 1 34 2 'integer-address 3 34))
(prn "F - 'save-type' saves the type of a value at runtime, turning it into a tagged-value"))
(reset)
(new-trace "new-tagged-value")
(add-fns
'((main
((1 integer-address) <- copy (34 literal))
((2 tagged-value-address) <- new-tagged-value (integer-address literal) (1 integer-address))
((3 integer-address) (4 boolean) <- maybe-coerce (2 tagged-value-address deref) (integer-address literal)))))
(run 'main)
(if (or (~is memory*.3 34) (~is memory*.4 t))
(prn "F - 'new-tagged-value' is the converse of 'maybe-coerce'"))
(reset)
(new-trace "list")
(add-fns
'((test1
((1 list-address) <- new (list literal))
((2 tagged-value-address) <- list-value-address (1 list-address))
((3 type-address) <- get-address (2 tagged-value-address deref) (0 offset))
((3 type-address deref) <- copy (integer literal))
((4 location) <- get-address (2 tagged-value-address deref) (1 offset))
((4 location deref) <- copy (34 literal))
((5 list-address-address) <- get-address (1 list-address deref) (1 offset))
((5 list-address-address deref) <- new (list literal))
((6 list-address) <- copy (5 list-address-address deref))
((7 tagged-value-address) <- list-value-address (6 list-address))
((8 type-address) <- get-address (7 tagged-value-address deref) (0 offset))
((8 type-address deref) <- copy (boolean literal))
((9 location) <- get-address (7 tagged-value-address deref) (1 offset))
((9 location deref) <- copy (t literal))
((10 list-address) <- get (6 list-address deref) (1 offset))
)))
(let first Memory-in-use-until
(run 'test1)
(if (or (~all first (map memory* '(1 2 3)))
(~is memory*.first 'integer)
(~is memory*.4 (+ first 1))
(~is (memory* (+ first 1)) 34)
(~is memory*.5 (+ first 2))
(let second memory*.6
(or
(~is (memory* (+ first 2)) second)
(~all second (map memory* '(6 7 8)))
(~is memory*.second 'boolean)
(~is memory*.9 (+ second 1))
(~is (memory* (+ second 1)) t)
(~is memory*.10 nil))))
(prn "F - lists can contain elements of different types")))
(add-fns
'((test2
((10 list-address) <- list-next (1 list-address)))))
(run 'test2)
(if (~is memory*.10 memory*.6)
(prn "F - 'list-next can move a list pointer to the next node"))
(reset)
(new-trace "new-list")
(add-fns
'((main
((1 integer) <- new-list (3 literal) (4 literal) (5 literal)))))
(run 'main)
(let first memory*.1
(if (or (~is memory*.first 'integer)
(~is (memory* (+ first 1)) 3)
(let second (memory* (+ first 2))
(or (~is memory*.second 'integer)
(~is (memory* (+ second 1)) 4)
(let third (memory* (+ second 2))
(or (~is memory*.third 'integer)
(~is (memory* (+ third 1)) 5)
(~is (memory* (+ third 2) nil)))))))
(prn "F - 'new-list' can construct a list of integers")))
(reset)
(new-trace "new-fn")
(add-fns
'((test1
((3 integer) <- add (1 integer) (2 integer)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
(test1))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4))
(prn "F - calling a user-defined function runs its instructions"))
(reset)
(new-trace "new-fn-once")
(add-fns
'((test1
((1 integer) <- copy (1 literal)))
(main
(test1))))
(run 'main)
(if (~is 2 curr-cycle*)
(prn "F - calling a user-defined function runs its instructions exactly once " curr-cycle*))
(reset)
(new-trace "new-fn-reply")
(add-fns
'((test1
((3 integer) <- add (1 integer) (2 integer))
(reply)
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
(test1))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4))
(prn "F - 'reply' stops executing the current function"))
(reset)
(new-trace "new-fn-reply-nested")
(add-fns
'((test1
((3 integer) <- test2))
(test2
(reply (2 integer)))
(main
((2 integer) <- copy (34 literal))
(test1))))
(run 'main)
(if (~iso memory* (obj 2 34 3 34))
(prn "F - 'reply' stops executing any callers as necessary"))
(reset)
(new-trace "new-fn-reply-once")
(add-fns
'((test1
((3 integer) <- add (1 integer) (2 integer))
(reply)
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
(test1))))
(run 'main)
(if (~is 5 curr-cycle*)
(prn "F - 'reply' executes instructions exactly once " curr-cycle*))
(reset)
(new-trace "new-fn-arg-sequential")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- arg)
((3 integer) <- add (4 integer) (5 integer))
(reply)
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
(test1 (1 integer) (2 integer))
)))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4
4 1 5 3))
(prn "F - 'arg' accesses in order the operands of the most recent function call (the caller)"))
(reset)
(new-trace "new-fn-arg-random-access")
(add-fns
'((test1
((5 integer) <- arg (1 literal))
((4 integer) <- arg (0 literal))
((3 integer) <- add (4 integer) (5 integer))
(reply)
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
(test1 (1 integer) (2 integer))
)))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4
4 1 5 3))
(prn "F - 'arg' with index can access function call arguments out of order"))
(reset)
(new-trace "new-fn-arg-status")
(add-fns
'((test1
((4 integer) (5 boolean) <- arg))
(main
(test1 (1 literal))
)))
(run 'main)
(if (~iso memory* (obj 4 1 5 t))
(prn "F - 'arg' sets a second oarg when arg exists"))
(reset)
(new-trace "new-fn-arg-missing")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- arg))
(main
(test1 (1 literal))
)))
(run 'main)
(if (~iso memory* (obj 4 1))
(prn "F - missing 'arg' doesn't cause error"))
(reset)
(new-trace "new-fn-arg-missing-2")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) (6 boolean) <- arg))
(main
(test1 (1 literal))
)))
(run 'main)
(if (~iso memory* (obj 4 1 6 nil))
(prn "F - missing 'arg' wipes second oarg when provided"))
(reset)
(new-trace "new-fn-arg-missing-3")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- copy (34 literal))
((5 integer) (6 boolean) <- arg))
(main
(test1 (1 literal))
)))
(run 'main)
(if (~iso memory* (obj 4 1 6 nil))
(prn "F - missing 'arg' consistently wipes its oarg"))
(reset)
(new-trace "new-fn-arg-missing-4")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) (6 boolean) <- arg)
{
(break-if (6 boolean))
((5 integer) <- copy (1 literal))
}
((7 integer) <- add (4 integer) (5 integer)))
(main
(test1 (34 literal))
)))
(run 'main)
(if (~iso memory* (obj 4 34 5 1 6 nil 7 35))
(prn "F - function with optional second arg"))
(reset)
(new-trace "new-fn-arg-by-value")
(add-fns
'((test1
((1 integer) <- copy (0 literal))
((2 integer) <- arg))
(main
((1 integer) <- copy (34 literal))
(test1 (1 integer)))))
(run 'main)
(if (~iso memory* (obj 1 0 2 34))
(prn "F - 'arg' passes by value"))
(reset)
(new-trace "new-fn-reply-oarg")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- arg)
((6 integer) <- add (4 integer) (5 integer))
(reply (6 integer))
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
((3 integer) <- test1 (1 integer) (2 integer)))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4
4 1 5 3 6 4))
(prn "F - 'reply' can take aguments that are returned, or written back into output args of caller"))
(reset)
(new-trace "new-fn-reply-oarg-multiple")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- arg)
((6 integer) <- add (4 integer) (5 integer))
(reply (6 integer) (5 integer))
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
((3 integer) (7 integer) <- test1 (1 integer) (2 integer)))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4 7 3
4 1 5 3 6 4))
(prn "F - 'reply' permits a function to return multiple values at once"))
(reset)
(new-trace "new-fn-prepare-reply")
(add-fns
'((test1
((4 integer) <- arg)
((5 integer) <- arg)
((6 integer) <- add (4 integer) (5 integer))
(prepare-reply (6 integer) (5 integer))
(reply)
((4 integer) <- copy (34 literal)))
(main
((1 integer) <- copy (1 literal))
((2 integer) <- copy (3 literal))
((3 integer) (7 integer) <- test1 (1 integer) (2 integer)))))
(run 'main)
(if (~iso memory* (obj 1 1 2 3 3 4 7 3
4 1 5 3 6 4))
(prn "F - without args, 'reply' returns values from previous 'prepare-reply'."))
(reset)
(new-trace "convert-braces")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
{
((4 boolean) <- neq (1 integer) (3 integer))
(break-if (4 boolean))
((5 integer) <- copy (34 literal))
}
(reply)))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
((4 boolean) <- neq (1 integer) (3 integer))
(jump-if (4 boolean) (1 offset))
((5 integer) <- copy (34 literal))
(reply)))
(prn "F - convert-braces replaces break-if with a jump-if to after the next close-curly"))
(reset)
(new-trace "convert-braces-empty-block")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
{
(break)
}
(reply)))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
(jump (0 offset))
(reply)))
(prn "F - convert-braces works for degenerate blocks"))
(reset)
(new-trace "convert-braces-nested-break")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
{
((4 boolean) <- neq (1 integer) (3 integer))
(break-if (4 boolean))
{
((5 integer) <- copy (34 literal))
}
}
(reply)))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
((4 boolean) <- neq (1 integer) (3 integer))
(jump-if (4 boolean) (1 offset))
((5 integer) <- copy (34 literal))
(reply)))
(prn "F - convert-braces balances curlies when converting break"))
(reset)
(new-trace "convert-braces-repeated-jump")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
{
(break)
((2 integer) <- copy (5 literal))
}
{
(break)
((3 integer) <- copy (6 literal))
}
((4 integer) <- copy (7 literal))))
'(((1 integer) <- copy (4 literal))
(jump (1 offset))
((2 integer) <- copy (5 literal))
(jump (1 offset))
((3 integer) <- copy (6 literal))
((4 integer) <- copy (7 literal))))
(prn "F - convert-braces handles jumps on jumps"))
(reset)
(new-trace "convert-braces-nested-continue")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
{
((3 integer) <- add (2 integer) (2 integer))
{
((4 boolean) <- neq (1 integer) (3 integer))
}
(continue-if (4 boolean))
((5 integer) <- copy (34 literal))
}
(reply)))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (2 integer) (2 integer))
((4 boolean) <- neq (1 integer) (3 integer))
(jump-if (4 boolean) (-3 offset))
((5 integer) <- copy (34 literal))
(reply)))
(prn "F - convert-braces balances curlies when converting continue"))
(reset)
(new-trace "convert-braces-label")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
foo
((2 integer) <- copy (2 literal))))
'(((1 integer) <- copy (4 literal))
foo
((2 integer) <- copy (2 literal))))
(prn "F - convert-braces skips past labels"))
(reset)
(new-trace "convert-braces-label-increments-offset")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
{
(break)
foo
}
((2 integer) <- copy (2 literal))))
'(((1 integer) <- copy (4 literal))
(jump (1 offset))
foo
((2 integer) <- copy (2 literal))))
(prn "F - convert-braces treats labels as instructions"))
(reset)
(new-trace "convert-braces-label-increments-offset2")
(if (~iso (convert-braces
'(((1 integer) <- copy (4 literal))
{
(break)
foo
}
((2 integer) <- copy (5 literal))
{
(break)
((3 integer) <- copy (6 literal))
}
((4 integer) <- copy (7 literal))))
'(((1 integer) <- copy (4 literal))
(jump (1 offset))
foo
((2 integer) <- copy (5 literal))
(jump (1 offset))
((3 integer) <- copy (6 literal))
((4 integer) <- copy (7 literal))))
(prn "F - convert-braces treats labels as instructions - 2"))
(reset)
(new-trace "continue")
(add-fns
'((main
((1 integer) <- copy (4 literal))
((2 integer) <- copy (1 literal))
{
((2 integer) <- add (2 integer) (2 integer))
((3 boolean) <- neq (1 integer) (2 integer))
(continue-if (3 boolean))
((4 integer) <- copy (34 literal))
}
(reply))))
(run 'main)
(if (~iso memory* (obj 1 4 2 4 3 nil 4 34))
(prn "F - continue correctly loops"))
(reset)
(new-trace "continue-nested")
(add-fns
'((main
((1 integer) <- copy (4 literal))
((2 integer) <- copy (1 literal))
{
((2 integer) <- add (2 integer) (2 integer))
{
((3 boolean) <- neq (1 integer) (2 integer))
}
(continue-if (3 boolean))
((4 integer) <- copy (34 literal))
}
(reply))))
(run 'main)
(if (~iso memory* (obj 1 4 2 4 3 nil 4 34))
(prn "F - continue correctly loops"))
(reset)
(new-trace "continue-fail")
(add-fns
'((main
((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
{
((2 integer) <- add (2 integer) (2 integer))
{
((3 boolean) <- neq (1 integer) (2 integer))
}
(continue-if (3 boolean))
((4 integer) <- copy (34 literal))
}
(reply))))
(run 'main)
(if (~iso memory* (obj 1 4 2 4 3 nil 4 34))
(prn "F - continue might never trigger"))
(reset)
(new-trace "convert-names")
(if (~iso (convert-names
'(((x integer) <- copy (4 literal))
((y integer) <- copy (2 literal))
((z integer) <- add (x integer) (y integer))))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((3 integer) <- add (1 integer) (2 integer))))
(prn "F - convert-names renames symbolic names to integer locations"))
(reset)
(new-trace "convert-names-compound")
(if (~iso (convert-names
'(((x integer-boolean-pair) <- copy (4 literal))
((y integer) <- copy (2 literal))))
'(((1 integer-boolean-pair) <- copy (4 literal))
((3 integer) <- copy (2 literal))))
(prn "F - convert-names increments integer locations by the size of the type of the previous var"))
(reset)
(new-trace "convert-names-nil")
(if (~iso (convert-names
'(((x integer) <- copy (4 literal))
((y integer) <- copy (2 literal))
((nil integer) <- add (x integer) (y integer))))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((nil integer) <- add (1 integer) (2 integer))))
(prn "F - convert-names never renames nil"))
(reset)
(new-trace "convert-names-global")
(if (~iso (convert-names
'(((x integer) <- copy (4 literal))
((y integer global) <- copy (2 literal))
((default-scope integer) <- add (x integer) (y integer global))))
'(((1 integer) <- copy (4 literal))
((y integer global) <- copy (2 literal))
((default-scope integer) <- add (1 integer) (y integer global))))
(prn "F - convert-names never renames global operands"))
(reset)
(new-trace "convert-names-functions")
(if (~iso (convert-names
'(((x integer) <- copy (4 literal))
((y integer) <- copy (2 literal))
((z fn) <- add (x integer) (y integer))))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((z fn) <- add (1 integer) (2 integer))))
(prn "F - convert-names never renames nil"))
(reset)
(new-trace "convert-names-record-fields")
(if (~iso (convert-names
'(((x integer) <- get (34 integer-boolean-pair) (bool offset))))
'(((1 integer) <- get (34 integer-boolean-pair) (1 offset))))
(prn "F - convert-names replaces record field offsets"))
(reset)
(new-trace "convert-names-record-fields-ambiguous")
(if (errsafe (convert-names
'(((bool boolean) <- copy (t literal))
((x integer) <- get (34 integer-boolean-pair) (bool offset)))))
(prn "F - convert-names doesn't allow offsets and variables with the same name in a function"))
(reset)
(new-trace "convert-names-record-fields-ambiguous-2")
(if (errsafe (convert-names
'(((x integer) <- get (34 integer-boolean-pair) (bool offset))
((bool boolean) <- copy (t literal)))))
(prn "F - convert-names doesn't allow offsets and variables with the same name in a function - 2"))
(reset)
(new-trace "convert-names-record-fields-indirect")
(if (~iso (convert-names
'(((x integer) <- get (34 integer-boolean-pair-address deref) (bool offset))))
'(((1 integer) <- get (34 integer-boolean-pair-address deref) (1 offset))))
(prn "F - convert-names replaces field offsets for record addresses"))
(reset)
(new-trace "convert-names-record-fields-multiple")
(if (~iso (convert-names
'(((2 boolean) <- get (1 integer-boolean-pair) (bool offset))
((3 boolean) <- get (1 integer-boolean-pair) (bool offset))))
'(((2 boolean) <- get (1 integer-boolean-pair) (1 offset))
((3 boolean) <- get (1 integer-boolean-pair) (1 offset))))
(prn "F - convert-names replaces field offsets with multiple mentions"))
(reset)
(new-trace "convert-names-label")
(if (~iso (convert-names
'(((1 integer) <- copy (4 literal))
foo))
'(((1 integer) <- copy (4 literal))
foo))
(prn "F - convert-names skips past labels"))
(reset)
(new-trace "new-primitive")
(add-fns
'((main
((1 integer-address) <- new (integer literal)))))
(let before Memory-in-use-until
(run 'main)
(if (~iso memory*.1 before)
(prn "F - 'new' returns current high-water mark"))
(if (~iso Memory-in-use-until (+ before 1))
(prn "F - 'new' on primitive types increments high-water mark by their size")))
(reset)
(new-trace "new-array-literal")
(add-fns
'((main
((1 type-array-address) <- new (type-array literal) (5 literal)))))
(let before Memory-in-use-until
(run 'main)
(if (~iso memory*.1 before)
(prn "F - 'new' on array with literal size returns current high-water mark"))
(if (~iso Memory-in-use-until (+ before 6))
(prn "F - 'new' on primitive arrays increments high-water mark by their size")))
(reset)
(new-trace "new-array-direct")
(add-fns
'((main
((1 integer) <- copy (5 literal))
((2 type-array-address) <- new (type-array literal) (1 integer)))))
(let before Memory-in-use-until
(run 'main)
(if (~iso memory*.2 before)
(prn "F - 'new' on array with variable size returns current high-water mark"))
(if (~iso Memory-in-use-until (+ before 6))
(prn "F - 'new' on primitive arrays increments high-water mark by their (variable) size")))
(reset)
(new-trace "set-default-scope")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (2 literal))
((1 integer) <- copy (23 literal)))))
(let before Memory-in-use-until
(run 'main)
(if (~and (~is 23 memory*.1)
(is 23 (memory* (+ before 1))))
(prn "F - default-scope implicitly modifies variable locations")))
(reset)
(new-trace "set-default-scope-skips-offset")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (2 literal))
((1 integer) <- copy (23 offset)))))
(let before Memory-in-use-until
(run 'main)
(if (~and (~is 23 memory*.1)
(is 23 (memory* (+ before 1))))
(prn "F - default-scope skips 'offset' types just like literals")))
(reset)
(new-trace "default-scope-bounds-check")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (2 literal))
((2 integer) <- copy (23 literal)))))
(run 'main)
(let routine (car completed-routines*)
(if (no rep.routine!error)
(prn "F - default-scope checks bounds")))
(reset)
(new-trace "default-scope-and-get-indirect")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (5 literal))
((1 integer-boolean-pair-address) <- new (integer-boolean-pair literal))
((2 integer-address) <- get-address (1 integer-boolean-pair-address deref) (0 offset))
((2 integer-address deref) <- copy (34 literal))
((3 integer global) <- get (1 integer-boolean-pair-address deref) (0 offset)))))
(run 'main)
(each routine completed-routines*
(aif rep.routine!error (prn "error - " it)))
(if (~is 34 memory*.3)
(prn "F - indirect 'get' works in the presence of default-scope"))
(reset)
(new-trace "default-scope-and-index-indirect")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (5 literal))
((1 integer-array-address) <- new (integer-array literal) (4 literal))
((2 integer-address) <- index-address (1 integer-array-address deref) (2 offset))
((2 integer-address deref) <- copy (34 literal))
((3 integer global) <- index (1 integer-array-address deref) (2 offset)))))
(run 'main)
(each routine completed-routines*
(aif rep.routine!error (prn "error - " it)))
(if (~is 34 memory*.3)
(prn "F - indirect 'index' works in the presence of default-scope"))
(reset)
(if (~iso (convert-names
'(((x integer) <- copy (4 literal))
((y integer) <- copy (2 literal))
((default-scope integer) <- add (x integer) (y integer))))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (2 literal))
((default-scope integer) <- add (1 integer) (2 integer))))
(prn "F - convert-names never renames default-scope"))
(reset)
(new-trace "suppress-default-scope")
(add-fns
'((main
((default-scope scope-address) <- new (scope literal) (2 literal))
((1 integer global) <- copy (23 literal)))))
(let before Memory-in-use-until
(run 'main)
(if (~and (is 23 memory*.1)
(~is 23 (memory* (+ before 1))))
(prn "F - default-scope skipped for locations with metadata 'global'")))
(reset)
(new-trace "dispatch-clause")
(add-fns
'((test1
((default-scope scope-address) <- new (scope literal) (20 literal))
((first-arg-box tagged-value-address) <- arg)
{
((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
(break-unless (match? boolean))
((second-arg-box tagged-value-address) <- arg)
((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
((result integer) <- add (first-arg integer) (second-arg integer))
(reply (result integer))
}
(reply (t literal)))
(main
((1 tagged-value-address) <- new-tagged-value (integer literal) (34 literal))
((2 tagged-value-address) <- new-tagged-value (integer literal) (3 literal))
((3 integer) <- test1 (1 tagged-value-address) (2 tagged-value-address)))))
(run 'main)
(if (~is memory*.3 37)
(prn "F - an example function that checks that its oarg is an integer"))
(reset)
(new-trace "dispatch-multiple-clauses")
(add-fns
'((test1
((default-scope scope-address) <- new (scope literal) (20 literal))
((first-arg-box tagged-value-address) <- arg)
{
((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
(break-unless (match? boolean))
((second-arg-box tagged-value-address) <- arg)
((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
((result integer) <- add (first-arg integer) (second-arg integer))
(reply (result integer))
}
{
((first-arg boolean) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (boolean literal))
(break-unless (match? boolean))
((second-arg-box tagged-value-address) <- arg)
((second-arg boolean) <- maybe-coerce (second-arg-box tagged-value-address deref) (boolean literal))
((result boolean) <- or (first-arg boolean) (second-arg boolean))
(reply (result integer))
}
(reply (t literal)))
(main
((1 tagged-value-address) <- new-tagged-value (boolean literal) (t literal))
((2 tagged-value-address) <- new-tagged-value (boolean literal) (t literal))
((3 boolean) <- test1 (1 tagged-value-address) (2 tagged-value-address)))))
(run 'main)
(if (~is memory*.3 t)
(prn "F - an example function that can do different things (dispatch) based on the type of its args or oargs"))
(reset)
(new-trace "dispatch-multiple-calls")
(add-fns
'((test1
((default-scope scope-address) <- new (scope literal) (20 literal))
((first-arg-box tagged-value-address) <- arg)
{
((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
(break-unless (match? boolean))
((second-arg-box tagged-value-address) <- arg)
((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
((result integer) <- add (first-arg integer) (second-arg integer))
(reply (result integer))
}
{
((first-arg boolean) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (boolean literal))
(break-unless (match? boolean))
((second-arg-box tagged-value-address) <- arg)
((second-arg boolean) <- maybe-coerce (second-arg-box tagged-value-address deref) (boolean literal))
((result boolean) <- or (first-arg boolean) (second-arg boolean))
(reply (result integer))
}
(reply (t literal)))
(main
((1 tagged-value-address) <- new-tagged-value (boolean literal) (t literal))
((2 tagged-value-address) <- new-tagged-value (boolean literal) (t literal))
((3 boolean) <- test1 (1 tagged-value-address) (2 tagged-value-address))
((10 tagged-value-address) <- new-tagged-value (integer literal) (34 literal))
((11 tagged-value-address) <- new-tagged-value (integer literal) (3 literal))
((12 integer) <- test1 (10 tagged-value-address) (11 tagged-value-address)))))
(run 'main)
(if (~and (is memory*.3 t) (is memory*.12 37))
(prn "F - different calls can exercise different clauses of the same function"))
(reset)
(new-trace "scheduler")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal)))))
(run 'f1 'f2)
(when (~iso 2 curr-cycle*)
(prn "F - scheduler didn't run the right number of instructions: " curr-cycle*))
(if (~iso memory* (obj 1 3 2 4))
(prn "F - scheduler runs multiple functions: " memory*))
(check-trace-contents "scheduler orders functions correctly"
'(("schedule" "f1")
("schedule" "f2")
))
(check-trace-contents "scheduler orders schedule and run events correctly"
'(("schedule" "f1")
("run" "f1 0")
("schedule" "f2")
("run" "f2 0")
))
(reset)
(new-trace "scheduler-alternate")
(add-fns
'((f1
((1 integer) <- copy (3 literal))
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal))
((2 integer) <- copy (4 literal)))))
(= scheduling-interval* 1)
(run 'f1 'f2)
(check-trace-contents "scheduler alternates between routines"
'(("run" "f1 0")
("run" "f2 0")
("run" "f1 1")
("run" "f2 1")
))
(reset)
(new-trace "scheduler-sleep")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal)))))
(enq make-routine!f1 running-routines*)
(assert (is 1 len.running-routines*))
(let routine make-routine!f2
(= rep.routine!sleep '(23 literal))
(set sleeping-routines*.routine))
(= curr-cycle* 23)
(update-scheduler-state)
(if (~is 1 len.running-routines*)
(prn "F - scheduler lets routines sleep"))
(reset)
(new-trace "scheduler-wakeup")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal)))))
(enq make-routine!f1 running-routines*)
(assert (is 1 len.running-routines*))
(let routine make-routine!f2
(= rep.routine!sleep '(23 literal))
(set sleeping-routines*.routine))
(= curr-cycle* 24)
(update-scheduler-state)
(if (~is 2 len.running-routines*)
(prn "F - scheduler wakes up sleeping routines at the right time"))
(reset)
(new-trace "scheduler-sleep-location")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal)))))
(enq make-routine!f1 running-routines*)
(assert (is 1 len.running-routines*))
(let routine make-routine!f2
(= rep.routine!sleep '(23 0))
(set sleeping-routines*.routine))
(= memory*.23 0)
(update-scheduler-state)
(if (~is 1 len.running-routines*)
(prn "F - scheduler lets routines block on locations"))
(reset)
(new-trace "scheduler-wakeup-location")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal)))))
(enq make-routine!f1 running-routines*)
(assert (is 1 len.running-routines*))
(let routine make-routine!f2
(= rep.routine!sleep '(23 0))
(set sleeping-routines*.routine))
(= memory*.23 1)
(update-scheduler-state)
(if (~is 2 len.running-routines*)
(prn "F - scheduler unblocks routines blocked on locations"))
(reset)
(new-trace "scheduler-skip")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))))
(assert (empty running-routines*))
(let routine make-routine!f1
(= rep.routine!sleep '(23 literal))
(set sleeping-routines*.routine))
(= curr-cycle* 0)
(update-scheduler-state)
(assert (is curr-cycle* 24))
(if (~is 1 len.running-routines*)
(prn "F - scheduler skips ahead to earliest sleeping routines when nothing to run"))
(reset)
(new-trace "scheduler-deadlock")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))))
(assert (empty running-routines*))
(assert (empty completed-routines*))
(let routine make-routine!f1
(= rep.routine!sleep '(23 0))
(set sleeping-routines*.routine))
(= memory*.23 0)
(update-scheduler-state)
(assert (~empty completed-routines*))
(let routine completed-routines*.0
(when (~posmatch "deadlock" rep.routine!error)
(prn "F - scheduler detects deadlock")))
(reset)
(new-trace "scheduler-deadlock2")
(add-fns
'((f1
((1 integer) <- copy (3 literal)))))
(assert (empty running-routines*))
(let routine make-routine!f1
(= rep.routine!sleep '(23 0))
(set sleeping-routines*.routine))
(= memory*.23 1)
(update-scheduler-state)
(when (~empty completed-routines*)
(prn "F - scheduler ignores sleeping but ready threads when detecting deadlock"))
(reset)
(new-trace "sleep")
(add-fns
'((f1
(sleep (1 literal))
((1 integer) <- copy (3 literal))
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal))
((2 integer) <- copy (4 literal)))))
(run 'f1 'f2)
(check-trace-contents "scheduler handles sleeping routines"
'(("run" "f1 0")
("run" "sleeping until 2")
("schedule" "pushing f1 to sleep queue")
("run" "f2 0")
("run" "f2 1")
("schedule" "waking up f1")
("run" "f1 1")
("run" "f1 2")
))
(reset)
(new-trace "sleep-long")
(add-fns
'((f1
(sleep (20 literal))
((1 integer) <- copy (3 literal))
((1 integer) <- copy (3 literal)))
(f2
((2 integer) <- copy (4 literal))
((2 integer) <- copy (4 literal)))))
(run 'f1 'f2)
(check-trace-contents "scheduler progresses sleeping routines when there are no routines left to run"
'(("run" "f1 0")
("run" "sleeping until 21")
("schedule" "pushing f1 to sleep queue")
("run" "f2 0")
("run" "f2 1")
("schedule" "waking up f1")
("run" "f1 1")
("run" "f1 2")
))
(reset)
(new-trace "sleep-location")
(add-fns
'((f1
((1 integer) <- copy (0 literal))
(sleep (1 integer))
((2 integer) <- add (1 integer) (1 literal)))
(f2
(sleep (30 literal))
((1 integer) <- copy (3 literal)))))
(run 'f1 'f2)
(each routine completed-routines*
(aif rep.routine!error (prn "error - " it)))
(if (~is memory*.2 4)
(prn "F - sleep can block on a memory location"))
(reset)
(new-trace "sleep-scoped-location")
(add-fns
'((f1
((10 integer) <- copy (5 literal))
((default-scope scope-address) <- copy (10 literal))
((1 integer) <- copy (23 literal))
(sleep (1 integer))
((2 integer) <- add (1 integer) (1 literal)))
(f2
(sleep (30 literal))
((11 integer) <- copy (3 literal)))))
(run 'f1 'f2)
(if (~is memory*.12 4)
(prn "F - sleep can block on a scoped memory location"))
(reset)
(new-trace "fork")
(add-fns
'((f1
(fork (f2 fn)))
(f2
((2 integer) <- copy (4 literal)))))
(run 'f1)
(if (~iso memory*.2 4)
(prn "F - fork works"))
(reset)
(new-trace "fork-with-args")
(add-fns
'((f1
(fork (f2 fn) (4 literal)))
(f2
((2 integer) <- arg))))
(run 'f1)
(if (~iso memory*.2 4)
(prn "F - fork can pass args"))
(reset)
(new-trace "fork-copies-args")
(add-fns
'((f1
((default-scope scope-address) <- new (scope literal) (5 literal))
((x integer) <- copy (4 literal))
(fork (f2 fn) (x integer))
((x integer) <- copy (0 literal)))
(f2
((2 integer) <- arg))))
(run 'f1)
(if (~iso memory*.2 4)
(prn "F - fork passes args by value"))
(reset)
(new-trace "array-bounds-check")
(add-fns
'((main
((1 integer) <- copy (2 literal))
((2 integer) <- copy (23 literal))
((3 integer) <- copy (24 literal))
((4 integer) <- index (1 integer-array) (2 literal)))))
(run 'main)
(let routine (car completed-routines*)
(if (no rep.routine!error)
(prn "F - 'index' throws an error if out of bounds")))
(reset)
(new-trace "channel-new")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer) <- get (1 channel-address deref) (first-full offset))
((3 integer) <- get (1 channel-address deref) (first-free offset)))))
(run 'main)
(if (or (~is 0 memory*.2)
(~is 0 memory*.3))
(prn "F - 'new-channel' initializes 'first-full and 'first-free to 0"))
(reset)
(new-trace "channel-write")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((4 integer) <- get (1 channel-address deref) (first-full offset))
((5 integer) <- get (1 channel-address deref) (first-free offset)))))
(run 'main)
(if (or (~is 0 memory*.4)
(~is 1 memory*.5))
(prn "F - 'write' enqueues item to channel"))
(reset)
(new-trace "channel-read")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((4 tagged-value) (1 channel-address deref) <- read (1 channel-address))
((6 integer-address) <- maybe-coerce (4 tagged-value) (integer-address literal))
((7 integer) <- get (1 channel-address deref) (first-full offset))
((8 integer) <- get (1 channel-address deref) (first-free offset)))))
(run 'main)
(if (~is memory*.6 memory*.2)
(prn "F - 'read' returns written value"))
(if (or (~is 1 memory*.7)
(~is 1 memory*.8))
(prn "F - 'read' dequeues item from channel"))
(reset)
(new-trace "channel-write-wrap")
(add-fns
'((main
((1 channel-address) <- new-channel (1 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((4 integer) <- get (1 channel-address deref) (first-free offset))
(_ (1 channel-address deref) <- read (1 channel-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((5 integer) <- get (1 channel-address deref) (first-free offset)))))
(run 'main)
(if (or (~is 1 memory*.4)
(~is 0 memory*.5))
(prn "F - 'write' can wrap pointer back to start"))
(reset)
(new-trace "channel-read-wrap")
(add-fns
'((main
((1 channel-address) <- new-channel (1 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
(_ (1 channel-address deref) <- read (1 channel-address))
((4 integer) <- get (1 channel-address deref) (first-full offset))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
(_ (1 channel-address deref) <- read (1 channel-address))
((5 integer) <- get (1 channel-address deref) (first-full offset)))))
(run 'main)
(if (or (~is 1 memory*.4)
(~is 0 memory*.5))
(prn "F - 'read' can wrap pointer back to start"))
(reset)
(new-trace "channel-new-empty-not-full")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 boolean) <- empty? (1 channel-address deref))
((3 boolean) <- full? (1 channel-address deref)))))
(run 'main)
(if (or (~is t memory*.2)
(~is nil memory*.3))
(prn "F - a new channel is always empty, never full"))
(reset)
(new-trace "channel-write-not-empty")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((4 boolean) <- empty? (1 channel-address deref))
((5 boolean) <- full? (1 channel-address deref)))))
(run 'main)
(if (or (~is nil memory*.4)
(~is nil memory*.5))
(prn "F - a channel after writing is never empty"))
(reset)
(new-trace "channel-write-full")
(add-fns
'((main
((1 channel-address) <- new-channel (1 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((4 boolean) <- empty? (1 channel-address deref))
((5 boolean) <- full? (1 channel-address deref)))))
(run 'main)
(if (or (~is nil memory*.4)
(~is t memory*.5))
(prn "F - a channel after writing may be full"))
(reset)
(new-trace "channel-read-not-full")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
(_ (1 channel-address deref) <- read (1 channel-address))
((4 boolean) <- empty? (1 channel-address deref))
((5 boolean) <- full? (1 channel-address deref)))))
(run 'main)
(if (or (~is nil memory*.4)
(~is nil memory*.5))
(prn "F - a channel after reading is never full"))
(reset)
(new-trace "channel-read-empty")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
(_ (1 channel-address deref) <- read (1 channel-address))
((4 boolean) <- empty? (1 channel-address deref))
((5 boolean) <- full? (1 channel-address deref)))))
(run 'main)
(if (or (~is t memory*.4)
(~is nil memory*.5))
(prn "F - a channel after reading may be empty"))
(reset)
(new-trace "channel-read-block")
(add-fns
'((main
((1 channel-address) <- new-channel (3 literal))
((2 tagged-value) (1 channel-address deref) <- read (1 channel-address)))))
(run 'main)
(let routine (car completed-routines*)
(when (or (no routine)
(no rep.routine!error)
(~posmatch "deadlock" rep.routine!error))
(prn "F - 'read' on empty channel blocks (puts the routine to sleep until the channel gets data)")))
(reset)
(new-trace "channel-write-block")
(add-fns
'((main
((1 channel-address) <- new-channel (1 literal))
((2 integer-address) <- new (integer literal))
((2 integer-address deref) <- copy (34 literal))
((3 tagged-value-address) <- new-tagged-value (integer-address literal) (2 integer-address))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref))
((1 channel-address deref) <- write (1 channel-address) (3 tagged-value-address deref)))))
(run 'main)
(let routine (car completed-routines*)
(when (or (no routine)
(no rep.routine!error)
(~posmatch "deadlock" rep.routine!error))
(prn "F - 'write' on full channel blocks (puts the routine to sleep until the channel gets data)")))
(reset)
(new-trace "channel-handoff")
(add-fns
'((f1
((default-scope scope-address) <- new (scope literal) (30 literal))
((chan channel-address) <- new-channel (3 literal))
(fork (f2 fn) (chan channel-address))
((1 tagged-value global) <- read (chan channel-address)))
(f2
((default-scope scope-address) <- new (scope literal) (30 literal))
((n integer-address) <- new (integer literal))
((n integer-address deref) <- copy (24 literal))
((ochan channel-address) <- arg)
((x tagged-value-address) <- new-tagged-value (integer-address literal) (n integer-address))
((ochan channel-address deref) <- write (ochan channel-address) (x tagged-value-address deref)))))
(run 'f1)
(each routine completed-routines*
(aif rep.routine!error (prn "error - " it)))
(if (~is 24 (memory* memory*.2))
(prn "F - channels are meant to be shared between routines"))
(reset)
(if (~iso (convert-quotes
'(((1 integer) <- copy (4 literal))
(defer [
((3 integer) <- copy (6 literal))
])
((2 integer) <- copy (5 literal))))
'(((1 integer) <- copy (4 literal))
((2 integer) <- copy (5 literal))
((3 integer) <- copy (6 literal))))
(prn "F - convert-quotes can handle 'defer'"))
(reset)