4262 - literal 'null'

This commit is contained in:
Kartik Agaram 2018-06-17 11:20:53 -07:00
parent dd66068298
commit 01ce563dfe
48 changed files with 268 additions and 246 deletions

View File

@ -90,13 +90,6 @@ type foo = bar
type foo = baz
+error: 'type' conflict: 'foo' defined as both 'bar' and 'baz'
:(scenario type_abbreviation_for_compound)
type foo = address:number
def main [
a:foo <- copy 0
]
+transform: product type after expanding abbreviations: ("address" "number")
//: cleaning up type abbreviations between tests and before exiting
:(before "End save_snapshots")
@ -129,13 +122,6 @@ put(Type_abbreviations, "num", new_type_tree("number"));
put(Type_abbreviations, "bool", new_type_tree("boolean"));
put(Type_abbreviations, "char", new_type_tree("character"));
:(scenario use_type_abbreviations_when_declaring_type_abbreviations)
type foo = &:num
def main [
a:foo <- copy 0
]
+transform: product type after expanding abbreviations: ("address" "number")
//:: Expand type aliases before running.
//: We'll do this in a transform so that we don't need to define abbreviations
//: before we use them.

View File

@ -102,15 +102,19 @@ bool types_match(const reagent& to, const reagent& from) {
if (is_literal(from)) {
if (is_mu_array(to)) return false;
// End Matching Types For Literal(to)
// allow writing 0 to any address
if (is_mu_address(to)) return from.name == "0";
if (!to.type) return false;
if (is_mu_address(to)) return types_match_literal_to_address(from);
// End Literal types_match Special-cases
return size_of(to) == 1; // literals are always scalars
}
return types_strictly_match(to, from);
}
bool types_match_literal_to_address(const reagent& from) {
// End Literal->Address types_match(from) Special-cases
return false;
}
//: copy arguments for later layers
bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) {
// End Preprocess types_strictly_match(reagent to, reagent from)

View File

@ -3,6 +3,8 @@
:(before "End Mu Types Initialization")
put(Type_ordinal, "literal-boolean", 0);
//: 'true'
:(scenario true)
def main [
1:boolean <- copy true
@ -21,6 +23,8 @@ if (name == "true") {
:(before "End Literal types_match Special-cases")
if (is_mu_boolean(to)) return from.name == "false" || from.name == "true";
//: 'false'
:(scenario false)
def main [
1:boolean <- copy false
@ -36,3 +40,50 @@ if (name == "false") {
type = new type_tree("literal-boolean");
set_value(0);
}
//: 'null'
:(scenario null)
def main [
1:address:number <- copy null
]
+mem: storing 0 in location 1
:(scenario null_has_wildcard_type)
def main [
1:address:boolean <- copy null
]
+mem: storing 0 in location 1
:(before "End Mu Types Initialization")
put(Type_ordinal, "literal-address", 0);
:(before "End Parsing reagent")
if (name == "null") {
if (type != NULL) {
raise << "'null' is a literal and can't take a type\n" << end();
return;
}
type = new type_tree("literal-address");
set_value(0);
}
:(before "End Literal->Address types_match(from) Special-cases")
// allow writing null to any address
if (from.name == "null") return true;
//: scenarios for type abbreviations that we couldn't write until now
:(scenario type_abbreviation_for_compound)
type foo = address:number
def main [
1:foo <- copy null
]
+transform: product type after expanding abbreviations: ("address" "number")
:(scenario use_type_abbreviations_when_declaring_type_abbreviations)
type foo = &:num
def main [
1:foo <- copy null
]
+transform: product type after expanding abbreviations: ("address" "number")

View File

@ -31,7 +31,7 @@ canonize(x);
:(scenario store_to_0_fails)
% Hide_errors = true;
def main [
1:address:num <- copy 0
1:address:num <- copy null
1:address:num/lookup <- copy 34
]
-mem: storing 34 in location 0
@ -41,7 +41,7 @@ def main [
:(scenario lookup_0_fails)
% Hide_errors = true;
def main [
1:address:num <- copy 0
1:address:num <- copy null
2:num <- copy 1:address:num/lookup
]
+error: main: tried to lookup 0 in '2:num <- copy 1:address:num/lookup'
@ -49,14 +49,14 @@ def main [
:(scenario lookup_0_dumps_callstack)
% Hide_errors = true;
def main [
foo 0
foo null
]
def foo [
1:address:num <- next-input
2:num <- copy 1:address:num/lookup
]
+error: foo: tried to lookup 0 in '2:num <- copy 1:address:num/lookup'
+error: called from main: foo 0
+error: called from main: foo null
:(code)
void canonize(reagent& x) {

View File

@ -245,7 +245,7 @@ else {
:(scenario transform_names_transforms_container_elements)
def main [
p:&:point <- copy 0
p:&:point <- copy null
a:num <- get *p:&:point, y:offset
b:num <- get *p:&:point, x:offset
]

View File

@ -153,7 +153,7 @@ def foo [ # dummy
]
def main [
local-scope
0:space/names:foo <- copy 0 # specify surrounding space
0:space/names:foo <- copy null # specify surrounding space
x:bool <- copy true
x:num/space:1 <- copy 34
x/space:1 <- copy 35

View File

@ -439,33 +439,6 @@ container foo [
]
$error: 0
:(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses)
def main [
1:num <- foo 0
]
def foo x:&:num -> y:num [
return 34
]
def foo x:num -> y:num [
return 35
]
+mem: storing 35 in location 1
:(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses_2)
def main [
1:num <- foo 0 0
]
# Both variants need to bind 0 to address in first ingredient.
# We still want to prefer the variant with a number rather than address for
# _subsequent_ ingredients.
def foo x:&:num y:&:num -> z:num [ # put the bad match before the good one
return 34
]
def foo x:&:num y:num -> z:num [
return 35
]
+mem: storing 35 in location 1
:(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers)
% Hide_errors = true;
def main [

View File

@ -178,7 +178,7 @@ bool concrete_type_names_strictly_match(const type_tree* to, const type_tree* fr
if (to->atom && is_type_ingredient_name(to->name)) return true; // type ingredient matches anything
if (!to->atom && to->right == NULL && to->left != NULL && to->left->atom && is_type_ingredient_name(to->left->name)) return true;
if (from->atom && is_mu_address(to))
return from->name == "literal" && rhs_reagent.name == "0";
return from->name == "literal-address" && rhs_reagent.name == "null";
if (!from->atom && !to->atom)
return concrete_type_names_strictly_match(to->left, from->left, rhs_reagent)
&& concrete_type_names_strictly_match(to->right, from->right, rhs_reagent);
@ -330,7 +330,7 @@ void compute_type_ingredient_mappings(const recipe& exemplar, const instruction&
const reagent& exemplar_reagent = exemplar.ingredients.at(i);
reagent/*copy*/ ingredient = inst.ingredients.at(i);
canonize_type(ingredient);
if (is_mu_address(exemplar_reagent) && ingredient.name == "0") continue; // assume it matches
if (is_mu_address(exemplar_reagent) && ingredient.name == "null") continue; // assume it matches
accumulate_type_ingredients(exemplar_reagent, ingredient, mappings, exemplar, inst, caller_recipe, error);
}
limit = min(SIZE(inst.products), SIZE(exemplar.products));
@ -662,7 +662,7 @@ def main [
def bar x:_t -> result:&:_t [
local-scope
load-ingredients
result <- copy 0
result <- copy null
]
$error: 0
@ -782,7 +782,7 @@ def foo x:_elem -> y:_elem [
def main [
local-scope
# permit '0' to map to address to shape-shifting type-ingredient
1:&:char/raw <- foo 0
1:&:char/raw <- foo null
]
def foo x:&:_elem -> y:&:_elem [
local-scope
@ -953,7 +953,7 @@ def foo x:&:_elem -> y:num [
# version with headers padded with lots of unrelated concrete types
def main [
1:num <- copy 23
2:&:@:num <- copy 0
2:&:@:num <- copy null
3:num <- foo 2:&:@:num, 1:num
]
# variant with concrete type
@ -1023,7 +1023,7 @@ def foo x:&:_elem -> y:num [
:(scenario specialize_literal_as_address)
def main [
1:num <- foo 0
1:num <- foo null
]
# variant with concrete address type
def foo x:&:num -> y:num [

View File

@ -110,7 +110,7 @@ def foo x:&:num [
local-scope
load-ingredients
# modify the address, not the payload
x <- copy 0
x <- copy null
]
$error: 0
@ -207,7 +207,7 @@ def main [
def foo a:&:foo [
local-scope
load-ingredients
b:foo <- merge 0
b:foo <- merge null
# modify b, completely unrelated to immutable ingredient a
x:&:@:num <- get b, x:offset
*x <- put-index *x, 0, 34
@ -596,7 +596,7 @@ container test-list [
def foo x:&:test-list/contained-in:result -> result:&:test-list [
local-scope
load-ingredients
result <- copy 0
result <- copy null
]
$error: 0

View File

@ -86,10 +86,10 @@ scenario text-equal-with-empty [
scenario text-equal-with-null [
local-scope
x:text <- new [abcd]
y:text <- copy 0
y:text <- copy null
run [
10:bool/raw <- equal x, 0
11:bool/raw <- equal 0, x
10:bool/raw <- equal x, null
11:bool/raw <- equal null, x
12:bool/raw <- equal x, y
13:bool/raw <- equal y, x
14:bool/raw <- equal y, y
@ -339,7 +339,7 @@ def buffer-to-array in:&:buffer:_elem -> result:&:@:_elem [
local-scope
load-inputs
# propagate null buffer
return-unless in, 0
return-unless in, null
len:num <- get *in, length:offset
s:&:@:_elem <- get *in, data:offset
# we can't just return s because it is usually the wrong length
@ -406,7 +406,7 @@ scenario text-append-1 [
scenario text-append-null [
local-scope
x:text <- copy 0
x:text <- copy null
y:text <- new [ world!]
run [
z:text <- append x, y
@ -420,7 +420,7 @@ scenario text-append-null [
scenario text-append-null-2 [
local-scope
x:text <- new [hello,]
y:text <- copy 0
y:text <- copy null
run [
z:text <- append x, y
10:@:char/raw <- copy *z

View File

@ -30,7 +30,7 @@ def rest in:&:list:_elem -> result:&:list:_elem/contained-in:in [
scenario list-handling [
run [
local-scope
x:&:list:num <- push 3, 0
x:&:list:num <- push 3, null
x <- push 4, x
x <- push 5, x
10:num/raw <- first x
@ -73,7 +73,7 @@ def insert x:_elem, in:&:list:_elem -> in:&:list:_elem [
scenario inserting-into-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -99,7 +99,7 @@ scenario inserting-into-list [
scenario inserting-at-end-of-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -126,7 +126,7 @@ scenario inserting-at-end-of-list [
scenario inserting-after-start-of-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -160,7 +160,7 @@ def remove x:&:list:_elem/contained-in:in, in:&:list:_elem -> in:&:list:_elem [
return-unless x
next-node:&:list:_elem <- rest x
# clear next pointer of 'x'
*x <- put *x, next:offset, 0
*x <- put *x, next:offset, null
# if 'x' is at the head of 'in', return the new head
at-head?:bool <- equal x, in
return-if at-head?, next-node
@ -180,13 +180,13 @@ def remove x:&:list:_elem/contained-in:in, in:&:list:_elem -> in:&:list:_elem [
scenario removing-from-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
list2:&:list:num <- rest list # second element
list <- remove list2, list
10:bool/raw <- equal list2, 0
10:bool/raw <- equal list2, null
# check structure like before
list2 <- copy list
11:num/raw <- first list2
@ -204,7 +204,7 @@ scenario removing-from-list [
scenario removing-from-start-of-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -225,7 +225,7 @@ scenario removing-from-start-of-list [
scenario removing-from-end-of-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -233,7 +233,7 @@ scenario removing-from-end-of-list [
list2:&:list:num <- rest list
list2 <- rest list2
list <- remove list2, list
10:bool/raw <- equal list2, 0
10:bool/raw <- equal list2, null
# check structure like before
list2 <- copy list
11:num/raw <- first list2
@ -251,7 +251,7 @@ scenario removing-from-end-of-list [
scenario removing-from-singleton-list [
local-scope
list:&:list:num <- push 3, 0
list:&:list:num <- push 3, null
run [
list <- remove list, list
1:num/raw <- deaddress list
@ -275,7 +275,7 @@ def reverse list:&:list:_elem temp:&:list:_elem/contained-in:result -> result:&:
scenario reverse-list [
local-scope
list:&:list:num <- push 1, 0
list:&:list:num <- push 1, null
list <- push 2, list
list <- push 3, list
run [
@ -291,7 +291,7 @@ scenario reverse-list [
scenario stash-list [
local-scope
list:&:list:num <- push 1, 0
list:&:list:num <- push 1, null
list <- push 2, list
list <- push 3, list
run [
@ -356,7 +356,7 @@ def to-buffer in:&:list:_elem, buf:&:buffer:char -> buf:&:buffer:char [
scenario stash-empty-list [
local-scope
x:&:list:num <- copy 0
x:&:list:num <- copy null
run [
stash x
]

View File

@ -10,7 +10,7 @@ def push x:_elem, in:&:duplex-list:_elem/contained-in:result -> result:&:duplex-
local-scope
load-inputs
result:&:duplex-list:_elem <- new {(duplex-list _elem): type}
*result <- merge x, in, 0
*result <- merge x, in, null
return-unless in
put *in, prev:offset, result
]
@ -18,21 +18,27 @@ def push x:_elem, in:&:duplex-list:_elem/contained-in:result -> result:&:duplex-
def first in:&:duplex-list:_elem -> result:_elem [
local-scope
load-inputs
return-unless in, 0
{
break-if in
zero:&:_elem <- new _elem:type
zero-result:_elem <- copy *zero
abandon zero
return zero-result
}
result <- get *in, value:offset
]
def next in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
local-scope
load-inputs
return-unless in, 0
return-unless in, null
result <- get *in, next:offset
]
def prev in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
local-scope
load-inputs
return-unless in, 0
return-unless in, null
result <- get *in, prev:offset
return result
]
@ -43,7 +49,7 @@ scenario duplex-list-handling [
# reserve locations 0-9 to check for missing null check
10:num/raw <- copy 34
11:num/raw <- copy 35
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
list2:&:duplex-list:num <- copy list
@ -108,7 +114,7 @@ def insert x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
scenario inserting-into-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -145,7 +151,7 @@ scenario inserting-into-duplex-list [
scenario inserting-at-end-of-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -183,7 +189,7 @@ scenario inserting-at-end-of-duplex-list [
scenario inserting-after-start-of-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -229,8 +235,8 @@ def remove x:&:duplex-list:_elem/contained-in:in, in:&:duplex-list:_elem -> in:&
next-node:&:duplex-list:_elem <- get *x, next:offset
prev-node:&:duplex-list:_elem <- get *x, prev:offset
# null x's pointers
*x <- put *x, next:offset, 0
*x <- put *x, prev:offset, 0
*x <- put *x, next:offset, null
*x <- put *x, prev:offset, null
# if next-node is not null, set its prev pointer
{
break-unless next-node
@ -249,13 +255,13 @@ def remove x:&:duplex-list:_elem/contained-in:in, in:&:duplex-list:_elem -> in:&
scenario removing-from-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
list2:&:duplex-list:num <- next list # second element
list <- remove list2, list
10:bool/raw <- equal list2, 0
10:bool/raw <- equal list2, null
# check structure like before
list2 <- copy list
11:num/raw <- first list2
@ -278,7 +284,7 @@ scenario removing-from-duplex-list [
scenario removing-from-start-of-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -304,7 +310,7 @@ scenario removing-from-start-of-duplex-list [
scenario removing-from-end-of-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -312,7 +318,7 @@ scenario removing-from-end-of-duplex-list [
list2:&:duplex-list:num <- next list
list2 <- next list2
list <- remove list2, list
10:bool/raw <- equal list2, 0
10:bool/raw <- equal list2, null
# check structure like before
list2 <- copy list
11:num/raw <- first list2
@ -335,7 +341,7 @@ scenario removing-from-end-of-duplex-list [
scenario removing-from-singleton-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
run [
list <- remove list, list
1:num/raw <- deaddress list
@ -364,7 +370,7 @@ def remove x:&:duplex-list:_elem/contained-in:in, n:num, in:&:duplex-list:_elem
scenario removing-multiple-from-duplex-list [
local-scope
list:&:duplex-list:num <- push 3, 0
list:&:duplex-list:num <- push 3, null
list <- push 4, list
list <- push 5, list
run [
@ -391,21 +397,21 @@ def remove-between start:&:duplex-list:_elem, end:&:duplex-list:_elem/contained-
assert next, [malformed duplex list]
# start->next->prev = 0
# start->next = end
*next <- put *next, prev:offset, 0
*next <- put *next, prev:offset, null
*start <- put *start, next:offset, end
return-unless end
# end->prev->next = 0
# end->prev = start
prev:&:duplex-list:_elem <- get *end, prev:offset
assert prev, [malformed duplex list - 2]
*prev <- put *prev, next:offset, 0
*prev <- put *prev, next:offset, null
*end <- put *end, prev:offset, start
]
scenario remove-range [
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
local-scope
list:&:duplex-list:num <- push 18, 0
list:&:duplex-list:num <- push 18, null
list <- push 17, list
list <- push 16, list
list <- push 15, list
@ -416,7 +422,7 @@ scenario remove-range [
# first pointer: to the third element
list2:&:duplex-list:num <- next list
list2 <- next list2
list2 <- remove-between list2, 0
list2 <- remove-between list2, null
# now check the list
10:num/raw <- get *list, value:offset
list <- next list
@ -436,7 +442,7 @@ scenario remove-range [
scenario remove-range-to-final [
local-scope
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
list:&:duplex-list:num <- push 18, 0
list:&:duplex-list:num <- push 18, null
list <- push 17, list
list <- push 16, list
list <- push 15, list
@ -471,7 +477,7 @@ scenario remove-range-to-final [
scenario remove-range-empty [
local-scope
# construct a duplex list with three elements [13, 14, 15]
list:&:duplex-list:num <- push 15, 0
list:&:duplex-list:num <- push 15, null
list <- push 14, list
list <- push 13, list
run [
@ -498,7 +504,7 @@ scenario remove-range-empty [
scenario remove-range-to-end [
local-scope
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
list:&:duplex-list:num <- push 18, 0
list:&:duplex-list:num <- push 18, null
list <- push 17, list
list <- push 16, list
list <- push 15, list
@ -507,7 +513,7 @@ scenario remove-range-to-end [
run [
# remove the third element and beyond
list2:&:duplex-list:num <- next list
remove-between list2, 0
remove-between list2, null
# now check the list
10:num/raw <- get *list, value:offset
list <- next list
@ -604,7 +610,7 @@ def match x:&:duplex-list:_elem, y:&:@:_elem -> result:bool [
scenario duplex-list-match [
local-scope
list:&:duplex-list:char <- push 97/a, 0
list:&:duplex-list:char <- push 97/a, null
list <- push 98/b, list
list <- push 99/c, list
list <- push 100/d, list
@ -649,7 +655,7 @@ def dump-from x:&:duplex-list:_elem [
scenario stash-duplex-list [
local-scope
list:&:duplex-list:num <- push 1, 0
list:&:duplex-list:num <- push 1, null
list <- push 2, list
list <- push 3, list
run [
@ -714,7 +720,7 @@ def to-buffer in:&:duplex-list:_elem, buf:&:buffer:char -> buf:&:buffer:char [
scenario stash-empty-duplex-list [
local-scope
x:&:duplex-list:num <- copy 0
x:&:duplex-list:num <- copy null
run [
stash x
]

View File

@ -7,7 +7,7 @@ container stream:_elem [
def new-stream s:&:@:_elem -> result:&:stream:_elem [
local-scope
load-inputs
return-unless s, 0/null
return-unless s, null
result <- new {(stream _elem): type}
*result <- put *result, index:offset, 0
*result <- put *result, data:offset, s

View File

@ -183,7 +183,7 @@ def main [
:(scenario hash_of_zero_address)
def main [
1:&:num <- copy 0
1:&:num <- copy null
2:num <- hash 1:&:num
]
+mem: storing 0 in location 2

View File

@ -389,7 +389,7 @@ if (is_mu_recipe(to)) {
:(scenario call_variable_compound_ingredient)
def main [
{1: (recipe (address number) -> number)} <- copy f
2:&:num <- copy 0
2:&:num <- copy null
3:num <- call {1: (recipe (address number) -> number)}, 2:&:num
]
def f x:&:num -> y:num [

View File

@ -909,6 +909,6 @@ def print screen:&:screen, n:&:_elem -> screen:&:screen [
break-if bg-color-found?
bg-color <- copy 0/black
}
n2:num <- copy n
n2:num <- deaddress n
screen <- print screen, n2, color, bg-color
]

View File

@ -30,7 +30,7 @@ def start-reading resources:&:resources, filename:text -> contents:&:source:char
}
# real file system
file:num <- $open-file-for-reading filename
return-unless file, 0/contents, true/error
return-unless file, null/no-contents, true/error
contents:&:source:char, sink:&:sink:char <- new-channel 30
start-running receive-from-file file, sink
]
@ -39,7 +39,7 @@ def slurp resources:&:resources, filename:text -> contents:text, error?:bool [
local-scope
load-inputs
source:&:source:char, error?:bool <- start-reading resources, filename
return-if error?, 0/contents
return-if error?, null/no-contents
buf:&:buffer:char <- new-buffer 30/capacity
{
c:char, done?:bool, source <- read source
@ -70,7 +70,7 @@ def start-reading-from-fake-resource resources:&:resources, resource:text -> con
start-running receive-from-text curr-contents, sink
return
}
return 0/not-found, true/error-found
return null/no-such-resource, true/error-found
]
def receive-from-file file:num, sink:&:sink:char -> sink:&:sink:char [
@ -115,7 +115,7 @@ def start-writing resources:&:resources, filename:text -> sink:&:sink:char, rout
}
# real file system
file:num <- $open-file-for-writing filename
return-unless file, 0/sink, 0/routine-id, true/error
return-unless file, null/sink, 0/routine-id, true/error
{
break-if file
msg:text <- append [no such file: ] filename
@ -175,7 +175,7 @@ def transmit-to-fake-resource resources:&:resources, filename:text, source:&:sou
contents:text <- buffer-to-array buf
new-resource:resource <- merge filename, contents
# write to resources
curr-filename:text <- copy 0
curr-filename:text <- copy null
data:&:@:resource <- get *resources, data:offset
# replace file contents if it already exists
i:num <- copy 0

View File

@ -7,14 +7,14 @@ scenario example-server-test [
# that way repeatedly running the test will give ports time to timeout and
# close before reusing them
make-random-nondeterministic
port:num <- random-in-range 0/real-random-numbers, 8000, 8100
port:num <- random-in-range null/real-random-numbers, 8000, 8100
run [
socket:num <- $open-server-socket port
assert socket, [
F - example-server-test: $open-server-socket failed]
handler-routine:number <- start-running serve-one-request socket, example-handler
]
source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port
source:&:source:char <- start-reading-from-network null/real-resources, [localhost/], port
response:text <- drain source
10:@:char/raw <- copy *response
memory-should-contain [

View File

@ -4,16 +4,16 @@
def main [
local-scope
open-console # take control of screen, keyboard and mouse
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
# The chessboard function takes keyboard and screen objects as inputs.
#
# In Mu it is good form (though not required) to explicitly state what
# hardware a function needs.
#
# Here the console and screen are both 0, which usually indicates real
# Here the console and screen are both null, which usually indicates real
# hardware rather than a fake for testing as you'll see below.
chessboard 0/screen, 0/console
chessboard null/screen, null/console
close-console # clean up screen, keyboard and mouse
]
@ -249,27 +249,27 @@ def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool,
local-scope
load-inputs
from-file:num, quit?:bool, error?:bool <- read-file stdin, screen
return-if quit?, 0/dummy
return-if error?, 0/dummy
return-if quit?, null/dummy
return-if error?, null/dummy
# construct the move object
result:&:move <- new move:type
*result <- put *result, from-file:offset, from-file
from-rank:num, quit?, error? <- read-rank stdin, screen
return-if quit?, 0/dummy
return-if error?, 0/dummy
return-if quit?, null/dummy
return-if error?, null/dummy
*result <- put *result, from-rank:offset, from-rank
error? <- expect-from-channel stdin, 45/dash, screen
return-if error?, 0/dummy, false/quit
return-if error?, null/dummy, false/quit
to-file:num, quit?, error? <- read-file stdin, screen
return-if quit?, 0/dummy
return-if error?, 0/dummy
return-if quit?, null/dummy
return-if error?, null/dummy
*result <- put *result, to-file:offset, to-file
to-rank:num, quit?, error? <- read-rank stdin, screen
return-if quit?, 0/dummy
return-if error?, 0/dummy
return-if quit?, null/dummy
return-if error?, null/dummy
*result <- put *result, to-rank:offset, to-rank
error? <- expect-from-channel stdin, 10/newline, screen
return-if error?, 0/dummy, false/quit
return-if error?, null/dummy, false/quit
]
# valid values for file: 0-7

View File

@ -13,7 +13,7 @@
def main [
local-scope
l:&:list:num <- copy 0
l:&:list:num <- copy null
l <- push 3, l
l <- push 2, l
l <- push 1, l
@ -30,8 +30,8 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
local-scope
load-inputs
return-continuation-until-mark 100/mark
done? <- equal l, 0/nil
return-if done?, false
done? <- equal l, null
return-if done?, 0/dummy
n <- first l
l <- rest l
]

View File

@ -15,7 +15,7 @@
def main [
local-scope
l:&:list:num <- copy 0
l:&:list:num <- copy null
l <- push 3, l
l <- push 2, l
l <- push 1, l
@ -32,7 +32,7 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
local-scope
load-inputs
{
done? <- equal l, 0
done? <- equal l, null
break-if done?
n <- first l
l <- rest l

View File

@ -16,7 +16,7 @@
def main [
local-scope
l:&:list:num <- copy 0
l:&:list:num <- copy null
l <- push 3, l
l <- push 2, l
l <- push 1, l
@ -36,7 +36,7 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
load-inputs
a:num <- copy 0
{
done? <- equal l, 0
done? <- equal l, null
break-if done?
n <- first l
l <- rest l

View File

@ -6,10 +6,10 @@ def main text:text [
local-scope
load-inputs
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
e:&:editor <- new-editor text, 0/left, 5/right
render 0/screen, e
wait-for-event 0/console
render null/screen, e
wait-for-event null/console
close-console
]
@ -61,7 +61,7 @@ def new-editor s:text, left:num, right:num -> result:&:editor [
*result <- put *result, cursor-row:offset, 1/top
*result <- put *result, cursor-column:offset, left
# initialize empty contents
init:&:duplex-list:char <- push 167/§, 0/tail
init:&:duplex-list:char <- push 167/§, null
*result <- put *result, data:offset, init
*result <- put *result, top-of-screen:offset, init
*result <- put *result, before-cursor:offset, init
@ -80,7 +80,7 @@ scenario editor-initializes-without-data [
local-scope
assume-screen 5/width, 3/height
run [
e:&:editor <- new-editor 0/data, 2/left, 5/right
e:&:editor <- new-editor null/data, 2/left, 5/right
2:editor/raw <- copy *e
]
memory-should-contain [

View File

@ -6,10 +6,10 @@ def! main text:text [
local-scope
load-inputs
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
editor:&:editor <- new-editor text, 5/left, 45/right
editor-render 0/screen, editor
editor-event-loop 0/screen, 0/console, editor
editor-render null/screen, editor
editor-event-loop null/screen, null/console, editor
close-console
]
@ -223,7 +223,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
next:&:duplex-list:char <- next before-cursor
{
# at end of all text? no need to scroll? just print the character and leave
at-end?:bool <- equal next, 0/null
at-end?:bool <- equal next, null
break-unless at-end?
bottom:num <- subtract screen-height, 1
at-bottom?:bool <- equal save-row, bottom
@ -701,7 +701,7 @@ after <insert-character-special-case> [
just-before-wrap?:bool <- greater-or-equal cursor-column, before-wrap-column
next:&:duplex-list:char <- next before-cursor
# at end of line? next == 0 || next.value == 10/newline
at-end-of-line?:bool <- equal next, 0
at-end-of-line?:bool <- equal next, null
{
break-if at-end-of-line?
next-character:char <- get *next, value:offset

View File

@ -113,7 +113,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
data:&:duplex-list:char <- get *editor, data:offset
# if at start of text (before-cursor at § sentinel), return
prev:&:duplex-list:char <- prev before-cursor
return-unless prev, false/no-more-render, 0/nothing-deleted
return-unless prev, false/no-more-render, null/nothing-deleted
trace 10, [app], [delete-before-cursor]
original-row:num <- get *editor, cursor-row:offset
scroll?:bool <- move-cursor-coordinates-left editor
@ -2616,7 +2616,7 @@ def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&
start:&:duplex-list:char <- get *editor, before-cursor:offset
end:&:duplex-list:char <- next start
{
at-end-of-text?:bool <- equal end, 0/null
at-end-of-text?:bool <- equal end, null
break-if at-end-of-text?
curr:char <- get *end, value:offset
at-end-of-line?:bool <- equal curr, 10/newline

View File

@ -6,10 +6,10 @@
def! main [
local-scope
open-console
clear-screen 0/screen # non-scrolling app
env:&:environment <- new-programming-environment 0/filesystem, 0/screen
render-all 0/screen, env, render
event-loop 0/screen, 0/console, env, 0/filesystem
clear-screen null/screen # non-scrolling app
env:&:environment <- new-programming-environment null/filesystem, null/screen
render-all null/screen, env, render
event-loop null/screen, null/console, env, null/filesystem
]
container environment [

View File

@ -10,11 +10,11 @@
def! main [
local-scope
open-console
clear-screen 0/screen # non-scrolling app
env:&:environment <- new-programming-environment 0/filesystem, 0/screen
env <- restore-sandboxes env, 0/filesystem
render-all 0/screen, env, render
event-loop 0/screen, 0/console, env, 0/filesystem
clear-screen null/screen # non-scrolling app
env:&:environment <- new-programming-environment null/filesystem, null/screen
env <- restore-sandboxes env, null/filesystem
render-all null/screen, env, render
event-loop null/screen, null/console, env, null/filesystem
]
container environment [
@ -170,7 +170,7 @@ def run-sandboxes env:&:environment, resources:&:resources, screen:&:screen -> e
# needs to be before running them, in case we die when running
save-sandboxes env, resources
# clear sandbox editor
init:&:duplex-list:char <- push 167/§, 0/tail
init:&:duplex-list:char <- push 167/§, null
*current-sandbox <- put *current-sandbox, data:offset, init
*current-sandbox <- put *current-sandbox, top-of-screen:offset, init
}
@ -475,8 +475,8 @@ def restore-sandboxes env:&:environment, resources:&:resources -> env:&:environm
load-inputs
# read all scenarios, pushing them to end of a list of scenarios
idx:num <- copy 0
curr:&:sandbox <- copy 0
prev:&:sandbox <- copy 0
curr:&:sandbox <- copy null
prev:&:sandbox <- copy null
{
filename:text <- append [lesson/], idx
contents:text <- slurp resources, filename
@ -686,7 +686,7 @@ def editor-contents editor:&:editor -> result:text [
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
return-unless curr, 0
return-unless curr, null
{
break-unless curr
c:char <- get *curr, value:offset
@ -939,15 +939,15 @@ after <global-keypress> [
]
# sandbox belonging to 'env' whose next-sandbox is 'in'
# return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
# return null if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [
local-scope
load-inputs
curr:&:sandbox <- get *env, sandbox:offset
return-unless curr, 0/nil
return-unless curr, null
next:&:sandbox <- get *curr, next-sandbox:offset
{
return-unless next, 0/nil
return-unless next, null
found?:bool <- equal next, in
break-if found?
curr <- copy next

View File

@ -184,7 +184,7 @@ def find-sandbox env:&:environment, click-row:num -> result:&:sandbox [
curr-sandbox <- get *curr-sandbox, next-sandbox:offset
loop
}
return 0/not-found
return null/not-found
]
def click-on-sandbox-area? click-row:num, click-column:num, env:&:environment -> result:bool [

View File

@ -171,9 +171,9 @@ def find-click-in-sandbox-output env:&:environment, click-row:num -> sandbox:&:s
}
# return sandbox if click is in its output region
response-starting-row:num <- get *sandbox, response-starting-row-on-screen:offset
return-unless response-starting-row, 0/no-click-in-sandbox-output, 0/sandbox-index
return-unless response-starting-row, null/no-click-in-sandbox-output, 0/sandbox-index
click-in-response?:bool <- greater-or-equal click-row, response-starting-row
return-unless click-in-response?, 0/no-click-in-sandbox-output, 0/sandbox-index
return-unless click-in-response?, null/no-click-in-sandbox-output, 0/sandbox-index
return sandbox, sandbox-index
]
@ -184,7 +184,7 @@ def toggle-expected-response sandbox:&:sandbox -> sandbox:&:sandbox [
{
# if expected-response is set, reset
break-unless expected-response
*sandbox <- put *sandbox, expected-response:offset, 0
*sandbox <- put *sandbox, expected-response:offset, null
}
{
# if not, set expected response to the current response

View File

@ -235,7 +235,7 @@ def find-click-in-sandbox-code env:&:environment, click-row:num -> sandbox:&:san
click-on-sandbox-code?:bool <- and click-above-response?, click-below-menu?
{
break-if click-on-sandbox-code?
return 0/no-click-in-sandbox-output
return null/no-click-in-sandbox-output
}
return sandbox
]

View File

@ -310,7 +310,7 @@ scenario run-updates-errors-for-shape-shifting-recipes [
|recipe foo x:_elem -> z:_elem [|
| local-scope|
| load-ingredients|
| y:&:num <- copy 0|
| y:&:num <- copy null|
| z <- add x, y|
|]|
]
@ -326,7 +326,7 @@ scenario run-updates-errors-for-shape-shifting-recipes [
.recipe foo x:_elem -> z:_elem [ ┊ .
. local-scope ┊─────────────────────────────────────────────────.
. load-ingredients ┊0 edit copy to recipe delete .
. y:&:num <- copy 0 ┊foo 2 .
. y:&:num <- copy null ┊foo 2 .
. z <- add x, y ┊foo_2: 'add' requires number ingredients, but go↩.
.] ┊t 'y' .
. ┊─────────────────────────────────────────────────.
@ -346,7 +346,7 @@ scenario run-updates-errors-for-shape-shifting-recipes [
.recipe foo x:_elem -> z:_elem [ ┊ .
. local-scope ┊─────────────────────────────────────────────────.
. load-ingredients ┊0 edit copy to recipe delete .
. y:&:num <- copy 0 ┊foo 2 .
. y:&:num <- copy null ┊foo 2 .
. z <- add x, y ┊foo_3: 'add' requires number ingredients, but go↩.
.] ┊t 'y' .
. ┊─────────────────────────────────────────────────.
@ -367,7 +367,7 @@ scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [
]
]
# call code that uses other variants of it, but not it itself
test-sandbox:text <- new [x:&:list:num <- copy 0
test-sandbox:text <- new [x:&:list:num <- copy null
to-text x]
env:&:environment <- new-programming-environment resources, screen, test-sandbox
render-all screen, env, render

View File

@ -206,7 +206,7 @@ def add-operation editor:&:editor, op:&:operation -> editor:&:editor [
undo <- push op undo
*editor <- put *editor, undo:offset, undo
redo:&:list:&:operation <- get *editor, redo:offset
redo <- copy 0
redo <- copy null
*editor <- put *editor, redo:offset, redo
]

View File

@ -5,8 +5,8 @@
def main [
local-scope
source-file:&:source:char <- start-reading 0/real-filesystem, [/tmp/mu-x]
sink-file:&:sink:char, write-routine:num <- start-writing 0/real-filesystem, [/tmp/mu-y]
source-file:&:source:char <- start-reading null/real-filesystem, [/tmp/mu-x]
sink-file:&:sink:char, write-routine:num <- start-writing null/real-filesystem, [/tmp/mu-y]
{
c:char, done?:bool, source-file <- read source-file
break-if done?

View File

@ -3,7 +3,7 @@
def main [
local-scope
$print [aaa] 10/newline
google:&:source:char <- start-reading-from-network 0/real-resources, [google.com/]
google:&:source:char <- start-reading-from-network null/real-resources, [google.com/]
$print [bbb] 10/newline
n:num <- copy 0
buf:&:buffer:char <- new-buffer 30
@ -21,9 +21,9 @@ def main [
}
result:text <- buffer-to-array buf
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
len:num <- length *result
print 0/real-screen, result
print null/real-screen, result
wait-for-some-interaction
close-console
]

View File

@ -22,7 +22,7 @@ result <- add a t1]
def lambda-to-mu in:text -> out:text [
local-scope
load-inputs
out <- copy 0
out <- copy null
cells:&:cell <- parse in
out <- to-mu cells
]
@ -84,7 +84,7 @@ scenario pair-is-not-atom [
# construct (a . nil)
s:text <- new [a]
x:&:cell <- new-atom s
y:&:cell <- new-pair x, 0/nil
y:&:cell <- new-pair x, null
10:bool/raw <- is-atom? y
11:bool/raw <- is-pair? y
memory-should-contain [
@ -114,7 +114,7 @@ def first x:&:cell -> result:&:cell [
local-scope
load-inputs
pair:pair, pair?:bool <- maybe-convert *x, pair:variant
return-unless pair?, 0/nil
return-unless pair?, null
result <- get pair, first:offset
]
@ -122,7 +122,7 @@ def rest x:&:cell -> result:&:cell [
local-scope
load-inputs
pair:pair, pair?:bool <- maybe-convert *x, pair:variant
return-unless pair?, 0/nil
return-unless pair?, null
result <- get pair, rest:offset
]
@ -161,7 +161,7 @@ scenario cell-operations-on-pair [
# construct (a . nil)
s:text <- new [a]
x:&:cell <- new-atom s
y:&:cell <- new-pair x, 0/nil
y:&:cell <- new-pair x, null
x2:&:cell <- first y
10:bool/raw <- equal x, x2
11:&:cell/raw <- rest y
@ -187,7 +187,7 @@ def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
# skip whitespace
in <- skip-whitespace in
c:char, eof?:bool <- peek in
return-if eof?, 0/nil
return-if eof?, null
pair?:bool <- equal c, 40/open-paren
{
break-if pair?
@ -223,7 +223,7 @@ def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
close-paren?:bool <- equal c, 41/close-paren
break-if close-paren?
first:&:cell, in <- parse in
*out <- merge 1/pair, first, 0/nil
*out <- merge 1/pair, first, null
}
# read in any remaining elements
curr:&:cell <- copy out
@ -245,7 +245,7 @@ def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
is-dot?:bool <- atom-match? next, [.]
{
break-if is-dot?
next-curr:&:cell <- new-pair next, 0/nil
next-curr:&:cell <- new-pair next, null
curr <- set-rest curr, next-curr
curr <- rest curr
}
@ -276,7 +276,7 @@ def skip-whitespace in:&:stream:char -> in:&:stream:char [
load-inputs
{
done?:bool <- end-of-stream? in
return-if done?, 0/null
return-if done?, null
c:char <- peek in
space?:bool <- space? c
break-unless space?
@ -586,5 +586,5 @@ def to-mu in:&:cell, buf:&:buffer:char -> buf:&:buffer:char, result-name:text [
# null cell? no change.
# pair with all atoms? gensym a new variable
# pair containing other pairs? recurse
result-name <- copy 0
result-name <- copy null
]

1
mu.vim
View File

@ -55,6 +55,7 @@ syntax match muLiteral %[^ ]\+:type/[^ ,]*\|[^ ]\+:type\>%
syntax match muLiteral %[^ ]\+:offset/[^ ,]*\|[^ ]\+:offset\>%
syntax match muLiteral %[^ ]\+:variant/[^ ,]*\|[^ ]\+:variant\>%
syntax match muLiteral % true\(\/[^ ]*\)\?\| false\(\/[^ ]*\)\?% " literals will never be the first word in an instruction
syntax match muLiteral % null\(\/[^ ]*\)\?%
highlight link muLiteral Constant
" sources of action at a distance

View File

@ -6,10 +6,10 @@ def main text:text [
local-scope
load-inputs
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
e:&:editor <- new-editor text, 0/left, 5/right
render 0/screen, e
wait-for-event 0/console
render null/screen, e
wait-for-event null/console
close-console
]
@ -61,7 +61,7 @@ def new-editor s:text, left:num, right:num -> result:&:editor [
*result <- put *result, cursor-row:offset, 1/top
*result <- put *result, cursor-column:offset, left
# initialize empty contents
init:&:duplex-list:char <- push 167/§, 0/tail
init:&:duplex-list:char <- push 167/§, null
*result <- put *result, data:offset, init
*result <- put *result, top-of-screen:offset, init
*result <- put *result, before-cursor:offset, init
@ -80,7 +80,7 @@ scenario editor-initializes-without-data [
local-scope
assume-screen 5/width, 3/height
run [
e:&:editor <- new-editor 0/data, 2/left, 5/right
e:&:editor <- new-editor null/data, 2/left, 5/right
2:editor/raw <- copy *e
]
memory-should-contain [

View File

@ -6,10 +6,10 @@ def! main text:text [
local-scope
load-inputs
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
editor:&:editor <- new-editor text, 5/left, 45/right
editor-render 0/screen, editor
editor-event-loop 0/screen, 0/console, editor
editor-render null/screen, editor
editor-event-loop null/screen, null/console, editor
close-console
]
@ -223,7 +223,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
next:&:duplex-list:char <- next before-cursor
{
# at end of all text? no need to scroll? just print the character and leave
at-end?:bool <- equal next, 0/null
at-end?:bool <- equal next, null
break-unless at-end?
bottom:num <- subtract screen-height, 1
at-bottom?:bool <- equal save-row, bottom
@ -701,7 +701,7 @@ after <insert-character-special-case> [
just-before-wrap?:bool <- greater-or-equal cursor-column, before-wrap-column
next:&:duplex-list:char <- next before-cursor
# at end of line? next == 0 || next.value == 10/newline
at-end-of-line?:bool <- equal next, 0
at-end-of-line?:bool <- equal next, null
{
break-if at-end-of-line?
next-character:char <- get *next, value:offset

View File

@ -113,7 +113,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
data:&:duplex-list:char <- get *editor, data:offset
# if at start of text (before-cursor at § sentinel), return
prev:&:duplex-list:char <- prev before-cursor
return-unless prev, false/no-more-render, 0/nothing-deleted
return-unless prev, false/no-more-render, null/nothing-deleted
trace 10, [app], [delete-before-cursor]
original-row:num <- get *editor, cursor-row:offset
move-cursor-coordinates-left editor
@ -2353,7 +2353,7 @@ def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&
start:&:duplex-list:char <- get *editor, before-cursor:offset
end:&:duplex-list:char <- next start
{
at-end-of-text?:bool <- equal end, 0/null
at-end-of-text?:bool <- equal end, null
break-if at-end-of-text?
curr:char <- get *end, value:offset
at-end-of-line?:bool <- equal curr, 10/newline

View File

@ -3,10 +3,10 @@
def! main [
local-scope
open-console
clear-screen 0/screen # non-scrolling app
env:&:environment <- new-programming-environment 0/filesystem, 0/screen
render-all 0/screen, env, render
event-loop 0/screen, 0/console, env, 0/filesystem
clear-screen null/screen # non-scrolling app
env:&:environment <- new-programming-environment null/filesystem, null/screen
render-all null/screen, env, render
event-loop null/screen, null/console, env, null/filesystem
]
container environment [

View File

@ -10,11 +10,11 @@
def! main [
local-scope
open-console
clear-screen 0/screen # non-scrolling app
env:&:environment <- new-programming-environment 0/filesystem, 0/screen
env <- restore-sandboxes env, 0/filesystem
render-all 0/screen, env, render
event-loop 0/screen, 0/console, env, 0/filesystem
clear-screen null/screen # non-scrolling app
env:&:environment <- new-programming-environment null/filesystem, null/screen
env <- restore-sandboxes env, null/filesystem
render-all null/screen, env, render
event-loop null/screen, null/console, env, null/filesystem
]
container environment [
@ -160,7 +160,7 @@ def run-sandboxes env:&:environment, resources:&:resources, screen:&:screen -> e
# needs to be before running them, in case we die when running
save-sandboxes env, resources
# clear sandbox editor
init:&:duplex-list:char <- push 167/§, 0/tail
init:&:duplex-list:char <- push 167/§, null
*current-sandbox <- put *current-sandbox, data:offset, init
*current-sandbox <- put *current-sandbox, top-of-screen:offset, init
}
@ -458,8 +458,8 @@ def restore-sandboxes env:&:environment, resources:&:resources -> env:&:environm
load-inputs
# read all scenarios, pushing them to end of a list of scenarios
idx:num <- copy 0
curr:&:sandbox <- copy 0
prev:&:sandbox <- copy 0
curr:&:sandbox <- copy null
prev:&:sandbox <- copy null
{
filename:text <- append [lesson/], idx
contents:text <- slurp resources, filename
@ -668,7 +668,7 @@ def editor-contents editor:&:editor -> result:text [
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
return-unless curr, 0
return-unless curr, null
{
break-unless curr
c:char <- get *curr, value:offset
@ -817,15 +817,15 @@ after <global-keypress> [
]
# sandbox belonging to 'env' whose next-sandbox is 'in'
# return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
# return null if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox
def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [
local-scope
load-inputs
curr:&:sandbox <- get *env, sandbox:offset
return-unless curr, 0/nil
return-unless curr, null
next:&:sandbox <- get *curr, next-sandbox:offset
{
return-unless next, 0/nil
return-unless next, null
found?:bool <- equal next, in
break-if found?
curr <- copy next

View File

@ -194,7 +194,7 @@ def find-sandbox env:&:environment, click-row:num -> result:&:sandbox [
curr-sandbox <- get *curr-sandbox, next-sandbox:offset
loop
}
return 0/not-found
return null/not-found
]
def click-on-sandbox-area? click-row:num, env:&:environment -> result:bool [

View File

@ -173,9 +173,9 @@ def find-click-in-sandbox-output env:&:environment, click-row:num -> sandbox:&:s
}
# return sandbox if click is in its output region
response-starting-row:num <- get *sandbox, response-starting-row-on-screen:offset
return-unless response-starting-row, 0/no-click-in-sandbox-output, 0/sandbox-index
return-unless response-starting-row, null/no-click-in-sandbox-output, 0/sandbox-index
click-in-response?:bool <- greater-or-equal click-row, response-starting-row
return-unless click-in-response?, 0/no-click-in-sandbox-output, 0/sandbox-index
return-unless click-in-response?, null/no-click-in-sandbox-output, 0/sandbox-index
return sandbox, sandbox-index
]
@ -186,7 +186,7 @@ def toggle-expected-response sandbox:&:sandbox -> sandbox:&:sandbox [
{
# if expected-response is set, reset
break-unless expected-response
*sandbox <- put *sandbox, expected-response:offset, 0
*sandbox <- put *sandbox, expected-response:offset, null
}
{
# if not, set expected response to the current response

View File

@ -225,7 +225,7 @@ def find-click-in-sandbox-code env:&:environment, click-row:num -> sandbox:&:san
click-on-sandbox-code?:bool <- and click-above-response?, click-below-menu?
{
break-if click-on-sandbox-code?
return 0/no-click-in-sandbox-output
return null/no-click-in-sandbox-output
}
return sandbox
]

View File

@ -253,7 +253,7 @@ scenario run-updates-errors-for-shape-shifting-recipes [
|recipe foo x:_elem -> z:_elem [|
| local-scope|
| load-ingredients|
| y:&:num <- copy 0|
| y:&:num <- copy null|
| z <- add x, y|
|]|
]
@ -308,7 +308,7 @@ scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [
]
]
# call code that uses other variants of it, but not it itself
test-sandbox:text <- new [x:&:list:num <- copy 0
test-sandbox:text <- new [x:&:list:num <- copy null
to-text x]
env:&:environment <- new-programming-environment resources, screen, test-sandbox
render-all screen, env, render

View File

@ -204,7 +204,7 @@ def add-operation editor:&:editor, op:&:operation -> editor:&:editor [
undo <- push op undo
*editor <- put *editor, undo:offset, undo
redo:&:list:&:operation <- get *editor, redo:offset
redo <- copy 0
redo <- copy null
*editor <- put *editor, redo:offset, redo
]

View File

@ -4,26 +4,26 @@
# screens.
def main [
open-console
clear-screen 0/screen # non-scrolling app
clear-screen null/screen # non-scrolling app
10:char <- copy 97/a
print 0/screen, 10:char/a, 1/red, 2/green
1:num/raw, 2:num/raw <- cursor-position 0/screen
wait-for-event 0/console
clear-screen 0/screen
move-cursor 0/screen, 0/row, 4/column
print null/screen, 10:char/a, 1/red, 2/green
1:num/raw, 2:num/raw <- cursor-position null/screen
wait-for-event null/console
clear-screen null/screen
move-cursor null/screen, 0/row, 4/column
10:char <- copy 98/b
print 0/screen, 10:char
wait-for-event 0/console
move-cursor 0/screen, 0/row, 0/column
clear-line 0/screen
wait-for-event 0/console
cursor-down 0/screen
wait-for-event 0/console
cursor-right 0/screen
wait-for-event 0/console
cursor-left 0/screen
wait-for-event 0/console
cursor-up 0/screen
wait-for-event 0/console
print null/screen, 10:char
wait-for-event null/console
move-cursor null/screen, 0/row, 0/column
clear-line null/screen
wait-for-event null/console
cursor-down null/screen
wait-for-event null/console
cursor-right null/screen
wait-for-event null/console
cursor-left null/screen
wait-for-event null/console
cursor-up null/screen
wait-for-event null/console
close-console
]

View File

@ -31,7 +31,8 @@ function! HighlightTangledFile()
syntax match muLiteral %[^ ]\+:type/[^ ,]*\|[^ ]\+:type\>%
syntax match muLiteral %[^ ]\+:offset/[^ ,]*\|[^ ]\+:offset\>%
syntax match muLiteral %[^ ]\+:variant/[^ ,]*\|[^ ]\+:variant\>%
syntax keyword muLiteral true false null
syntax match muLiteral % true\(\/[^ ]*\)\?\| false\(\/[^ ]*\)\?% " literals will never be the first word in an instruction
syntax match muLiteral % null\(\/[^ ]*\)\?%
highlight link muLiteral Constant
syntax match muAssign " <- \|\<raw\>" | highlight link muAssign SpecialChar
" common keywords