2735 - define recipes using 'def'

I'm dropping all mention of 'recipe' terminology from the Readme. That
way I hope to avoid further bike-shedding discussions while I very
slowly decide on the right terminology with my students.

I could be smarter in my error messages and use 'recipe' when code uses
it and 'function' otherwise. But what about other words like ingredient?
It would all add complexity that I'm not yet sure is worthwhile. But I
do want separate experiences for veteran programmers reading about Mu on
github and for people learning programming using Mu.
This commit is contained in:
Kartik K. Agaram 2016-03-08 01:30:14 -08:00
parent 27ba0937a3
commit 1ead356219
98 changed files with 1344 additions and 1342 deletions

View File

@ -2,7 +2,7 @@
:(scenarios load) // use 'load' instead of 'run' in all scenarios in this layer
:(scenario first_recipe)
recipe main [
def main [
1:number <- copy 23
]
+parse: instruction: copy
@ -24,10 +24,10 @@ vector<recipe_ordinal> load(istream& in) {
if (!has_data(in)) break;
string command = next_word(in);
// Command Handlers
if (command == "recipe") {
if (command == "recipe" || command == "def") {
result.push_back(slurp_recipe(in));
}
else if (command == "recipe!") {
else if (command == "recipe!" || command == "def!") {
Disable_redefine_checks = true;
result.push_back(slurp_recipe(in));
Disable_redefine_checks = false;
@ -248,9 +248,10 @@ void clear_recently_added_recipes() {
:(scenario parse_comment_outside_recipe)
# this comment will be dropped by the tangler, so we need a dummy recipe to stop that
recipe f1 [ ]
def f1 [
]
# this comment will go through to 'load'
recipe main [
def main [
1:number <- copy 23
]
+parse: instruction: copy
@ -258,7 +259,7 @@ recipe main [
+parse: product: 1: "number"
:(scenario parse_comment_amongst_instruction)
recipe main [
def main [
# comment
1:number <- copy 23
]
@ -267,7 +268,7 @@ recipe main [
+parse: product: 1: "number"
:(scenario parse_comment_amongst_instruction_2)
recipe main [
def main [
# comment
1:number <- copy 23
# comment
@ -277,7 +278,7 @@ recipe main [
+parse: product: 1: "number"
:(scenario parse_comment_amongst_instruction_3)
recipe main [
def main [
1:number <- copy 23
# comment
2:number <- copy 23
@ -290,7 +291,7 @@ recipe main [
+parse: product: 2: "number"
:(scenario parse_comment_after_instruction)
recipe main [
def main [
1:number <- copy 23 # comment
]
+parse: instruction: copy
@ -298,19 +299,19 @@ recipe main [
+parse: product: 1: "number"
:(scenario parse_label)
recipe main [
def main [
+foo
]
+parse: label: +foo
:(scenario parse_dollar_as_recipe_name)
recipe main [
def main [
$foo
]
+parse: instruction: $foo
:(scenario parse_multiple_properties)
recipe main [
def main [
1:number <- copy 23/foo:bar:baz
]
+parse: instruction: copy
@ -318,7 +319,7 @@ recipe main [
+parse: product: 1: "number"
:(scenario parse_multiple_products)
recipe main [
def main [
1:number, 2:number <- copy 23
]
+parse: instruction: copy
@ -327,7 +328,7 @@ recipe main [
+parse: product: 2: "number"
:(scenario parse_multiple_ingredients)
recipe main [
def main [
1:number, 2:number <- copy 23, 4:number
]
+parse: instruction: copy
@ -337,7 +338,7 @@ recipe main [
+parse: product: 2: "number"
:(scenario parse_multiple_types)
recipe main [
def main [
1:number, 2:address:number <- copy 23, 4:number
]
+parse: instruction: copy
@ -347,7 +348,7 @@ recipe main [
+parse: product: 2: ("address" "number")
:(scenario parse_properties)
recipe main [
def main [
1:address:number/lookup <- copy 23
]
+parse: product: 1: ("address" "number"), {"lookup": ()}
@ -365,19 +366,19 @@ void test_parse_comment_terminated_by_eof() {
:(scenario forbid_redefining_recipes)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 23
]
recipe main [
def main [
1:number <- copy 24
]
+error: redefining recipe main
:(scenario permit_forcibly_redefining_recipes)
recipe main [
def main [
1:number <- copy 23
]
recipe! main [
def! main [
1:number <- copy 24
]
-error: redefining recipe main

View File

@ -7,13 +7,13 @@
:(scenarios load)
:(scenario string_literal)
recipe main [
def main [
1:address:array:character <- copy [abc def] # copy can't really take a string
]
+parse: ingredient: "abc def": "literal-string"
:(scenario string_literal_with_colons)
recipe main [
def main [
1:address:array:character <- copy [abc:def/ghi]
]
+parse: ingredient: "abc:def/ghi": "literal-string"
@ -145,26 +145,26 @@ void strip_last(string& s) {
}
:(scenario string_literal_nested)
recipe main [
def main [
1:address:array:character <- copy [abc [def]]
]
+parse: ingredient: "abc [def]": "literal-string"
:(scenario string_literal_escaped)
recipe main [
def main [
1:address:array:character <- copy [abc \[def]
]
+parse: ingredient: "abc [def": "literal-string"
:(scenario string_literal_escaped_comment_aware)
recipe main [
def main [
1:address:array:character <- copy [
abc \\\[def]
]
+parse: ingredient: "\nabc \[def": "literal-string"
:(scenario string_literal_and_comment)
recipe main [
def main [
1:address:array:character <- copy [abc] # comment
]
+parse: --- defining main
@ -174,14 +174,14 @@ recipe main [
+parse: product: 1: ("address" "array" "character")
:(scenario string_literal_escapes_newlines_in_trace)
recipe main [
def main [
copy [abc
def]
]
+parse: ingredient: "abc\ndef": "literal-string"
:(scenario string_literal_can_skip_past_comments)
recipe main [
def main [
copy [
# ']' inside comment
bar
@ -190,7 +190,7 @@ recipe main [
+parse: ingredient: "\n # ']' inside comment\n bar\n ": "literal-string"
:(scenario string_literal_empty)
recipe main [
def main [
copy []
]
+parse: ingredient: "": "literal-string"

View File

@ -2,7 +2,7 @@
:(scenarios load)
:(scenario noninteger_literal)
recipe main [
def main [
1:number <- copy 3.14159
]
+parse: ingredient: 3.14159: "literal-fractional-number"

View File

@ -10,14 +10,14 @@
//: another. Later layers will add more primitives.
:(scenario copy_literal)
recipe main [
def main [
1:number <- copy 23
]
+run: 1:number <- copy 23
+mem: storing 23 in location 1
:(scenario copy)
recipe main [
def main [
1:number <- copy 23
2:number <- copy 1:number
]
@ -26,7 +26,7 @@ recipe main [
+mem: storing 23 in location 2
:(scenario copy_multiple)
recipe main [
def main [
1:number, 2:number <- copy 23, 24
]
+mem: storing 23 in location 1
@ -330,7 +330,7 @@ void run(string form) {
}
:(scenario run_label)
recipe main [
def main [
+foo
1:number <- copy 23
2:number <- copy 1:number
@ -340,14 +340,14 @@ recipe main [
-run: +foo
:(scenario run_dummy)
recipe main [
def main [
_ <- copy 0
]
+run: _ <- copy 0
:(scenario write_to_0_disallowed)
% Hide_errors = true;
recipe main [
def main [
0:number <- copy 34
]
-mem: storing 34 in location 0
@ -356,25 +356,25 @@ recipe main [
//: to put spaces around the '<-'.
:(scenario comma_without_space)
recipe main [
def main [
1:number, 2:number <- copy 2,2
]
+mem: storing 2 in location 1
:(scenario space_without_comma)
recipe main [
def main [
1:number, 2:number <- copy 2 2
]
+mem: storing 2 in location 1
:(scenario comma_before_space)
recipe main [
def main [
1:number, 2:number <- copy 2, 2
]
+mem: storing 2 in location 1
:(scenario comma_after_space)
recipe main [
def main [
1:number, 2:number <- copy 2 ,2
]
+mem: storing 2 in location 1

View File

@ -46,34 +46,34 @@ void check_instruction(const recipe_ordinal r) {
:(scenario copy_checks_reagent_count)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 34, 35
]
+error: ingredients and products should match in '1:number <- copy 34, 35'
:(scenario write_scalar_to_array_disallowed)
% Hide_errors = true;
recipe main [
def main [
1:array:number <- copy 34
]
+error: main: can't copy 34 to 1:array:number; types don't match
:(scenario write_scalar_to_array_disallowed_2)
% Hide_errors = true;
recipe main [
def main [
1:number, 2:array:number <- copy 34, 35
]
+error: main: can't copy 35 to 2:array:number; types don't match
:(scenario write_scalar_to_address_disallowed)
% Hide_errors = true;
recipe main [
def main [
1:address:number <- copy 34
]
+error: main: can't copy 34 to 1:address:number; types don't match
:(scenario write_address_to_number_allowed)
recipe main [
def main [
1:address:number <- copy 12/unsafe
2:number <- copy 1:address:number
]
@ -81,7 +81,7 @@ recipe main [
$error: 0
:(scenario write_boolean_to_number_allowed)
recipe main [
def main [
1:boolean <- copy 1/true
2:number <- copy 1:boolean
]
@ -89,7 +89,7 @@ recipe main [
$error: 0
:(scenario write_number_to_boolean_allowed)
recipe main [
def main [
1:number <- copy 34
2:boolean <- copy 1:number
]

View File

@ -35,13 +35,13 @@ case ADD: {
}
:(scenario add_literal)
recipe main [
def main [
1:number <- add 23, 34
]
+mem: storing 57 in location 1
:(scenario add)
recipe main [
def main [
1:number <- copy 23
2:number <- copy 34
3:number <- add 1:number, 2:number
@ -49,21 +49,21 @@ recipe main [
+mem: storing 57 in location 3
:(scenario add_multiple)
recipe main [
def main [
1:number <- add 3, 4, 5
]
+mem: storing 12 in location 1
:(scenario add_checks_type)
% Hide_errors = true;
recipe main [
def main [
1:number <- add 2:boolean, 1
]
+error: main: 'add' requires number ingredients, but got 2:boolean
:(scenario add_checks_return_type)
% Hide_errors = true;
recipe main [
def main [
1:address:number <- add 2, 2
]
+error: main: 'add' should yield a number, but got 1:address:number
@ -110,13 +110,13 @@ bool is_raw(const reagent& r) {
}
:(scenario subtract_literal)
recipe main [
def main [
1:number <- subtract 5, 2
]
+mem: storing 3 in location 1
:(scenario subtract)
recipe main [
def main [
1:number <- copy 23
2:number <- copy 34
3:number <- subtract 1:number, 2:number
@ -124,7 +124,7 @@ recipe main [
+mem: storing -11 in location 3
:(scenario subtract_multiple)
recipe main [
def main [
1:number <- subtract 6, 3, 2
]
+mem: storing 1 in location 1
@ -163,13 +163,13 @@ case MULTIPLY: {
}
:(scenario multiply_literal)
recipe main [
def main [
1:number <- multiply 2, 3
]
+mem: storing 6 in location 1
:(scenario multiply)
recipe main [
def main [
1:number <- copy 4
2:number <- copy 6
3:number <- multiply 1:number, 2:number
@ -177,7 +177,7 @@ recipe main [
+mem: storing 24 in location 3
:(scenario multiply_multiple)
recipe main [
def main [
1:number <- multiply 2, 3, 4
]
+mem: storing 24 in location 1
@ -219,13 +219,13 @@ case DIVIDE: {
}
:(scenario divide_literal)
recipe main [
def main [
1:number <- divide 8, 2
]
+mem: storing 4 in location 1
:(scenario divide)
recipe main [
def main [
1:number <- copy 27
2:number <- copy 3
3:number <- divide 1:number, 2:number
@ -233,7 +233,7 @@ recipe main [
+mem: storing 9 in location 3
:(scenario divide_multiple)
recipe main [
def main [
1:number <- divide 12, 3, 2
]
+mem: storing 2 in location 1
@ -287,14 +287,14 @@ case DIVIDE_WITH_REMAINDER: {
}
:(scenario divide_with_remainder_literal)
recipe main [
def main [
1:number, 2:number <- divide-with-remainder 9, 2
]
+mem: storing 4 in location 1
+mem: storing 1 in location 2
:(scenario divide_with_remainder)
recipe main [
def main [
1:number <- copy 27
2:number <- copy 11
3:number, 4:number <- divide-with-remainder 1:number, 2:number
@ -303,20 +303,20 @@ recipe main [
+mem: storing 5 in location 4
:(scenario divide_with_decimal_point)
recipe main [
def main [
1:number <- divide 5, 2
]
+mem: storing 2.5 in location 1
:(scenario divide_by_zero)
recipe main [
def main [
1:number <- divide 4, 0
]
+mem: storing inf in location 1
:(scenario divide_by_zero_2)
% Hide_errors = true;
recipe main [
def main [
1:number <- divide-with-remainder 4, 0
]
# integer division can't return floating-point infinity
@ -364,32 +364,32 @@ case SHIFT_LEFT: {
}
:(scenario shift_left_by_zero)
recipe main [
def main [
1:number <- shift-left 1, 0
]
+mem: storing 1 in location 1
:(scenario shift_left_1)
recipe main [
def main [
1:number <- shift-left 1, 4
]
+mem: storing 16 in location 1
:(scenario shift_left_2)
recipe main [
def main [
1:number <- shift-left 3, 2
]
+mem: storing 12 in location 1
:(scenario shift_left_by_negative)
% Hide_errors = true;
recipe main [
def main [
1:number <- shift-left 3, -1
]
+error: main: second ingredient can't be negative in '1:number <- shift-left 3, -1'
:(scenario shift_left_ignores_fractional_part)
recipe main [
def main [
1:number <- divide 3, 2
2:number <- shift-left 1:number, 1
]
@ -435,32 +435,32 @@ case SHIFT_RIGHT: {
}
:(scenario shift_right_by_zero)
recipe main [
def main [
1:number <- shift-right 1, 0
]
+mem: storing 1 in location 1
:(scenario shift_right_1)
recipe main [
def main [
1:number <- shift-right 1024, 1
]
+mem: storing 512 in location 1
:(scenario shift_right_2)
recipe main [
def main [
1:number <- shift-right 3, 1
]
+mem: storing 1 in location 1
:(scenario shift_right_by_negative)
% Hide_errors = true;
recipe main [
def main [
1:number <- shift-right 4, -1
]
+error: main: second ingredient can't be negative in '1:number <- shift-right 4, -1'
:(scenario shift_right_ignores_fractional_part)
recipe main [
def main [
1:number <- divide 3, 2
2:number <- shift-right 1:number, 1
]
@ -501,25 +501,25 @@ case AND_BITS: {
}
:(scenario and_bits_1)
recipe main [
def main [
1:number <- and-bits 8, 3
]
+mem: storing 0 in location 1
:(scenario and_bits_2)
recipe main [
def main [
1:number <- and-bits 3, 2
]
+mem: storing 2 in location 1
:(scenario and_bits_3)
recipe main [
def main [
1:number <- and-bits 14, 3
]
+mem: storing 2 in location 1
:(scenario and_bits_negative)
recipe main [
def main [
1:number <- and-bits -3, 4
]
+mem: storing 4 in location 1
@ -559,19 +559,19 @@ case OR_BITS: {
}
:(scenario or_bits_1)
recipe main [
def main [
1:number <- or-bits 3, 8
]
+mem: storing 11 in location 1
:(scenario or_bits_2)
recipe main [
def main [
1:number <- or-bits 3, 10
]
+mem: storing 11 in location 1
:(scenario or_bits_3)
recipe main [
def main [
1:number <- or-bits 4, 6
]
+mem: storing 6 in location 1
@ -611,19 +611,19 @@ case XOR_BITS: {
}
:(scenario xor_bits_1)
recipe main [
def main [
1:number <- xor-bits 3, 8
]
+mem: storing 11 in location 1
:(scenario xor_bits_2)
recipe main [
def main [
1:number <- xor-bits 3, 10
]
+mem: storing 9 in location 1
:(scenario xor_bits_3)
recipe main [
def main [
1:number <- xor-bits 4, 6
]
+mem: storing 2 in location 1
@ -662,25 +662,25 @@ case FLIP_BITS: {
}
:(scenario flip_bits_zero)
recipe main [
def main [
1:number <- flip-bits 0
]
+mem: storing -1 in location 1
:(scenario flip_bits_negative)
recipe main [
def main [
1:number <- flip-bits -1
]
+mem: storing 0 in location 1
:(scenario flip_bits_1)
recipe main [
def main [
1:number <- flip-bits 3
]
+mem: storing -4 in location 1
:(scenario flip_bits_2)
recipe main [
def main [
1:number <- flip-bits 12
]
+mem: storing -13 in location 1

View File

@ -33,7 +33,7 @@ case AND: {
}
:(scenario and)
recipe main [
def main [
1:boolean <- copy 1
2:boolean <- copy 0
3:boolean <- and 1:boolean, 2:boolean
@ -41,19 +41,19 @@ recipe main [
+mem: storing 0 in location 3
:(scenario and_2)
recipe main [
def main [
1:boolean <- and 1, 1
]
+mem: storing 1 in location 1
:(scenario and_multiple)
recipe main [
def main [
1:boolean <- and 1, 1, 0
]
+mem: storing 0 in location 1
:(scenario and_multiple_2)
recipe main [
def main [
1:boolean <- and 1, 1, 1
]
+mem: storing 1 in location 1
@ -91,7 +91,7 @@ case OR: {
}
:(scenario or)
recipe main [
def main [
1:boolean <- copy 1
2:boolean <- copy 0
3:boolean <- or 1:boolean, 2:boolean
@ -99,19 +99,19 @@ recipe main [
+mem: storing 1 in location 3
:(scenario or_2)
recipe main [
def main [
1:boolean <- or 0, 0
]
+mem: storing 0 in location 1
:(scenario or_multiple)
recipe main [
def main [
1:boolean <- and 0, 0, 0
]
+mem: storing 0 in location 1
:(scenario or_multiple_2)
recipe main [
def main [
1:boolean <- or 0, 0, 1
]
+mem: storing 1 in location 1
@ -151,14 +151,14 @@ case NOT: {
}
:(scenario not)
recipe main [
def main [
1:boolean <- copy 1
2:boolean <- not 1:boolean
]
+mem: storing 0 in location 2
:(scenario not_multiple)
recipe main [
def main [
1:boolean, 2:boolean, 3:boolean <- not 1, 0, 1
]
+mem: storing 0 in location 1

View File

@ -1,7 +1,7 @@
//: Jump primitives
:(scenario jump_can_skip_instructions)
recipe main [
def main [
jump 1:offset
1:number <- copy 1
]
@ -38,7 +38,7 @@ case JUMP: {
put(Type_ordinal, "offset", 0);
:(scenario jump_backward)
recipe main [
def main [
jump 1:offset # 0 -+
jump 3:offset # | +-+ 1
# \/ /\ |
@ -81,7 +81,7 @@ case JUMP_IF: {
}
:(scenario jump_if)
recipe main [
def main [
jump-if 999, 1:offset
123:number <- copy 1
]
@ -91,7 +91,7 @@ recipe main [
-mem: storing 1 in location 123
:(scenario jump_if_fallthrough)
recipe main [
def main [
jump-if 0, 1:offset
123:number <- copy 1
]
@ -133,7 +133,7 @@ case JUMP_UNLESS: {
}
:(scenario jump_unless)
recipe main [
def main [
jump-unless 0, 1:offset
123:number <- copy 1
]
@ -143,7 +143,7 @@ recipe main [
-mem: storing 1 in location 123
:(scenario jump_unless_fallthrough)
recipe main [
def main [
jump-unless 999, 1:offset
123:number <- copy 1
]

View File

@ -36,7 +36,7 @@ case EQUAL: {
}
:(scenario equal)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 33
3:boolean <- equal 1:number, 2:number
@ -46,7 +46,7 @@ recipe main [
+mem: storing 0 in location 3
:(scenario equal_2)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 34
3:boolean <- equal 1:number, 2:number
@ -56,13 +56,13 @@ recipe main [
+mem: storing 1 in location 3
:(scenario equal_multiple)
recipe main [
def main [
1:boolean <- equal 34, 34, 34
]
+mem: storing 1 in location 1
:(scenario equal_multiple_2)
recipe main [
def main [
1:boolean <- equal 34, 34, 35
]
+mem: storing 0 in location 1
@ -107,7 +107,7 @@ case GREATER_THAN: {
}
:(scenario greater_than)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 33
3:boolean <- greater-than 1:number, 2:number
@ -115,7 +115,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario greater_than_2)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 34
3:boolean <- greater-than 1:number, 2:number
@ -123,13 +123,13 @@ recipe main [
+mem: storing 0 in location 3
:(scenario greater_than_multiple)
recipe main [
def main [
1:boolean <- greater-than 36, 35, 34
]
+mem: storing 1 in location 1
:(scenario greater_than_multiple_2)
recipe main [
def main [
1:boolean <- greater-than 36, 35, 35
]
+mem: storing 0 in location 1
@ -174,7 +174,7 @@ case LESSER_THAN: {
}
:(scenario lesser_than)
recipe main [
def main [
1:number <- copy 32
2:number <- copy 33
3:boolean <- lesser-than 1:number, 2:number
@ -182,7 +182,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario lesser_than_2)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 33
3:boolean <- lesser-than 1:number, 2:number
@ -190,13 +190,13 @@ recipe main [
+mem: storing 0 in location 3
:(scenario lesser_than_multiple)
recipe main [
def main [
1:boolean <- lesser-than 34, 35, 36
]
+mem: storing 1 in location 1
:(scenario lesser_than_multiple_2)
recipe main [
def main [
1:boolean <- lesser-than 34, 35, 35
]
+mem: storing 0 in location 1
@ -241,7 +241,7 @@ case GREATER_OR_EQUAL: {
}
:(scenario greater_or_equal)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 33
3:boolean <- greater-or-equal 1:number, 2:number
@ -249,7 +249,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario greater_or_equal_2)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 34
3:boolean <- greater-or-equal 1:number, 2:number
@ -257,7 +257,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario greater_or_equal_3)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 35
3:boolean <- greater-or-equal 1:number, 2:number
@ -265,13 +265,13 @@ recipe main [
+mem: storing 0 in location 3
:(scenario greater_or_equal_multiple)
recipe main [
def main [
1:boolean <- greater-or-equal 36, 35, 35
]
+mem: storing 1 in location 1
:(scenario greater_or_equal_multiple_2)
recipe main [
def main [
1:boolean <- greater-or-equal 36, 35, 36
]
+mem: storing 0 in location 1
@ -316,7 +316,7 @@ case LESSER_OR_EQUAL: {
}
:(scenario lesser_or_equal)
recipe main [
def main [
1:number <- copy 32
2:number <- copy 33
3:boolean <- lesser-or-equal 1:number, 2:number
@ -324,7 +324,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario lesser_or_equal_2)
recipe main [
def main [
1:number <- copy 33
2:number <- copy 33
3:boolean <- lesser-or-equal 1:number, 2:number
@ -332,7 +332,7 @@ recipe main [
+mem: storing 1 in location 3
:(scenario lesser_or_equal_3)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 33
3:boolean <- lesser-or-equal 1:number, 2:number
@ -340,13 +340,13 @@ recipe main [
+mem: storing 0 in location 3
:(scenario lesser_or_equal_multiple)
recipe main [
def main [
1:boolean <- lesser-or-equal 34, 35, 35
]
+mem: storing 1 in location 1
:(scenario lesser_or_equal_multiple_2)
recipe main [
def main [
1:boolean <- lesser-or-equal 34, 35, 34
]
+mem: storing 0 in location 1

View File

@ -1,7 +1,7 @@
//: Allow mu programs to log facts just like we've been doing in C++ so far.
:(scenario trace)
recipe main [
def main [
trace 1, [foo], [this is a trace in mu]
]
+foo: this is a trace in mu
@ -59,19 +59,19 @@ case STASH: {
}
:(scenario stash_literal_string)
recipe main [
def main [
stash [foo]
]
+app: foo
:(scenario stash_literal_number)
recipe main [
def main [
stash [foo:], 4
]
+app: foo: 4
:(scenario stash_number)
recipe main [
def main [
1:number <- copy 34
stash [foo:], 1:number
]
@ -187,7 +187,7 @@ case _SAVE_TRACE: {
:(scenario assert)
% Hide_errors = true; // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
recipe main [
def main [
assert 0, [this is an assert in mu]
]
+error: this is an assert in mu

View File

@ -16,7 +16,7 @@ get(Type, point).elements.push_back(reagent("y:number"));
//: container. Don't do this in general. I'm tagging exceptions with /raw to
//: avoid errors.
:(scenario copy_multiple_locations)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 35
3:point <- copy 1:point/unsafe
@ -27,7 +27,7 @@ recipe main [
//: trying to copy to a differently-typed destination will fail
:(scenario copy_checks_size)
% Hide_errors = true;
recipe main [
def main [
2:point <- copy 1:number
]
+error: main: can't copy 1:number to 2:point; types don't match
@ -43,7 +43,7 @@ get(Type, point_number).elements.push_back(reagent("xy:point"));
get(Type, point_number).elements.push_back(reagent("z:number"));
:(scenario copy_handles_nested_container_elements)
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -55,7 +55,7 @@ recipe main [
//: numbers, no matter how large they are.
:(scenario compare_multiple_locations)
recipe main [
def main [
1:number <- copy 34 # first
2:number <- copy 35
3:number <- copy 36
@ -67,7 +67,7 @@ recipe main [
+mem: storing 1 in location 7
:(scenario compare_multiple_locations_2)
recipe main [
def main [
1:number <- copy 34 # first
2:number <- copy 35
3:number <- copy 36
@ -109,7 +109,7 @@ if (t.kind == CONTAINER) {
}
:(scenario stash_container)
recipe main [
def main [
1:number <- copy 34 # first
2:number <- copy 35
3:number <- copy 36
@ -119,7 +119,7 @@ recipe main [
//:: To access elements of a container, use 'get'
:(scenario get)
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
15:number <- get 12:point/raw, 1:offset # unsafe
@ -205,7 +205,7 @@ const reagent element_type(const reagent& canonized_base, long long int offset_v
}
:(scenario get_handles_nested_container_elements)
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -215,7 +215,7 @@ recipe main [
:(scenario get_out_of_bounds)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -225,7 +225,7 @@ recipe main [
:(scenario get_out_of_bounds_2)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -235,7 +235,7 @@ recipe main [
:(scenario get_product_type_mismatch)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -246,7 +246,7 @@ recipe main [
//: we might want to call 'get' without saving the results, say in a sandbox
:(scenario get_without_product)
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
get 12:point/raw, 1:offset # unsafe
@ -256,7 +256,7 @@ recipe main [
//:: To write to elements of containers, you need their address.
:(scenario get_address)
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
15:address:number <- get-address 12:point/raw, 1:offset # unsafe
@ -333,7 +333,7 @@ case GET_ADDRESS: {
:(scenario get_address_out_of_bounds)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -343,7 +343,7 @@ recipe main [
:(scenario get_address_out_of_bounds_2)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 34
13:number <- copy 35
14:number <- copy 36
@ -357,7 +357,7 @@ container boolbool [
x:boolean
y:boolean
]
recipe main [
def main [
12:boolean <- copy 1
13:boolean <- copy 0
15:boolean <- get-address 12:boolbool, 1:offset
@ -466,7 +466,7 @@ container foo [
y:number
]
recipe main [
def main [
1:number <- copy 34
2:number <- copy 35
3:number <- get 1:foo, 0:offset
@ -515,14 +515,14 @@ Next_type_ordinal = 1000;
:(scenario run_complains_on_unknown_types)
% Hide_errors = true;
recipe main [
def main [
# integer is not a type
1:integer <- copy 0
]
+error: main: unknown type integer in '1:integer <- copy 0'
:(scenario run_allows_type_definition_after_use)
recipe main [
def main [
1:bar <- copy 0/unsafe
]
@ -616,7 +616,7 @@ container foo [
y:number
]
recipe main [
def main [
1:foo <- merge 3, 4
]
+mem: storing 3 in location 1
@ -643,21 +643,21 @@ case MERGE: {
//: type-check 'merge' to avoid interpreting numbers as addresses
:(scenario merge_check)
recipe main [
def main [
1:point <- merge 3, 4
]
$error: 0
:(scenario merge_check_missing_element)
% Hide_errors = true;
recipe main [
def main [
1:point <- merge 3
]
+error: main: too few ingredients in '1:point <- merge 3'
:(scenario merge_check_extra_element)
% Hide_errors = true;
recipe main [
def main [
1:point <- merge 3, 4, 5
]
+error: main: too many ingredients in '1:point <- merge 3, 4, 5'
@ -668,7 +668,7 @@ recipe main [
//: container fields.
:(scenario merge_check_recursive_containers)
recipe main [
def main [
1:point <- merge 3, 4
1:point-number <- merge 1:point, 5
]
@ -676,21 +676,21 @@ $error: 0
:(scenario merge_check_recursive_containers_2)
% Hide_errors = true;
recipe main [
def main [
1:point <- merge 3, 4
2:point-number <- merge 1:point
]
+error: main: too few ingredients in '2:point-number <- merge 1:point'
:(scenario merge_check_recursive_containers_3)
recipe main [
def main [
1:point-number <- merge 3, 4, 5
]
$error: 0
:(scenario merge_check_recursive_containers_4)
% Hide_errors = true;
recipe main [
def main [
1:point-number <- merge 3, 4
]
+error: main: too few ingredients in '1:point-number <- merge 3, 4'
@ -807,7 +807,7 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product
:(scenario merge_check_product)
% Hide_errors = true;
recipe main [
def main [
1:number <- merge 3
]
+error: main: 'merge' should yield a container in '1:number <- merge 3'

View File

@ -2,7 +2,7 @@
//: 'lookup' property.
:(scenario copy_indirect)
recipe main [
def main [
1:address:number <- copy 2/unsafe
2:number <- copy 34
# This loads location 1 as an address and looks up *that* location.
@ -16,7 +16,7 @@ canonize(x);
//: similarly, write to addresses pointing at other locations using the
//: 'lookup' property
:(scenario store_indirect)
recipe main [
def main [
1:address:number <- copy 2/unsafe
1:address:number/lookup <- copy 34
]
@ -32,7 +32,7 @@ if (x.value == 0) {
//: writes to address 0 always loudly fail
:(scenario store_to_0_fails)
% Hide_errors = true;
recipe main [
def main [
1:address:number <- copy 0
1:address:number/lookup <- copy 34
]
@ -66,7 +66,7 @@ void lookup_memory(reagent& x) {
:(scenario canonize_non_pointer_fails_without_crashing)
% Hide_errors = true;
recipe foo [
def foo [
1:address:number <- get-address *p, x:offset
]
# don't crash
@ -130,7 +130,7 @@ void drop_one_lookup(reagent& r) {
//:: 'get' can read from container address
:(scenario get_indirect)
recipe main [
def main [
1:number <- copy 2
2:number <- copy 34
3:number <- copy 35
@ -139,7 +139,7 @@ recipe main [
+mem: storing 34 in location 4
:(scenario get_indirect2)
recipe main [
def main [
1:number <- copy 2
2:number <- copy 34
3:number <- copy 35
@ -149,7 +149,7 @@ recipe main [
+mem: storing 34 in location 5
:(scenario include_nonlookup_properties)
recipe main [
def main [
1:number <- copy 2
2:number <- copy 34
3:number <- copy 35
@ -166,7 +166,7 @@ canonize(base);
:(scenario get_address_indirect)
# 'get' can read from container address
recipe main [
def main [
1:number <- copy 2
2:number <- copy 34
3:number <- copy 35
@ -184,7 +184,7 @@ canonize(base);
//:: abbreviation for '/lookup': a prefix '*'
:(scenario lookup_abbreviation)
recipe main [
def main [
1:address:number <- copy 2/unsafe
2:number <- copy 34
3:number <- copy *1:address:number

View File

@ -7,7 +7,7 @@
//: You can create arrays using 'create-array'.
:(scenario create_array)
recipe main [
def main [
# create an array occupying locations 1 (for the size) and 2-4 (for the elements)
1:array:number:3 <- create-array
]
@ -67,7 +67,7 @@ case CREATE_ARRAY: {
:(scenario copy_array)
# Arrays can be copied around with a single instruction just like numbers,
# no matter how large they are.
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -80,7 +80,7 @@ recipe main [
+mem: storing 16 in location 8
:(scenario copy_array_indirect)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -94,7 +94,7 @@ recipe main [
+mem: storing 16 in location 9
:(scenario stash_array)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -149,7 +149,7 @@ container foo [
//:: To access elements of an array, use 'index'
:(scenario index)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -159,7 +159,7 @@ recipe main [
+mem: storing 14 in location 5
:(scenario index_direct_offset)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -234,7 +234,7 @@ type_tree* array_element(const type_tree* type) {
}
:(scenario index_indirect)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -246,7 +246,7 @@ recipe main [
:(scenario index_out_of_bounds)
% Hide_errors = true;
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -261,7 +261,7 @@ recipe main [
:(scenario index_out_of_bounds_2)
% Hide_errors = true;
recipe main [
def main [
1:array:point:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -276,7 +276,7 @@ recipe main [
:(scenario index_product_type_mismatch)
% Hide_errors = true;
recipe main [
def main [
1:array:point:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -292,7 +292,7 @@ recipe main [
//: we might want to call 'index' without saving the results, say in a sandbox
:(scenario index_without_product)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -304,7 +304,7 @@ recipe main [
//:: To write to elements of containers, you need their address.
:(scenario index_address)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -366,7 +366,7 @@ case INDEX_ADDRESS: {
:(scenario index_address_out_of_bounds)
% Hide_errors = true;
recipe main [
def main [
1:array:point:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -381,7 +381,7 @@ recipe main [
:(scenario index_address_out_of_bounds_2)
% Hide_errors = true;
recipe main [
def main [
1:array:point:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -396,7 +396,7 @@ recipe main [
:(scenario index_address_product_type_mismatch)
% Hide_errors = true;
recipe main [
def main [
1:array:point:3 <- create-array
2:number <- copy 14
3:number <- copy 15
@ -412,7 +412,7 @@ recipe main [
//:: compute the length of an array
:(scenario array_length)
recipe main [
def main [
1:array:number:3 <- create-array
2:number <- copy 14
3:number <- copy 15

View File

@ -20,7 +20,7 @@ get(Type, tmp).elements.push_back(reagent("p:point"));
//: avoid errors.
:(scenario copy_exclusive_container)
# Copying exclusive containers copies all their contents and an extra location for the tag.
recipe main [
def main [
1:number <- copy 1 # 'point' variant
2:number <- copy 34
3:number <- copy 35
@ -56,7 +56,7 @@ if (t.kind == EXCLUSIVE_CONTAINER) {
put(Type_ordinal, "variant", 0);
:(scenario maybe_convert)
recipe main [
def main [
12:number <- copy 1
13:number <- copy 35
14:number <- copy 36
@ -65,7 +65,7 @@ recipe main [
+mem: storing 13 in location 20
:(scenario maybe_convert_fail)
recipe main [
def main [
12:number <- copy 1
13:number <- copy 35
14:number <- copy 36
@ -147,7 +147,7 @@ const reagent variant_type(const reagent& canonized_base, long long int tag) {
:(scenario maybe_convert_product_type_mismatch)
% Hide_errors = true;
recipe main [
def main [
12:number <- copy 1
13:number <- copy 35
14:number <- copy 36
@ -194,7 +194,7 @@ exclusive-container foo [
y:number
]
recipe main [
def main [
1:number <- copy 34
2:foo <- merge 0/x, 1:number # tag must be a literal when merging exclusive containers
4:foo <- merge 1/y, 1:number
@ -214,7 +214,7 @@ exclusive-container foo [
container bar [
z:number
]
recipe main [
def main [
1:foo <- merge 0/x, 34
]
+mem: storing 0 in location 1
@ -230,7 +230,7 @@ exclusive-container foo [
container bar [
z:number
]
recipe main [
def main [
local-scope
1:number <- copy 0
2:foo <- merge 1:number, 34
@ -269,7 +269,7 @@ exclusive-container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 23, 1/y, 34
]
+mem: storing 23 in location 1
@ -287,7 +287,7 @@ exclusive-container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 23, 1/y, 34, 35
]
+error: main: too many ingredients in '1:foo <- merge 23, 1/y, 34, 35'
@ -301,7 +301,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 1/y, 23, 34
]
+mem: storing 1 in location 1
@ -318,7 +318,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 0/x, 23
]
$error: 0
@ -333,7 +333,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 1/y, 23
]
+error: main: too few ingredients in '1:foo <- merge 1/y, 23'
@ -362,7 +362,7 @@ exclusive-container bar [
y:foo
]
recipe main [
def main [
1:number <- copy 34
2:number <- copy 35
3:bar <- merge 0/x, 1:number

View File

@ -1,22 +1,22 @@
//: So far the recipes we define can't run each other. Let's fix that.
:(scenario calling_recipe)
recipe main [
def main [
f
]
recipe f [
def f [
3:number <- add 2, 2
]
+mem: storing 4 in location 3
:(scenario return_on_fallthrough)
recipe main [
def main [
f
1:number <- copy 0
2:number <- copy 0
3:number <- copy 0
]
recipe f [
def f [
4:number <- copy 0
5:number <- copy 0
]
@ -125,14 +125,14 @@ void finish_call_housekeeping(const instruction& call_instruction, const vector<
:(scenario calling_undefined_recipe_fails)
% Hide_errors = true;
recipe main [
def main [
foo
]
+error: main: undefined operation in 'foo '
:(scenario calling_undefined_recipe_handles_missing_result)
% Hide_errors = true;
recipe main [
def main [
x:number <- foo
]
+error: main: undefined operation in 'x:number <- foo '

View File

@ -2,20 +2,20 @@
//: ingredients, use 'next-ingredient'.
:(scenario next_ingredient)
recipe main [
def main [
f 2
]
recipe f [
def f [
12:number <- next-ingredient
13:number <- add 1, 12:number
]
+mem: storing 3 in location 13
:(scenario next_ingredient_missing)
recipe main [
def main [
f
]
recipe f [
def f [
_, 12:number <- next-ingredient
]
+mem: storing 0 in location 12
@ -86,19 +86,19 @@ case NEXT_INGREDIENT: {
:(scenario next_ingredient_fail_on_missing)
% Hide_errors = true;
recipe main [
def main [
f
]
recipe f [
def f [
11:number <- next-ingredient
]
+error: f: no ingredient to save in 11:number
:(scenario rewind_ingredients)
recipe main [
def main [
f 2
]
recipe f [
def f [
12:number <- next-ingredient # consume ingredient
_, 1:boolean <- next-ingredient # will not find any ingredients
rewind-ingredients
@ -124,10 +124,10 @@ case REWIND_INGREDIENTS: {
}
:(scenario ingredient)
recipe main [
def main [
f 1, 2
]
recipe f [
def f [
12:number <- ingredient 1 # consume second ingredient first
13:number, 1:boolean <- next-ingredient # next-ingredient tries to scan past that
]

View File

@ -1,10 +1,10 @@
//: Calls can also generate products, using 'reply'.
//: Calls can also generate products, using 'reply' or 'return'.
:(scenario reply)
recipe main [
def main [
1:number, 2:number <- f 34
]
recipe f [
def f [
12:number <- next-ingredient
13:number <- add 1, 12:number
reply 12:number, 13:number
@ -16,6 +16,7 @@ recipe f [
REPLY,
:(before "End Primitive Recipe Numbers")
put(Recipe_ordinal, "reply", REPLY);
put(Recipe_ordinal, "return", REPLY);
:(before "End Primitive Recipe Checks")
case REPLY: {
break; // checks will be performed by a transform below
@ -46,13 +47,13 @@ case REPLY: {
//: Products can include containers and exclusive containers, addresses and arrays.
:(scenario reply_container)
recipe main [
def main [
3:point <- f 2
]
recipe f [
def f [
12:number <- next-ingredient
13:number <- copy 35
reply 12:point/raw
return 12:point/raw
]
+run: result 0 is [2, 35]
+mem: storing 2 in location 3
@ -86,7 +87,7 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
reagent rhs = caller_instruction.products.at(i);
canonize_type(rhs);
if (!types_coercible(rhs, lhs)) {
raise << maybe(callee.name) << "reply ingredient " << lhs.original_string << " can't be saved in " << rhs.original_string << '\n' << end();
raise << maybe(callee.name) << reply_inst.name << " ingredient " << lhs.original_string << " can't be saved in " << rhs.original_string << '\n' << end();
raise << to_string(lhs.type) << " vs " << to_string(rhs.type) << '\n' << end();
goto finish_reply_check;
}
@ -117,16 +118,16 @@ void check_types_of_reply_instructions(recipe_ordinal r) {
:(scenario reply_type_mismatch)
% Hide_errors = true;
recipe main [
def main [
3:number <- f 2
]
recipe f [
def f [
12:number <- next-ingredient
13:number <- copy 35
14:point <- copy 12:point/raw
reply 14:point
return 14:point
]
+error: f: reply ingredient 14:point can't be saved in 3:number
+error: f: return ingredient 14:point can't be saved in 3:number
//: In mu we'd like to assume that any instruction doesn't modify its
//: ingredients unless they're also products. The /same-as-ingredient inside
@ -135,24 +136,24 @@ recipe f [
:(scenario reply_same_as_ingredient)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 0
2:number <- test1 1:number # call with different ingredient and product
]
recipe test1 [
def test1 [
10:number <- next-ingredient
reply 10:number/same-as-ingredient:0
return 10:number/same-as-ingredient:0
]
+error: main: '2:number <- test1 1:number' should write to 1:number rather than 2:number
:(scenario reply_same_as_ingredient_dummy)
recipe main [
def main [
1:number <- copy 0
_ <- test1 1:number # call with different ingredient and product
]
recipe test1 [
def test1 [
10:number <- next-ingredient
reply 10:number/same-as-ingredient:0
return 10:number/same-as-ingredient:0
]
$error: 0
@ -176,22 +177,22 @@ string to_string(const vector<double>& in) {
//: Conditional reply.
:(scenario reply_if)
recipe main [
def main [
1:number <- test1
]
recipe test1 [
reply-if 0, 34
reply 35
def test1 [
return-if 0, 34
return 35
]
+mem: storing 35 in location 1
:(scenario reply_if_2)
recipe main [
def main [
1:number <- test1
]
recipe test1 [
reply-if 1, 34
reply 35
def test1 [
return-if 1, 34
return 35
]
+mem: storing 34 in location 1
@ -201,7 +202,7 @@ recipe test1 [
// jump-unless a, 1:offset
// reply b, c, ...
// ```
if (curr.name == "reply-if") {
if (curr.name == "reply-if" || curr.name == "return-if") {
if (curr.products.empty()) {
curr.operation = get(Recipe_ordinal, "jump-unless");
curr.name = "jump-unless";
@ -216,7 +217,7 @@ if (curr.name == "reply-if") {
curr.ingredients.swap(results);
}
else {
raise << "'reply-if' never yields any products\n" << end();
raise << "'" << curr.name << "' never yields any products\n" << end();
}
}
// rewrite `reply-unless a, b, c, ...` to
@ -224,7 +225,7 @@ if (curr.name == "reply-if") {
// jump-if a, 1:offset
// reply b, c, ...
// ```
if (curr.name == "reply-unless") {
if (curr.name == "reply-unless" || curr.name == "return-unless") {
if (curr.products.empty()) {
curr.operation = get(Recipe_ordinal, "jump-if");
curr.name = "jump-if";
@ -239,6 +240,6 @@ if (curr.name == "reply-unless") {
curr.ingredients.swap(results);
}
else {
raise << "'reply-unless' never yields any products\n" << end();
raise << "'" << curr.name << "' never yields any products\n" << end();
}
}

View File

@ -47,7 +47,7 @@ if (r.type->name == "shared") {
:(scenarios run)
:(scenario new)
# call new two times with identical arguments; you should get back different results
recipe main [
def main [
1:address:shared:number/raw <- new number:type
2:address:shared:number/raw <- new number:type
3:boolean/raw <- equal 1:address:shared:number/raw, 2:address:shared:number/raw
@ -229,7 +229,7 @@ void ensure_space(long long int size) {
:(scenario new_initializes)
% Memory_allocated_until = 10;
% put(Memory, Memory_allocated_until, 1);
recipe main [
def main [
1:address:shared:number <- new number:type
2:number <- copy *1:address:shared:number
]
@ -237,13 +237,13 @@ recipe main [
:(scenario new_error)
% Hide_errors = true;
recipe main [
def main [
1:address:number/raw <- new number:type
]
+error: main: product of 'new' has incorrect type: 1:address:number/raw <- new number:type
:(scenario new_array)
recipe main [
def main [
1:address:shared:array:number/raw <- new number:type, 5
2:address:shared:number/raw <- new number:type
3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
@ -254,7 +254,7 @@ recipe main [
+mem: storing 7 in location 3
:(scenario new_empty_array)
recipe main [
def main [
1:address:shared:array:number/raw <- new number:type, 0
2:address:shared:number/raw <- new number:type
3:number/raw <- subtract 2:address:shared:number/raw, 1:address:shared:array:number/raw
@ -267,7 +267,7 @@ recipe main [
//: If a routine runs out of its initial allocation, it should allocate more.
:(scenario new_overflow)
% Initial_memory_per_routine = 3; // barely enough room for point allocation below
recipe main [
def main [
1:address:shared:number/raw <- new number:type
2:address:shared:point/raw <- new point:type # not enough room in initial page
]
@ -278,7 +278,7 @@ recipe main [
//: todo: custodians, etc. Following malloc/free is a temporary hack.
:(scenario new_reclaim)
recipe main [
def main [
1:address:shared:number <- new number:type
2:address:shared:number <- copy 1:address:shared:number # because 1 will get reset during abandon below
abandon 1:address:shared:number # unsafe
@ -367,7 +367,7 @@ if (get_or_insert(Free_list, size)) {
}
:(scenario new_differing_size_no_reclaim)
recipe main [
def main [
1:address:shared:number <- new number:type
2:address:shared:number <- copy 1:address:shared:number
abandon 1:address:shared:number
@ -378,7 +378,7 @@ recipe main [
+mem: storing 0 in location 4
:(scenario new_reclaim_array)
recipe main [
def main [
1:address:shared:array:number <- new number:type, 2
2:address:shared:array:number <- copy 1:address:shared:array:number
abandon 1:address:shared:array:number # unsafe
@ -389,7 +389,7 @@ recipe main [
+mem: storing 1 in location 4
:(scenario reset_on_abandon)
recipe main [
def main [
1:address:shared:number <- new number:type
abandon 1:address:shared:number
]
@ -400,7 +400,7 @@ recipe main [
//:: Manage refcounts when copying addresses.
:(scenario refcounts)
recipe main [
def main [
1:address:shared:number <- copy 1000/unsafe
2:address:shared:number <- copy 1:address:shared:number
1:address:shared:number <- copy 0
@ -458,7 +458,7 @@ if (x.type->value == get(Type_ordinal, "address")
}
:(scenario refcounts_2)
recipe main [
def main [
1:address:shared:number <- new number:type
# over-writing one allocation with another
1:address:shared:number <- new number:type
@ -470,13 +470,13 @@ recipe main [
+mem: automatically abandoning 1000
:(scenario refcounts_3)
recipe main [
def main [
1:address:shared:number <- new number:type
# passing in addresses to recipes increments refcount
foo 1:address:shared:number
1:address:shared:number <- copy 0
]
recipe foo [
def foo [
2:address:shared:number <- next-ingredient
# return does NOT yet decrement refcount; memory must be explicitly managed
2:address:shared:number <- copy 0
@ -492,7 +492,7 @@ recipe foo [
+mem: automatically abandoning 1000
:(scenario refcounts_4)
recipe main [
def main [
1:address:shared:number <- new number:type
# idempotent copies leave refcount unchanged
1:address:shared:number <- copy 1:address:shared:number
@ -504,14 +504,14 @@ recipe main [
+mem: incrementing refcount of 1000: 0 -> 1
:(scenario refcounts_5)
recipe main [
def main [
1:address:shared:number <- new number:type
# passing in addresses to recipes increments refcount
foo 1:address:shared:number
# return does NOT yet decrement refcount; memory must be explicitly managed
1:address:shared:number <- new number:type
]
recipe foo [
def foo [
2:address:shared:number <- next-ingredient
]
+run: 1:address:shared:number <- new number:type
@ -524,7 +524,7 @@ recipe foo [
//:: Extend 'new' to handle a unicode string literal argument.
:(scenario new_string)
recipe main [
def main [
1:address:shared:array:character <- new [abc def]
2:character <- index *1:address:shared:array:character, 5
]
@ -532,7 +532,7 @@ recipe main [
+mem: storing 101 in location 2
:(scenario new_string_handles_unicode)
recipe main [
def main [
1:address:shared:array:character <- new [a«c]
2:number <- length *1:address:shared:array:character
3:character <- index *1:address:shared:array:character, 1
@ -582,7 +582,7 @@ long long int new_mu_string(const string& contents) {
//: stash recognizes strings
:(scenario stash_string)
recipe main [
def main [
1:address:shared:array:character <- new [abc]
stash [foo:], 1:address:shared:array:character
]
@ -595,14 +595,14 @@ if (is_mu_string(r)) {
}
:(scenario unicode_string)
recipe main [
def main [
1:address:shared:array:character <- new []
stash [foo:], 1:address:shared:array:character
]
+app: foo:
:(scenario stash_space_after_string)
recipe main [
def main [
1:address:shared:array:character <- new [abc]
stash 1:address:shared:array:character, [foo]
]
@ -611,7 +611,7 @@ recipe main [
//: Allocate more to routine when initializing a literal string
:(scenario new_string_overflow)
% Initial_memory_per_routine = 2;
recipe main [
def main [
1:address:shared:number/raw <- new number:type
2:address:shared:array:character/raw <- new [a] # not enough room in initial page, if you take the array size into account
]

View File

@ -21,7 +21,7 @@
:(scenarios transform)
:(scenario brace_conversion)
recipe main [
def main [
{
break
1:number <- copy 0
@ -145,7 +145,7 @@ long long int matching_brace(long long int index, const list<pair<int, long long
}
:(scenario loop)
recipe main [
def main [
1:number <- copy 0
2:number <- copy 0
{
@ -160,7 +160,7 @@ recipe main [
+transform: jump -2:offset
:(scenario break_empty_block)
recipe main [
def main [
1:number <- copy 0
{
break
@ -171,7 +171,7 @@ recipe main [
+transform: jump 0:offset
:(scenario break_cascading)
recipe main [
def main [
1:number <- copy 0
{
break
@ -186,7 +186,7 @@ recipe main [
+transform: jump 0:offset
:(scenario break_cascading_2)
recipe main [
def main [
1:number <- copy 0
2:number <- copy 0
{
@ -205,7 +205,7 @@ recipe main [
+transform: jump 0:offset
:(scenario break_if)
recipe main [
def main [
1:number <- copy 0
2:number <- copy 0
{
@ -224,7 +224,7 @@ recipe main [
+transform: jump 0:offset
:(scenario break_nested)
recipe main [
def main [
1:number <- copy 0
{
2:number <- copy 0
@ -238,7 +238,7 @@ recipe main [
+transform: jump 4:offset
:(scenario break_nested_degenerate)
recipe main [
def main [
1:number <- copy 0
{
2:number <- copy 0
@ -251,7 +251,7 @@ recipe main [
+transform: jump 3:offset
:(scenario break_nested_degenerate_2)
recipe main [
def main [
1:number <- copy 0
{
2:number <- copy 0
@ -264,7 +264,7 @@ recipe main [
:(scenario break_label)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 0
{
break +foo:offset
@ -273,7 +273,7 @@ recipe main [
+transform: jump +foo:offset
:(scenario break_unless)
recipe main [
def main [
1:number <- copy 0
2:number <- copy 0
{
@ -288,7 +288,7 @@ recipe main [
+transform: copy ...
:(scenario loop_unless)
recipe main [
def main [
1:number <- copy 0
2:number <- copy 0
{
@ -303,7 +303,7 @@ recipe main [
+transform: copy ...
:(scenario loop_nested)
recipe main [
def main [
1:number <- copy 0
{
2:number <- copy 0
@ -318,7 +318,7 @@ recipe main [
+transform: jump-if 4, -5:offset
:(scenario loop_label)
recipe main [
def main [
1:number <- copy 0
+foo
2:number <- copy 0
@ -330,7 +330,7 @@ recipe main [
//: test how things actually run
:(scenarios run)
:(scenario brace_conversion_and_run)
recipe test-factorial [
def test-factorial [
1:number <- copy 5
2:number <- copy 1
{
@ -347,14 +347,14 @@ recipe test-factorial [
:(scenario break_outside_braces_fails)
% Hide_errors = true;
recipe main [
def main [
break
]
+error: break needs a '{' before
:(scenario break_conditional_without_ingredient_fails)
% Hide_errors = true;
recipe main [
def main [
{
break-if
}

View File

@ -8,7 +8,7 @@
//: iteration of some containing loop nest.
:(scenario jump_to_label)
recipe main [
def main [
jump +target:label
1:number <- copy 0
+target
@ -92,7 +92,7 @@ bool is_jump_target(string label) {
}
:(scenario break_to_label)
recipe main [
def main [
{
{
break +target:label
@ -104,7 +104,7 @@ recipe main [
-mem: storing 0 in location 1
:(scenario jump_if_to_label)
recipe main [
def main [
{
{
jump-if 1, +target:label
@ -116,7 +116,7 @@ recipe main [
-mem: storing 0 in location 1
:(scenario loop_unless_to_label)
recipe main [
def main [
{
{
loop-unless 0, +target:label # loop/break with a label don't care about braces
@ -128,7 +128,7 @@ recipe main [
-mem: storing 0 in location 1
:(scenario jump_runs_code_after_label)
recipe main [
def main [
# first a few lines of padding to exercise the offset computation
1:number <- copy 0
2:number <- copy 0
@ -143,21 +143,21 @@ recipe main [
:(scenario jump_fails_without_target)
% Hide_errors = true;
recipe main [
def main [
jump
]
+error: main: 'jump' expects an ingredient but got none
:(scenario jump_fails_without_target_2)
% Hide_errors = true;
recipe main [
def main [
jump-if 1/true
]
+error: main: 'jump-if' expects 2 ingredients but got 1
:(scenario recipe_fails_on_duplicate_jump_target)
% Hide_errors = true;
recipe main [
def main [
+label
1:number <- copy 0
+label
@ -167,7 +167,7 @@ recipe main [
:(scenario jump_ignores_nontarget_label)
% Hide_errors = true;
recipe main [
def main [
# first a few lines of padding to exercise the offset computation
1:number <- copy 0
2:number <- copy 0

View File

@ -3,7 +3,7 @@
//: convenience.
:(scenario transform_names)
recipe main [
def main [
x:number <- copy 0
]
+name: assign x 1
@ -12,7 +12,7 @@ recipe main [
:(scenarios transform)
:(scenario transform_names_fails_on_use_before_define)
% Hide_errors = true;
recipe main [
def main [
x:number <- copy y:number
]
+error: main: use before set: y
@ -147,7 +147,7 @@ bool is_special_name(const string& s) {
:(scenario transform_names_passes_dummy)
# _ is just a dummy result that never gets consumed
recipe main [
def main [
_, x:number <- copy 0, 1
]
+name: assign x 1
@ -157,7 +157,7 @@ recipe main [
:(scenarios run)
:(scenario transform_names_passes_raw)
% Hide_errors = true;
recipe main [
def main [
x:number/raw <- copy 0
]
-name: assign x 1
@ -166,28 +166,28 @@ recipe main [
:(scenarios transform)
:(scenario transform_names_fails_when_mixing_names_and_numeric_locations)
% Hide_errors = true;
recipe main [
def main [
x:number <- copy 1:number
]
+error: main: mixing variable names and numeric addresses
:(scenario transform_names_fails_when_mixing_names_and_numeric_locations_2)
% Hide_errors = true;
recipe main [
def main [
x:number <- copy 1
1:number <- copy x:number
]
+error: main: mixing variable names and numeric addresses
:(scenario transform_names_does_not_fail_when_mixing_names_and_raw_locations)
recipe main [
def main [
x:number <- copy 1:number/raw
]
-error: main: mixing variable names and numeric addresses
$error: 0
:(scenario transform_names_does_not_fail_when_mixing_names_and_literals)
recipe main [
def main [
x:number <- copy 1
]
-error: main: mixing variable names and numeric addresses
@ -196,7 +196,7 @@ $error: 0
//:: Support element names for containers in 'get' and 'get-address'.
:(scenario transform_names_transforms_container_elements)
recipe main [
def main [
p:address:point <- copy 0
a:number <- get *p:address:point, y:offset
b:number <- get *p:address:point, x:offset
@ -226,7 +226,7 @@ if (inst.name == "get" || inst.name == "get-address") {
//: this test is actually illegal so can't call run
:(scenarios transform)
:(scenario transform_names_handles_containers)
recipe main [
def main [
a:point <- copy 0/unsafe
b:number <- copy 0/unsafe
]
@ -237,7 +237,7 @@ recipe main [
:(scenarios run)
:(scenario transform_names_handles_exclusive_containers)
recipe main [
def main [
12:number <- copy 1
13:number <- copy 35
14:number <- copy 36

View File

@ -5,7 +5,7 @@
:(scenario set_default_space)
# if default-space is 10, and if an array of 5 locals lies from location 12 to 16 (inclusive),
# then local 0 is really location 12, local 1 is really location 13, and so on.
recipe main [
def main [
# pretend shared:array:location; in practice we'll use new
10:number <- copy 0 # refcount
11:number <- copy 5 # length
@ -15,7 +15,7 @@ recipe main [
+mem: storing 23 in location 13
:(scenario lookup_sidesteps_default_space)
recipe main [
def main [
# pretend pointer from outside
3:number <- copy 34
# pretend shared:array:location; in practice we'll use new
@ -31,7 +31,7 @@ recipe main [
//:: first disable name conversion for 'default-space'
:(scenario convert_names_passes_default_space)
% Hide_errors = true;
recipe main [
def main [
default-space:number, x:number <- copy 0, 1
]
+name: assign x 1
@ -101,7 +101,7 @@ long long int address(long long int offset, long long int base) {
}
:(scenario get_default_space)
recipe main [
def main [
default-space:address:shared:array:location <- copy 10/unsafe
1:address:shared:array:location/raw <- copy default-space:address:shared:array:location
]
@ -117,7 +117,7 @@ recipe main [
//:: fix 'get'
:(scenario lookup_sidesteps_default_space_in_get)
recipe main [
def main [
# pretend pointer to container from outside
12:number <- copy 34
13:number <- copy 35
@ -137,7 +137,7 @@ tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
//:: fix 'index'
:(scenario lookup_sidesteps_default_space_in_index)
recipe main [
def main [
# pretend pointer to array from outside
12:number <- copy 2
13:number <- copy 34
@ -159,7 +159,7 @@ tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
//:: allocate in a default space with names
:(scenario new_default_space)
recipe main [
def main [
new-default-space
x:number <- copy 0
y:number <- copy 3
@ -198,15 +198,15 @@ if (curr.name == "new-default-space") {
//:: from a recipe
:(scenario local_scope)
recipe main [
def main [
1:address <- foo
2:address <- foo
3:boolean <- equal 1:address, 2:address
]
recipe foo [
def foo [
local-scope
x:number <- copy 34
reply default-space:address:shared:array:location
return default-space:address:shared:array:location
]
# both calls to foo should have received the same default-space
+mem: storing 1 in location 3

View File

@ -6,7 +6,7 @@
:(scenario surrounding_space)
# location 1 in space 1 refers to the space surrounding the default space, here 20.
recipe main [
def main [
# pretend shared:array:location; in practice we'll use new
10:number <- copy 0 # refcount
11:number <- copy 5 # length
@ -19,7 +19,7 @@ recipe main [
1:number <- copy 32
1:number/space:1 <- copy 33
]
recipe dummy [ # just for the /names: property above
def dummy [ # just for the /names: property above
]
# chain space: 10 + /*skip refcount*/1 + /*skip length*/1
+mem: storing 20 in location 12
@ -57,6 +57,6 @@ long long int space_index(const reagent& x) {
}
:(scenario permit_space_as_variable_name)
recipe main [
def main [
space:number <- copy 0
]

View File

@ -4,26 +4,26 @@
//: surrounding space of the surrounding space, etc.
:(scenario closure)
recipe main [
def main [
default-space:address:shared:array:location <- new location:type, 30
1:address:shared:array:location/names:new-counter <- new-counter
2:number/raw <- increment-counter 1:address:shared:array:location/names:new-counter
3:number/raw <- increment-counter 1:address:shared:array:location/names:new-counter
]
recipe new-counter [
def new-counter [
default-space:address:shared:array:location <- new location:type, 30
x:number <- copy 23
y:number <- copy 3 # variable that will be incremented
reply default-space:address:shared:array:location
return default-space:address:shared:array:location
]
recipe increment-counter [
def increment-counter [
default-space:address:shared:array:location <- new location:type, 30
0:address:shared:array:location/names:new-counter <- next-ingredient # outer space must be created by 'new-counter' above
y:number/space:1 <- add y:number/space:1, 1 # increment
y:number <- copy 234 # dummy
reply y:number/space:1
return y:number/space:1
]
+name: lexically surrounding space for recipe increment-counter comes from new-counter
@ -152,7 +152,7 @@ bool already_transformed(const reagent& r, const map<string, long long int>& nam
:(scenario missing_surrounding_space)
% Hide_errors = true;
recipe f [
def f [
local-scope
x:number/space:1 <- copy 34
]

View File

@ -10,7 +10,7 @@
//: entirely.
:(scenario global_space)
recipe main [
def main [
# pretend shared:array:location; in practice we'll use new
10:number <- copy 0 # refcount
11:number <- copy 5 # length
@ -72,7 +72,7 @@ global_space = 0;
//: don't want to make them too comfortable to use.
:(scenario global_space_with_names)
recipe main [
def main [
global-space:address:shared:array:location <- new location:type, 10
x:number <- copy 23
1:number/space:global <- copy 24

View File

@ -8,7 +8,7 @@
:(scenario transform_fails_on_reusing_name_with_different_type)
% Hide_errors = true;
recipe main [
def main [
x:number <- copy 1
x:boolean <- copy 1
]
@ -67,19 +67,19 @@ void check_type(set<reagent>& known, const reagent& x, const recipe_ordinal r) {
}
:(scenario transform_fills_in_missing_types)
recipe main [
def main [
x:number <- copy 1
y:number <- add x, 1
]
:(scenario transform_fills_in_missing_types_in_product)
recipe main [
def main [
x:number <- copy 1
x <- copy 2
]
:(scenario transform_fills_in_missing_types_in_product_and_ingredient)
recipe main [
def main [
x:number <- copy 1
x <- add x, 1
]
@ -87,7 +87,7 @@ recipe main [
:(scenario transform_fails_on_missing_types_in_first_mention)
% Hide_errors = true;
recipe main [
def main [
x <- copy 1
x:number <- copy 2
]
@ -95,7 +95,7 @@ recipe main [
:(scenario typo_in_address_type_fails)
% Hide_errors = true;
recipe main [
def main [
y:address:shared:charcter <- new character:type
*y <- copy 67
]
@ -103,16 +103,16 @@ recipe main [
:(scenario array_type_without_size_fails)
% Hide_errors = true;
recipe main [
def main [
x:array:number <- merge 2, 12, 13
]
+error: main can't determine the size of array variable x. Either allocate it separately and make the type of x address:shared:..., or specify the length of the array in the type of x.
:(scenarios transform)
:(scenario transform_checks_types_of_identical_reagents_in_multiple_spaces)
recipe foo [ # dummy
def foo [ # dummy
]
recipe main [
def main [
local-scope
0:address:shared:array:location/names:foo <- copy 0 # specify surrounding space
x:boolean <- copy 1/true

View File

@ -172,11 +172,11 @@ void run_mu_scenario(const scenario& s) {
:(scenario forbid_redefining_scenario_even_if_forced)
% Hide_errors = true;
% Disable_redefine_checks = true;
recipe scenario-foo [
def scenario-foo [
1:number <- copy 34
]
recipe scenario-foo [
def scenario-foo [
1:number <- copy 35
]
+error: redefining recipe scenario-foo
@ -190,7 +190,7 @@ recipe scenario-foo [
//: 'run' interprets a string as a set of instructions
:(scenario run)
recipe main [
def main [
run [
1:number <- copy 13
]
@ -231,7 +231,7 @@ void bind_special_scenario_names(recipe_ordinal r) {
}
:(scenario run_multiple)
recipe main [
def main [
run [
1:number <- copy 13
]
@ -253,7 +253,7 @@ Scenario_testing_scenario = false;
:(scenario memory_check)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
memory-should-contain [
1 <- 13
]
@ -389,7 +389,7 @@ void check_string(long long int address, const string& literal) {
:(scenario memory_check_multiple)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
memory-should-contain [
1 <- 0
1 <- 0
@ -400,7 +400,7 @@ recipe main [
:(scenario memory_check_string_length)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 3
2:number <- copy 97 # 'a'
3:number <- copy 98 # 'b'
@ -412,7 +412,7 @@ recipe main [
+error: expected location 1 to contain length 2 of string [ab] but saw 3
:(scenario memory_check_string)
recipe main [
def main [
1:number <- copy 3
2:number <- copy 97 # 'a'
3:number <- copy 98 # 'b'
@ -429,7 +429,7 @@ recipe main [
:(scenario memory_invalid_string_check)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
memory-should-contain [
1 <- [abc]
]
@ -439,7 +439,7 @@ recipe main [
:(scenario memory_check_with_comment)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
memory-should-contain [
1 <- 34 # comment
]
@ -456,7 +456,7 @@ recipe main [
:(scenario trace_check_fails)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
trace-should-contain [
a: b
a: d
@ -515,7 +515,7 @@ vector<trace_line> parse_trace(const string& expected) {
:(scenario trace_check_fails_in_nonfirst_line)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
run [
trace 1, [a], [b]
]
@ -528,7 +528,7 @@ recipe main [
:(scenario trace_check_passes_silently)
% Scenario_testing_scenario = true;
recipe main [
def main [
run [
trace 1, [a], [b]
]
@ -546,7 +546,7 @@ $error: 0
:(scenario trace_negative_check_fails)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
run [
trace 1, [a], [b]
]
@ -589,7 +589,7 @@ bool check_trace_missing(const string& in) {
:(scenario trace_negative_check_passes_silently)
% Scenario_testing_scenario = true;
recipe main [
def main [
trace-should-not-contain [
a: b
]
@ -600,7 +600,7 @@ $error: 0
:(scenario trace_negative_check_fails_on_any_unexpected_line)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
run [
trace 1, [a], [d]
]
@ -612,7 +612,7 @@ recipe main [
+error: unexpected [d] in trace with label a
:(scenario trace_count_check)
recipe main [
def main [
run [
trace 1, [a], [foo]
]
@ -666,7 +666,7 @@ case CHECK_TRACE_COUNT_FOR_LABEL: {
:(scenario trace_count_check_2)
% Scenario_testing_scenario = true;
% Hide_errors = true;
recipe main [
def main [
run [
trace 1, [a], [foo]
]

View File

@ -7,7 +7,7 @@
//: todo: switch recipe.steps to a more efficient data structure.
:(scenario tangle_before)
recipe main [
def main [
1:number <- copy 0
<label1>
3:number <- copy 0
@ -152,7 +152,7 @@ void check_insert_fragments(unused recipe_ordinal) {
}
:(scenario tangle_before_and_after)
recipe main [
def main [
1:number <- copy 0
<label1>
4:number <- copy 0
@ -173,7 +173,7 @@ $mem: 4
:(scenario tangle_ignores_jump_target)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 0
+label1
4:number <- copy 0
@ -184,7 +184,7 @@ before +label1 [
+error: can't tangle before label +label1
:(scenario tangle_keeps_labels_separate)
recipe main [
def main [
1:number <- copy 0
<label1>
<label2>
@ -215,7 +215,7 @@ after <label2> [
$mem: 6
:(scenario tangle_stacks_multiple_fragments)
recipe main [
def main [
1:number <- copy 0
<label1>
6:number <- copy 0
@ -245,7 +245,7 @@ after <label1> [
$mem: 6
:(scenario tangle_supports_fragments_with_multiple_instructions)
recipe main [
def main [
1:number <- copy 0
<label1>
6:number <- copy 0
@ -269,13 +269,13 @@ after <label1> [
$mem: 6
:(scenario tangle_tangles_into_all_labels_with_same_name)
recipe main [
def main [
1:number <- copy 10
<label1>
4:number <- copy 10
recipe2
]
recipe recipe2 [
def recipe2 [
1:number <- copy 11
<label1>
4:number <- copy 11
@ -301,7 +301,7 @@ after <label1> [
$mem: 8
:(scenario tangle_tangles_into_all_labels_with_same_name_2)
recipe main [
def main [
1:number <- copy 10
<label1>
<label1>
@ -325,7 +325,7 @@ after <label1> [
$mem: 6
:(scenario tangle_tangles_into_all_labels_with_same_name_3)
recipe main [
def main [
1:number <- copy 10
<label1>
<foo>
@ -352,7 +352,7 @@ after <foo> [
$mem: 6
:(scenario tangle_handles_jump_target_inside_fragment)
recipe main [
def main [
1:number <- copy 10
<label1>
4:number <- copy 10
@ -373,7 +373,7 @@ before <label1> [
$mem: 3
:(scenario tangle_renames_jump_target)
recipe main [
def main [
1:number <- copy 10
<label1>
+label2
@ -395,7 +395,7 @@ before <label1> [
$mem: 3
:(scenario tangle_jump_to_base_recipe)
recipe main [
def main [
1:number <- copy 10
<label1>
+label2

View File

@ -4,13 +4,13 @@
:(scenarios load)
:(scenario dilated_reagent)
recipe main [
def main [
{1: number, foo: bar} <- copy 34
]
+parse: product: 1: "number", {"foo": "bar"}
:(scenario load_trailing_space_after_curly_bracket)
recipe main [
def main [
# line below has a space at the end
{
]
@ -18,14 +18,14 @@ recipe main [
:(scenarios run)
:(scenario dilated_reagent_with_comment)
recipe main [
def main [
{1: number, foo: bar} <- copy 34 # test comment
]
+parse: product: 1: "number", {"foo": "bar"}
$error: 0
:(scenario dilated_reagent_with_comment_immediately_following)
recipe main [
def main [
1:number <- copy {34: literal} # test comment
]
$error: 0

View File

@ -4,7 +4,7 @@
// (address to array of charaters) to (list of numbers)".
:(scenario dilated_reagent_with_nested_brackets)
recipe main [
def main [
{1: number, foo: (bar (baz quux))} <- copy 34
]
+parse: product: 1: "number", {"foo": ("bar" ("baz" "quux"))}
@ -59,7 +59,7 @@ string_tree* parse_string_tree(istream& in) {
:(scenario dilated_reagent_with_type_tree)
% Hide_errors = true; // 'map' isn't defined yet
recipe main [
def main [
{1: (foo (address array character) (bar number))} <- copy 34
]
# just to avoid errors
@ -70,7 +70,7 @@ container bar [
+parse: product: 1: ("foo" ("address" "array" "character") ("bar" "number"))
:(scenario dilated_reagent_in_static_array)
recipe main [
def main [
{1: (array (address shared number) 3)} <- create-array
5:address:address:shared:number <- index-address {1: (array (address shared number) 3)}, 0
*5:address:address:shared:number <- new number:type
@ -83,7 +83,7 @@ recipe main [
//: an exception is 'new', which takes a type tree as its ingredient *value*
:(scenario dilated_reagent_with_new)
recipe main [
def main [
x:address:shared:address:number <- new {(address number): type}
]
+new: size of ("address" "number") is 1

View File

@ -2,14 +2,14 @@
//: number of ingredients and yields some fixed number of products.
:(scenario recipe_with_header)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z:number <- add x, y
reply z
return z
]
+mem: storing 8 in location 1
@ -48,38 +48,38 @@ void load_recipe_header(istream& in, recipe& result) {
}
:(scenario recipe_handles_stray_comma)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number, [
def add2 x:number, y:number -> z:number, [
local-scope
load-ingredients
z:number <- add x, y
reply z
return z
]
+mem: storing 8 in location 1
:(scenario recipe_handles_stray_comma_2)
recipe main [
def main [
foo
]
recipe foo, [
def foo, [
1:number/raw <- add 2, 2
]
recipe bar [
def bar [
1:number/raw <- add 2, 3
]
+mem: storing 4 in location 1
:(scenario recipe_handles_missing_bracket)
% Hide_errors = true;
recipe main
def main
]
+error: recipe body must begin with '['
:(scenario recipe_handles_missing_bracket_2)
% Hide_errors = true;
recipe main
def main
local-scope
{
}
@ -90,7 +90,7 @@ recipe main
:(scenario recipe_handles_missing_bracket_3)
% Hide_errors = true;
recipe main # comment
def main # comment
local-scope
{
}
@ -110,7 +110,7 @@ for (long long int i = 0; i < SIZE(x.products); ++i)
//: If a recipe never mentions any ingredients or products, assume it has a header.
:(scenario recipe_without_ingredients_or_products_has_header)
recipe test [
def test [
1:number <- copy 34
]
+parse: recipe test has a header
@ -121,6 +121,7 @@ if (!result.has_header) {
for (long long int i = 0; i < SIZE(result.steps); ++i) {
const instruction& inst = result.steps.at(i);
if ((inst.name == "reply" && !inst.ingredients.empty())
|| (inst.name == "return" && !inst.ingredients.empty())
|| inst.name == "next-ingredient"
|| inst.name == "ingredient"
|| inst.name == "rewind-ingredients") {
@ -182,25 +183,25 @@ case NEXT_INGREDIENT_WITHOUT_TYPECHECKING: {
:(scenario show_clear_error_on_bad_call)
% Hide_errors = true;
recipe main [
def main [
1:number <- foo 34
]
recipe foo x:point -> y:number [
def foo x:point -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
+error: main: ingredient 0 has the wrong type at '1:number <- foo 34'
:(scenario show_clear_error_on_bad_call_2)
% Hide_errors = true;
recipe main [
def main [
1:point <- foo 34
]
recipe foo x:number -> y:number [
def foo x:number -> y:number [
local-scope
load-ingredients
reply x
return x
]
+error: main: product 0 has the wrong type at '1:point <- foo 34'
@ -245,11 +246,11 @@ bool is_unique_address(reagent x) {
:(scenario forbid_calls_with_nonshared_addresses)
% Hide_errors = true;
recipe main [
def main [
1:address:number <- copy 0
foo 1:address:number
]
recipe foo x:address:number [
def foo x:address:number [
local-scope
load-ingredients
]
@ -257,10 +258,10 @@ recipe foo x:address:number [
:(scenario forbid_calls_with_nonshared_addresses_2)
% Hide_errors = true;
recipe main [
def main [
1:address:number <- foo
]
recipe foo -> x:address:number [
def foo -> x:address:number [
local-scope
load-ingredients
x <- copy 0
@ -272,13 +273,13 @@ recipe foo -> x:address:number [
:(scenarios transform)
:(scenario recipe_headers_are_checked)
% Hide_errors = true;
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z:address:number <- copy 0/unsafe
reply z
return z
]
+error: add2: replied with the wrong type at 'reply z'
+error: add2: replied with the wrong type at 'return z'
:(before "End Checks")
Transform.push_back(check_reply_instructions_against_header); // idempotent
@ -290,7 +291,7 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
trace(9991, "transform") << "--- checking reply instructions against header for " << caller_recipe.name << end();
for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
const instruction& inst = caller_recipe.steps.at(i);
if (inst.name != "reply") continue;
if (inst.name != "reply" && inst.name != "return") continue;
if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) {
raise << maybe(caller_recipe.name) << "replied with the wrong number of products at '" << to_string(inst) << "'\n" << end();
continue;
@ -304,20 +305,20 @@ void check_reply_instructions_against_header(const recipe_ordinal r) {
:(scenario recipe_headers_are_checked_2)
% Hide_errors = true;
recipe add2 x:number, y:number [
def add2 x:number, y:number [
local-scope
load-ingredients
z:address:number <- copy 0/unsafe
reply z
return z
]
+error: add2: replied with the wrong number of products at 'reply z'
+error: add2: replied with the wrong number of products at 'return z'
:(scenario recipe_headers_check_for_duplicate_names)
% Hide_errors = true;
recipe add2 x:number, x:number -> z:number [
def add2 x:number, x:number -> z:number [
local-scope
load-ingredients
reply z
return z
]
+error: add2: x can't repeat in the ingredients
@ -344,14 +345,14 @@ void check_header_ingredients(const recipe_ordinal r) {
:(scenarios run)
:(scenario deduce_instruction_types_from_recipe_header)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z <- add x, y # no type for z
reply z
return z
]
+mem: storing 8 in location 1
@ -399,14 +400,14 @@ void deduce_types_from_header(const recipe_ordinal r) {
//: in the header.
:(scenario reply_based_on_header)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z <- add x, y
reply
return
]
+mem: storing 8 in location 1
@ -420,11 +421,12 @@ void fill_in_reply_ingredients(recipe_ordinal r) {
trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << caller_recipe.name << end();
for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) {
instruction& inst = caller_recipe.steps.at(i);
if (inst.name == "reply")
if (inst.name == "reply" || inst.name == "return")
add_header_products(inst, caller_recipe);
}
// fall through reply
if (caller_recipe.steps.at(SIZE(caller_recipe.steps)-1).name != "reply") {
const instruction& final_instruction = caller_recipe.steps.at(SIZE(caller_recipe.steps)-1);
if (final_instruction.name != "reply" && final_instruction.name != "return") {
instruction inst;
inst.name = "reply";
add_header_products(inst, caller_recipe);
@ -433,7 +435,7 @@ void fill_in_reply_ingredients(recipe_ordinal r) {
}
void add_header_products(instruction& inst, const recipe& caller_recipe) {
assert(inst.name == "reply");
assert(inst.name == "reply" || inst.name == "return");
// collect any products with the same names as ingredients
for (long long int i = 0; i < SIZE(caller_recipe.products); ++i) {
// if the ingredient is missing, add it from the header
@ -449,24 +451,24 @@ void add_header_products(instruction& inst, const recipe& caller_recipe) {
}
:(scenario explicit_reply_ignores_header)
recipe main [
def main [
1:number/raw, 2:number/raw <- add2 3, 5
]
recipe add2 a:number, b:number -> y:number, z:number [
def add2 a:number, b:number -> y:number, z:number [
local-scope
load-ingredients
y <- add a, b
z <- subtract a, b
reply a, z
return a, z
]
+mem: storing 3 in location 1
+mem: storing -2 in location 2
:(scenario reply_on_fallthrough_based_on_header)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z <- add x, y
@ -475,27 +477,27 @@ recipe add2 x:number, y:number -> z:number [
+mem: storing 8 in location 1
:(scenario reply_on_fallthrough_already_exists)
recipe main [
def main [
1:number/raw <- add2 3, 5
]
recipe add2 x:number, y:number -> z:number [
def add2 x:number, y:number -> z:number [
local-scope
load-ingredients
z <- add x, y # no type for z
reply z
return z
]
+transform: instruction: reply z
+transform: instruction: return z
-transform: instruction: reply z:number
+mem: storing 8 in location 1
:(scenario recipe_headers_perform_same_ingredient_check)
% Hide_errors = true;
recipe main [
def main [
1:number <- copy 34
2:number <- copy 34
3:number <- add2 1:number, 2:number
]
recipe add2 x:number, y:number -> x:number [
def add2 x:number, y:number -> x:number [
local-scope
load-ingredients
]

View File

@ -3,13 +3,13 @@
//: names like 'print' or 'length' in many mutually extensible ways.
:(scenario static_dispatch)
recipe main [
def main [
7:number/raw <- test 3
]
recipe test a:number -> z:number [
def test a:number -> z:number [
z <- copy 1
]
recipe test a:number, b:number -> z:number [
def test a:number, b:number -> z:number [
z <- copy 2
]
+mem: storing 1 in location 7
@ -115,13 +115,13 @@ string next_unused_recipe_name(const string& recipe_name) {
//: call with the most suitable variant.
:(scenario static_dispatch_picks_most_similar_variant)
recipe main [
def main [
7:number/raw <- test 3, 4, 5
]
recipe test a:number -> z:number [
def test a:number -> z:number [
z <- copy 1
]
recipe test a:number, b:number -> z:number [
def test a:number, b:number -> z:number [
z <- copy 2
]
+mem: storing 2 in location 7
@ -336,37 +336,37 @@ bool next_stash(const call& c, instruction* stash_inst) {
}
:(scenario static_dispatch_disabled_in_recipe_without_variants)
recipe main [
def main [
1:number <- test 3
]
recipe test [
def test [
2:number <- next-ingredient # ensure no header
reply 34
return 34
]
+mem: storing 34 in location 1
:(scenario static_dispatch_disabled_on_headerless_definition)
% Hide_errors = true;
recipe test a:number -> z:number [
def test a:number -> z:number [
z <- copy 1
]
recipe test [
reply 34
def test [
return 34
]
+error: redefining recipe test
:(scenario static_dispatch_disabled_on_headerless_definition_2)
% Hide_errors = true;
recipe test [
reply 34
def test [
return 34
]
recipe test a:number -> z:number [
def test a:number -> z:number [
z <- copy 1
]
+error: redefining recipe test
:(scenario static_dispatch_on_primitive_names)
recipe main [
def main [
1:number <- copy 34
2:number <- copy 34
3:boolean <- equal 1:number, 2:number
@ -376,7 +376,7 @@ recipe main [
]
# temporarily hardcode number equality to always fail
recipe equal x:number, y:number -> z:boolean [
def equal x:number, y:number -> z:boolean [
local-scope
load-ingredients
z <- copy 0/false
@ -387,15 +387,15 @@ recipe equal x:number, y:number -> z:boolean [
+mem: storing 1 in location 6
:(scenario static_dispatch_works_with_dummy_results_for_containers)
recipe main [
def main [
_ <- test 3, 4
]
recipe test a:number -> z:point [
def test a:number -> z:point [
local-scope
load-ingredients
z <- merge a, 0
]
recipe test a:number, b:number -> z:point [
def test a:number, b:number -> z:point [
local-scope
load-ingredients
z <- merge a, b
@ -403,14 +403,14 @@ recipe test a:number, b:number -> z:point [
$error: 0
:(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use)
recipe main [
def main [
x:address:shared:foo <- new foo:type
test x
]
container foo [
x:number
]
recipe test a:address:shared:foo -> z:number [
def test a:address:shared:foo -> z:number [
local-scope
load-ingredients
z:number <- get *a, x:offset
@ -418,11 +418,11 @@ recipe test a:address:shared:foo -> z:number [
$error: 0
:(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use)
recipe main [
def main [
x:address:shared:foo <- new foo:type
test x
]
recipe test a:address:shared:foo -> z:number [
def test a:address:shared:foo -> z:number [
local-scope
load-ingredients
z:number <- get *a, x:offset
@ -433,78 +433,78 @@ container foo [
$error: 0
:(scenario static_dispatch_prefers_literals_to_be_numbers_rather_than_addresses)
recipe main [
def main [
1:number <- foo 0
]
recipe foo x:address:number -> y:number [
reply 34
def foo x:address:number -> y:number [
return 34
]
recipe foo x:number -> y:number [
reply 35
def foo x:number -> y:number [
return 35
]
+mem: storing 35 in location 1
:(scenario static_dispatch_on_non_literal_character_ignores_variant_with_numbers)
% Hide_errors = true;
recipe main [
def main [
local-scope
x:character <- copy 10/newline
1:number/raw <- foo x
]
recipe foo x:number -> y:number [
def foo x:number -> y:number [
load-ingredients
reply 34
return 34
]
+error: main: ingredient 0 has the wrong type at '1:number/raw <- foo x'
-mem: storing 34 in location 1
:(scenario static_dispatch_dispatches_literal_to_boolean_before_character)
recipe main [
def main [
1:number/raw <- foo 0 # valid literal for boolean
]
recipe foo x:character -> y:number [
def foo x:character -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:boolean -> y:number [
def foo x:boolean -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
# boolean variant is preferred
+mem: storing 35 in location 1
:(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range)
recipe main [
def main [
1:number/raw <- foo 97 # not a valid literal for boolean
]
recipe foo x:character -> y:number [
def foo x:character -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:boolean -> y:number [
def foo x:boolean -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
# character variant is preferred
+mem: storing 34 in location 1
:(scenario static_dispatch_dispatches_literal_to_number_if_at_all_possible)
recipe main [
def main [
1:number/raw <- foo 97
]
recipe foo x:character -> y:number [
def foo x:character -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:number -> y:number [
def foo x:number -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
# number variant is preferred
+mem: storing 35 in location 1
@ -523,42 +523,42 @@ string header_label(recipe_ordinal r) {
}
:(scenario reload_variant_retains_other_variants)
recipe main [
def main [
1:number <- copy 34
2:number <- foo 1:number
]
recipe foo x:number -> y:number [
def foo x:number -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:address:number -> y:number [
def foo x:address:number -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
recipe! foo x:address:number -> y:number [
def! foo x:address:number -> y:number [
local-scope
load-ingredients
reply 36
return 36
]
+mem: storing 34 in location 2
$error: 0
:(scenario dispatch_errors_come_after_unknown_name_errors)
% Hide_errors = true;
recipe main [
def main [
y:number <- foo x
]
recipe foo a:number -> b:number [
def foo a:number -> b:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo a:boolean -> b:number [
def foo a:boolean -> b:number [
local-scope
load-ingredients
reply 35
return 35
]
+error: main: missing type for x in 'y:number <- foo x'
+error: main: failed to find a matching call for 'y:number <- foo x'

View File

@ -5,7 +5,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
1:foo:number <- merge 12, 13
3:foo:point <- merge 14, 15, 16
]
@ -21,7 +21,7 @@ container foo:_a:_b [
x:_a
y:_b
]
recipe main [
def main [
1:foo:number:boolean <- merge 34, 1/true
]
$error: 0
@ -31,7 +31,7 @@ container foo:_a:_b [
x:_a
y:_b
]
recipe main [
def main [
1:address:shared:array:character <- new [abc]
# compound types for type ingredients
{2: (foo number (address shared array character))} <- merge 34/x, 1:address:shared:array:character/y
@ -47,7 +47,7 @@ container bar:_a:_b [
# dilated element
{data: (foo _a (address shared _b))}
]
recipe main [
def main [
1:address:shared:array:character <- new [abc]
2:bar:number:array:character <- merge 34/x, 1:address:shared:array:character/y
]
@ -112,7 +112,7 @@ exclusive-container foo:_t [
x:_t
y:number
]
recipe main [
def main [
1:foo:number <- merge 0/x, 34
3:foo:point <- merge 0/x, 15, 16
6:foo:point <- merge 1/y, 23
@ -157,7 +157,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
1:foo:point <- merge 14, 15, 16
2:number <- get 1:foo:point, y:offset
]
@ -178,7 +178,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
1:foo:point <- merge 14, 15, 16
2:point <- get 1:foo:point, x:offset
]
@ -190,7 +190,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
1:foo:address:point <- merge 34/unsafe, 48
2:address:point <- get 1:foo:address:point, x:offset
]
@ -205,7 +205,7 @@ container bar [
x:foo:point
y:number
]
recipe main [
def main [
1:bar <- merge 14, 15, 16, 17
2:number <- get 1:bar, 1:offset
]
@ -216,7 +216,7 @@ container foo:_a:_b [
x:_a
y:_b
]
recipe main [
def main [
1:address:shared:array:character <- new [abc]
{2: (foo number (address shared array character))} <- merge 34/x, 1:address:shared:array:character/y
3:address:shared:array:character <- get {2: (foo number (address shared array character))}, y:offset
@ -488,7 +488,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
10:foo:point <- merge 14, 15, 16
1:number <- get 10:foo, 1:offset
]
@ -501,7 +501,7 @@ container foo:_t [
x:_t
y:number
]
recipe main [
def main [
10:foo:point <- merge 14, 15, 16
1:address:number <- get-address 10:foo:point, 1:offset
]
@ -528,7 +528,7 @@ exclusive-container bar [
x:number
y:number
]
recipe main [
def main [
1:foo:bar <- merge 23, 1/y, 34
]
+mem: storing 23 in location 1
@ -546,7 +546,7 @@ exclusive-container bar [
x:number
y:number
]
recipe main [
def main [
1:foo:bar <- merge 23, 1/y, 34, 35
]
+error: main: too many ingredients in '1:foo:bar <- merge 23, 1/y, 34, 35'
@ -560,7 +560,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo:bar <- merge 1/y, 23, 34
]
+mem: storing 1 in location 1
@ -577,7 +577,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo:bar <- merge 0/x, 23
]
$error: 0
@ -592,7 +592,7 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo:bar <- merge 1/y, 23
]
+error: main: too few ingredients in '1:foo:bar <- merge 1/y, 23'

View File

@ -1,18 +1,18 @@
//:: Like container definitions, recipes too can contain type parameters.
:(scenario shape_shifting_recipe)
recipe main [
def main [
10:point <- merge 14, 15
11:point <- foo 10:point
]
# non-matching variant
recipe foo a:number -> result:number [
def foo a:number -> result:number [
local-scope
load-ingredients
result <- copy 34
]
# matching shape-shifting variant
recipe foo a:_t -> result:_t [
def foo a:_t -> result:_t [
local-scope
load-ingredients
result <- copy a
@ -542,18 +542,18 @@ void ensure_all_concrete_types(/*const*/ reagent& x, const recipe& exemplar) {
}
:(scenario shape_shifting_recipe_2)
recipe main [
def main [
10:point <- merge 14, 15
11:point <- foo 10:point
]
# non-matching shape-shifting variant
recipe foo a:_t, b:_t -> result:number [
def foo a:_t, b:_t -> result:number [
local-scope
load-ingredients
result <- copy 34
]
# matching shape-shifting variant
recipe foo a:_t -> result:_t [
def foo a:_t -> result:_t [
local-scope
load-ingredients
result <- copy a
@ -562,12 +562,12 @@ recipe foo a:_t -> result:_t [
+mem: storing 15 in location 12
:(scenario shape_shifting_recipe_nonroot)
recipe main [
def main [
10:foo:point <- merge 14, 15, 16
20:point/raw <- bar 10:foo:point
]
# shape-shifting recipe with type ingredient following some other type
recipe bar a:foo:_t -> result:_t [
def bar a:foo:_t -> result:_t [
local-scope
load-ingredients
result <- get a, x:offset
@ -584,22 +584,22 @@ container c:_a:_b [
a:_a
b:_b
]
recipe main [
def main [
s:address:shared:array:character <- new [abc]
{x: (c (address shared array character) number)} <- merge s, 34
foo x
]
recipe foo x:c:_bar:_baz [
def foo x:c:_bar:_baz [
local-scope
load-ingredients
]
:(scenario shape_shifting_recipe_type_deduction_ignores_offsets)
recipe main [
def main [
10:foo:point <- merge 14, 15, 16
20:point/raw <- bar 10:foo:point
]
recipe bar a:foo:_t -> result:_t [
def bar a:foo:_t -> result:_t [
local-scope
load-ingredients
x:number <- copy 1
@ -613,16 +613,16 @@ container foo:_t [
+mem: storing 15 in location 21
:(scenario shape_shifting_recipe_empty)
recipe main [
def main [
foo 1
]
# shape-shifting recipe with no body
recipe foo a:_t [
def foo a:_t [
]
# shouldn't crash
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient)
recipe main [
def main [
1:address:shared:foo:point <- bar 3
11:foo:point <- copy *1:address:shared:foo:point
]
@ -630,7 +630,7 @@ container foo:_t [
x:_t
y:number
]
recipe bar x:number -> result:address:shared:foo:_t [
def bar x:number -> result:address:shared:foo:_t [
local-scope
load-ingredients
# new refers to _t in its ingredient *value*
@ -641,11 +641,11 @@ recipe bar x:number -> result:address:shared:foo:_t [
+mem: storing 0 in location 13
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient_2)
recipe main [
def main [
1:address:shared:foo:point <- bar 3
11:foo:point <- copy *1:address:shared:foo:point
]
recipe bar x:number -> result:address:shared:foo:_t [
def bar x:number -> result:address:shared:foo:_t [
local-scope
load-ingredients
# new refers to _t in its ingredient *value*
@ -661,14 +661,14 @@ container foo:_t [
+mem: storing 0 in location 13
:(scenario shape_shifting_recipe_supports_compound_types)
recipe main [
def main [
1:address:shared:point <- new point:type
2:address:number <- get-address *1:address:shared:point, y:offset
*2:address:number <- copy 34
3:address:shared:point <- bar 1:address:shared:point # specialize _t to address:shared:point
4:point <- copy *3:address:shared:point
]
recipe bar a:_t -> result:_t [
def bar a:_t -> result:_t [
local-scope
load-ingredients
result <- copy a
@ -677,26 +677,26 @@ recipe bar a:_t -> result:_t [
:(scenario shape_shifting_recipe_error)
% Hide_errors = true;
recipe main [
def main [
a:number <- copy 3
b:address:shared:number <- foo a
]
recipe foo a:_t -> b:_t [
def foo a:_t -> b:_t [
load-ingredients
b <- copy a
]
+error: main: no call found for 'b:address:shared:number <- foo a'
:(scenario specialize_inside_recipe_without_header)
recipe main [
def main [
foo 3
]
recipe foo [
def foo [
local-scope
x:number <- next-ingredient # ensure no header
1:number/raw <- bar x # call a shape-shifting recipe
]
recipe bar x:_elem -> y:_elem [
def bar x:_elem -> y:_elem [
local-scope
load-ingredients
y <- add x, 1
@ -704,12 +704,12 @@ recipe bar x:_elem -> y:_elem [
+mem: storing 4 in location 1
:(scenario specialize_with_literal)
recipe main [
def main [
local-scope
# permit literal to map to number
1:number/raw <- foo 3
]
recipe foo x:_elem -> y:_elem [
def foo x:_elem -> y:_elem [
local-scope
load-ingredients
y <- add x, 1
@ -717,12 +717,12 @@ recipe foo x:_elem -> y:_elem [
+mem: storing 4 in location 1
:(scenario specialize_with_literal_2)
recipe main [
def main [
local-scope
# permit literal to map to character
1:character/raw <- foo 3
]
recipe foo x:_elem -> y:_elem [
def foo x:_elem -> y:_elem [
local-scope
load-ingredients
y <- add x, 1
@ -730,12 +730,12 @@ recipe foo x:_elem -> y:_elem [
+mem: storing 4 in location 1
:(scenario specialize_with_literal_3)
recipe main [
def main [
local-scope
# permit '0' to map to address to shape-shifting type-ingredient
1:address:shared:character/raw <- foo 0
]
recipe foo x:address:_elem -> y:address:_elem [
def foo x:address:_elem -> y:address:_elem [
local-scope
load-ingredients
y <- copy x
@ -745,12 +745,12 @@ $error: 0
:(scenario specialize_with_literal_4)
% Hide_errors = true;
recipe main [
def main [
local-scope
# ambiguous call: what's the type of its ingredient?!
foo 0
]
recipe foo x:address:_elem -> y:address:_elem [
def foo x:address:_elem -> y:address:_elem [
local-scope
load-ingredients
y <- copy x
@ -759,10 +759,10 @@ recipe foo x:address:_elem -> y:address:_elem [
+error: foo: failed to map a type to y
:(scenario specialize_with_literal_5)
recipe main [
def main [
foo 3, 4 # recipe mapping two variables to literals
]
recipe foo x:_elem, y:_elem [
def foo x:_elem, y:_elem [
local-scope
load-ingredients
1:number/raw <- add x, y
@ -771,22 +771,22 @@ recipe foo x:_elem, y:_elem [
:(scenario multiple_shape_shifting_variants)
# try to call two different shape-shifting recipes with the same name
recipe main [
def main [
e1:d1:number <- merge 3
e2:d2:number <- merge 4, 5
1:number/raw <- foo e1
2:number/raw <- foo e2
]
# the two shape-shifting definitions
recipe foo a:d1:_elem -> b:number [
def foo a:d1:_elem -> b:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo a:d2:_elem -> b:number [
def foo a:d2:_elem -> b:number [
local-scope
load-ingredients
reply 35
return 35
]
# the shape-shifting containers they use
container d1:_elem [
@ -801,21 +801,21 @@ container d2:_elem [
:(scenario multiple_shape_shifting_variants_2)
# static dispatch between shape-shifting variants, _including pointer lookups_
recipe main [
def main [
e1:d1:number <- merge 3
e2:address:shared:d2:number <- new {(d2 number): type}
1:number/raw <- foo e1
2:number/raw <- foo *e2 # different from previous scenario
]
recipe foo a:d1:_elem -> b:number [
def foo a:d1:_elem -> b:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo a:d2:_elem -> b:number [
def foo a:d2:_elem -> b:number [
local-scope
load-ingredients
reply 35
return 35
]
container d1:_elem [
x:_elem
@ -829,15 +829,15 @@ container d2:_elem [
:(scenario missing_type_in_shape_shifting_recipe)
% Hide_errors = true;
recipe main [
def main [
a:d1:number <- merge 3
foo a
]
recipe foo a:d1:_elem -> b:number [
def foo a:d1:_elem -> b:number [
local-scope
load-ingredients
copy e # no such variable
reply 34
return 34
]
container d1:_elem [
x:_elem
@ -848,15 +848,15 @@ container d1:_elem [
:(scenario missing_type_in_shape_shifting_recipe_2)
% Hide_errors = true;
recipe main [
def main [
a:d1:number <- merge 3
foo a
]
recipe foo a:d1:_elem -> b:number [
def foo a:d1:_elem -> b:number [
local-scope
load-ingredients
get e, x:offset # unknown variable in a 'get', which does some extra checking
reply 34
return 34
]
container d1:_elem [
x:_elem
@ -867,108 +867,108 @@ container d1:_elem [
:(scenarios transform)
:(scenario specialize_recursive_shape_shifting_recipe)
recipe main [
def main [
1:number <- copy 34
2:number <- foo 1:number
]
recipe foo x:_elem -> y:number [
def foo x:_elem -> y:number [
local-scope
load-ingredients
{
break
y:number <- foo x
}
reply y
return y
]
+transform: new specialization: foo_2
# transform terminates
:(scenarios run)
:(scenario specialize_most_similar_variant)
recipe main [
def main [
1:address:shared:number <- new number:type
2:number <- foo 1:address:shared:number
]
recipe foo x:_elem -> y:number [
def foo x:_elem -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:address:shared:_elem -> y:number [
def foo x:address:shared:_elem -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
+mem: storing 35 in location 2
:(scenario specialize_most_similar_variant_2)
# version with headers padded with lots of unrelated concrete types
recipe main [
def main [
1:number <- copy 23
2:address:shared:array:number <- copy 0
3:number <- foo 2:address:shared:array:number, 1:number
]
# variant with concrete type
recipe foo dummy:address:shared:array:number, x:number -> y:number, dummy:address:shared:array:number [
def foo dummy:address:shared:array:number, x:number -> y:number, dummy:address:shared:array:number [
local-scope
load-ingredients
reply 34
return 34
]
# shape-shifting variant
recipe foo dummy:address:shared:array:number, x:_elem -> y:number, dummy:address:shared:array:number [
def foo dummy:address:shared:array:number, x:_elem -> y:number, dummy:address:shared:array:number [
local-scope
load-ingredients
reply 35
return 35
]
# prefer the concrete variant
+mem: storing 34 in location 3
:(scenario specialize_most_similar_variant_3)
recipe main [
def main [
1:address:shared:array:character <- new [abc]
foo 1:address:shared:array:character
]
recipe foo x:address:shared:array:character [
def foo x:address:shared:array:character [
2:number <- copy 34
]
recipe foo x:address:_elem [
def foo x:address:_elem [
2:number <- copy 35
]
# make sure the more precise version was used
+mem: storing 34 in location 2
:(scenario specialize_literal_as_number)
recipe main [
def main [
1:number <- foo 23
]
recipe foo x:_elem -> y:number [
def foo x:_elem -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
recipe foo x:character -> y:number [
def foo x:character -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
+mem: storing 34 in location 1
:(scenario specialize_literal_as_number_2)
# version calling with literal
recipe main [
def main [
1:number <- foo 0
]
# variant with concrete type
recipe foo x:number -> y:number [
def foo x:number -> y:number [
local-scope
load-ingredients
reply 34
return 34
]
# shape-shifting variant
recipe foo x:address:shared:_elem -> y:number [
def foo x:address:shared:_elem -> y:number [
local-scope
load-ingredients
reply 35
return 35
]
# prefer the concrete variant, ignore concrete types in scoring the shape-shifting variant
+mem: storing 34 in location 1

View File

@ -4,12 +4,12 @@
//: One hole for now: variables in surrounding spaces are implicitly mutable.
:(scenario can_modify_value_ingredients)
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
foo *p
]
recipe foo p:point [
def foo p:point [
local-scope
load-ingredients
x:address:number <- get-address p, x:offset
@ -18,12 +18,12 @@ recipe foo p:point [
$error: 0
:(scenario can_modify_ingredients_that_are_also_products)
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
p <- foo p
]
recipe foo p:address:shared:point -> p:address:shared:point [
def foo p:address:shared:point -> p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -32,12 +32,12 @@ recipe foo p:address:shared:point -> p:address:shared:point [
$error: 0
:(scenario ignore_literal_ingredients_for_immutability_checks)
recipe main [
def main [
local-scope
p:address:shared:d1 <- new d1:type
q:number <- foo p
]
recipe foo p:address:shared:d1 -> q:number [
def foo p:address:shared:d1 -> q:number [
local-scope
load-ingredients
x:address:shared:d1 <- new d1:type
@ -52,12 +52,12 @@ $error: 0
:(scenario cannot_modify_immutable_ingredients)
% Hide_errors = true;
recipe main [
def main [
local-scope
x:address:shared:number <- new number:type
foo x
]
recipe foo x:address:shared:number [
def foo x:address:shared:number [
local-scope
load-ingredients
*x <- copy 34
@ -66,12 +66,12 @@ recipe foo x:address:shared:number [
:(scenario cannot_take_address_inside_immutable_ingredients)
% Hide_errors = true;
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:shared:point [
def foo p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -81,17 +81,17 @@ recipe foo p:address:shared:point [
:(scenario cannot_call_mutating_recipes_on_immutable_ingredients)
% Hide_errors = true;
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:shared:point [
def foo p:address:shared:point [
local-scope
load-ingredients
bar p
]
recipe bar p:address:shared:point -> p:address:shared:point [
def bar p:address:shared:point -> p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -101,12 +101,12 @@ recipe bar p:address:shared:point -> p:address:shared:point [
:(scenario cannot_modify_copies_of_immutable_ingredients)
% Hide_errors = true;
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:shared:point [
def foo p:address:shared:point [
local-scope
load-ingredients
q:address:shared:point <- copy p
@ -115,12 +115,12 @@ recipe foo p:address:shared:point [
+error: foo: cannot modify q after instruction 'x:address:number <- get-address *q, x:offset' because that would modify ingredient p which is not also a product of foo
:(scenario can_modify_copies_of_mutable_ingredients)
recipe main [
def main [
local-scope
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:shared:point -> p:address:shared:point [
def foo p:address:shared:point -> p:address:shared:point [
local-scope
load-ingredients
q:address:shared:point <- copy p
@ -133,10 +133,10 @@ $error: 0
container foo [
x:address:shared:array:number # contains an address
]
recipe main [
def main [
# don't run anything
]
recipe foo a:address:shared:foo [
def foo a:address:shared:foo [
local-scope
load-ingredients
x:address:shared:array:number <- get *a, x:offset # just a regular get of the container
@ -149,10 +149,10 @@ recipe foo a:address:shared:foo [
container foo [
x:address:shared:array:number # contains an address
]
recipe main [
def main [
# don't run anything
]
recipe foo a:address:shared:foo [
def foo a:address:shared:foo [
local-scope
load-ingredients
b:foo <- merge 0 # completely unrelated to 'a'
@ -167,10 +167,10 @@ $error: 0
container foo [
x:number
]
recipe main [
def main [
# don't run anything
]
recipe foo a:address:shared:array:address:number [
def foo a:address:shared:array:address:number [
local-scope
load-ingredients
x:address:number <- index *a, 0 # just a regular index of the array
@ -183,10 +183,10 @@ recipe foo a:address:shared:array:address:number [
container foo [
x:address:shared:array:number # contains an address
]
recipe main [
def main [
# don't run anything
]
recipe foo a:address:shared:array:address:number [
def foo a:address:shared:array:address:number [
local-scope
load-ingredients
b:address:shared:array:address:number <- new {(address number): type}, 3 # completely unrelated to 'a'
@ -199,17 +199,17 @@ $error: 0
container test-list [
next:address:shared:test-list
]
recipe main [
def main [
local-scope
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:shared:test-list [
def foo p:address:shared:test-list [
local-scope
load-ingredients
p2:address:shared:test-list <- bar p
]
recipe bar x:address:shared:test-list -> y:address:shared:test-list [
def bar x:address:shared:test-list -> y:address:shared:test-list [
local-scope
load-ingredients
y <- get *x, next:offset
@ -217,18 +217,18 @@ recipe bar x:address:shared:test-list -> y:address:shared:test-list [
$error: 0
:(scenario handle_optional_ingredients_in_immutability_checks)
recipe main [
def main [
k:address:shared:number <- new number:type
test k
]
# recipe taking an immutable address ingredient
recipe test k:address:shared:number [
def test k:address:shared:number [
local-scope
load-ingredients
foo k
]
# ..calling a recipe with an optional address ingredient
recipe foo -> [
def foo -> [
local-scope
load-ingredients
k:address:shared:number, found?:boolean <- next-ingredient
@ -237,17 +237,17 @@ $error: 0
//: when checking for immutable ingredients, remember to take space into account
:(scenario check_space_of_reagents_in_immutability_checks)
recipe main [
def main [
a:address:shared:array:location <- new-closure
b:address:shared:number <- new number:type
run-closure b:address:shared:number, a:address:shared:array:location
]
recipe new-closure [
def new-closure [
new-default-space
x:address:shared:number <- new number:type
reply default-space
return default-space
]
recipe run-closure x:address:shared:number, s:address:shared:array:location [
def run-closure x:address:shared:number, s:address:shared:array:location [
local-scope
load-ingredients
0:address:shared:array:location/names:new-closure <- copy s
@ -336,18 +336,18 @@ set<long long int> scan_contained_in_product_indices(const instruction& inst, se
container test-list [
next:address:shared:test-list
]
recipe main [
def main [
local-scope
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:shared:test-list [ # p is immutable
def foo p:address:shared:test-list [ # p is immutable
local-scope
load-ingredients
p2:address:shared:test-list <- test-next p # p2 is immutable
p3:address:address:shared:test-list <- get-address *p2, next:offset # signal modification of p2
]
recipe test-next x:address:shared:test-list -> y:address:shared:test-list/contained-in:x [
def test-next x:address:shared:test-list -> y:address:shared:test-list/contained-in:x [
local-scope
load-ingredients
y <- get *x, next:offset
@ -447,23 +447,23 @@ set<long long int> ingredient_indices(const instruction& inst, const set<reagent
container test-list [
next:address:shared:test-list
]
recipe main [
def main [
local-scope
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:shared:test-list -> p:address:shared:test-list [
def foo p:address:shared:test-list -> p:address:shared:test-list [
local-scope
load-ingredients
p2:address:shared:test-list <- test-next p
p <- test-remove p2, p
]
recipe test-next x:address:shared:test-list -> y:address:shared:test-list [
def test-next x:address:shared:test-list -> y:address:shared:test-list [
local-scope
load-ingredients
y <- get *x, next:offset
]
recipe test-remove x:address:shared:test-list/contained-in:from, from:address:shared:test-list -> from:address:shared:test-list [
def test-remove x:address:shared:test-list/contained-in:from, from:address:shared:test-list -> from:address:shared:test-list [
local-scope
load-ingredients
x2:address:address:shared:test-list <- get-address *x, next:offset # pretend modification

View File

@ -5,10 +5,10 @@
//: todo: support storing shape-shifting recipes into recipe variables and calling them
:(scenario call_literal_recipe)
recipe main [
def main [
1:number <- call f, 34
]
recipe f x:number -> y:number [
def f x:number -> y:number [
local-scope
load-ingredients
y <- copy x
@ -16,11 +16,11 @@ recipe f x:number -> y:number [
+mem: storing 34 in location 1
:(scenario call_variable)
recipe main [
def main [
{1: (recipe number -> number)} <- copy f
2:number <- call {1: (recipe number -> number)}, 34
]
recipe f x:number -> y:number [
def f x:number -> y:number [
local-scope
load-ingredients
y <- copy x
@ -75,10 +75,10 @@ case CALL: {
:(scenario call_check_literal_recipe)
% Hide_errors = true;
recipe main [
def main [
1:number <- call f, 34
]
recipe f x:point -> y:point [
def f x:point -> y:point [
local-scope
load-ingredients
y <- copy x
@ -88,11 +88,11 @@ recipe f x:point -> y:point [
:(scenario call_check_variable_recipe)
% Hide_errors = true;
recipe main [
def main [
{1: (recipe point -> point)} <- copy f
2:number <- call {1: (recipe point -> point)}, 34
]
recipe f x:point -> y:point [
def f x:point -> y:point [
local-scope
load-ingredients
y <- copy x
@ -153,12 +153,12 @@ bool is_mu_recipe(reagent r) {
:(scenario copy_typecheck_recipe_variable)
% Hide_errors = true;
recipe main [
def main [
3:number <- copy 34 # abc def
{1: (recipe number -> number)} <- copy f # store literal in a matching variable
{2: (recipe boolean -> boolean)} <- copy {1: (recipe number -> number)} # mismatch between recipe variables
]
recipe f x:number -> y:number [
def f x:number -> y:number [
local-scope
load-ingredients
y <- copy x
@ -167,10 +167,10 @@ recipe f x:number -> y:number [
:(scenario copy_typecheck_recipe_variable_2)
% Hide_errors = true;
recipe main [
def main [
{1: (recipe number -> number)} <- copy f # mismatch with a recipe literal
]
recipe f x:boolean -> y:boolean [
def f x:boolean -> y:boolean [
local-scope
load-ingredients
y <- copy x

View File

@ -2,14 +2,14 @@
//: guarantees on how the operations in each are interleaved with each other.
:(scenario scheduler)
recipe f1 [
def f1 [
start-running f2
# wait for f2 to run
{
jump-unless 1:number, -1
}
]
recipe f2 [
def f2 [
1:number <- copy 1
]
+schedule: f1
@ -181,7 +181,7 @@ case START_RUNNING: {
:(scenario scheduler_runs_single_routine)
% Scheduling_interval = 1;
recipe f1 [
def f1 [
1:number <- copy 0
2:number <- copy 0
]
@ -192,12 +192,12 @@ recipe f1 [
:(scenario scheduler_interleaves_routines)
% Scheduling_interval = 1;
recipe f1 [
def f1 [
start-running f2
1:number <- copy 0
2:number <- copy 0
]
recipe f2 [
def f2 [
3:number <- copy 0
4:number <- copy 0
]
@ -213,24 +213,24 @@ recipe f2 [
+run: 2:number <- copy 0
:(scenario start_running_takes_ingredients)
recipe f1 [
def f1 [
start-running f2, 3
# wait for f2 to run
{
jump-unless 1:number, -1
}
]
recipe f2 [
def f2 [
1:number <- next-ingredient
2:number <- add 1:number, 1
]
+mem: storing 4 in location 2
:(scenario start_running_returns_routine_id)
recipe f1 [
def f1 [
1:number <- start-running f2
]
recipe f2 [
def f2 [
12:number <- copy 44
]
+mem: storing 2 in location 1
@ -244,7 +244,7 @@ recipe f2 [
% Routines.push_back(new routine(f2));
% Routines.back()->state = COMPLETED; // f2 not meant to run
# must have at least one routine without escaping
recipe f3 [
def f3 [
3:number <- copy 0
]
# by interleaving '+' lines with '-' lines, we allow f1 and f3 to run in any order
@ -258,7 +258,7 @@ recipe f3 [
:(scenario scheduler_starts_at_middle_of_routines)
% Routines.push_back(new routine(COPY));
% Routines.back()->state = COMPLETED;
recipe f1 [
def f1 [
1:number <- copy 0
2:number <- copy 0
]
@ -270,12 +270,12 @@ recipe f1 [
:(scenario scheduler_terminates_routines_after_errors)
% Hide_errors = true;
% Scheduling_interval = 2;
recipe f1 [
def f1 [
start-running f2
1:number <- copy 0
2:number <- copy 0
]
recipe f2 [
def f2 [
# divide by 0 twice
3:number <- divide-with-remainder 4, 0
4:number <- divide-with-remainder 4, 0
@ -292,11 +292,11 @@ recipe f2 [
//:: Routines are marked completed when their parent completes.
:(scenario scheduler_kills_orphans)
recipe main [
def main [
start-running f1
# f1 never actually runs because its parent completes without waiting for it
]
recipe f1 [
def f1 [
1:number <- copy 0
]
-schedule: f1
@ -323,13 +323,13 @@ bool has_completed_parent(long long int routine_index) {
:(scenario routine_state_test)
% Scheduling_interval = 2;
recipe f1 [
def f1 [
1:number/child-id <- start-running f2
12:number <- copy 0 # race condition since we don't care about location 12
# thanks to Scheduling_interval, f2's one instruction runs in between here and completes
2:number/state <- routine-state 1:number/child-id
]
recipe f2 [
def f2 [
12:number <- copy 0
# trying to run a second instruction marks routine as completed
]
@ -445,7 +445,7 @@ case _DUMP_ROUTINES: {
:(scenario routine_discontinues_past_limit)
% Scheduling_interval = 2;
recipe f1 [
def f1 [
1:number/child-id <- start-running f2
limit-time 1:number/child-id, 10
# padding loop just to make sure f2 has time to completed
@ -453,7 +453,7 @@ recipe f1 [
2:number <- subtract 2:number, 1
jump-if 2:number, -2:offset
]
recipe f2 [
def f2 [
jump -1:offset # run forever
$print [should never get here], 10/newline
]
@ -514,7 +514,7 @@ case LIMIT_TIME: {
//:: make sure that each routine gets a different alloc to start
:(scenario new_concurrent)
recipe f1 [
def f1 [
start-running f2
1:address:shared:number/raw <- new number:type
# wait for f2 to complete
@ -522,7 +522,7 @@ recipe f1 [
loop-unless 4:number/raw
}
]
recipe f2 [
def f2 [
2:address:shared:number/raw <- new number:type
# hack: assumes scheduler implementation
3:boolean/raw <- equal 1:address:shared:number/raw, 2:address:shared:number/raw

View File

@ -4,14 +4,14 @@
//: operate.
:(scenario wait_for_location)
recipe f1 [
def f1 [
1:number <- copy 0
start-running f2
wait-for-location 1:number
# now wait for f2 to run and modify location 1 before using its value
2:number <- copy 1:number
]
recipe f2 [
def f2 [
1:number <- copy 34
]
# if we got the synchronization wrong we'd be storing 0 in location 2
@ -65,14 +65,14 @@ for (long long int i = 0; i < SIZE(Routines); ++i) {
//: also allow waiting on a routine to stop running
:(scenario wait_for_routine)
recipe f1 [
def f1 [
1:number <- copy 0
12:number/routine <- start-running f2
wait-for-routine 12:number/routine
# now wait for f2 to run and modify location 1 before using its value
3:number <- copy 1:number
]
recipe f2 [
def f2 [
1:number <- copy 34
]
+schedule: f1

View File

@ -2,20 +2,20 @@
# to-text-line gets called implicitly in various places
# define it to be identical to 'to-text' by default
recipe to-text-line x:_elem -> y:address:shared:array:character [
def to-text-line x:_elem -> y:address:shared:array:character [
local-scope
load-ingredients
y <- to-text x
]
# to-text on text is just the identity function
recipe to-text x:address:shared:array:character -> y:address:shared:array:character [
def to-text x:address:shared:array:character -> y:address:shared:array:character [
local-scope
load-ingredients
reply x
return x
]
recipe equal a:address:shared:array:character, b:address:shared:array:character -> result:boolean [
def equal a:address:shared:array:character, b:address:shared:array:character -> result:boolean [
local-scope
load-ingredients
a-len:number <- length *a
@ -25,7 +25,7 @@ recipe equal a:address:shared:array:character, b:address:shared:array:character
trace 99, [text-equal], [comparing lengths]
length-equal?:boolean <- equal a-len, b-len
break-if length-equal?
reply 0
return 0
}
# compare each corresponding character
trace 99, [text-equal], [comparing characters]
@ -38,12 +38,12 @@ recipe equal a:address:shared:array:character, b:address:shared:array:character
{
chars-match?:boolean <- equal a2, b2
break-if chars-match?
reply 0
return 0
}
i <- add i, 1
loop
}
reply 1
return 1
]
scenario text-equal-reflexive [
@ -117,7 +117,7 @@ container buffer [
data:address:shared:array:character
]
recipe new-buffer capacity:number -> result:address:shared:buffer [
def new-buffer capacity:number -> result:address:shared:buffer [
local-scope
load-ingredients
result <- new buffer:type
@ -125,10 +125,10 @@ recipe new-buffer capacity:number -> result:address:shared:buffer [
*len:address:number <- copy 0
s:address:address:shared:array:character <- get-address *result, data:offset
*s <- new character:type, capacity
reply result
return result
]
recipe grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
def grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
local-scope
load-ingredients
# double buffer size
@ -150,7 +150,7 @@ recipe grow-buffer in:address:shared:buffer -> in:address:shared:buffer [
}
]
recipe buffer-full? in:address:shared:buffer -> result:boolean [
def buffer-full? in:address:shared:buffer -> result:boolean [
local-scope
load-ingredients
len:number <- get *in, length:offset
@ -160,7 +160,7 @@ recipe buffer-full? in:address:shared:buffer -> result:boolean [
]
# most broadly applicable definition of append to a buffer: just call to-text
recipe append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
def append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
local-scope
load-ingredients
text:address:shared:array:character <- to-text x
@ -176,7 +176,7 @@ recipe append buf:address:shared:buffer, x:_elem -> buf:address:shared:buffer [
}
]
recipe append in:address:shared:buffer, c:character -> in:address:shared:buffer [
def append in:address:shared:buffer, c:character -> in:address:shared:buffer [
local-scope
load-ingredients
len:address:number <- get-address *in, length:offset
@ -185,9 +185,9 @@ recipe append in:address:shared:buffer, c:character -> in:address:shared:buffer
backspace?:boolean <- equal c, 8/backspace
break-unless backspace?
empty?:boolean <- lesser-or-equal *len, 0
reply-if empty?
return-if empty?
*len <- subtract *len, 1
reply
return
}
{
# grow buffer if necessary
@ -263,14 +263,14 @@ scenario buffer-append-handles-backspace [
]
]
recipe to-text n:number -> result:address:shared:array:character [
def to-text n:number -> result:address:shared:array:character [
local-scope
load-ingredients
# is n zero?
{
break-if n
result <- new [0]
reply
return
}
# save sign
negate-result:boolean <- copy 0
@ -317,27 +317,27 @@ recipe to-text n:number -> result:address:shared:array:character [
}
]
recipe to-text x:boolean -> result:address:shared:array:character [
def to-text x:boolean -> result:address:shared:array:character [
local-scope
load-ingredients
n:number <- copy x:boolean
result <- to-text n
]
recipe to-text x:address:_elem -> result:address:shared:array:character [
def to-text x:address:_elem -> result:address:shared:array:character [
local-scope
load-ingredients
n:number <- copy x
result <- to-text n
]
recipe buffer-to-array in:address:shared:buffer -> result:address:shared:array:character [
def buffer-to-array in:address:shared:buffer -> result:address:shared:array:character [
local-scope
load-ingredients
{
# propagate null buffer
break-if in
reply 0
return 0
}
len:number <- get *in, length:offset
s:address:shared:array:character <- get *in, data:offset
@ -387,7 +387,7 @@ scenario integer-to-decimal-digit-negative [
]
]
recipe append a:address:shared:array:character, b:address:shared:array:character -> result:address:shared:array:character [
def append a:address:shared:array:character, b:address:shared:array:character -> result:address:shared:array:character [
local-scope
load-ingredients
# result = new character[a.length + b.length]
@ -449,13 +449,13 @@ scenario replace-character-in-text [
]
]
recipe replace s:address:shared:array:character, oldc:character, newc:character, from:number/optional -> s:address:shared:array:character [
def replace s:address:shared:array:character, oldc:character, newc:character, from:number/optional -> s:address:shared:array:character [
local-scope
load-ingredients
len:number <- length *s
i:number <- find-next s, oldc, from
done?:boolean <- greater-or-equal i, len
reply-if done?, s/same-as-ingredient:0
return-if done?, s/same-as-ingredient:0
dest:address:character <- index-address *s, i
*dest <- copy newc
i <- add i, 1
@ -507,7 +507,7 @@ scenario replace-all-characters [
]
# replace underscores in first with remaining args
recipe interpolate template:address:shared:array:character -> result:address:shared:array:character [
def interpolate template:address:shared:array:character -> result:address:shared:array:character [
local-scope
load-ingredients # consume just the template
# compute result-len, space to allocate for result
@ -621,68 +621,68 @@ scenario interpolate-at-end [
]
# result:boolean <- space? c:character
recipe space? c:character -> result:boolean [
def space? c:character -> result:boolean [
local-scope
load-ingredients
# most common case first
result <- equal c, 32/space
reply-if result
return-if result
result <- equal c, 10/newline
reply-if result
return-if result
result <- equal c, 9/tab
reply-if result
return-if result
result <- equal c, 13/carriage-return
reply-if result
return-if result
# remaining uncommon cases in sorted order
# http://unicode.org code-points in unicode-set Z and Pattern_White_Space
result <- equal c, 11/ctrl-k
reply-if result
return-if result
result <- equal c, 12/ctrl-l
reply-if result
return-if result
result <- equal c, 133/ctrl-0085
reply-if result
return-if result
result <- equal c, 160/no-break-space
reply-if result
return-if result
result <- equal c, 5760/ogham-space-mark
reply-if result
return-if result
result <- equal c, 8192/en-quad
reply-if result
return-if result
result <- equal c, 8193/em-quad
reply-if result
return-if result
result <- equal c, 8194/en-space
reply-if result
return-if result
result <- equal c, 8195/em-space
reply-if result
return-if result
result <- equal c, 8196/three-per-em-space
reply-if result
return-if result
result <- equal c, 8197/four-per-em-space
reply-if result
return-if result
result <- equal c, 8198/six-per-em-space
reply-if result
return-if result
result <- equal c, 8199/figure-space
reply-if result
return-if result
result <- equal c, 8200/punctuation-space
reply-if result
return-if result
result <- equal c, 8201/thin-space
reply-if result
return-if result
result <- equal c, 8202/hair-space
reply-if result
return-if result
result <- equal c, 8206/left-to-right
reply-if result
return-if result
result <- equal c, 8207/right-to-left
reply-if result
return-if result
result <- equal c, 8232/line-separator
reply-if result
return-if result
result <- equal c, 8233/paragraph-separator
reply-if result
return-if result
result <- equal c, 8239/narrow-no-break-space
reply-if result
return-if result
result <- equal c, 8287/medium-mathematical-space
reply-if result
return-if result
result <- equal c, 12288/ideographic-space
]
recipe trim s:address:shared:array:character -> result:address:shared:array:character [
def trim s:address:shared:array:character -> result:address:shared:array:character [
local-scope
load-ingredients
len:number <- length *s
@ -693,7 +693,7 @@ recipe trim s:address:shared:array:character -> result:address:shared:array:char
at-end?:boolean <- greater-or-equal start, len
break-unless at-end?
result <- new character:type, 0
reply
return
}
curr:character <- index *s, start
whitespace?:boolean <- space? curr
@ -788,7 +788,7 @@ scenario trim-newline-tab [
]
]
recipe find-next text:address:shared:array:character, pattern:character, idx:number -> next-index:number [
def find-next text:address:shared:array:character, pattern:character, idx:number -> next-index:number [
local-scope
load-ingredients
len:number <- length *text
@ -801,7 +801,7 @@ recipe find-next text:address:shared:array:character, pattern:character, idx:num
idx <- add idx, 1
loop
}
reply idx
return idx
]
scenario text-find-next [
@ -886,7 +886,7 @@ scenario text-find-next-second [
# search for a pattern of multiple characters
# fairly dumb algorithm
recipe find-next text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> next-index:number [
def find-next text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> next-index:number [
local-scope
load-ingredients
first:character <- index *pattern, 0
@ -903,7 +903,7 @@ recipe find-next text:address:shared:array:character, pattern:address:shared:arr
idx <- find-next text, first, idx
loop
}
reply idx
return idx
]
scenario find-next-text-1 [
@ -962,7 +962,7 @@ scenario find-next-suffix-match-2 [
]
# checks if pattern matches at index 'idx'
recipe match-at text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> result:boolean [
def match-at text:address:shared:array:character, pattern:address:shared:array:character, idx:number -> result:boolean [
local-scope
load-ingredients
pattern-len:number <- length *pattern
@ -972,7 +972,7 @@ recipe match-at text:address:shared:array:character, pattern:address:shared:arra
x <- subtract x, pattern-len
enough-room?:boolean <- lesser-or-equal idx, x
break-if enough-room?
reply 0/not-found
return 0/not-found
}
# check each character of pattern
pattern-idx:number <- copy 0
@ -984,13 +984,13 @@ recipe match-at text:address:shared:array:character, pattern:address:shared:arra
{
match?:boolean <- equal c, exp
break-if match?
reply 0/not-found
return 0/not-found
}
idx <- add idx, 1
pattern-idx <- add pattern-idx, 1
loop
}
reply 1/found
return 1/found
]
scenario match-at-checks-pattern-at-index [
@ -1090,7 +1090,7 @@ scenario match-at-inside-bounds-2 [
]
]
recipe split s:address:shared:array:character, delim:character -> result:address:shared:array:address:shared:array:character [
def split s:address:shared:array:character, delim:character -> result:address:shared:array:address:shared:array:character [
local-scope
load-ingredients
# empty text? return empty array
@ -1099,7 +1099,7 @@ recipe split s:address:shared:array:character, delim:character -> result:address
empty?:boolean <- equal len, 0
break-unless empty?
result <- new {(address shared array character): type}, 0
reply
return
}
# count #pieces we need room for
count:number <- copy 1 # n delimiters = n+1 pieces
@ -1217,7 +1217,7 @@ scenario text-split-empty-piece [
]
]
recipe split-first text:address:shared:array:character, delim:character -> x:address:shared:array:character, y:address:shared:array:character [
def split-first text:address:shared:array:character, delim:character -> x:address:shared:array:character, y:address:shared:array:character [
local-scope
load-ingredients
# empty text? return empty texts
@ -1227,7 +1227,7 @@ recipe split-first text:address:shared:array:character, delim:character -> x:add
break-unless empty?
x:address:shared:array:character <- new []
y:address:shared:array:character <- new []
reply
return
}
idx:number <- find-next text, delim, 0
x:address:shared:array:character <- copy-range text, 0, idx
@ -1248,7 +1248,7 @@ scenario text-split-first [
]
]
recipe copy-range buf:address:shared:array:character, start:number, end:number -> result:address:shared:array:character [
def copy-range buf:address:shared:array:character, start:number, end:number -> result:address:shared:array:character [
local-scope
load-ingredients
# if end is out of bounds, trim it
@ -1305,24 +1305,24 @@ scenario text-copy-out-of-bounds-2 [
]
]
recipe min x:number, y:number -> z:number [
def min x:number, y:number -> z:number [
local-scope
load-ingredients
{
return-x?:boolean <- lesser-than x, y
break-if return-x?
reply y
return y
}
reply x
return x
]
recipe max x:number, y:number -> z:number [
def max x:number, y:number -> z:number [
local-scope
load-ingredients
{
return-x?:boolean <- greater-than x, y
break-if return-x?
reply y
return y
}
reply x
return x
]

View File

@ -31,7 +31,7 @@ container channel [
data:address:shared:array:character
]
recipe new-channel capacity:number -> result:address:shared:channel [
def new-channel capacity:number -> result:address:shared:channel [
local-scope
load-ingredients
result <- new channel:type
@ -47,7 +47,7 @@ recipe new-channel capacity:number -> result:address:shared:channel [
*dest <- new character:type, capacity
]
recipe write chan:address:shared:channel, val:character -> chan:address:shared:channel [
def write chan:address:shared:channel, val:character -> chan:address:shared:channel [
local-scope
load-ingredients
{
@ -73,7 +73,7 @@ recipe write chan:address:shared:channel, val:character -> chan:address:shared:c
}
]
recipe read chan:address:shared:channel -> result:character, chan:address:shared:channel [
def read chan:address:shared:channel -> result:character, chan:address:shared:channel [
local-scope
load-ingredients
{
@ -98,7 +98,7 @@ recipe read chan:address:shared:channel -> result:character, chan:address:shared
}
]
recipe clear-channel chan:address:shared:channel -> chan:address:shared:channel [
def clear-channel chan:address:shared:channel -> chan:address:shared:channel [
local-scope
load-ingredients
{
@ -175,7 +175,7 @@ scenario channel-wrap [
## helpers
# An empty channel has first-empty and first-full both at the same value.
recipe channel-empty? chan:address:shared:channel -> result:boolean [
def channel-empty? chan:address:shared:channel -> result:boolean [
local-scope
load-ingredients
# return chan.first-full == chan.first-free
@ -186,7 +186,7 @@ recipe channel-empty? chan:address:shared:channel -> result:boolean [
# A full channel has first-empty just before first-full, wasting one slot.
# (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
recipe channel-full? chan:address:shared:channel -> result:boolean [
def channel-full? chan:address:shared:channel -> result:boolean [
local-scope
load-ingredients
# tmp = chan.first-free + 1
@ -204,7 +204,7 @@ recipe channel-full? chan:address:shared:channel -> result:boolean [
result <- equal full, tmp
]
recipe channel-capacity chan:address:shared:channel -> result:number [
def channel-capacity chan:address:shared:channel -> result:number [
local-scope
load-ingredients
q:address:shared:array:character <- get *chan, data:offset
@ -264,7 +264,7 @@ scenario channel-read-not-full [
]
# helper for channels of characters in particular
recipe buffer-lines in:address:shared:channel, out:address:shared:channel -> out:address:shared:channel, in:address:shared:channel [
def buffer-lines in:address:shared:channel, out:address:shared:channel -> out:address:shared:channel, in:address:shared:channel [
local-scope
load-ingredients
# repeat forever

View File

@ -12,7 +12,7 @@ scenario array-from-args [
]
# create an array out of a list of scalar args
recipe new-array -> result:address:shared:array:character [
def new-array -> result:address:shared:array:character [
local-scope
capacity:number <- copy 0
{
@ -36,5 +36,5 @@ recipe new-array -> result:address:shared:array:character [
i <- add i, 1
loop
}
reply result
return result
]

View File

@ -8,7 +8,7 @@ container list:_elem [
next:address:shared:list:_elem
]
recipe push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
def push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
local-scope
load-ingredients
result:address:shared:list:_elem <- new {(list _elem): type}
@ -16,16 +16,16 @@ recipe push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_ele
*val <- copy x
next:address:address:shared:list:_elem <- get-address *result, next:offset
*next <- copy in
reply result # needed explicitly because we need to replace 'in' with 'result'
return result # needed explicitly because we need to replace 'in' with 'result'
]
recipe first in:address:shared:list:_elem -> result:_elem [
def first in:address:shared:list:_elem -> result:_elem [
local-scope
load-ingredients
result <- get *in, value:offset
]
recipe rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
def rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
local-scope
load-ingredients
result <- get *in, next:offset
@ -51,7 +51,7 @@ scenario list-handling [
]
]
recipe to-text in:address:shared:list:_elem -> result:address:shared:array:character [
def to-text in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
@ -60,7 +60,7 @@ recipe to-text in:address:shared:list:_elem -> result:address:shared:array:chara
]
# variant of 'to-text' which stops printing after a few elements (and so is robust to cycles)
recipe to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
def to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
@ -68,13 +68,13 @@ recipe to-text-line in:address:shared:list:_elem -> result:address:shared:array:
result <- buffer-to-array buf
]
recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
def to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
local-scope
load-ingredients
{
break-if in
buf <- append buf, 48/0
reply
return
}
# append in.value to buf
val:_elem <- get *in, value:offset
@ -82,7 +82,7 @@ recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:
# now prepare next
next:address:shared:list:_elem <- rest in
nextn:number <- copy next
reply-unless next
return-unless next
space:character <- copy 32/space
buf <- append buf, space:character
s:address:shared:array:character <- new [-> ]
@ -94,14 +94,14 @@ recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:
break-if optional-ingredient-found?
# unlimited recursion
buf <- to-buffer next, buf
reply
return
}
{
break-unless remaining
# limited recursion
remaining <- subtract remaining, 1
buf <- to-buffer next, buf, remaining
reply
return
}
# past recursion depth; insert ellipses and stop
s:address:shared:array:character <- new [...]

View File

@ -53,7 +53,7 @@ case ROUND: {
}
:(scenario round_to_nearest_integer)
recipe main [
def main [
1:number <- round 12.2
]
+mem: storing 12 in location 1

View File

@ -7,7 +7,7 @@ container duplex-list:_elem [
]
# should I say in/contained-in:result, allow ingredients to refer to products?
recipe push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
def push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
result:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
@ -20,29 +20,29 @@ recipe push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:du
prev:address:address:shared:duplex-list:_elem <- get-address *in, prev:offset
*prev <- copy result
}
reply result # needed explicitly because we need to replace 'in' with 'result'
return result # needed explicitly because we need to replace 'in' with 'result'
]
recipe first in:address:shared:duplex-list:_elem -> result:_elem [
def first in:address:shared:duplex-list:_elem -> result:_elem [
local-scope
load-ingredients
reply-unless in, 0
return-unless in, 0
result <- get *in, value:offset
]
recipe next in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
def next in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
local-scope
load-ingredients
reply-unless in, 0
return-unless in, 0
result <- get *in, next:offset
]
recipe prev in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
def prev in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
local-scope
load-ingredients
reply-unless in, 0
return-unless in, 0
result <- get *in, prev:offset
reply result
return result
]
scenario duplex-list-handling [
@ -87,7 +87,7 @@ scenario duplex-list-handling [
]
# insert 'x' after 'in'
recipe insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
def insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
new-node:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
@ -104,7 +104,7 @@ recipe insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:
y <- get-address *new-node, next:offset
*y <- copy next-node
# if next-node is not null
reply-unless next-node
return-unless next-node
# next-node.prev = new-node
y <- get-address *next-node, prev:offset
*y <- copy new-node
@ -222,11 +222,11 @@ scenario inserting-after-start-of-duplex-list [
#
# Returns null if and only if list is empty. Beware: in that case any other
# pointers to the head are now invalid.
recipe remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
def remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
# if 'x' is null, return
reply-unless x
return-unless x
next-node:address:shared:duplex-list:_elem <- get *x, next:offset
prev-node:address:shared:duplex-list:_elem <- get *x, prev:offset
# null x's pointers
@ -245,11 +245,11 @@ recipe remove x:address:shared:duplex-list:_elem/contained-in:in, in:address:sha
break-unless prev-node
tmp <- get-address *prev-node, next:offset
*tmp <- copy next-node
reply
return
}
# if prev-node is null, then we removed the node at 'in'
# return the new head rather than the old 'in'
reply next-node
return next-node
]
scenario removing-from-duplex-list [
@ -347,19 +347,19 @@ scenario removing-from-singleton-list [
# remove values between 'start' and 'end' (both exclusive)
# also clear pointers back out from start/end for hygiene
recipe remove-between start:address:shared:duplex-list:_elem, end:address:shared:duplex-list:_elem/contained-in:start -> start:address:shared:duplex-list:_elem [
def remove-between start:address:shared:duplex-list:_elem, end:address:shared:duplex-list:_elem/contained-in:start -> start:address:shared:duplex-list:_elem [
local-scope
load-ingredients
reply-unless start
return-unless start
# start->next->prev = 0
# start->next = end
next:address:address:shared:duplex-list:_elem <- get-address *start, next:offset
nothing-to-delete?:boolean <- equal *next, end
reply-if nothing-to-delete?
return-if nothing-to-delete?
prev:address:address:shared:duplex-list:_elem <- get-address **next, prev:offset
*prev <- copy 0
*next <- copy end
reply-unless end
return-unless end
# end->prev->next = 0
# end->prev = start
prev <- get-address *end, prev:offset
@ -455,11 +455,11 @@ scenario remove-range-empty [
]
# insert list beginning at 'new' after 'in'
recipe insert-range in:address:shared:duplex-list:_elem, start:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
def insert-range in:address:shared:duplex-list:_elem, start:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
reply-unless in
reply-unless start
return-unless in
return-unless start
end:address:shared:duplex-list:_elem <- copy start
{
next:address:shared:duplex-list:_elem <- next end/insert-range
@ -481,18 +481,18 @@ recipe insert-range in:address:shared:duplex-list:_elem, start:address:shared:du
*dest <- copy in
]
recipe append in:address:shared:duplex-list:_elem, new:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
def append in:address:shared:duplex-list:_elem, new:address:shared:duplex-list:_elem/contained-in:in -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
last:address:shared:duplex-list:_elem <- last in
dest:address:address:shared:duplex-list:_elem <- get-address *last, next:offset
*dest <- copy new
reply-unless new
return-unless new
dest <- get-address *new, prev:offset
*dest <- copy last
]
recipe last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem [
def last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem [
local-scope
load-ingredients
result <- copy in
@ -505,7 +505,7 @@ recipe last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-
]
# helper for debugging
recipe dump-from x:address:shared:duplex-list:_elem [
def dump-from x:address:shared:duplex-list:_elem [
local-scope
load-ingredients
$print x, [: ]

View File

@ -4,7 +4,7 @@ container stream [
data:address:shared:array:character
]
recipe new-stream s:address:shared:array:character -> result:address:shared:stream [
def new-stream s:address:shared:array:character -> result:address:shared:stream [
local-scope
load-ingredients
result <- new stream:type
@ -14,14 +14,14 @@ recipe new-stream s:address:shared:array:character -> result:address:shared:stre
*d <- copy s
]
recipe rewind-stream in:address:shared:stream -> in:address:shared:stream [
def rewind-stream in:address:shared:stream -> in:address:shared:stream [
local-scope
load-ingredients
x:address:number <- get-address *in, index:offset
*x <- copy 0
]
recipe read-line in:address:shared:stream -> result:address:shared:array:character, in:address:shared:stream [
def read-line in:address:shared:stream -> result:address:shared:array:character, in:address:shared:stream [
local-scope
load-ingredients
idx:address:number <- get-address *in, index:offset
@ -31,7 +31,7 @@ recipe read-line in:address:shared:stream -> result:address:shared:array:charact
*idx <- add next-idx, 1 # skip newline
]
recipe end-of-stream? in:address:shared:stream -> result:boolean [
def end-of-stream? in:address:shared:stream -> result:boolean [
local-scope
load-ingredients
idx:number <- get *in, index:offset

View File

@ -143,13 +143,13 @@ container foo [
x:number
y:character
]
recipe main [
def main [
1:foo <- merge 34, 97/a
3:number <- hash 1:foo
reply-unless 3:number
return-unless 3:number
4:foo <- merge 34, 98/a
6:number <- hash 4:foo
reply-unless 6:number
return-unless 6:number
7:boolean <- equal 3:number, 6:number
]
# hash on containers includes all elements
@ -164,13 +164,13 @@ container bar [
a:number
b:number
]
recipe main [
def main [
1:foo <- merge 0/x, 34, 35
4:number <- hash 1:foo
reply-unless 4:number
return-unless 4:number
5:foo <- merge 0/x, 34, 36
8:number <- hash 5:foo
reply-unless 8:number
return-unless 8:number
9:boolean <- equal 4:number, 8:number
]
# hash on containers includes all elements
@ -181,13 +181,13 @@ container foo [
x:number
y:character/ignore-for-hash
]
recipe main [
def main [
1:foo <- merge 34, 97/a
3:number <- hash 1:foo
reply-unless 3:number
return-unless 3:number
4:foo <- merge 34, 98/a
6:number <- hash 4:foo
reply-unless 6:number
return-unless 6:number
7:boolean <- equal 3:number, 6:number
]
# hashes match even though y is different
@ -197,7 +197,7 @@ recipe main [
//: current implementation works like we think it does.
:(scenario hash_of_zero_address)
recipe main [
def main [
1:address:number <- copy 0
2:number <- hash 1:address:number
]
@ -206,7 +206,7 @@ recipe main [
//: This is probably too aggressive, but we need some way to avoid depending
//: on the precise bit pattern of a floating-point number.
:(scenario hash_of_numbers_ignores_fractional_part)
recipe main [
def main [
1:number <- hash 1.5
2:number <- hash 1
3:boolean <- equal 1:number, 2:number
@ -214,22 +214,22 @@ recipe main [
+mem: storing 1 in location 3
:(scenario hash_of_array_same_as_string)
recipe main [
def main [
10:number <- copy 3
11:number <- copy 97
12:number <- copy 98
13:number <- copy 99
2:number <- hash 10:array:number/unsafe
reply-unless 2:number
return-unless 2:number
3:address:shared:array:character <- new [abc]
4:number <- hash 3:address:shared:array:character
reply-unless 4:number
return-unless 4:number
5:boolean <- equal 2:number, 4:number
]
+mem: storing 1 in location 5
:(scenario hash_ignores_address_value)
recipe main [
def main [
1:address:shared:number <- new number:type
*1:address:shared:number <- copy 34
2:number <- hash 1:address:shared:number
@ -242,15 +242,15 @@ recipe main [
+mem: storing 1 in location 5
:(scenario hash_ignores_address_refcount)
recipe main [
def main [
1:address:shared:number <- new number:type
*1:address:shared:number <- copy 34
2:number <- hash 1:address:shared:number
reply-unless 2:number
return-unless 2:number
# increment refcount
3:address:shared:number <- copy 1:address:shared:number
4:number <- hash 3:address:shared:number
reply-unless 4:number
return-unless 4:number
5:boolean <- equal 2:number, 4:number
]
# hash doesn't change when refcount changes
@ -265,13 +265,13 @@ container bar [
x:number
y:character
]
recipe main [
def main [
1:foo <- merge 34, 97/a
3:number <- hash 1:foo
reply-unless 3:number
return-unless 3:number
4:bar <- merge 34, 97/a
6:number <- hash 4:bar
reply-unless 6:number
return-unless 6:number
7:boolean <- equal 3:number, 6:number
]
# containers with identical elements return identical hashes
@ -283,17 +283,17 @@ container foo [
y:character
z:address:shared:number
]
recipe main [
def main [
1:address:shared:number <- new number:type
*1:address:shared:number <- copy 34
2:foo <- merge 34, 97/a, 1:address:shared:number
5:number <- hash 2:foo
reply-unless 5:number
return-unless 5:number
6:address:shared:number <- new number:type
*6:address:shared:number <- copy 34
7:foo <- merge 34, 97/a, 6:address:shared:number
10:number <- hash 7:foo
reply-unless 10:number
return-unless 10:number
11:boolean <- equal 5:number, 10:number
]
# containers with identical 'leaf' elements return identical hashes
@ -309,13 +309,13 @@ container bar [
x:number
y:number
]
recipe main [
def main [
1:foo <- merge 34, 97/a, 47, 48
6:number <- hash 1:foo
reply-unless 6:number
return-unless 6:number
7:foo <- merge 34, 97/a, 47, 48
12:number <- hash 7:foo
reply-unless 12:number
return-unless 12:number
13:boolean <- equal 6:number, 12:number
]
# containers with identical 'leaf' elements return identical hashes
@ -330,13 +330,13 @@ container bar [
a:number
b:number
]
recipe main [
def main [
1:foo <- merge 0/x, 34, 35
4:number <- hash 1:foo
reply-unless 4:number
return-unless 4:number
5:bar <- merge 34, 35
7:number <- hash 5:bar
reply-unless 7:number
return-unless 7:number
8:boolean <- equal 4:number, 7:number
]
# hash on containers includes all elements
@ -347,7 +347,7 @@ recipe main [
//: version around and check that the new one is consistent with it.
:(scenario hash_matches_old_version)
recipe main [
def main [
1:address:shared:array:character <- new [abc]
2:number <- hash 1:address:shared:array:character
3:number <- hash_old 1:address:shared:array:character

View File

@ -36,7 +36,7 @@ container table_row:_key:_value [
value:_value
]
recipe new-table capacity:number -> result:address:shared:table:_key:_value [
def new-table capacity:number -> result:address:shared:table:_key:_value [
local-scope
load-ingredients
result <- new {(table _key _value): type}
@ -46,7 +46,7 @@ recipe new-table capacity:number -> result:address:shared:table:_key:_value [
*data <- new {(table_row _key _value): type}, capacity
]
recipe put table:address:shared:table:_key:_value, key:_key, value:_value -> table:address:shared:table:_key:_value [
def put table:address:shared:table:_key:_value, key:_key, value:_value -> table:address:shared:table:_key:_value [
local-scope
load-ingredients
hash:number <- hash key
@ -62,15 +62,15 @@ recipe put table:address:shared:table:_key:_value, key:_key, value:_value -> tab
*x <- merge 1/true, key, value
]
recipe abs n:number -> result:number [
def abs n:number -> result:number [
local-scope
load-ingredients
positive?:boolean <- greater-or-equal n, 0
reply-if positive?, n
return-if positive?, n
result <- multiply n, -1
]
recipe index table:address:shared:table:_key:_value, key:_key -> result:_value [
def index table:address:shared:table:_key:_value, key:_key -> result:_value [
local-scope
load-ingredients
hash:number <- hash key

View File

@ -14,7 +14,7 @@ container screen-cell [
color:number
]
recipe new-fake-screen w:number, h:number -> result:address:shared:screen [
def new-fake-screen w:number, h:number -> result:address:shared:screen [
local-scope
load-ingredients
result <- new screen:type
@ -32,7 +32,7 @@ recipe new-fake-screen w:number, h:number -> result:address:shared:screen [
result <- clear-screen result
]
recipe clear-screen screen:address:shared:screen -> screen:address:shared:screen [
def clear-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists
@ -58,13 +58,13 @@ recipe clear-screen screen:address:shared:screen -> screen:address:shared:screen
*x <- copy 0
x <- get-address *screen, cursor-column:offset
*x <- copy 0
reply
return
}
# otherwise, real screen
clear-display
]
recipe sync-screen screen:address:shared:screen -> screen:address:shared:screen [
def sync-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
{
@ -74,10 +74,10 @@ recipe sync-screen screen:address:shared:screen -> screen:address:shared:screen
# do nothing for fake screens
]
recipe fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
def fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
local-scope
load-ingredients
reply-unless screen, 1/true
return-unless screen, 1/true
buf:address:shared:array:screen-cell <- get *screen, data:offset
i:number <- copy 0
len:number <- length *buf
@ -89,12 +89,12 @@ recipe fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
i <- add i, 1
loop-unless curr-contents
# not 0
reply 0/false
return 0/false
}
reply 1/true
return 1/true
]
recipe print screen:address:shared:screen, c:character -> screen:address:shared:screen [
def print screen:address:shared:screen, c:character -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -119,14 +119,14 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
# if cursor is out of bounds, silently exit
row:address:number <- get-address *screen, cursor-row:offset
legal?:boolean <- greater-or-equal *row, 0
reply-unless legal?
return-unless legal?
legal? <- lesser-than *row, height
reply-unless legal?
return-unless legal?
column:address:number <- get-address *screen, cursor-column:offset
legal? <- greater-or-equal *column, 0
reply-unless legal?
return-unless legal?
legal? <- lesser-than *column, width
reply-unless legal?
return-unless legal?
#? $print [print-character (], *row, [, ], *column, [): ], c, 10/newline
# special-case: newline
{
@ -141,7 +141,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
*column <- copy 0
*row <- add *row, 1
}
reply
return
}
# save character in fake screen
index:number <- multiply *row, width
@ -165,7 +165,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
cursor-color:address:number <- get-address *cursor, color:offset
*cursor-color <- copy 7/white
}
reply
return
}
cursor:address:screen-cell <- index-address *buf, index
cursor-contents:address:character <- get-address *cursor, contents:offset
@ -179,7 +179,7 @@ recipe print screen:address:shared:screen, c:character -> screen:address:shared:
break-if at-right?
*column <- add *column, 1
}
reply
return
}
# otherwise, real screen
print-character-to-display c, color, bg-color
@ -356,7 +356,7 @@ scenario print-character-at-bottom-right [
]
]
recipe clear-line screen:address:shared:screen -> screen:address:shared:screen [
def clear-line screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 0/nul
@ -376,13 +376,13 @@ recipe clear-line screen:address:shared:screen -> screen:address:shared:screen [
}
# now back to where the cursor was
*column <- copy original-column
reply
return
}
# otherwise, real screen
clear-line-on-display
]
recipe cursor-position screen:address:shared:screen -> row:number, column:number [
def cursor-position screen:address:shared:screen -> row:number, column:number [
local-scope
load-ingredients
# if x exists, lookup cursor in fake screen
@ -390,12 +390,12 @@ recipe cursor-position screen:address:shared:screen -> row:number, column:number
break-unless screen
row:number <- get *screen, cursor-row:offset
column:number <- get *screen, cursor-column:offset
reply
return
}
row, column <- cursor-position-on-display
]
recipe move-cursor screen:address:shared:screen, new-row:number, new-column:number -> screen:address:shared:screen [
def move-cursor screen:address:shared:screen, new-row:number, new-column:number -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -405,7 +405,7 @@ recipe move-cursor screen:address:shared:screen, new-row:number, new-column:numb
*row <- copy new-row
column:address:number <- get-address *screen, cursor-column:offset
*column <- copy new-column
reply
return
}
# otherwise, real screen
move-cursor-on-display new-row, new-column
@ -442,7 +442,7 @@ scenario clear-line-erases-printed-characters [
]
]
recipe cursor-down screen:address:shared:screen -> screen:address:shared:screen [
def cursor-down screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -457,13 +457,13 @@ recipe cursor-down screen:address:shared:screen -> screen:address:shared:screen
break-if at-bottom?
*row <- add *row, 1
}
reply
return
}
# otherwise, real screen
move-cursor-down-on-display
]
recipe cursor-up screen:address:shared:screen -> screen:address:shared:screen [
def cursor-up screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -476,13 +476,13 @@ recipe cursor-up screen:address:shared:screen -> screen:address:shared:screen [
break-if at-top?
*row <- subtract *row, 1
}
reply
return
}
# otherwise, real screen
move-cursor-up-on-display
]
recipe cursor-right screen:address:shared:screen -> screen:address:shared:screen [
def cursor-right screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -497,13 +497,13 @@ recipe cursor-right screen:address:shared:screen -> screen:address:shared:screen
break-if at-bottom?
*column <- add *column, 1
}
reply
return
}
# otherwise, real screen
move-cursor-right-on-display
]
recipe cursor-left screen:address:shared:screen -> screen:address:shared:screen [
def cursor-left screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -516,13 +516,13 @@ recipe cursor-left screen:address:shared:screen -> screen:address:shared:screen
break-if at-top?
*column <- subtract *column, 1
}
reply
return
}
# otherwise, real screen
move-cursor-left-on-display
]
recipe cursor-to-start-of-line screen:address:shared:screen -> screen:address:shared:screen [
def cursor-to-start-of-line screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
row:number <- cursor-position screen
@ -530,90 +530,90 @@ recipe cursor-to-start-of-line screen:address:shared:screen -> screen:address:sh
screen <- move-cursor screen, row, column
]
recipe cursor-to-next-line screen:address:shared:screen -> screen:address:shared:screen [
def cursor-to-next-line screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
screen <- cursor-down screen
screen <- cursor-to-start-of-line screen
]
recipe screen-width screen:address:shared:screen -> width:number [
def screen-width screen:address:shared:screen -> width:number [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
{
break-unless screen
width <- get *screen, num-columns:offset
reply
return
}
# otherwise, real screen
width <- display-width
]
recipe screen-height screen:address:shared:screen -> height:number [
def screen-height screen:address:shared:screen -> height:number [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
{
break-unless screen
height <- get *screen, num-rows:offset
reply
return
}
# otherwise, real screen
height <- display-height
]
recipe hide-cursor screen:address:shared:screen -> screen:address:shared:screen [
def hide-cursor screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
{
break-unless screen
reply
return
}
# otherwise, real screen
hide-cursor-on-display
]
recipe show-cursor screen:address:shared:screen -> screen:address:shared:screen [
def show-cursor screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
{
break-unless screen
reply
return
}
# otherwise, real screen
show-cursor-on-display
]
recipe hide-screen screen:address:shared:screen -> screen:address:shared:screen [
def hide-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
# todo: help test this
{
break-unless screen
reply
return
}
# otherwise, real screen
hide-display
]
recipe show-screen screen:address:shared:screen -> screen:address:shared:screen [
def show-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
# todo: help test this
{
break-unless screen
reply
return
}
# otherwise, real screen
show-display
]
recipe print screen:address:shared:screen, s:address:shared:array:character -> screen:address:shared:screen [
def print screen:address:shared:screen, s:address:shared:array:character -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -660,7 +660,7 @@ scenario print-text-stops-at-right-margin [
]
]
recipe print-integer screen:address:shared:screen, n:number -> screen:address:shared:screen [
def print-integer screen:address:shared:screen, n:number -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -681,7 +681,7 @@ recipe print-integer screen:address:shared:screen, n:number -> screen:address:sh
]
# for now, we can only print integers
recipe print screen:address:shared:screen, n:number -> screen:address:shared:screen [
def print screen:address:shared:screen, n:number -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -700,7 +700,7 @@ recipe print screen:address:shared:screen, n:number -> screen:address:shared:scr
]
# addresses
recipe print screen:address:shared:screen, n:address:_elem -> screen:address:shared:screen [
def print screen:address:shared:screen, n:address:_elem -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient

View File

@ -115,7 +115,7 @@ if (s == "screen") return true;
:(scenarios run)
:(scenario convert_names_does_not_fail_when_mixing_special_names_and_numeric_locations)
% Scenario_testing_scenario = true;
recipe main [
def main [
screen:number <- copy 1:number
]
-error: mixing variable names and numeric addresses in main

View File

@ -25,7 +25,7 @@ container console [
events:address:shared:array:event
]
recipe new-fake-console events:address:shared:array:event -> result:address:shared:console [
def new-fake-console events:address:shared:array:event -> result:address:shared:console [
local-scope
load-ingredients
result:address:shared:console <- new console:type
@ -35,7 +35,7 @@ recipe new-fake-console events:address:shared:array:event -> result:address:shar
*idx <- copy 0
]
recipe read-event console:address:shared:console -> result:event, console:address:shared:console, found?:boolean, quit?:boolean [
def read-event console:address:shared:console -> result:event, console:address:shared:console, found?:boolean, quit?:boolean [
local-scope
load-ingredients
{
@ -47,32 +47,32 @@ recipe read-event console:address:shared:console -> result:event, console:addres
done?:boolean <- greater-or-equal *current-event-index, max
break-unless done?
dummy:address:shared:event <- new event:type
reply *dummy, console/same-as-ingredient:0, 1/found, 1/quit
return *dummy, console/same-as-ingredient:0, 1/found, 1/quit
}
result <- index *buf, *current-event-index
*current-event-index <- add *current-event-index, 1
reply result, console/same-as-ingredient:0, 1/found, 0/quit
return result, console/same-as-ingredient:0, 1/found, 0/quit
}
switch # real event source is infrequent; avoid polling it too much
result:event, found?:boolean <- check-for-interaction
reply result, console/same-as-ingredient:0, found?, 0/quit
return result, console/same-as-ingredient:0, found?, 0/quit
]
# variant of read-event for just keyboard events. Discards everything that
# isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get
# newlines, tabs, ctrl-d..
recipe read-key console:address:shared:console -> result:character, console:address:shared:console, found?:boolean, quit?:boolean [
def read-key console:address:shared:console -> result:character, console:address:shared:console, found?:boolean, quit?:boolean [
local-scope
load-ingredients
x:event, console, found?:boolean, quit?:boolean <- read-event console
reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
return-if quit?, 0, console/same-as-ingredient:0, found?, quit?
return-unless found?, 0, console/same-as-ingredient:0, found?, quit?
c:address:character <- maybe-convert x, text:variant
reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
reply *c, console/same-as-ingredient:0, 1/found, 0/quit
return-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
return *c, console/same-as-ingredient:0, 1/found, 0/quit
]
recipe send-keys-to-channel console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen -> console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen [
def send-keys-to-channel console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen -> console:address:shared:console, chan:address:shared:channel, screen:address:shared:screen [
local-scope
load-ingredients
{
@ -86,7 +86,7 @@ recipe send-keys-to-channel console:address:shared:console, chan:address:shared:
}
]
recipe wait-for-event console:address:shared:console -> console:address:shared:console [
def wait-for-event console:address:shared:console -> console:address:shared:console [
local-scope
load-ingredients
{
@ -96,13 +96,13 @@ recipe wait-for-event console:address:shared:console -> console:address:shared:c
]
# use this helper to skip rendering if there's lots of other events queued up
recipe has-more-events? console:address:shared:console -> result:boolean [
def has-more-events? console:address:shared:console -> result:boolean [
local-scope
load-ingredients
{
break-unless console
# fake consoles should be plenty fast; never skip
reply 0/false
return 0/false
}
result <- interactions-left?
]

View File

@ -2,7 +2,7 @@
//: return some result in string form.
:(scenario run_interactive_code)
recipe main [
def main [
1:number/raw <- copy 0
2:address:shared:array:character <- new [1:number/raw <- copy 34]
run-interactive 2:address:shared:array:character
@ -11,7 +11,7 @@ recipe main [
+mem: storing 34 in location 3
:(scenario run_interactive_empty)
recipe main [
def main [
1:address:shared:array:character <- copy 0/unsafe
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
]
@ -92,7 +92,7 @@ bool run_interactive(long long int address) {
"$start-tracking-products\n" +
command + "\n" +
"$stop-tracking-products\n" +
"reply screen\n" +
"return screen\n" +
"]\n");
transform_all();
Current_routine = save_current_routine;
@ -159,7 +159,7 @@ load(string(
"errors:address:shared:array:character <- save-errors\n" +
"stashes:address:shared:array:character <- save-app-trace\n" +
"$cleanup-run-interactive\n" +
"reply output, errors, screen, stashes, completed?\n" +
"return output, errors, screen, stashes, completed?\n" +
"]\n");
transform_all();
Recently_added_recipes.clear();
@ -169,7 +169,7 @@ Recently_added_recipes.clear();
if (s == "interactive") return "";
:(scenario run_interactive_comments)
recipe main [
def main [
1:address:shared:array:character <- new [# ab
add 2, 2]
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
@ -265,7 +265,7 @@ case _CLEANUP_RUN_INTERACTIVE: {
}
:(scenario "run_interactive_converts_result_to_text")
recipe main [
def main [
# try to interactively add 2 and 2
1:address:shared:array:character <- new [add 2, 2]
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
@ -275,7 +275,7 @@ recipe main [
+mem: storing 52 in location 11
:(scenario "run_interactive_returns_text")
recipe main [
def main [
# try to interactively add 2 and 2
1:address:shared:array:character <- new [
x:address:shared:array:character <- new [a]
@ -290,7 +290,7 @@ recipe main [
+mem: storing 98 in location 12
:(scenario "run_interactive_returns_errors")
recipe main [
def main [
# run a command that generates an error
1:address:shared:array:character <- new [x:number <- copy 34
get x:number, foo:offset]
@ -305,7 +305,7 @@ get x:number, foo:offset]
# ...
:(scenario run_interactive_with_comment)
recipe main [
def main [
# 2 instructions, with a comment after the first
1:address:shared:array:number <- new [a:number <- copy 0 # abc
b:number <- copy 0
@ -320,7 +320,7 @@ void test_run_interactive_cleans_up_any_created_specializations() {
// define a generic recipe
assert(!contains_key(Recipe_ordinal, "foo"));
load("recipe foo x:_elem -> n:number [\n"
" reply 34\n"
" return 34\n"
"]\n");
assert(SIZE(Recently_added_recipes) == 1); // foo
assert(variant_count("foo") == 1);
@ -494,7 +494,7 @@ case RELOAD: {
}
:(scenario reload_continues_past_error)
recipe main [
def main [
local-scope
x:address:shared:array:character <- new [recipe foo [
get 1234:number, foo:offset
@ -515,7 +515,7 @@ void test_reload_cleans_up_any_created_specializations() {
" x:address:shared:array:character <- new [recipe foo x:_elem -> n:number [\n"
"local-scope\n"
"load-ingredients\n"
"reply 34\n"
"return 34\n"
"]\n"
"recipe main2 [\n"
"local-scope\n"

View File

@ -43,7 +43,7 @@ assert(Max_callstack_depth == 9989);
//:
//: begin instruction modifying transforms
//: 56.2 check header ingredients
//: ↳ 56.4 fill in reply ingredients
//: ↳ 56.4 fill in return ingredients
//: 48 check or set types by name
//:
//: begin type modifying transforms
@ -68,9 +68,9 @@ assert(Max_callstack_depth == 9989);
//: ↳ 56 check calls against header
//: ↳ 43 transform 'new' to 'allocate'
//: 30 check merge calls
//: 36 check types of reply instructions
//: 36 check types of return instructions
//: 43 check default space
//: 56 check reply instructions against header
//: 56 check return instructions against header
//: end checks
//: end transforms

View File

@ -210,7 +210,7 @@ Running Mu will always recompile it if necessary:
As a sneak peek, here's how you perform some simple arithmetic:
```nim
recipe example1 [
def example1 [
a:number <- add 2, 2
a <- multiply a, 3
]
@ -218,10 +218,10 @@ As a sneak peek, here's how you perform some simple arithmetic:
But it's easier to read in color:
<img alt='code example' src='html/example1.png' width='188px'>
<img alt='code example' src='html/example1.png'>
Mu functions or 'recipes' are lists of instructions, one to a line. Each
instruction operates on some *ingredients* and returns some *products*.
Mu functions are lists of instructions, one to a line. Each instruction
operates on some *ingredients* and returns some *products*.
```
[products] <- instruction [ingredients]
@ -255,31 +255,31 @@ Try out the program now:
```
Not much to see yet, since it doesn't print anything. To print the result, try
adding the instruction `$print a` to the recipe.
adding the instruction `$print a` to the function.
---
Here's a second example, of a recipe that can take ingredients:
Here's a second example, of a function that can take ingredients:
<img alt='fahrenheit to celsius' src='html/f2c-1.png' width='426px'>
<img alt='fahrenheit to celsius' src='html/f2c-1.png'>
Recipes can specify headers showing their expected ingredients and products,
separated by `->` (unlike the `<-` in *calls*).
Since Mu is a low-level VM language, it provides extra control at the cost of
verbosity. Using `local-scope`, you have explicit control over stack frames to
isolate your recipes (in a type-safe manner; more on that below). One
isolate your functions (in a type-safe manner; more on that below). One
consequence: you have to explicitly `load-ingredients` after you set up the
stack.
An alternative syntax is what the above example is converted to internally:
<img alt='fahrenheit to celsius desugared' src='html/f2c-2.png' width='426px'>
<img alt='fahrenheit to celsius desugared' src='html/f2c-2.png'>
The header gets dropped after checking types at call-sites, and after
replacing `load-ingredients` with explicit instructions to load each
ingredient separately, and to explicitly return products to the caller. After
this translation recipes are once again just lists of instructions.
this translation functions are once again just lists of instructions.
This alternative syntax isn't just an implementation detail. I've actually
found it easier to teach functions to non-programmers by starting with this
@ -290,7 +290,7 @@ names of variables gradually get translated through the pipe.
A third example, this time illustrating conditionals:
<img alt='factorial example' src='html/factorial.png' width='330px'>
<img alt='factorial example' src='html/factorial.png'>
In spite of how it looks, this is still just a list of instructions.
Internally, the instructions `break` and `loop` get converted to `jump`
@ -311,7 +311,7 @@ You can also run its unit tests:
Here's what one of the tests inside `factorial.mu` looks like:
<img alt='test example' src='html/factorial-test.png' width='250px'>
<img alt='test example' src='html/factorial-test.png'>
Every test conceptually spins up a really lightweight virtual machine, so you
can do things like check the value of specific locations in memory. You can
@ -319,7 +319,7 @@ also print to screen and check that the screen contains what you expect at the
end of a test. For example, `chessboard.mu` checks the initial position of a
game of chess (delimiting the edges of the screen with periods):
<img alt='screen test' src='html/chessboard-test.png' width='320px'>
<img alt='screen test' src='html/chessboard-test.png'>
Similarly you can fake the keyboard to pretend someone typed something:
@ -348,11 +348,11 @@ might turn into this:
You shouldn't rely on the specific address Mu chooses for a variable, but it
will be unique (other variables won't clobber it) and consistent (all mentions
of the name will map to the same address inside a recipe).
of the name will map to the same address inside a function).
Things get more complicated when your recipes call other recipes. Mu
doesn't preserve uniqueness of addresses across recipes, so you need to
organize your names into spaces. At the start of each recipe (like
Things get more complicated when your functions call other functions. Mu
doesn't preserve uniqueness of addresses across functions, so you need to
organize your names into spaces. At the start of each function (like
`factorial` above), set its *default space*:
```nim
@ -371,10 +371,10 @@ or
default-space:address:array:location <- new location:type, 30/capacity
```
Without one of these lines, all variables in the recipe will be *global*,
Without one of these lines, all variables in the function will be *global*,
something you rarely want. (Luckily, this is also the sort of mistake that
will be easily caught by tests.) *With* this line, all addresses in your
recipe will by default refer to one of the (30, in the final case) slots
function will by default refer to one of the (30, in the final case) slots
inside this local space. (If you choose the last, most explicit option and
need more than 30 slots, Mu will complain asking you to increase capacity.)
@ -444,7 +444,7 @@ An alternative way to define factorial is by inserting *labels* and later
inserting code at them.
```nim
recipe factorial [
def factorial [
local-scope
n:number <- next-ingredient
{
@ -457,7 +457,7 @@ inserting code at them.
# if n=0 return 1
zero?:boolean <- equal n, 0
break-unless zero?
reply 1
return 1
]
after <recursive-case> [
@ -465,7 +465,7 @@ inserting code at them.
x:number <- subtract n, 1
subresult:number <- factorial x
result:number <- multiply subresult, n
reply result
return result
]
```
@ -473,7 +473,7 @@ inserting code at them.
Any instruction without ingredients or products that starts with a
non-alphanumeric character is a label. By convention we use '+' to indicate
recipe-local label names you can jump to, and surround in '<>' global label
function-local label names you can jump to, and surround in '<>' global label
names for inserting code at.
---
@ -481,7 +481,7 @@ names for inserting code at.
Another example, this time with concurrency.
```
recipe main [
def main [
start-running thread2
{
$print 34
@ -489,7 +489,7 @@ Another example, this time with concurrency.
}
]
recipe thread2 [
def thread2 [
{
$print 35
loop
@ -569,9 +569,9 @@ d) Try out the programming environment:
Screenshot:
<img alt='programming environment' src='html/edit.png' width='720px'>
<img alt='programming environment' src='html/edit.png'>
You write recipes on the left and try them out in *sandboxes* on the right.
You write functions on the left and try them out in *sandboxes* on the right.
Hit F4 to rerun all sandboxes with the latest version of the code. More
details: http://akkartik.name/post/mu. Beware, it won't save your edits by
default. But if you create a sub-directory called `lesson/` under `mu/` it
@ -580,12 +580,12 @@ back up each version you try out.
Once you have a sandbox you can click on its result to mark it as expected:
<img alt='expected result' src='html/expected-result.png' width='180px'>
<img alt='expected result' src='html/expected-result.png'>
Later if the result changes it'll be flagged in red to draw your attention to
it. Thus, manually tested sandboxes become reproducible automated tests.
<img alt='unexpected result' src='html/unexpected-result.png' width='180px'>
<img alt='unexpected result' src='html/unexpected-result.png'>
Another feature: Clicking on the code in a sandbox expands its trace for you
to browse. To add to the trace, use `stash`. For example:

View File

@ -1,6 +1,6 @@
# example program: communicating between routines using channels
recipe producer chan:address:shared:channel -> chan:address:shared:channel [
def producer chan:address:shared:channel -> chan:address:shared:channel [
# produce characters 1 to 5 on a channel
local-scope
load-ingredients
@ -18,7 +18,7 @@ recipe producer chan:address:shared:channel -> chan:address:shared:channel [
}
]
recipe consumer chan:address:shared:channel -> chan:address:shared:channel [
def consumer chan:address:shared:channel -> chan:address:shared:channel [
# consume and print integers from a channel
local-scope
load-ingredients
@ -32,7 +32,7 @@ recipe consumer chan:address:shared:channel -> chan:address:shared:channel [
}
]
recipe main [
def main [
local-scope
chan:address:shared:channel <- new-channel 3
# create two background 'routines' that communicate by a channel

View File

@ -2,7 +2,7 @@
# display the position after each move.
# recipes are mu's names for functions
recipe main [
def main [
open-console # take control of screen, keyboard and mouse
# The chessboard recipe takes keyboard and screen objects as 'ingredients'.
@ -66,7 +66,7 @@ scenario print-board-and-read-move [
## Here's how 'chessboard' is implemented.
recipe chessboard screen:address:shared:screen, console:address:shared:console -> screen:address:shared:screen, console:address:shared:console [
def chessboard screen:address:shared:screen, console:address:shared:console -> screen:address:shared:screen, console:address:shared:console [
local-scope
load-ingredients
board:address:shared:array:address:shared:array:character <- initial-position
@ -109,7 +109,7 @@ recipe chessboard screen:address:shared:screen, console:address:shared:console -
## a board is an array of files, a file is an array of characters (squares)
recipe new-board initial-position:address:shared:array:character -> board:address:shared:array:address:shared:array:character [
def new-board initial-position:address:shared:array:character -> board:address:shared:array:address:shared:array:character [
local-scope
load-ingredients
# assert(length(initial-position) == 64)
@ -129,7 +129,7 @@ recipe new-board initial-position:address:shared:array:character -> board:addres
}
]
recipe new-file position:address:shared:array:character, index:number -> result:address:shared:array:character [
def new-file position:address:shared:array:character, index:number -> result:address:shared:array:character [
local-scope
load-ingredients
index <- multiply index, 8
@ -146,7 +146,7 @@ recipe new-file position:address:shared:array:character, index:number -> result:
}
]
recipe print-board screen:address:shared:screen, board:address:shared:array:address:shared:array:character -> screen:address:shared:screen [
def print-board screen:address:shared:screen, board:address:shared:array:address:shared:array:character -> screen:address:shared:screen [
local-scope
load-ingredients
row:number <- copy 7 # start printing from the top of the board
@ -185,7 +185,7 @@ recipe print-board screen:address:shared:screen, board:address:shared:array:addr
screen <- cursor-to-next-line screen
]
recipe initial-position -> board:address:shared:array:address:shared:array:character [
def initial-position -> board:address:shared:array:address:shared:array:character [
local-scope
# layout in memory (in raster order):
# R P _ _ _ _ p r
@ -242,61 +242,61 @@ container move [
]
# prints only error messages to screen
recipe read-move stdin:address:shared:channel, screen:address:shared:screen -> result:address:shared:move, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
def read-move stdin:address:shared:channel, screen:address:shared:screen -> result:address:shared:move, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
local-scope
load-ingredients
from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen
reply-if quit?, 0/dummy, quit?, error?
reply-if error?, 0/dummy, quit?, error?
return-if quit?, 0/dummy, quit?, error?
return-if error?, 0/dummy, quit?, error?
# construct the move object
result:address:shared:move <- new move:type
x:address:number <- get-address *result, from-file:offset
*x <- copy from-file
x <- get-address *result, from-rank:offset
*x, quit?, error? <- read-rank stdin, screen
reply-if quit?, 0/dummy, quit?, error?
reply-if error?, 0/dummy, quit?, error?
return-if quit?, 0/dummy, quit?, error?
return-if error?, 0/dummy, quit?, error?
error? <- expect-from-channel stdin, 45/dash, screen
reply-if error?, 0/dummy, 0/quit, error?
return-if error?, 0/dummy, 0/quit, error?
x <- get-address *result, to-file:offset
*x, quit?, error? <- read-file stdin, screen
reply-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean
reply-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean
return-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean
return-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean
x:address:number <- get-address *result, to-rank:offset
*x, quit?, error? <- read-rank stdin, screen
reply-if quit?, 0/dummy, quit?, error?
reply-if error?, 0/dummy, quit?, error?
return-if quit?, 0/dummy, quit?, error?
return-if error?, 0/dummy, quit?, error?
error? <- expect-from-channel stdin, 10/newline, screen
reply-if error?, 0/dummy, 0/quit, error?
reply result, quit?, error?
return-if error?, 0/dummy, 0/quit, error?
return result, quit?, error?
]
# valid values for file: 0-7
recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> file:number, quit:boolean, error:boolean, stdin:address:shared:channel, screen:address:shared:screen [
def read-file stdin:address:shared:channel, screen:address:shared:screen -> file:number, quit:boolean, error:boolean, stdin:address:shared:channel, screen:address:shared:screen [
local-scope
load-ingredients
c:character, stdin <- read stdin
{
q-pressed?:boolean <- equal c, 81/Q
break-unless q-pressed?
reply 0/dummy, 1/quit, 0/error
return 0/dummy, 1/quit, 0/error
}
{
q-pressed? <- equal c, 113/q
break-unless q-pressed?
reply 0/dummy, 1/quit, 0/error
return 0/dummy, 1/quit, 0/error
}
{
empty-fake-keyboard?:boolean <- equal c, 0/eof
break-unless empty-fake-keyboard?
reply 0/dummy, 1/quit, 0/error
return 0/dummy, 1/quit, 0/error
}
{
newline?:boolean <- equal c, 10/newline
break-unless newline?
error-message:address:shared:array:character <- new [that's not enough]
print screen, error-message
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
file:number <- subtract c, 97/a
# 'a' <= file <= 'h'
@ -307,7 +307,7 @@ recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> f
print screen, error-message
print screen, c
cursor-to-next-line screen
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
{
below-max:boolean <- lesser-than file, 8
@ -315,32 +315,32 @@ recipe read-file stdin:address:shared:channel, screen:address:shared:screen -> f
error-message <- new [file too high: ]
print screen, error-message
print screen, c
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
reply file, 0/quit, 0/error
return file, 0/quit, 0/error
]
# valid values: 0-7, -1 (quit), -2 (error)
recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
def read-rank stdin:address:shared:channel, screen:address:shared:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:shared:channel, screen:address:shared:screen [
local-scope
load-ingredients
c:character, stdin <- read stdin
{
q-pressed?:boolean <- equal c, 8/Q
break-unless q-pressed?
reply 0/dummy, 1/quit, 0/error
return 0/dummy, 1/quit, 0/error
}
{
q-pressed? <- equal c, 113/q
break-unless q-pressed?
reply 0/dummy, 1/quit, 0/error
return 0/dummy, 1/quit, 0/error
}
{
newline?:boolean <- equal c, 10 # newline
break-unless newline?
error-message:address:shared:array:character <- new [that's not enough]
print screen, error-message
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
rank:number <- subtract c, 49/'1'
# assert'1' <= rank <= '8'
@ -350,7 +350,7 @@ recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> r
error-message <- new [rank too low: ]
print screen, error-message
print screen, c
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
{
below-max:boolean <- lesser-or-equal rank, 7
@ -358,14 +358,14 @@ recipe read-rank stdin:address:shared:channel, screen:address:shared:screen -> r
error-message <- new [rank too high: ]
print screen, error-message
print screen, c
reply 0/dummy, 0/quit, 1/error
return 0/dummy, 0/quit, 1/error
}
reply rank, 0/quit, 0/error
return rank, 0/quit, 0/error
]
# read a character from the given channel and check that it's what we expect
# return true on error
recipe expect-from-channel stdin:address:shared:channel, expected:character, screen:address:shared:screen -> result:boolean, stdin:address:shared:channel, screen:address:shared:screen [
def expect-from-channel stdin:address:shared:channel, expected:character, screen:address:shared:screen -> result:boolean, stdin:address:shared:channel, screen:address:shared:screen [
local-scope
load-ingredients
c:character, stdin <- read stdin
@ -542,7 +542,7 @@ F read-move-file: routine failed to pause after coming up (before any keys were
]
]
recipe make-move board:address:shared:array:address:shared:array:character, m:address:shared:move -> board:address:shared:array:address:shared:array:character [
def make-move board:address:shared:array:address:shared:array:character, m:address:shared:move -> board:address:shared:array:address:shared:array:character [
local-scope
load-ingredients
from-file:number <- get *m, from-file:offset

View File

@ -2,7 +2,7 @@
#
# Keeps printing 'a' until you press a key or click on the mouse.
recipe main [
def main [
local-scope
open-console
{

View File

@ -1,19 +1,19 @@
# example program: maintain multiple counters with isolated lexical scopes
# (spaces)
recipe new-counter n:number -> default-space:address:shared:array:location [
def new-counter n:number -> default-space:address:shared:array:location [
default-space <- new location:type, 30
load-ingredients
]
recipe increment-counter outer:address:shared:array:location/names:new-counter, x:number -> n:number/space:1 [
def increment-counter outer:address:shared:array:location/names:new-counter, x:number -> n:number/space:1 [
local-scope
load-ingredients
0:address:shared:array:location/names:new-counter <- copy outer # setup outer space; it *must* come from 'new-counter'
n/space:1 <- add n/space:1, x
]
recipe main [
def main [
local-scope
# counter A
a:address:shared:array:location <- new-counter 34
@ -24,9 +24,7 @@ recipe main [
b-value:number <- increment-counter b, 2
a-value:number <- increment-counter a, 1
# check results
$print [Contents of counters
]
$print [Contents of counters], 10/newline
# trailing space in next line is to help with syntax highlighting
$print [a: ], a-value, [ b: ], b-value, [
]
$print [a: ], a-value, [ b: ], b-value, 10/newline
]

View File

@ -1,6 +1,6 @@
# example program: managing the display
recipe main [
def main [
open-console
print-character-to-display 97, 1/red, 2/green
1:number/raw, 2:number/raw <- cursor-position-on-display

View File

@ -2,7 +2,7 @@
# temporary main for this layer: just render the given text at the given
# screen dimensions, then stop
recipe! main text:address:shared:array:character [
def! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -48,7 +48,7 @@ container editor-data [
# creates a new editor widget and renders its initial appearance to screen
# top/left/right constrain the screen area available to the new editor
# right is exclusive
recipe new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
def new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
local-scope
load-ingredients
# no clipping of bounds
@ -79,13 +79,13 @@ recipe new-editor s:address:shared:array:character, screen:address:shared:screen
<editor-initialization>
]
recipe insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
def insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
local-scope
load-ingredients
# early exit if text is empty
reply-unless text, editor/same-as-ingredient:0
return-unless text, editor/same-as-ingredient:0
len:number <- length *text
reply-unless len, editor/same-as-ingredient:0
return-unless len, editor/same-as-ingredient:0
idx:number <- copy 0
# now we can start appending the rest, character by character
curr:address:shared:duplex-list:character <- get *editor, data:offset
@ -99,7 +99,7 @@ recipe insert-text editor:address:shared:editor-data, text:address:shared:array:
idx <- add idx, 1
loop
}
reply editor/same-as-ingredient:0
return editor/same-as-ingredient:0
]
scenario editor-initializes-without-data [
@ -129,10 +129,10 @@ scenario editor-initializes-without-data [
# Assumes cursor should be at coordinates (cursor-row, cursor-column) and
# updates before-cursor to match. Might also move coordinates if they're
# outside text.
recipe render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
def render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
return-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
left:number <- get *editor, left:offset
screen-height:number <- screen-height screen
right:number <- get *editor, right:offset
@ -226,10 +226,10 @@ recipe render screen:address:shared:screen, editor:address:shared:editor-data ->
}
bottom:address:number <- get-address *editor, bottom:offset
*bottom <- copy row
reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
return row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
]
recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
def clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 32/space
@ -248,23 +248,23 @@ recipe clear-line-delimited screen:address:shared:screen, column:number, right:n
}
]
recipe clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
def clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
# if it's the real screen, use the optimized primitive
{
break-if screen
clear-display-from row, column, left, right
reply screen/same-as-ingredient:0
return screen/same-as-ingredient:0
}
# if not, go the slower route
screen <- move-cursor screen, row, column
clear-line-delimited screen, column, right
clear-rest-of-screen screen, row, left, right
reply screen/same-as-ingredient:0
return screen/same-as-ingredient:0
]
recipe clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
def clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
row <- add row, 1
@ -422,7 +422,7 @@ after <character-c-received> [
]
# so far the previous color is all the information we need; that may change
recipe get-color color:number, c:character -> color:number [
def get-color color:number, c:character -> color:number [
local-scope
load-ingredients
color-is-white?:boolean <- equal color, 7/white
@ -464,7 +464,7 @@ recipe get-color color:number, c:character -> color:number [
}
# otherwise no change
+exit
reply color
return color
]
scenario render-colors-assignment [

View File

@ -2,7 +2,7 @@
# temporary main: interactive editor
# hit ctrl-c to exit
recipe! main text:address:shared:array:character [
def! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -11,7 +11,7 @@ recipe! main text:address:shared:array:character [
close-console
]
recipe editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
def editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
local-scope
load-ingredients
{
@ -45,35 +45,35 @@ recipe editor-event-loop screen:address:shared:screen, console:address:shared:co
]
# process click, return if it was on current editor
recipe move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
def move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor, 0/false
return-unless editor, 0/false
click-row:number <- get t, row:offset
reply-unless click-row, 0/false # ignore clicks on 'menu'
return-unless click-row, 0/false # ignore clicks on 'menu'
click-column:number <- get t, column:offset
left:number <- get *editor, left:offset
too-far-left?:boolean <- lesser-than click-column, left
reply-if too-far-left?, 0/false
return-if too-far-left?, 0/false
right:number <- get *editor, right:offset
too-far-right?:boolean <- greater-than click-column, right
reply-if too-far-right?, 0/false
return-if too-far-right?, 0/false
# position cursor
<move-cursor-begin>
editor <- snap-cursor screen, editor, click-row, click-column
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
# gain focus
reply 1/true
return 1/true
]
# Variant of 'render' that only moves the cursor (coordinates and
# before-cursor). If it's past the end of a line, it 'slides' it left. If it's
# past the last line it positions at end of last line.
recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
def snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor
return-unless editor
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
@ -155,11 +155,11 @@ recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-da
# Process an event 'e' and try to minimally update the screen.
# Set 'go-render?' to true to indicate the caller must perform a non-minimal update.
recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
def handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
go-render? <- copy 0/false
reply-unless editor
return-unless editor
screen-width:number <- screen-width screen
screen-height:number <- screen-height screen
left:number <- get *editor, left:offset
@ -179,12 +179,12 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
# ignore any other special characters
regular-character?:boolean <- greater-or-equal *c, 32/space
go-render? <- copy 0/false
reply-unless regular-character?
return-unless regular-character?
# otherwise type it in
<insert-character-begin>
editor, screen, go-render?:boolean <- insert-at-cursor editor, *c, screen
<insert-character-end>
reply
return
}
# special key to modify the text or move the cursor
k:address:number <- maybe-convert e:event, keycode:variant
@ -192,10 +192,10 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
# handlers for each special key will go here
<handle-special-key>
go-render? <- copy 1/true
reply
return
]
recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
def insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -226,7 +226,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
move-cursor screen, save-row, save-column
print screen, c
go-render? <- copy 0/false
reply
return
}
{
# not at right margin? print the character and rest of line
@ -240,7 +240,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
# hit right margin? give up and let caller render
go-render? <- copy 1/true
at-right?:boolean <- greater-than curr-column, right
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -252,14 +252,14 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
loop
}
go-render? <- copy 0/false
reply
return
}
go-render? <- copy 1/true
reply
return
]
# helper for tests
recipe editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
def editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
local-scope
load-ingredients
left:number <- get *editor, left:offset
@ -697,7 +697,7 @@ after <insert-character-special-case> [
<scroll-down>
}
go-render? <- copy 1/true
reply
return
}
]
@ -818,11 +818,11 @@ after <handle-special-character> [
editor <- insert-new-line-and-indent editor, screen
<insert-enter-end>
go-render? <- copy 1/true
reply
return
}
]
recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
def insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -846,7 +846,7 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
}
# indent if necessary
indent?:boolean <- get *editor, indent?:offset
reply-unless indent?
return-unless indent?
d:address:shared:duplex-list:character <- get *editor, data:offset
end-of-previous-line:address:shared:duplex-list:character <- prev *before-cursor
indent:number <- line-indent end-of-previous-line, d
@ -862,13 +862,13 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
# takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
# the number of spaces at the start of the line containing 'curr'.
recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
def line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
reply-unless curr
return-unless curr
at-start?:boolean <- equal curr, start
reply-if at-start?
return-if at-start?
{
curr <- prev curr
break-unless curr
@ -995,7 +995,7 @@ after <handle-special-key> [
indent?:address:boolean <- get-address *editor, indent?:offset
*indent? <- copy 0/false
go-render? <- copy 1/true
reply
return
}
]
@ -1006,13 +1006,13 @@ after <handle-special-key> [
indent?:address:boolean <- get-address *editor, indent?:offset
*indent? <- copy 1/true
go-render? <- copy 1/true
reply
return
}
]
## helpers
recipe draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
def draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
style:character, style-found?:boolean <- next-ingredient

View File

@ -32,7 +32,7 @@ after <handle-special-character> [
editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen
<insert-character-end>
go-render? <- copy 1/true
reply
return
}
]
@ -73,14 +73,14 @@ after <handle-special-character> [
<backspace-character-begin>
editor, screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character <- delete-before-cursor editor, screen
<backspace-character-end>
reply
return
}
]
# return values:
# go-render? - whether caller needs to update the screen
# backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.
recipe delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
def delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -88,7 +88,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
# if at start of text (before-cursor at § sentinel), return
prev:address:shared:duplex-list:character <- prev *before-cursor
go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
reply-unless prev
return-unless prev
trace 10, [app], [delete-before-cursor]
original-row:number <- get *editor, cursor-row:offset
editor, scroll?:boolean <- move-cursor-coordinates-left editor
@ -96,14 +96,14 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
data <- remove *before-cursor, data # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
*before-cursor <- copy prev
go-render? <- copy 1/true
reply-if scroll?
return-if scroll?
screen-width:number <- screen-width screen
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
# did we just backspace over a newline?
same-row?:boolean <- equal cursor-row, original-row
go-render? <- copy 1/true
reply-unless same-row?
return-unless same-row?
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
curr:address:shared:duplex-list:character <- next *before-cursor
@ -113,7 +113,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
# hit right margin? give up and let caller render
at-right?:boolean <- greater-or-equal curr-column, right
go-render? <- copy 1/true
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -130,7 +130,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
go-render? <- copy 0/false
]
recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
def move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:shared:duplex-list:character <- get *editor, before-cursor:offset
@ -144,7 +144,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
trace 10, [app], [decrementing cursor column]
*cursor-column <- subtract *cursor-column, 1
go-render? <- copy 0/false
reply
return
}
# if at left margin, we must move to previous row:
top-of-screen?:boolean <- equal *cursor-row, 1 # exclude menu bar
@ -179,7 +179,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
break-if wrap?
*cursor-column <- add left, end-of-line
}
reply
return
}
# case 2: if previous-character was not newline, we're just at a wrapped line
trace 10, [app], [wrapping to previous line]
@ -189,13 +189,13 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
# takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
# the length of the previous line before the 'curr' pointer.
recipe previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
def previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
reply-unless curr
return-unless curr
at-start?:boolean <- equal curr, start
reply-if at-start?
return-if at-start?
{
curr <- prev curr
break-unless curr
@ -338,23 +338,23 @@ after <handle-special-key> [
<delete-character-begin>
editor, screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character <- delete-at-cursor editor, screen
<delete-character-end>
reply
return
}
]
recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
def delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
data:address:shared:duplex-list:character <- get *editor, data:offset
deleted-cell:address:shared:duplex-list:character <- next *before-cursor
go-render? <- copy 0/false
reply-unless deleted-cell
return-unless deleted-cell
currc:character <- get *deleted-cell, value:offset
data <- remove deleted-cell, data
deleted-newline?:boolean <- equal currc, 10/newline
go-render? <- copy 1/true
reply-if deleted-newline?
return-if deleted-newline?
# wasn't a newline? render rest of line
curr:address:shared:duplex-list:character <- next *before-cursor # refresh after remove above
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -366,7 +366,7 @@ recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared
# hit right margin? give up and let caller render
at-right?:boolean <- greater-or-equal curr-column, screen-width
go-render? <- copy 1/true
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -421,11 +421,11 @@ after <handle-special-key> [
screen <- move-cursor screen, *cursor-row, *cursor-column
undo-coalesce-tag:number <- copy 2/right-arrow
<move-cursor-end>
reply
return
}
]
recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
def move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:shared:duplex-list:character <- get *editor before-cursor:offset
@ -442,11 +442,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
*cursor-column <- copy left
below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal
go-render? <- copy 0/false
reply-unless below-screen?
return-unless below-screen?
<scroll-down>
*cursor-row <- subtract *cursor-row, 1 # bring back into screen range
go-render? <- copy 1/true
reply
return
}
# if the line wraps, move cursor to start of next row
{
@ -463,11 +463,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
*cursor-row <- add *cursor-row, 1
*cursor-column <- copy left
below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal
reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
return-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
<scroll-down>
*cursor-row <- subtract *cursor-row, 1 # bring back into screen range
go-render? <- copy 1/true
reply
return
}
# otherwise move cursor one character right
*cursor-column <- add *cursor-column, 1
@ -691,13 +691,13 @@ after <handle-special-key> [
# if not at start of text (before-cursor at § sentinel)
prev:address:shared:duplex-list:character <- prev *before-cursor
go-render? <- copy 0/false
reply-unless prev
return-unless prev
<move-cursor-begin>
editor, go-render? <- move-cursor-coordinates-left editor
*before-cursor <- copy prev
undo-coalesce-tag:number <- copy 1/left-arrow
<move-cursor-end>
reply
return
}
]
@ -954,11 +954,11 @@ after <handle-special-key> [
editor, go-render? <- move-to-previous-line editor
undo-coalesce-tag:number <- copy 3/up-arrow
<move-cursor-end>
reply
return
}
]
recipe move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
def move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -982,14 +982,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
curr:address:shared:duplex-list:character <- before-previous-line curr, editor
no-motion?:boolean <- equal curr, old
go-render? <- copy 0/false
reply-if no-motion?
return-if no-motion?
}
{
old <- copy curr
curr <- before-previous-line curr, editor
no-motion?:boolean <- equal curr, old
go-render? <- copy 0/false
reply-if no-motion?
return-if no-motion?
}
*before-cursor <- copy curr
*cursor-row <- subtract *cursor-row, 1
@ -1010,14 +1010,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
loop
}
go-render? <- copy 0/false
reply
return
}
{
# if cursor already at top, scroll up
break-unless already-at-top?
<scroll-up>
go-render? <- copy 1/true
reply
return
}
]
@ -1179,11 +1179,11 @@ after <handle-special-key> [
editor, go-render? <- move-to-next-line editor, screen-height
undo-coalesce-tag:number <- copy 4/down-arrow
<move-cursor-end>
reply
return
}
]
recipe move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
def move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -1207,7 +1207,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
scroll?:boolean <- greater-than *cursor-row, 1
break-if scroll?, +try-to-scroll:label
go-render? <- copy 0/false
reply
return
}
*cursor-row <- add *cursor-row, 1
*before-cursor <- copy next-line
@ -1227,7 +1227,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
loop
}
go-render? <- copy 0/false
reply
return
}
+try-to-scroll
<scroll-down>
@ -1306,7 +1306,7 @@ after <handle-special-character> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
@ -1319,11 +1319,11 @@ after <handle-special-key> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
recipe move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
def move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
# update cursor column
@ -1477,7 +1477,7 @@ after <handle-special-character> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
@ -1490,11 +1490,11 @@ after <handle-special-key> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
recipe move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
def move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -1620,11 +1620,11 @@ after <handle-special-character> [
deleted-cells:address:shared:duplex-list:character <- delete-to-start-of-line editor
<delete-to-start-of-line-end>
go-render? <- copy 1/true
reply
return
}
]
recipe delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
def delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
local-scope
load-ingredients
# compute range to delete
@ -1754,11 +1754,11 @@ after <handle-special-character> [
deleted-cells:address:shared:duplex-list:character <- delete-to-end-of-line editor
<delete-to-end-of-line-end>
go-render? <- copy 1/true
reply
return
}
]
recipe delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
def delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
local-scope
load-ingredients
# compute range to delete
@ -1937,13 +1937,13 @@ after <scroll-down> [
*top-of-screen <- before-start-of-next-line *top-of-screen, max
no-movement?:boolean <- equal old-top, *top-of-screen
go-render? <- copy 0/false
reply-if no-movement?
return-if no-movement?
]
# takes a pointer into the doubly-linked list, scans ahead at most 'max'
# positions until the next newline
# beware: never return null pointer.
recipe before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
def before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
local-scope
load-ingredients
count:number <- copy 0
@ -1957,7 +1957,7 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
count <- add count, 1
}
{
reply-unless curr, original
return-unless curr, original
done?:boolean <- greater-or-equal count, max
break-if done?
c:character <- get *curr, value:offset
@ -1967,8 +1967,8 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
count <- add count, 1
loop
}
reply-unless curr, original
reply curr
return-unless curr, original
return curr
]
scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
@ -2304,13 +2304,13 @@ after <scroll-up> [
*top-of-screen <- before-previous-line *top-of-screen, editor
no-movement?:boolean <- equal old-top, *top-of-screen
go-render? <- copy 0/false
reply-if no-movement?
return-if no-movement?
]
# takes a pointer into the doubly-linked list, scans back to before start of
# previous *wrapped* line
# beware: never return null pointer
recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
def before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
local-scope
load-ingredients
curr:address:shared:duplex-list:character <- copy in
@ -2327,8 +2327,8 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
break-if len
# empty line; just skip this newline
prev:address:shared:duplex-list:character <- prev curr
reply-unless prev, curr
reply prev
return-unless prev, curr
return prev
}
_, max:number <- divide-with-remainder len, max-line-length
# remainder 0 => scan one width-worth
@ -2348,7 +2348,7 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
count <- add count, 1
loop
}
reply curr
return curr
]
scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
@ -2698,7 +2698,7 @@ after <handle-special-character> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
@ -2714,18 +2714,18 @@ after <handle-special-key> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
# page-down skips entire wrapped lines, so it can't scroll past lines
# taking up the entire screen
recipe page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
def page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
# if editor contents don't overflow screen, do nothing
bottom-of-screen:address:shared:duplex-list:character <- get *editor, bottom-of-screen:offset
reply-unless bottom-of-screen
return-unless bottom-of-screen
# if not, position cursor at final character
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
*before-cursor <- prev bottom-of-screen
@ -2890,7 +2890,7 @@ after <handle-special-character> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
@ -2907,11 +2907,11 @@ after <handle-special-key> [
no-movement?:boolean <- equal *top-of-screen, old-top
# don't bother re-rendering if nothing changed. todo: test this
go-render? <- not no-movement?
reply
return
}
]
recipe page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
def page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
local-scope
load-ingredients
max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line

View File

@ -3,7 +3,7 @@
# Consists of one editor on the left for recipes and one on the right for the
# sandbox.
recipe! main [
def! main [
local-scope
open-console
initial-recipe:address:shared:array:character <- restore [recipes.mu]
@ -21,7 +21,7 @@ container programming-environment-data [
sandbox-in-focus?:boolean # false => cursor in recipes; true => cursor in current-sandbox
]
recipe new-programming-environment screen:address:shared:screen, initial-recipe-contents:address:shared:array:character, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
def new-programming-environment screen:address:shared:screen, initial-recipe-contents:address:shared:array:character, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
width:number <- screen-width screen
@ -48,7 +48,7 @@ recipe new-programming-environment screen:address:shared:screen, initial-recipe-
<programming-environment-initialization>
]
recipe event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
def event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
local-scope
load-ingredients
recipes:address:shared:editor-data <- get *env, recipes:offset
@ -180,7 +180,7 @@ recipe event-loop screen:address:shared:screen, console:address:shared:console,
}
]
recipe resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
def resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
clear-screen screen # update screen dimensions
@ -372,7 +372,7 @@ def]
]
]
recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
def render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
trace 10, [app], [render all]
@ -405,7 +405,7 @@ recipe render-all screen:address:shared:screen, env:address:shared:programming-e
show-screen screen
]
recipe render-recipes screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
def render-recipes screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
trace 11, [app], [render recipes]
@ -424,7 +424,7 @@ recipe render-recipes screen:address:shared:screen, env:address:shared:programmi
]
# replaced in a later layer
recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
def render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -439,7 +439,7 @@ recipe render-sandbox-side screen:address:shared:screen, env:address:shared:prog
clear-screen-from screen, row, left, left, right
]
recipe update-cursor screen:address:shared:screen, recipes:address:shared:editor-data, current-sandbox:address:shared:editor-data, sandbox-in-focus?:boolean, env:address:shared:programming-environment-data -> screen:address:shared:screen [
def update-cursor screen:address:shared:screen, recipes:address:shared:editor-data, current-sandbox:address:shared:editor-data, sandbox-in-focus?:boolean, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
<update-cursor-special-cases>
@ -458,10 +458,10 @@ recipe update-cursor screen:address:shared:screen, recipes:address:shared:editor
# print a text 's' to 'editor' in 'color' starting at 'row'
# clear rest of last line, move cursor to next line
recipe render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
def render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless s
return-unless s
column:number <- copy left
screen <- move-cursor screen, row, column
screen-height:number <- screen-height screen
@ -519,10 +519,10 @@ recipe render screen:address:shared:screen, s:address:shared:array:character, le
]
# like 'render' for texts, but with colorization for comments like in the editor
recipe render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
def render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless s
return-unless s
color:number <- copy 7/white
column:number <- copy left
screen <- move-cursor screen, row, column
@ -608,7 +608,7 @@ after <global-type> [
## helpers
recipe draw-vertical screen:address:shared:screen, col:number, y:number, bottom:number -> screen:address:shared:screen [
def draw-vertical screen:address:shared:screen, col:number, y:number, bottom:number -> screen:address:shared:screen [
local-scope
load-ingredients
style:character, style-found?:boolean <- next-ingredient

View File

@ -4,7 +4,7 @@
# (non-editable) sandboxes below the editor, showing the result and a maybe
# few other things.
recipe! main [
def! main [
local-scope
open-console
initial-recipe:address:shared:array:character <- restore [recipes.mu]
@ -142,11 +142,11 @@ after <global-keypress> [
}
]
recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
errors-found?:boolean, env, screen <- update-recipes env, screen
reply-if errors-found?
return-if errors-found?
# check contents of right editor (sandbox)
<run-sandboxes-begin>
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -189,7 +189,7 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add
# copy code from recipe editor, persist, load into mu
# replaced in a later layer (whereupon errors-found? will actually be set)
recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
recipes:address:shared:editor-data <- get *env, recipes:offset
@ -200,7 +200,7 @@ recipe update-recipes env:address:shared:programming-environment-data, screen:ad
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset
@ -209,14 +209,14 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
*response, _, *fake-screen <- run-interactive data
]
recipe update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
def update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
local-scope
load-ingredients
screen <- move-cursor screen, 0, 2
screen <- print screen, msg, color, 238/grey/background
]
recipe save-sandboxes env:address:shared:programming-environment-data [
def save-sandboxes env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -237,7 +237,7 @@ recipe save-sandboxes env:address:shared:programming-environment-data [
}
]
recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
def! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
trace 11, [app], [render sandbox side]
@ -261,13 +261,13 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro
clear-rest-of-screen screen, row, left, right
]
recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
def render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
reply-unless sandbox
return-unless sandbox
screen-height:number <- screen-height screen
at-bottom?:boolean <- greater-or-equal row, screen-height
reply-if at-bottom?:boolean
return-if at-bottom?:boolean
hidden?:boolean <- lesser-than idx, render-from
{
break-if hidden?
@ -304,7 +304,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
}
+render-sandbox-end
at-bottom?:boolean <- greater-or-equal row, screen-height
reply-if at-bottom?
return-if at-bottom?
# draw solid line after sandbox
draw-horizontal screen, row, left, right, 9473/horizontal-double
}
@ -324,7 +324,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
]
# assumes programming environment has no sandboxes; restores them from previous session
recipe restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
def restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
local-scope
load-ingredients
# read all scenarios, pushing them to end of a list of scenarios
@ -358,10 +358,10 @@ recipe restore-sandboxes env:address:shared:programming-environment-data -> env:
# print the fake sandbox screen to 'screen' with appropriate delimiters
# leave cursor at start of next line
recipe render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
def render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless sandbox-screen
return-unless sandbox-screen
# print 'screen:'
header:address:shared:array:character <- new [screen:]
row <- render screen, header, left, right, 245/grey, row
@ -510,7 +510,7 @@ scenario run-instruction-manages-screen-per-sandbox [
]
]
recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
def editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
@ -518,7 +518,7 @@ recipe editor-contents editor:address:shared:editor-data -> result:address:share
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
reply-unless curr, 0
return-unless curr, 0
{
break-unless curr
c:character <- get *curr, value:offset
@ -655,7 +655,7 @@ after <update-cursor-special-cases> [
break-unless scrolling?
cursor-column:number <- get *current-sandbox, left:offset
screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2
reply
return
}
]
@ -678,21 +678,21 @@ 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
recipe previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
def previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
local-scope
load-ingredients
curr:address:shared:sandbox-data <- get *env, sandbox:offset
reply-unless curr, 0/nil
return-unless curr, 0/nil
next:address:shared:sandbox-data <- get *curr, next-sandbox:offset
{
reply-unless next, 0/nil
return-unless next, 0/nil
found?:boolean <- equal next, in
break-if found?
curr <- copy next
next <- get *curr, next-sandbox:offset
loop
}
reply curr
return curr
]
scenario scrolling-down-on-recipe-side [

View File

@ -92,7 +92,7 @@ after <global-touch> [
}
]
recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
def empty-editor? editor:address:shared:editor-data -> result:boolean [
local-scope
load-ingredients
head:address:shared:duplex-list:character <- get *editor, data:offset
@ -100,13 +100,13 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
result <- not first
]
recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
start:number <- get **sandbox, starting-row-on-screen:offset
in-editor?:boolean <- lesser-than click-row, start
reply-if in-editor?, 0
return-if in-editor?, 0
{
next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
break-unless next-sandbox

View File

@ -77,14 +77,14 @@ after <global-touch> [
}
]
recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
def delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
local-scope
load-ingredients
click-column:number <- get t, column:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
right:number <- get *current-sandbox, right:offset
at-right?:boolean <- equal click-column, right
reply-unless at-right?, 0/false
return-unless at-right?, 0/false
click-row:number <- get t, row:offset
prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
@ -108,13 +108,13 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-
break-unless reset-scroll?
*render-from <- copy -1
}
reply 1/true # force rerender
return 1/true # force rerender
}
prev <- get-address *curr, next-sandbox:offset
curr <- get *curr, next-sandbox:offset
loop
}
reply 0/false
return 0/false
]
scenario deleting-sandbox-after-scroll [

View File

@ -132,7 +132,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
def find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
# assert click-row >= sandbox.starting-row-on-screen
@ -152,13 +152,13 @@ recipe find-click-in-sandbox-output env:address:shared:programming-environment-d
}
# return sandbox if click is in its output region
response-starting-row:number <- get *sandbox, response-starting-row-on-screen:offset
reply-unless response-starting-row, 0/no-click-in-sandbox-output
return-unless response-starting-row, 0/no-click-in-sandbox-output
click-in-response?:boolean <- greater-or-equal click-row, response-starting-row
reply-unless click-in-response?, 0/no-click-in-sandbox-output
reply sandbox
return-unless click-in-response?, 0/no-click-in-sandbox-output
return sandbox
]
recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
def toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
@ -166,7 +166,7 @@ recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:a
# if expected-response is set, reset
break-unless *expected-response
*expected-response <- copy 0
reply sandbox/same-as-ingredient:0
return sandbox/same-as-ingredient:0
}
# if not, current response is the expected response
response:address:shared:array:character <- get *sandbox, response:offset

View File

@ -81,7 +81,7 @@ scenario sandbox-shows-app-trace-and-result [
1:address:shared:array:character <- new [
recipe foo [
stash [abc]
reply 4
reply 4
]]
# run it
2:address:shared:array:character <- new [foo]
@ -127,7 +127,7 @@ container sandbox-data [
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset
@ -166,7 +166,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
def find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
# assert click-row >= sandbox.starting-row-on-screen
@ -192,9 +192,9 @@ recipe find-click-in-sandbox-code env:address:shared:programming-environment-dat
click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
{
break-if click-on-sandbox-code?
reply 0/no-click-in-sandbox-output
return 0/no-click-in-sandbox-output
}
reply sandbox
return sandbox
]
# when rendering a sandbox, dump its trace before response/warning if display-trace? property is set

View File

@ -5,7 +5,7 @@ container programming-environment-data [
]
# copy code from recipe editor, persist, load into mu, save any errors
recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
recipes:address:shared:editor-data <- get *env, recipes:offset
@ -19,7 +19,7 @@ recipe! update-recipes env:address:shared:programming-environment-data, screen:a
status:address:shared:array:character <- new [errors found ]
update-status screen, status, 1/red
errors-found? <- copy 1/true
reply
return
}
errors-found? <- copy 0/false
]
@ -81,7 +81,7 @@ container sandbox-data [
errors:address:shared:array:character
]
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset

View File

@ -72,7 +72,7 @@ after <handle-special-character> [
redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
*redo <- push op, *redo
<handle-undo>
reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
@ -88,7 +88,7 @@ after <handle-special-character> [
undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
*undo <- push op, *undo
<handle-redo>
reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
@ -189,14 +189,14 @@ before <insert-enter-end> [
# redo stack, because it's now obsolete.
# Beware: since we're counting cursor moves as operations, this means just
# moving the cursor can lose work on the undo stack.
recipe add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
def add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
local-scope
load-ingredients
undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
*undo <- push op *undo
redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
*redo <- copy 0
reply editor/same-as-ingredient:0
return editor/same-as-ingredient:0
]
after <handle-undo> [

View File

@ -1,4 +1,4 @@
recipe example1 [
def example1 [
local-scope
a:number <- add 2, 2
a <- multiply a, 3

View File

@ -1,20 +1,20 @@
# example program: compute the factorial of 5
recipe main [
def main [
local-scope
x:number <- factorial 5
$print [result: ], x, [
]
]
recipe factorial n:number -> result:number [
def factorial n:number -> result:number [
local-scope
load-ingredients
{
# if n=0 return 1
zero?:boolean <- equal n, 0
break-unless zero?
reply 1
return 1
}
# return n * factorial(n-1)
x:number <- subtract n, 1

View File

@ -1,6 +1,6 @@
# example program: running multiple routines
recipe main [
def main [
start-running thread2
{
$print 34
@ -8,7 +8,7 @@ recipe main [
}
]
recipe thread2 [
def thread2 [
{
$print 35
loop

View File

@ -1,6 +1,6 @@
# example program: creating and using global variables
recipe main [
def main [
# allocate 5 locations for globals
global-space:address:shared:array:location <- new location:type, 5
# read to globals by using /space:global
@ -8,7 +8,7 @@ recipe main [
foo
]
recipe foo [
def foo [
# ditto for writing to globals
$print 1:number/space:global, 10/newline
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

4
mu.vim
View File

@ -58,9 +58,9 @@ syntax keyword muKeyword default-space global-space new-default-space local-scop
syntax match muDelimiter "[{}]" | highlight link muDelimiter Delimiter
syntax match muAssign " <- \|\<raw\>" | highlight link muAssign SpecialChar
syntax match muGlobal %[^ ]\+:global/\?[^ ,]*% | highlight link muGlobal SpecialChar
syntax keyword muControl reply reply-if reply-unless jump jump-if jump-unless loop loop-if loop-unless break break-if break-unless current-continuation continue-from create-delimited-continuation reply-delimited-continuation | highlight muControl ctermfg=3
syntax keyword muControl reply reply-if reply-unless return return-if return-unless jump jump-if jump-unless loop loop-if loop-unless break break-if break-unless current-continuation continue-from create-delimited-continuation reply-delimited-continuation | highlight muControl ctermfg=3
" common keywords
syntax keyword muRecipe recipe recipe! before after | highlight muRecipe ctermfg=208
syntax keyword muRecipe recipe recipe! def def! before after | highlight muRecipe ctermfg=208
syntax match muRecipe " -> "
syntax keyword muScenario scenario | highlight muScenario ctermfg=34
syntax keyword muData container exclusive-container | highlight muData ctermfg=226

View File

@ -2,7 +2,7 @@
# temporary main for this layer: just render the given text at the given
# screen dimensions, then stop
recipe! main text:address:shared:array:character [
def! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -48,7 +48,7 @@ container editor-data [
# creates a new editor widget and renders its initial appearance to screen
# top/left/right constrain the screen area available to the new editor
# right is exclusive
recipe new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
def new-editor s:address:shared:array:character, screen:address:shared:screen, left:number, right:number -> result:address:shared:editor-data, screen:address:shared:screen [
local-scope
load-ingredients
# no clipping of bounds
@ -79,13 +79,13 @@ recipe new-editor s:address:shared:array:character, screen:address:shared:screen
<editor-initialization>
]
recipe insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
def insert-text editor:address:shared:editor-data, text:address:shared:array:character -> editor:address:shared:editor-data [
local-scope
load-ingredients
# early exit if text is empty
reply-unless text, editor/same-as-ingredient:0
return-unless text, editor/same-as-ingredient:0
len:number <- length *text
reply-unless len, editor/same-as-ingredient:0
return-unless len, editor/same-as-ingredient:0
idx:number <- copy 0
# now we can start appending the rest, character by character
curr:address:shared:duplex-list:character <- get *editor, data:offset
@ -99,7 +99,7 @@ recipe insert-text editor:address:shared:editor-data, text:address:shared:array:
idx <- add idx, 1
loop
}
reply editor/same-as-ingredient:0
return editor/same-as-ingredient:0
]
scenario editor-initializes-without-data [
@ -129,10 +129,10 @@ scenario editor-initializes-without-data [
# Assumes cursor should be at coordinates (cursor-row, cursor-column) and
# updates before-cursor to match. Might also move coordinates if they're
# outside text.
recipe render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
def render screen:address:shared:screen, editor:address:shared:editor-data -> last-row:number, last-column:number, screen:address:shared:screen, editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
return-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
left:number <- get *editor, left:offset
screen-height:number <- screen-height screen
right:number <- get *editor, right:offset
@ -226,10 +226,10 @@ recipe render screen:address:shared:screen, editor:address:shared:editor-data ->
}
bottom:address:number <- get-address *editor, bottom:offset
*bottom <- copy row
reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
return row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
]
recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
def clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 32/space
@ -248,23 +248,23 @@ recipe clear-line-delimited screen:address:shared:screen, column:number, right:n
}
]
recipe clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
def clear-screen-from screen:address:shared:screen, row:number, column:number, left:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
# if it's the real screen, use the optimized primitive
{
break-if screen
clear-display-from row, column, left, right
reply screen/same-as-ingredient:0
return screen/same-as-ingredient:0
}
# if not, go the slower route
screen <- move-cursor screen, row, column
clear-line-delimited screen, column, right
clear-rest-of-screen screen, row, left, right
reply screen/same-as-ingredient:0
return screen/same-as-ingredient:0
]
recipe clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
def clear-rest-of-screen screen:address:shared:screen, row:number, left:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
row <- add row, 1
@ -422,7 +422,7 @@ after <character-c-received> [
]
# so far the previous color is all the information we need; that may change
recipe get-color color:number, c:character -> color:number [
def get-color color:number, c:character -> color:number [
local-scope
load-ingredients
color-is-white?:boolean <- equal color, 7/white
@ -464,7 +464,7 @@ recipe get-color color:number, c:character -> color:number [
}
# otherwise no change
+exit
reply color
return color
]
scenario render-colors-assignment [

View File

@ -2,7 +2,7 @@
# temporary main: interactive editor
# hit ctrl-c to exit
recipe! main text:address:shared:array:character [
def! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -11,7 +11,7 @@ recipe! main text:address:shared:array:character [
close-console
]
recipe editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
def editor-event-loop screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data -> screen:address:shared:screen, console:address:shared:console, editor:address:shared:editor-data [
local-scope
load-ingredients
{
@ -45,35 +45,35 @@ recipe editor-event-loop screen:address:shared:screen, console:address:shared:co
]
# process click, return if it was on current editor
recipe move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
def move-cursor-in-editor screen:address:shared:screen, editor:address:shared:editor-data, t:touch-event -> in-focus?:boolean, editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor, 0/false
return-unless editor, 0/false
click-row:number <- get t, row:offset
reply-unless click-row, 0/false # ignore clicks on 'menu'
return-unless click-row, 0/false # ignore clicks on 'menu'
click-column:number <- get t, column:offset
left:number <- get *editor, left:offset
too-far-left?:boolean <- lesser-than click-column, left
reply-if too-far-left?, 0/false
return-if too-far-left?, 0/false
right:number <- get *editor, right:offset
too-far-right?:boolean <- greater-than click-column, right
reply-if too-far-right?, 0/false
return-if too-far-right?, 0/false
# position cursor
<move-cursor-begin>
editor <- snap-cursor screen, editor, click-row, click-column
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
# gain focus
reply 1/true
return 1/true
]
# Variant of 'render' that only moves the cursor (coordinates and
# before-cursor). If it's past the end of a line, it 'slides' it left. If it's
# past the last line it positions at end of last line.
recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
def snap-cursor screen:address:shared:screen, editor:address:shared:editor-data, target-row:number, target-column:number -> editor:address:shared:editor-data [
local-scope
load-ingredients
reply-unless editor
return-unless editor
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
@ -155,11 +155,11 @@ recipe snap-cursor screen:address:shared:screen, editor:address:shared:editor-da
# Process an event 'e' and try to minimally update the screen.
# Set 'go-render?' to true to indicate the caller must perform a non-minimal update.
recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
def handle-keyboard-event screen:address:shared:screen, editor:address:shared:editor-data, e:event -> screen:address:shared:screen, editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
go-render? <- copy 0/false
reply-unless editor
return-unless editor
screen-width:number <- screen-width screen
screen-height:number <- screen-height screen
left:number <- get *editor, left:offset
@ -179,12 +179,12 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
# ignore any other special characters
regular-character?:boolean <- greater-or-equal *c, 32/space
go-render? <- copy 0/false
reply-unless regular-character?
return-unless regular-character?
# otherwise type it in
<insert-character-begin>
editor, screen, go-render?:boolean <- insert-at-cursor editor, *c, screen
<insert-character-end>
reply
return
}
# special key to modify the text or move the cursor
k:address:number <- maybe-convert e:event, keycode:variant
@ -192,10 +192,10 @@ recipe handle-keyboard-event screen:address:shared:screen, editor:address:shared
# handlers for each special key will go here
<handle-special-key>
go-render? <- copy 1/true
reply
return
]
recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
def insert-at-cursor editor:address:shared:editor-data, c:character, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -226,7 +226,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
move-cursor screen, save-row, save-column
print screen, c
go-render? <- copy 0/false
reply
return
}
{
# not at right margin? print the character and rest of line
@ -240,7 +240,7 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
# hit right margin? give up and let caller render
go-render? <- copy 1/true
at-right?:boolean <- greater-than curr-column, right
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -252,14 +252,14 @@ recipe insert-at-cursor editor:address:shared:editor-data, c:character, screen:a
loop
}
go-render? <- copy 0/false
reply
return
}
go-render? <- copy 1/true
reply
return
]
# helper for tests
recipe editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
def editor-render screen:address:shared:screen, editor:address:shared:editor-data -> screen:address:shared:screen, editor:address:shared:editor-data [
local-scope
load-ingredients
left:number <- get *editor, left:offset
@ -697,7 +697,7 @@ after <insert-character-special-case> [
<scroll-down>
}
go-render? <- copy 1/true
reply
return
}
]
@ -818,11 +818,11 @@ after <handle-special-character> [
editor <- insert-new-line-and-indent editor, screen
<insert-enter-end>
go-render? <- copy 1/true
reply
return
}
]
recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
def insert-new-line-and-indent editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -846,7 +846,7 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
}
# indent if necessary
indent?:boolean <- get *editor, indent?:offset
reply-unless indent?
return-unless indent?
d:address:shared:duplex-list:character <- get *editor, data:offset
end-of-previous-line:address:shared:duplex-list:character <- prev *before-cursor
indent:number <- line-indent end-of-previous-line, d
@ -862,13 +862,13 @@ recipe insert-new-line-and-indent editor:address:shared:editor-data, screen:addr
# takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
# the number of spaces at the start of the line containing 'curr'.
recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
def line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
reply-unless curr
return-unless curr
at-start?:boolean <- equal curr, start
reply-if at-start?
return-if at-start?
{
curr <- prev curr
break-unless curr
@ -995,7 +995,7 @@ after <handle-special-key> [
indent?:address:boolean <- get-address *editor, indent?:offset
*indent? <- copy 0/false
go-render? <- copy 1/true
reply
return
}
]
@ -1006,13 +1006,13 @@ after <handle-special-key> [
indent?:address:boolean <- get-address *editor, indent?:offset
*indent? <- copy 1/true
go-render? <- copy 1/true
reply
return
}
]
## helpers
recipe draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
def draw-horizontal screen:address:shared:screen, row:number, x:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
style:character, style-found?:boolean <- next-ingredient

View File

@ -32,7 +32,7 @@ after <handle-special-character> [
editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen
<insert-character-end>
go-render? <- copy 1/true
reply
return
}
]
@ -73,14 +73,14 @@ after <handle-special-character> [
<backspace-character-begin>
editor, screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character <- delete-before-cursor editor, screen
<backspace-character-end>
reply
return
}
]
# return values:
# go-render? - whether caller needs to update the screen
# backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.
recipe delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
def delete-before-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, backspaced-cell:address:shared:duplex-list:character [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -88,7 +88,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
# if at start of text (before-cursor at § sentinel), return
prev:address:shared:duplex-list:character <- prev *before-cursor
go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted
reply-unless prev
return-unless prev
trace 10, [app], [delete-before-cursor]
original-row:number <- get *editor, cursor-row:offset
editor, scroll?:boolean <- move-cursor-coordinates-left editor
@ -96,14 +96,14 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
data <- remove *before-cursor, data # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor
*before-cursor <- copy prev
go-render? <- copy 1/true
reply-if scroll?
return-if scroll?
screen-width:number <- screen-width screen
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
# did we just backspace over a newline?
same-row?:boolean <- equal cursor-row, original-row
go-render? <- copy 1/true
reply-unless same-row?
return-unless same-row?
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
curr:address:shared:duplex-list:character <- next *before-cursor
@ -113,7 +113,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
# hit right margin? give up and let caller render
at-right?:boolean <- greater-or-equal curr-column, right
go-render? <- copy 1/true
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -130,7 +130,7 @@ recipe delete-before-cursor editor:address:shared:editor-data, screen:address:sh
go-render? <- copy 0/false
]
recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
def move-cursor-coordinates-left editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:shared:duplex-list:character <- get *editor, before-cursor:offset
@ -144,7 +144,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
trace 10, [app], [decrementing cursor column]
*cursor-column <- subtract *cursor-column, 1
go-render? <- copy 0/false
reply
return
}
# if at left margin, we must move to previous row:
top-of-screen?:boolean <- equal *cursor-row, 1 # exclude menu bar
@ -179,7 +179,7 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
break-if wrap?
*cursor-column <- add left, end-of-line
}
reply
return
}
# case 2: if previous-character was not newline, we're just at a wrapped line
trace 10, [app], [wrapping to previous line]
@ -189,13 +189,13 @@ recipe move-cursor-coordinates-left editor:address:shared:editor-data -> editor:
# takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
# the length of the previous line before the 'curr' pointer.
recipe previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
def previous-line-length curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
reply-unless curr
return-unless curr
at-start?:boolean <- equal curr, start
reply-if at-start?
return-if at-start?
{
curr <- prev curr
break-unless curr
@ -338,23 +338,23 @@ after <handle-special-key> [
<delete-character-begin>
editor, screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character <- delete-at-cursor editor, screen
<delete-character-end>
reply
return
}
]
recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
def delete-at-cursor editor:address:shared:editor-data, screen:address:shared:screen -> editor:address:shared:editor-data, screen:address:shared:screen, go-render?:boolean, deleted-cell:address:shared:duplex-list:character [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
data:address:shared:duplex-list:character <- get *editor, data:offset
deleted-cell:address:shared:duplex-list:character <- next *before-cursor
go-render? <- copy 0/false
reply-unless deleted-cell
return-unless deleted-cell
currc:character <- get *deleted-cell, value:offset
data <- remove deleted-cell, data
deleted-newline?:boolean <- equal currc, 10/newline
go-render? <- copy 1/true
reply-if deleted-newline?
return-if deleted-newline?
# wasn't a newline? render rest of line
curr:address:shared:duplex-list:character <- next *before-cursor # refresh after remove above
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -366,7 +366,7 @@ recipe delete-at-cursor editor:address:shared:editor-data, screen:address:shared
# hit right margin? give up and let caller render
at-right?:boolean <- greater-or-equal curr-column, screen-width
go-render? <- copy 1/true
reply-if at-right?
return-if at-right?
break-unless curr
# newline? done.
currc:character <- get *curr, value:offset
@ -421,11 +421,11 @@ after <handle-special-key> [
screen <- move-cursor screen, *cursor-row, *cursor-column
undo-coalesce-tag:number <- copy 2/right-arrow
<move-cursor-end>
reply
return
}
]
recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
def move-cursor-coordinates-right editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
before-cursor:address:shared:duplex-list:character <- get *editor before-cursor:offset
@ -442,11 +442,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
*cursor-column <- copy left
below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal
go-render? <- copy 0/false
reply-unless below-screen?
return-unless below-screen?
<scroll-down>
*cursor-row <- subtract *cursor-row, 1 # bring back into screen range
go-render? <- copy 1/true
reply
return
}
# if the line wraps, move cursor to start of next row
{
@ -463,11 +463,11 @@ recipe move-cursor-coordinates-right editor:address:shared:editor-data, screen-h
*cursor-row <- add *cursor-row, 1
*cursor-column <- copy left
below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal
reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
return-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render
<scroll-down>
*cursor-row <- subtract *cursor-row, 1 # bring back into screen range
go-render? <- copy 1/true
reply
return
}
# otherwise move cursor one character right
*cursor-column <- add *cursor-column, 1
@ -691,13 +691,13 @@ after <handle-special-key> [
# if not at start of text (before-cursor at § sentinel)
prev:address:shared:duplex-list:character <- prev *before-cursor
go-render? <- copy 0/false
reply-unless prev
return-unless prev
<move-cursor-begin>
editor, go-render? <- move-cursor-coordinates-left editor
*before-cursor <- copy prev
undo-coalesce-tag:number <- copy 1/left-arrow
<move-cursor-end>
reply
return
}
]
@ -954,11 +954,11 @@ after <handle-special-key> [
editor, go-render? <- move-to-previous-line editor
undo-coalesce-tag:number <- copy 3/up-arrow
<move-cursor-end>
reply
return
}
]
recipe move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
def move-to-previous-line editor:address:shared:editor-data -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -982,14 +982,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
curr:address:shared:duplex-list:character <- before-previous-line curr, editor
no-motion?:boolean <- equal curr, old
go-render? <- copy 0/false
reply-if no-motion?
return-if no-motion?
}
{
old <- copy curr
curr <- before-previous-line curr, editor
no-motion?:boolean <- equal curr, old
go-render? <- copy 0/false
reply-if no-motion?
return-if no-motion?
}
*before-cursor <- copy curr
*cursor-row <- subtract *cursor-row, 1
@ -1010,14 +1010,14 @@ recipe move-to-previous-line editor:address:shared:editor-data -> editor:address
loop
}
go-render? <- copy 0/false
reply
return
}
{
# if cursor already at top, scroll up
break-unless already-at-top?
<scroll-up>
go-render? <- copy 1/true
reply
return
}
]
@ -1179,11 +1179,11 @@ after <handle-special-key> [
editor, go-render? <- move-to-next-line editor, screen-height
undo-coalesce-tag:number <- copy 4/down-arrow
<move-cursor-end>
reply
return
}
]
recipe move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
def move-to-next-line editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data, go-render?:boolean [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -1207,7 +1207,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
scroll?:boolean <- greater-than *cursor-row, 1
break-if scroll?, +try-to-scroll:label
go-render? <- copy 0/false
reply
return
}
*cursor-row <- add *cursor-row, 1
*before-cursor <- copy next-line
@ -1227,7 +1227,7 @@ recipe move-to-next-line editor:address:shared:editor-data, screen-height:number
loop
}
go-render? <- copy 0/false
reply
return
}
+try-to-scroll
<scroll-down>
@ -1306,7 +1306,7 @@ after <handle-special-character> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
@ -1319,11 +1319,11 @@ after <handle-special-key> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
recipe move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
def move-to-start-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
# update cursor column
@ -1477,7 +1477,7 @@ after <handle-special-character> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
@ -1490,11 +1490,11 @@ after <handle-special-key> [
undo-coalesce-tag:number <- copy 0/never
<move-cursor-end>
go-render? <- copy 0/false
reply
return
}
]
recipe move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
def move-to-end-of-line editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
@ -1620,11 +1620,11 @@ after <handle-special-character> [
deleted-cells:address:shared:duplex-list:character <- delete-to-start-of-line editor
<delete-to-start-of-line-end>
go-render? <- copy 1/true
reply
return
}
]
recipe delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
def delete-to-start-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
local-scope
load-ingredients
# compute range to delete
@ -1754,11 +1754,11 @@ after <handle-special-character> [
deleted-cells:address:shared:duplex-list:character <- delete-to-end-of-line editor
<delete-to-end-of-line-end>
go-render? <- copy 1/true
reply
return
}
]
recipe delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
def delete-to-end-of-line editor:address:shared:editor-data -> result:address:shared:duplex-list:character, editor:address:shared:editor-data [
local-scope
load-ingredients
# compute range to delete
@ -1937,13 +1937,13 @@ after <scroll-down> [
*top-of-screen <- before-start-of-next-line *top-of-screen, max
no-movement?:boolean <- equal old-top, *top-of-screen
go-render? <- copy 0/false
reply-if no-movement?
return-if no-movement?
]
# takes a pointer into the doubly-linked list, scans ahead at most 'max'
# positions until the next newline
# beware: never return null pointer.
recipe before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
def before-start-of-next-line original:address:shared:duplex-list:character, max:number -> curr:address:shared:duplex-list:character [
local-scope
load-ingredients
count:number <- copy 0
@ -1957,7 +1957,7 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
count <- add count, 1
}
{
reply-unless curr, original
return-unless curr, original
done?:boolean <- greater-or-equal count, max
break-if done?
c:character <- get *curr, value:offset
@ -1967,8 +1967,8 @@ recipe before-start-of-next-line original:address:shared:duplex-list:character,
count <- add count, 1
loop
}
reply-unless curr, original
reply curr
return-unless curr, original
return curr
]
scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
@ -2304,13 +2304,13 @@ after <scroll-up> [
*top-of-screen <- before-previous-line *top-of-screen, editor
no-movement?:boolean <- equal old-top, *top-of-screen
go-render? <- copy 0/false
reply-if no-movement?
return-if no-movement?
]
# takes a pointer into the doubly-linked list, scans back to before start of
# previous *wrapped* line
# beware: never return null pointer
recipe before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
def before-previous-line in:address:shared:duplex-list:character, editor:address:shared:editor-data -> out:address:shared:duplex-list:character [
local-scope
load-ingredients
curr:address:shared:duplex-list:character <- copy in
@ -2327,8 +2327,8 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
break-if len
# empty line; just skip this newline
prev:address:shared:duplex-list:character <- prev curr
reply-unless prev, curr
reply prev
return-unless prev, curr
return prev
}
_, max:number <- divide-with-remainder len, max-line-length
# remainder 0 => scan one width-worth
@ -2348,7 +2348,7 @@ recipe before-previous-line in:address:shared:duplex-list:character, editor:addr
count <- add count, 1
loop
}
reply curr
return curr
]
scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
@ -2698,7 +2698,7 @@ after <handle-special-character> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
@ -2714,18 +2714,18 @@ after <handle-special-key> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
# page-down skips entire wrapped lines, so it can't scroll past lines
# taking up the entire screen
recipe page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
def page-down editor:address:shared:editor-data -> editor:address:shared:editor-data [
local-scope
load-ingredients
# if editor contents don't overflow screen, do nothing
bottom-of-screen:address:shared:duplex-list:character <- get *editor, bottom-of-screen:offset
reply-unless bottom-of-screen
return-unless bottom-of-screen
# if not, position cursor at final character
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
*before-cursor <- prev bottom-of-screen
@ -2890,7 +2890,7 @@ after <handle-special-character> [
<move-cursor-end>
no-movement?:boolean <- equal *top-of-screen, old-top
go-render? <- not no-movement?
reply
return
}
]
@ -2907,11 +2907,11 @@ after <handle-special-key> [
no-movement?:boolean <- equal *top-of-screen, old-top
# don't bother re-rendering if nothing changed. todo: test this
go-render? <- not no-movement?
reply
return
}
]
recipe page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
def page-up editor:address:shared:editor-data, screen-height:number -> editor:address:shared:editor-data [
local-scope
load-ingredients
max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line

View File

@ -1,6 +1,6 @@
## putting the environment together out of editors
recipe! main [
def! main [
local-scope
open-console
initial-sandbox:address:shared:array:character <- new []
@ -19,7 +19,7 @@ container programming-environment-data [
current-sandbox:address:shared:editor-data
]
recipe new-programming-environment screen:address:shared:screen, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
def new-programming-environment screen:address:shared:screen, initial-sandbox-contents:address:shared:array:character -> result:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
width:number <- screen-width screen
@ -39,7 +39,7 @@ recipe new-programming-environment screen:address:shared:screen, initial-sandbox
<programming-environment-initialization>
]
recipe event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
def event-loop screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data -> screen:address:shared:screen, console:address:shared:console, env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -136,7 +136,7 @@ recipe event-loop screen:address:shared:screen, console:address:shared:console,
}
]
recipe resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
def resize screen:address:shared:screen, env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
clear-screen screen # update screen dimensions
@ -152,7 +152,7 @@ recipe resize screen:address:shared:screen, env:address:shared:programming-envir
*cursor-column <- copy 0
]
recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
def render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
trace 10, [app], [render all]
@ -178,7 +178,7 @@ recipe render-all screen:address:shared:screen, env:address:shared:programming-e
]
# replaced in a later layer
recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
def render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -193,7 +193,7 @@ recipe render-sandbox-side screen:address:shared:screen, env:address:shared:prog
clear-screen-from screen, row, left, left, right
]
recipe update-cursor screen:address:shared:screen, current-sandbox:address:shared:editor-data, env:address:shared:programming-environment-data -> screen:address:shared:screen [
def update-cursor screen:address:shared:screen, current-sandbox:address:shared:editor-data, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
<update-cursor-special-cases>
@ -204,10 +204,10 @@ recipe update-cursor screen:address:shared:screen, current-sandbox:address:share
# print a text 's' to 'editor' in 'color' starting at 'row'
# clear rest of last line, move cursor to next line
recipe render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
def render screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless s
return-unless s
column:number <- copy left
screen <- move-cursor screen, row, column
screen-height:number <- screen-height screen
@ -265,10 +265,10 @@ recipe render screen:address:shared:screen, s:address:shared:array:character, le
]
# like 'render' for texts, but with colorization for comments like in the editor
recipe render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
def render-code screen:address:shared:screen, s:address:shared:array:character, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless s
return-unless s
color:number <- copy 7/white
column:number <- copy left
screen <- move-cursor screen, row, column
@ -340,6 +340,6 @@ after <global-type> [
]
# dummy
recipe restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
def restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
# do nothing; redefined later
]

View File

@ -129,7 +129,7 @@ after <global-keypress> [
}
]
recipe run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def run-sandboxes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
errors-found?:boolean, env, screen <- update-recipes env, screen, test-recipes
@ -175,7 +175,7 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add
# load code from recipes.mu, or from test-recipes in tests
# replaced in a later layer (whereupon errors-found? will actually be set)
recipe update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
{
@ -191,7 +191,7 @@ recipe update-recipes env:address:shared:programming-environment-data, screen:ad
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset
@ -200,14 +200,14 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
*response, _, *fake-screen <- run-interactive data
]
recipe update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
def update-status screen:address:shared:screen, msg:address:shared:array:character, color:number -> screen:address:shared:screen [
local-scope
load-ingredients
screen <- move-cursor screen, 0, 2
screen <- print screen, msg, color, 238/grey/background
]
recipe save-sandboxes env:address:shared:programming-environment-data [
def save-sandboxes env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
@ -228,7 +228,7 @@ recipe save-sandboxes env:address:shared:programming-environment-data [
}
]
recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
def! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen, env:address:shared:programming-environment-data [
local-scope
load-ingredients
trace 11, [app], [render sandbox side]
@ -252,14 +252,14 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro
clear-rest-of-screen screen, row, left, right
]
recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
def render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
env:address:shared:programming-environment-data, _/optional <- next-ingredient
reply-unless sandbox
return-unless sandbox
screen-height:number <- screen-height screen
at-bottom?:boolean <- greater-or-equal row, screen-height
reply-if at-bottom?:boolean
return-if at-bottom?:boolean
hidden?:boolean <- lesser-than idx, render-from
{
break-if hidden?
@ -296,7 +296,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
}
+render-sandbox-end
at-bottom?:boolean <- greater-or-equal row, screen-height
reply-if at-bottom?
return-if at-bottom?
# draw solid line after sandbox
draw-horizontal screen, row, left, right, 9473/horizontal-double
}
@ -316,7 +316,7 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san
]
# assumes programming environment has no sandboxes; restores them from previous session
recipe! restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
def! restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
local-scope
load-ingredients
# read all scenarios, pushing them to end of a list of scenarios
@ -350,10 +350,10 @@ recipe! restore-sandboxes env:address:shared:programming-environment-data -> env
# print the fake sandbox screen to 'screen' with appropriate delimiters
# leave cursor at start of next line
recipe render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
def render-screen screen:address:shared:screen, sandbox-screen:address:shared:screen, left:number, right:number, row:number -> row:number, screen:address:shared:screen [
local-scope
load-ingredients
reply-unless sandbox-screen
return-unless sandbox-screen
# print 'screen:'
header:address:shared:array:character <- new [screen:]
row <- render screen, header, left, right, 245/grey, row
@ -421,10 +421,10 @@ scenario run-updates-results [
assume-screen 50/width, 12/height
# define a recipe (no indent for the 'add' line below so column numbers are more obvious)
1:address:shared:array:character <- new [
recipe foo [
def foo [
local-scope
z:number <- add 2, 2
reply z
return z
]]
# sandbox editor contains an instruction without storing outputs
2:address:shared:array:character <- new [foo]
@ -446,10 +446,10 @@ reply z
]
# make a change (incrementing one of the args to 'add'), then rerun
1:address:shared:array:character <- new [
recipe foo [
def foo [
local-scope
z:number <- add 2, 3
reply z
return z
]]
assume-console [
press F4
@ -501,7 +501,7 @@ scenario run-instruction-manages-screen-per-sandbox [
]
]
recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
def editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
@ -509,7 +509,7 @@ recipe editor-contents editor:address:shared:editor-data -> result:address:share
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
reply-unless curr, 0
return-unless curr, 0
{
break-unless curr
c:character <- get *curr, value:offset
@ -646,7 +646,7 @@ after <update-cursor-special-cases> [
break-unless scrolling?
cursor-column:number <- get *current-sandbox, left:offset
screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2
reply
return
}
]
@ -668,21 +668,21 @@ 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
recipe previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
def previous-sandbox env:address:shared:programming-environment-data, in:address:shared:sandbox-data -> out:address:shared:sandbox-data [
local-scope
load-ingredients
curr:address:shared:sandbox-data <- get *env, sandbox:offset
reply-unless curr, 0/nil
return-unless curr, 0/nil
next:address:shared:sandbox-data <- get *curr, next-sandbox:offset
{
reply-unless next, 0/nil
return-unless next, 0/nil
found?:boolean <- equal next, in
break-if found?
curr <- copy next
next <- get *curr, next-sandbox:offset
loop
}
reply curr
return curr
]
scenario scrolling-through-multiple-sandboxes [

View File

@ -93,7 +93,7 @@ after <global-touch> [
}
]
recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
def empty-editor? editor:address:shared:editor-data -> result:boolean [
local-scope
load-ingredients
head:address:shared:duplex-list:character <- get *editor, data:offset
@ -101,13 +101,13 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
result <- not first
]
recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
start:number <- get **sandbox, starting-row-on-screen:offset
in-editor?:boolean <- lesser-than click-row, start
reply-if in-editor?, 0
return-if in-editor?, 0
{
next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
break-unless next-sandbox

View File

@ -76,14 +76,14 @@ after <global-touch> [
}
]
recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
def delete-sandbox t:touch-event, env:address:shared:programming-environment-data -> was-delete?:boolean, env:address:shared:programming-environment-data [
local-scope
load-ingredients
click-column:number <- get t, column:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
right:number <- get *current-sandbox, right:offset
at-right?:boolean <- equal click-column, right
reply-unless at-right?, 0/false
return-unless at-right?, 0/false
click-row:number <- get t, row:offset
prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
@ -107,13 +107,13 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment-
break-unless reset-scroll?
*render-from <- copy -1
}
reply 1/true # force rerender
return 1/true # force rerender
}
prev <- get-address *curr, next-sandbox:offset
curr <- get *curr, next-sandbox:offset
loop
}
reply 0/false
return 0/false
]
scenario deleting-sandbox-after-scroll [

View File

@ -5,8 +5,8 @@ scenario sandbox-click-on-result-toggles-color-to-green [
assume-screen 50/width, 20/height
# basic recipe
1:address:shared:array:character <- new [
recipe foo [
reply 4
def foo [
return 4
]]
# run it
2:address:shared:array:character <- new [foo]
@ -59,8 +59,8 @@ recipe foo [
]
# now change the result
1:address:shared:array:character <- new [
recipe foo [
reply 3
def foo [
return 3
]]
# then rerun
assume-console [
@ -131,7 +131,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
def find-click-in-sandbox-output env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
# assert click-row >= sandbox.starting-row-on-screen
@ -151,13 +151,13 @@ recipe find-click-in-sandbox-output env:address:shared:programming-environment-d
}
# return sandbox if click is in its output region
response-starting-row:number <- get *sandbox, response-starting-row-on-screen:offset
reply-unless response-starting-row, 0/no-click-in-sandbox-output
return-unless response-starting-row, 0/no-click-in-sandbox-output
click-in-response?:boolean <- greater-or-equal click-row, response-starting-row
reply-unless click-in-response?, 0/no-click-in-sandbox-output
reply sandbox
return-unless click-in-response?, 0/no-click-in-sandbox-output
return sandbox
]
recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
def toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
@ -165,7 +165,7 @@ recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:a
# if expected-response is set, reset
break-unless *expected-response
*expected-response <- copy 0
reply sandbox/same-as-ingredient:0
return sandbox/same-as-ingredient:0
}
# if not, current response is the expected response
response:address:shared:array:character <- get *sandbox, response:offset

View File

@ -119,7 +119,7 @@ container sandbox-data [
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset
@ -158,7 +158,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
def find-click-in-sandbox-code env:address:shared:programming-environment-data, click-row:number -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
# assert click-row >= sandbox.starting-row-on-screen
@ -184,9 +184,9 @@ recipe find-click-in-sandbox-code env:address:shared:programming-environment-dat
click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
{
break-if click-on-sandbox-code?
reply 0/no-click-in-sandbox-output
return 0/no-click-in-sandbox-output
}
reply sandbox
return sandbox
]
# when rendering a sandbox, dump its trace before response/warning if display-trace? property is set

View File

@ -6,7 +6,7 @@ container programming-environment-data [
# copy code from recipe editor, persist, load into mu, save any errors
# test-recipes is a hook for testing
recipe! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
def! update-recipes env:address:shared:programming-environment-data, screen:address:shared:screen, test-recipes:address:shared:array:character -> errors-found?:boolean, env:address:shared:programming-environment-data, screen:address:shared:screen [
local-scope
load-ingredients
recipe-errors:address:address:shared:array:character <- get-address *env, recipe-errors:offset
@ -25,7 +25,7 @@ recipe! update-recipes env:address:shared:programming-environment-data, screen:a
status:address:shared:array:character <- new [errors found ]
update-status screen, status, 1/red
errors-found? <- copy 1/true
reply
return
}
errors-found? <- copy 0/false
]
@ -79,7 +79,7 @@ container sandbox-data [
errors:address:shared:array:character
]
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
def! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data, idx:number -> sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data [
local-scope
load-ingredients
data:address:shared:array:character <- get *sandbox, data:offset
@ -91,7 +91,7 @@ recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:p
{
break-unless recipe-errors
*errors <- copy recipe-errors
reply
return
}
*response, *errors, *fake-screen, *trace, completed?:boolean <- run-interactive data
{
@ -131,7 +131,7 @@ scenario run-shows-errors-in-get [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
1:address:shared:array:character <- new [
recipe foo [
def foo [
get 123:number, foo:offset
]]
2:address:shared:array:character <- new [foo]
@ -379,7 +379,7 @@ scenario run-shows-missing-type-errors [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
1:address:shared:array:character <- new [
recipe foo [
def foo [
x <- copy 0
]]
2:address:shared:array:character <- new [foo]
@ -410,7 +410,7 @@ scenario run-shows-unbalanced-bracket-errors [
assume-screen 50/width, 20/height
# recipe is incomplete (unbalanced '[')
1:address:shared:array:character <- new [
recipe foo «
def foo «
x <- copy 0
]
replace 1:address:shared:array:character, 171/«, 91 # '['
@ -439,7 +439,7 @@ scenario run-shows-get-on-non-container-errors [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
1:address:shared:array:character <- new [
recipe foo [
def foo [
local-scope
x:address:shared:point <- new point:type
get x:address:shared:point, 1:offset
@ -467,7 +467,7 @@ scenario run-shows-non-literal-get-argument-errors [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
1:address:shared:array:character <- new [
recipe foo [
def foo [
local-scope
x:number <- copy 0
y:address:shared:point <- new point:type
@ -497,7 +497,7 @@ scenario run-shows-errors-everytime [
assume-screen 50/width, 20/height
# try to run a file with an error
1:address:shared:array:character <- new [
recipe foo [
def foo [
local-scope
x:number <- copy y:number
]]
@ -635,7 +635,7 @@ a:number <- next-ingredient
b:number <- next-ingredient
stash [dividing by], b
_, c:number <- divide-with-remainder a, b
reply b
return b
]]
2:address:shared:array:character <- new [foo 4, 0]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 2:address:shared:array:character

View File

@ -72,7 +72,7 @@ after <handle-special-character> [
redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
*redo <- push op, *redo
<handle-undo>
reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
@ -88,7 +88,7 @@ after <handle-special-character> [
undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
*undo <- push op, *undo
<handle-redo>
reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
@ -189,14 +189,14 @@ before <insert-enter-end> [
# redo stack, because it's now obsolete.
# Beware: since we're counting cursor moves as operations, this means just
# moving the cursor can lose work on the undo stack.
recipe add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
def add-operation editor:address:shared:editor-data, op:address:shared:operation -> editor:address:shared:editor-data [
local-scope
load-ingredients
undo:address:address:shared:list:address:shared:operation <- get-address *editor, undo:offset
*undo <- push op *undo
redo:address:address:shared:list:address:shared:operation <- get-address *editor, redo:offset
*redo <- copy 0
reply editor/same-as-ingredient:0
return editor/same-as-ingredient:0
]
after <handle-undo> [

View File

@ -3,7 +3,7 @@
# The zero screen below means 'use the real screen'. Tests can also use fake
# screens.
recipe main [
def main [
open-console
10:character <- copy 97/a
print 0/screen, 10:character/a, 2/red

View File

@ -1,16 +1,16 @@
recipe test a:number -> b:number [
def test a:number -> b:number [
local-scope
load-ingredients
b <- add a, 1
]
recipe test a:number, b:number -> c:number [
def test a:number, b:number -> c:number [
local-scope
load-ingredients
c <- add a, b
]
recipe main [
def main [
local-scope
a:number <- test 3 # selects single-ingredient version
$print a, 10/newline

View File

@ -6,7 +6,7 @@
# This isn't a very tasteful example, just a simple demonstration of
# possibilities.
recipe factorial n:number -> result:number [
def factorial n:number -> result:number [
local-scope
load-ingredients
{
@ -19,7 +19,7 @@ after <base-case> [
# if n=0 return 1
zero?:boolean <- equal n, 0
break-unless zero?
reply 1
return 1
]
after <recursive-case> [
@ -29,7 +29,7 @@ after <recursive-case> [
result <- multiply subresult, n
]
recipe main [
def main [
1:number <- factorial 5
$print [result: ], 1:number, [
]

2
x.mu
View File

@ -1,6 +1,6 @@
# example program: add two numbers
recipe main [
def main [
11:number <- copy 1
12:number <- copy 3
13:number <- add 11:number, 12:number