2576 - distinguish allocated addresses from others

This is the one major refinement on the C programming model I'm planning
to introduce in mu. Instead of Rust's menagerie of pointer types and
static checking, I want to introduce just one new type, and use it to
perform ref-counting at runtime.

So far all we're doing is updating new's interface. The actual
ref-counting implementation is next.

One implication: I might sometimes need duplicate implementations for a
recipe with allocated vs vanilla addresses of the same type. So far it
seems I can get away with just always passing in allocated addresses;
the situations when you want to pass an unallocated address to a recipe
should be few and far between.
This commit is contained in:
Kartik K. Agaram 2016-01-19 23:18:03 -08:00
parent 7163e18a77
commit 455fbac64f
56 changed files with 3364 additions and 3300 deletions

View File

@ -50,14 +50,17 @@ void canonize(reagent& x) {
void lookup_memory(reagent& x) {
if (!x.type || x.type->value != get(Type_ordinal, "address")) {
raise_error << maybe(current_recipe_name()) << "tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
return;
}
// compute value
if (x.value == 0) {
raise_error << maybe(current_recipe_name()) << "tried to /lookup 0\n" << end();
return;
}
trace(9999, "mem") << "location " << x.value << " is " << no_scientific(get_or_insert(Memory, x.value)) << end();
x.set_value(get_or_insert(Memory, x.value));
drop_from_type(x, "address");
// End Drop Address In lookup_memory(x)
drop_one_lookup(x);
}
@ -89,6 +92,7 @@ bool canonize_type(reagent& r) {
return false;
}
drop_from_type(r, "address");
// End Drop Address In canonize_type(r)
drop_one_lookup(r);
}
return true;

View File

@ -430,8 +430,10 @@ bool is_mu_string(const reagent& x) {
return x.type
&& x.type->value == get(Type_ordinal, "address")
&& x.type->right
&& x.type->right->value == get(Type_ordinal, "array")
&& x.type->right->value == get(Type_ordinal, "shared")
&& x.type->right->right
&& x.type->right->right->value == get(Type_ordinal, "character")
&& x.type->right->right->right == NULL;
&& x.type->right->right->value == get(Type_ordinal, "array")
&& x.type->right->right->right
&& x.type->right->right->right->value == get(Type_ordinal, "character")
&& x.type->right->right->right->right == NULL;
}

131
038new.cc
View File

@ -1,12 +1,55 @@
//: A simple memory allocator to create space for new variables at runtime.
//: Creating space for new variables at runtime.
//: Mu has two primitives for managing allocations:
//: - 'allocate' reserves a specified amount of space
//: - 'abandon' returns allocated space to be reused by future calls to 'allocate'
//:
//: In practice it's useful to let programs copy addresses anywhere they want,
//: but a prime source of (particularly security) bugs is accessing memory
//: after it's been abandoned. To avoid this, mu programs use a safer
//: primitive called 'new', which performs two operations:
//:
//: - it takes a type rather than a size, to save you the trouble of
//: calculating sizes of different variables.
//: - it allocates an extra location where it tracks so-called 'reference
//: counts' or refcounts: the number of address variables in your program that
//: point to this allocation. The initial refcount of an allocation starts out
//: at 1 (the product of the 'new' instruction). When other variables are
//: copied from it the refcount is incremented. When a variable stops pointing
//: at it the refcount is decremented. When the refcount goes to 0 the
//: allocation is automatically abandoned.
//:
//: Mu programs guarantee you'll have no memory corruption bugs as long as you
//: use 'new' and never use 'allocate' or 'abandon'. However, they don't help
//: you at all to remember to abandon memory after you're done with it. To
//: minimize memory use, be sure to reset allocated addresses to 0 when you're
//: done with them.
//: To help you distinguish addresses that point at allocations, 'new' returns
//: type address:shared:___. Think of 'shared' as a generic container that
//: contains one extra field: the refcount. However, lookup operations will
//: transparently drop the 'shared' and access to the refcount. Copying
//: between shared and non-shared addresses is forbidden.
:(before "End Mu Types Initialization")
type_ordinal shared = put(Type_ordinal, "shared", Next_type_ordinal++);
get_or_insert(Type, shared).name = "shared";
:(before "End Drop Address In lookup_memory(x)")
if (x.properties.at(0).second->value == "shared") {
//x.set_value(x.value+1); // doesn't work yet
drop_from_type(x, "shared");
}
:(before "End Drop Address In canonize_type(r)")
if (r.properties.at(0).second->value == "shared") {
drop_from_type(r, "shared");
}
:(scenarios run)
:(scenario new)
# call new two times with identical arguments; you should get back different results
recipe main [
1:address:number/raw <- new number:type
2:address:number/raw <- new number:type
3:boolean/raw <- equal 1:address:number/raw, 2:address:number/raw
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
]
+mem: storing 0 in location 3
@ -53,6 +96,7 @@ case NEW: {
reagent product(inst.products.at(0));
canonize_type(product);
drop_from_type(product, "address");
drop_from_type(product, "shared");
if (SIZE(inst.ingredients) > 1) {
// array allocation
drop_from_type(product, "array");
@ -174,29 +218,29 @@ void ensure_space(long long int size) {
% Memory_allocated_until = 10;
% put(Memory, Memory_allocated_until, 1);
recipe main [
1:address:number <- new number:type
2:number <- copy *1:address:number
1:address:shared:number <- new number:type
2:number <- copy *1:address:shared:number
]
+mem: storing 0 in location 2
:(scenario new_array)
recipe main [
1:address:array:number/raw <- new number:type, 5
2:address:number/raw <- new number:type
3:number/raw <- subtract 2:address:number/raw, 1:address:array:number/raw
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
]
+run: 1:address:array:number/raw <- new number:type, 5
+run: 1:address:shared:array:number/raw <- new number:type, 5
+mem: array size is 5
# don't forget the extra location for array size
+mem: storing 6 in location 3
:(scenario new_empty_array)
recipe main [
1:address:array:number/raw <- new number:type, 0
2:address:number/raw <- new number:type
3:number/raw <- subtract 2:address:number/raw, 1:address:array:number/raw
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
]
+run: 1:address:array:number/raw <- new number:type, 0
+run: 1:address:shared:array:number/raw <- new number:type, 0
+mem: array size is 0
+mem: storing 1 in location 3
@ -204,8 +248,8 @@ recipe main [
:(scenario new_overflow)
% Initial_memory_per_routine = 2;
recipe main [
1:address:number/raw <- new number:type
2:address:point/raw <- new point:type # not enough room in initial page
1:address:shared:number/raw <- new number:type
2:address:shared:point/raw <- new point:type # not enough room in initial page
]
+new: routine allocated memory from 1000 to 1002
+new: routine allocated memory from 1002 to 1004
@ -215,10 +259,10 @@ recipe main [
:(scenario new_reclaim)
recipe main [
1:address:number <- new number:type
abandon 1:address:number
2:address:number <- new number:type # must be same size as abandoned memory to reuse
3:boolean <- equal 1:address:number, 2:address:number
1:address:shared:number <- new number:type
abandon 1:address:shared:number
2:address:shared:number <- new number:type # must be same size as abandoned memory to reuse
3:boolean <- equal 1:address:shared:number, 2:address:shared:number
]
# both allocations should have returned the same address
+mem: storing 1 in location 3
@ -240,8 +284,8 @@ case ABANDON: {
}
reagent types = inst.ingredients.at(0);
canonize_type(types);
if (!types.type || types.type->value != get(Type_ordinal, "address")) {
raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'abandon' should be an address, but got " << inst.ingredients.at(0).original_string << '\n' << end();
if (!types.type || types.type->value != get(Type_ordinal, "address") || types.type->right->value != get(Type_ordinal, "shared")) {
raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'abandon' should be an address:shared:___, but got " << inst.ingredients.at(0).original_string << '\n' << end();
break;
}
break;
@ -254,6 +298,7 @@ case ABANDON: {
// lookup_memory without drop_one_lookup {
types.set_value(get_or_insert(Memory, types.value));
drop_from_type(types, "address");
drop_from_type(types, "shared");
// }
abandon(address, size_of(types));
break;
@ -293,20 +338,20 @@ if (Free_list[size]) {
:(scenario new_differing_size_no_reclaim)
recipe main [
1:address:number <- new number:type
abandon 1:address:number
2:address:array:number <- new number:type, 2 # different size
3:boolean <- equal 1:address:number, 2:address:array:number
1:address:shared:number <- new number:type
abandon 1:address:shared:number
2:address:shared:array:number <- new number:type, 2 # different size
3:boolean <- equal 1:address:shared:number, 2:address:shared:array:number
]
# no reuse
+mem: storing 0 in location 3
:(scenario new_reclaim_array)
recipe main [
1:address:array:number <- new number:type, 2
abandon 1:address:array:number
2:address:array:number <- new number:type, 2
3:boolean <- equal 1:address:array:number, 2:address:array:number
1:address:shared:array:number <- new number:type, 2
abandon 1:address:shared:array:number
2:address:shared:array:number <- new number:type, 2
3:boolean <- equal 1:address:shared:array:number, 2:address:shared:array:number
]
# reuse
+mem: storing 1 in location 3
@ -315,17 +360,17 @@ recipe main [
:(scenario new_string)
recipe main [
1:address:array:character <- new [abc def]
2:character <- index *1:address:array:character, 5
1:address:shared:array:character <- new [abc def]
2:character <- index *1:address:shared:array:character, 5
]
# number code for 'e'
+mem: storing 101 in location 2
:(scenario new_string_handles_unicode)
recipe main [
1:address:array:character <- new [a«c]
2:number <- length *1:address:array:character
3:character <- index *1:address:array:character, 1
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
]
+mem: storing 3 in location 2
# unicode for '«'
@ -370,8 +415,8 @@ long long int new_mu_string(const string& contents) {
:(scenario stash_string)
recipe main [
1:address:array:character <- new [abc]
stash [foo:], 1:address:array:character
1:address:shared:array:character <- new [abc]
stash [foo:], 1:address:shared:array:character
]
+app: foo: abc
@ -383,15 +428,15 @@ if (is_mu_string(r)) {
:(scenario unicode_string)
recipe main [
1:address:array:character <- new []
stash [foo:], 1:address:array:character
1:address:shared:array:character <- new []
stash [foo:], 1:address:shared:array:character
]
+app: foo:
:(scenario stash_space_after_string)
recipe main [
1:address:array:character <- new [abc]
stash 1:address:array:character [foo]
1:address:shared:array:character <- new [abc]
stash 1:address:shared:array:character, [foo]
]
+app: abc foo
@ -399,8 +444,8 @@ recipe main [
:(scenario new_string_overflow)
% Initial_memory_per_routine = 2;
recipe main [
1:address:number/raw <- new number:type
2:address:array:character/raw <- new [a] # not enough room in initial page, if you take the array size into account
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
]
+new: routine allocated memory from 1000 to 1002
+new: routine allocated memory from 1002 to 1004

View File

@ -92,8 +92,10 @@ long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe)
}
type_ordinal skip_addresses(type_tree* type, const string& recipe_name) {
type_ordinal address = get(Type_ordinal, "address");
type_ordinal shared = get(Type_ordinal, "shared");
for (; type; type = type->right) {
if (type->value != get(Type_ordinal, "address"))
if (type->value != address && type->value != shared)
return type->value;
}
raise_error << maybe(recipe_name) << "expected a container" << '\n' << end();

View File

@ -7,7 +7,7 @@
# then location 0 is really location 11, location 1 is really location 12, and so on.
recipe main [
10:number <- copy 5 # pretend array; in practice we'll use new
default-space:address:array:location <- copy 10/unsafe
default-space:address:shared:array:location <- copy 10/unsafe
1:number <- copy 23
]
+mem: storing 23 in location 12
@ -19,7 +19,7 @@ recipe main [
# pretend array
1000:number <- copy 5
# actual start of this recipe
default-space:address:array:location <- copy 1000/unsafe
default-space:address:shared:array:location <- copy 1000/unsafe
1:address:number <- copy 3/unsafe
8:number/raw <- copy *1:address:number
]
@ -70,7 +70,7 @@ recipe main [
# pretend array
1000:number <- copy 5
# actual start of this recipe
default-space:address:array:location <- copy 1000/unsafe
default-space:address:shared:array:location <- copy 1000/unsafe
1:address:point <- copy 12/unsafe
9:number/raw <- get *1:address:point, 1:offset
]
@ -90,7 +90,7 @@ recipe main [
# pretend array
1000:number <- copy 5
# actual start of this recipe
default-space:address:array:location <- copy 1000/unsafe
default-space:address:shared:array:location <- copy 1000/unsafe
1:address:array:number <- copy 12/unsafe
9:number/raw <- index *1:address:array:number, 1
]
@ -119,7 +119,7 @@ if (s == "number-of-locals") return true;
:(before "End Rewrite Instruction(curr, recipe result)")
// rewrite `new-default-space` to
// `default-space:address:array:location <- new location:type, number-of-locals:literal`
// `default-space:address:shared:array:location <- new location:type, number-of-locals:literal`
// where N is Name[recipe][""]
if (curr.name == "new-default-space") {
rewrite_default_space_instruction(curr);
@ -150,7 +150,7 @@ recipe main [
recipe foo [
local-scope
x:number <- copy 34
reply default-space:address:array:location
reply default-space:address:shared:array:location
]
# both calls to foo should have received the same default-space
+mem: storing 1 in location 3
@ -186,7 +186,7 @@ void rewrite_default_space_instruction(instruction& curr) {
curr.ingredients.push_back(reagent("number-of-locals:literal"));
if (!curr.products.empty())
raise_error << "new-default-space can't take any results\n" << end();
curr.products.push_back(reagent("default-space:address:array:location"));
curr.products.push_back(reagent("default-space:address:shared:array:location"));
}
//:: helpers
@ -212,11 +212,13 @@ long long int address(long long int offset, long long int base) {
|| !x.type
|| x.type->value != get(Type_ordinal, "address")
|| !x.type->right
|| x.type->right->value != get(Type_ordinal, "array")
|| x.type->right->value != get(Type_ordinal, "shared")
|| !x.type->right->right
|| x.type->right->right->value != get(Type_ordinal, "location")
|| x.type->right->right->right) {
raise_error << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
|| x.type->right->right->value != get(Type_ordinal, "array")
|| !x.type->right->right->right
|| x.type->right->right->right->value != get(Type_ordinal, "location")
|| x.type->right->right->right->right) {
raise_error << maybe(current_recipe_name()) << "'default-space' should be of type address:shared:array:location, but tried to write " << to_string(data) << '\n' << end();
}
current_call().default_space = data.at(0);
return;
@ -224,8 +226,8 @@ long long int address(long long int offset, long long int base) {
:(scenario get_default_space)
recipe main [
default-space:address:array:location <- copy 10/unsafe
1:address:array:location/raw <- copy default-space:address:array:location
default-space:address:shared:array:location <- copy 10/unsafe
1:address:shared:array:location/raw <- copy default-space:address:shared:array:location
]
+mem: storing 10 in location 1

View File

@ -9,8 +9,8 @@
recipe main [
10:number <- copy 5 # pretend array
20:number <- copy 5 # pretend array
default-space:address:array:location <- copy 10/unsafe
0:address:array:location/names:dummy <- copy 20/unsafe # later layers will explain the /names: property
default-space:address:shared:array:location <- copy 10/unsafe
0:address:shared:array:location/names:dummy <- copy 20/unsafe # later layers will explain the /names: property
1:number <- copy 32
1:number/space:1 <- copy 33
]

View File

@ -5,22 +5,22 @@
:(scenario closure)
recipe main [
default-space:address:array:location <- new location:type, 30
1:address:array:location/names:new-counter <- new-counter
2:number/raw <- increment-counter 1:address:array:location/names:new-counter
3:number/raw <- increment-counter 1:address:array:location/names:new-counter
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 [
default-space:address:array:location <- new location:type, 30
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:array:location
reply default-space:address:shared:array:location
]
recipe increment-counter [
default-space:address:array:location <- new location:type, 30
0:address:array:location/names:new-counter <- next-ingredient # outer space must be created by 'new-counter' above
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
@ -52,11 +52,13 @@ void collect_surrounding_spaces(const recipe_ordinal r) {
if (!type
|| type->value != get(Type_ordinal, "address")
|| !type->right
|| type->right->value != get(Type_ordinal, "array")
|| type->right->value != get(Type_ordinal, "shared")
|| !type->right->right
|| type->right->right->value != get(Type_ordinal, "location")
|| type->right->right->right) {
raise_error << "slot 0 should always have type address:array:location, but is " << inst.products.at(j).to_string() << '\n' << end();
|| type->right->right->value != get(Type_ordinal, "array")
|| !type->right->right->right
|| type->right->right->right->value != get(Type_ordinal, "location")
|| type->right->right->right->right) {
raise_error << "slot 0 should always have type address:shared:array:location, but is " << inst.products.at(j).to_string() << '\n' << end();
continue;
}
string_tree* s = property(inst.products.at(j), "names");

View File

@ -9,8 +9,8 @@ recipe main [
10:number <- copy 5
20:number <- copy 5
# actual start of this recipe
global-space:address:array:location <- copy 20/unsafe
default-space:address:array:location <- copy 10/unsafe
global-space:address:shared:array:location <- copy 20/unsafe
default-space:address:shared:array:location <- copy 10/unsafe
1:number <- copy 23
1:number/space:global <- copy 24
]
@ -35,11 +35,13 @@ global_space = 0;
|| !x.type
|| x.type->value != get(Type_ordinal, "address")
|| !x.type->right
|| x.type->right->value != get(Type_ordinal, "array")
|| x.type->right->value != get(Type_ordinal, "shared")
|| !x.type->right->right
|| x.type->right->right->value != get(Type_ordinal, "location")
|| x.type->right->right->right) {
raise_error << maybe(current_recipe_name()) << "'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
|| x.type->right->right->value != get(Type_ordinal, "array")
|| !x.type->right->right->right
|| x.type->right->right->right->value != get(Type_ordinal, "location")
|| x.type->right->right->right->right) {
raise_error << maybe(current_recipe_name()) << "'global-space' should be of type address:shared:array:location, but tried to write " << to_string(data) << '\n' << end();
}
if (Current_routine->global_space)
raise_error << "routine already has a global-space; you can't over-write your globals" << end();
@ -61,7 +63,7 @@ global_space = 0;
:(scenario global_space_with_names)
% Hide_errors = true;
recipe main [
global-space:address:array:location <- new location:type, 10
global-space:address:shared:array:location <- new location:type, 10
x:number <- copy 23
1:number/space:global <- copy 24
]

View File

@ -89,7 +89,7 @@ recipe main [
:(scenario typo_in_address_type_fails)
% Hide_errors = true;
recipe main [
y:address:charcter <- new character:type
y:address:shared:charcter <- new character:type
*y <- copy 67
]
+error: main: unknown type charcter in 'y:address:charcter <- new character:type'
+error: main: unknown type charcter in 'y:address:shared:charcter <- new character:type'

View File

@ -99,9 +99,9 @@ scenario foo [
:(scenario read_scenario_with_bracket_in_comment_in_nested_string)
scenario foo [
1:address:array:character <- new [# not a comment]
1:address:shared:array:character <- new [# not a comment]
]
+run: 1:address:array:character <- new [# not a comment]
+run: 1:address:shared:array:character <- new [# not a comment]
//:: Run scenarios when we run 'mu test'.
//: Treat the text of the scenario as a regular series of instructions.

View File

@ -38,7 +38,7 @@ void rewrite_stashes_to_text_named(recipe& caller) {
def.name = "to-text-line";
def.ingredients.push_back(inst.ingredients.at(j));
ostringstream ingredient_name;
ingredient_name << "stash_" << stash_instruction_idx << '_' << j << ":address:array:character";
ingredient_name << "stash_" << stash_instruction_idx << '_' << j << ":address:shared:array:character";
def.products.push_back(reagent(ingredient_name.str()));
new_instructions.push_back(def);
inst.ingredients.at(j).clear(); // reclaim old memory

View File

@ -71,7 +71,7 @@ container bar [
:(scenario dilated_reagent_with_new)
recipe main [
x:address:address:number <- new {(address number): type}
x:address:shared:address:number <- new {(address number): type}
]
+new: size of <"address" : <"number" : <>>> is 1

View File

@ -297,13 +297,13 @@ $error: 0
:(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_first_use)
% Hide_errors = true;
recipe main [
x:address:foo <- new foo:type
x:address:shared:foo <- new foo:type
test x
]
container foo [
x:number
]
recipe test a:address:foo -> z:number [
recipe test a:address:shared:foo -> z:number [
local-scope
load-ingredients
z:number <- get *a, x:offset
@ -313,10 +313,10 @@ $error: 0
:(scenario static_dispatch_works_with_compound_type_containing_container_defined_after_second_use)
% Hide_errors = true;
recipe main [
x:address:foo <- new foo:type
x:address:shared:foo <- new foo:type
test x
]
recipe test a:address:foo -> z:number [
recipe test a:address:shared:foo -> z:number [
local-scope
load-ingredients
z:number <- get *a, x:offset

View File

@ -535,14 +535,14 @@ container foo:_t [
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient)
recipe main [
1:address:foo:point <- bar 3
11:foo:point <- copy *1:address:foo:point
1:address:shared:foo:point <- bar 3
11:foo:point <- copy *1:address:shared:foo:point
]
container foo:_t [
x:_t
y:number
]
recipe bar x:number -> result:address:foo:_t [
recipe bar x:number -> result:address:shared:foo:_t [
local-scope
load-ingredients
# new refers to _t in its ingredient *value*
@ -554,10 +554,10 @@ recipe bar x:number -> result:address:foo:_t [
:(scenario shape_shifting_recipe_handles_shape_shifting_new_ingredient_2)
recipe main [
1:address:foo:point <- bar 3
11:foo:point <- copy *1:address:foo:point
1:address:shared:foo:point <- bar 3
11:foo:point <- copy *1:address:shared:foo:point
]
recipe bar x:number -> result:address:foo:_t [
recipe bar x:number -> result:address:shared:foo:_t [
local-scope
load-ingredients
# new refers to _t in its ingredient *value*
@ -574,11 +574,11 @@ container foo:_t [
:(scenario shape_shifting_recipe_supports_compound_types)
recipe main [
1:address:point <- new point:type
2:address:number <- get-address *1:address:point, y:offset
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:point <- bar 1:address:point # specialize _t to address:point
4:point <- copy *3:address:point
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 [
local-scope
@ -716,7 +716,7 @@ container d2:_elem [
# static dispatch between shape-shifting variants, _including pointer lookups_
recipe main [
e1:d1:number <- merge 3
e2:address:d2:number <- new {(d2 number): type}
e2:address:shared:d2:number <- new {(d2 number): type}
1:number/raw <- foo e1
2:number/raw <- foo *e2 # different from previous scenario
]
@ -799,15 +799,15 @@ recipe foo x:_elem -> y:number [
:(scenarios run)
:(scenario specialize_most_similar_variant)
recipe main [
1:address:number <- new number:type
2:number <- foo 1:address:number
1:address:shared:number <- new number:type
2:number <- foo 1:address:shared:number
]
recipe foo x:_elem -> y:number [
local-scope
load-ingredients
reply 34
]
recipe foo x:address:_elem -> y:number [
recipe foo x:address:shared:_elem -> y:number [
local-scope
load-ingredients
reply 35

View File

@ -5,7 +5,7 @@
% Hide_warnings = true;
recipe main [
local-scope
p:address:point <- new point:type
p:address:shared:point <- new point:type
foo *p
]
recipe foo p:point [
@ -20,10 +20,10 @@ $warn: 0
% Hide_warnings = true;
recipe main [
local-scope
p:address:point <- new point:type
p:address:shared:point <- new point:type
p <- foo p
]
recipe foo p:address:point -> p:address:point [
recipe foo p:address:shared:point -> p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -35,13 +35,13 @@ $warn: 0
% Hide_warnings = true;
recipe main [
local-scope
p:address:d1 <- new d1:type
p:address:shared:d1 <- new d1:type
q:number <- foo p
]
recipe foo p:address:d1 -> q:number [
recipe foo p:address:shared:d1 -> q:number [
local-scope
load-ingredients
x:address:d1 <- new d1:type
x:address:shared:d1 <- new d1:type
y:address:number <- get-address *x, p:offset # ignore this 'p'
q <- copy 34
]
@ -55,10 +55,10 @@ $warn: 0
% Hide_warnings = true;
recipe main [
local-scope
p:address:point <- new point:type
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:point [
recipe foo p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -70,15 +70,15 @@ recipe foo p:address:point [
% Hide_warnings = true;
recipe main [
local-scope
p:address:point <- new point:type
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:point [
recipe foo p:address:shared:point [
local-scope
load-ingredients
bar p
]
recipe bar p:address:point -> p:address:point [
recipe bar p:address:shared:point -> p:address:shared:point [
local-scope
load-ingredients
x:address:number <- get-address *p, x:offset
@ -90,13 +90,13 @@ recipe bar p:address:point -> p:address:point [
% Hide_warnings = true;
recipe main [
local-scope
p:address:point <- new point:type
p:address:shared:point <- new point:type
foo p
]
recipe foo p:address:point [
recipe foo p:address:shared:point [
local-scope
load-ingredients
q:address:point <- copy p
q:address:shared:point <- copy p
x:address:number <- get-address *q, x:offset
]
+warn: 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
@ -104,19 +104,19 @@ recipe foo p:address:point [
:(scenario can_traverse_immutable_ingredients)
% Hide_warnings = true;
container test-list [
next:address:test-list
next:address:shared:test-list
]
recipe main [
local-scope
p:address:test-list <- new test-list:type
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:test-list [
recipe foo p:address:shared:test-list [
local-scope
load-ingredients
p2:address:test-list <- bar p
p2:address:shared:test-list <- bar p
]
recipe bar x:address:test-list -> y:address:test-list [
recipe bar x:address:shared:test-list -> y:address:shared:test-list [
local-scope
load-ingredients
y <- get *x, next:offset
@ -126,11 +126,11 @@ $warn: 0
:(scenario handle_optional_ingredients_in_immutability_checks)
% Hide_warnings = true;
recipe main [
k:address:number <- new number:type
k:address:shared:number <- new number:type
test k
]
# recipe taking an immutable address ingredient
recipe test k:address:number [
recipe test k:address:shared:number [
local-scope
load-ingredients
foo k
@ -139,7 +139,7 @@ recipe test k:address:number [
recipe foo -> [
local-scope
load-ingredients
k:address:number, found?:boolean <- next-ingredient
k:address:shared:number, found?:boolean <- next-ingredient
]
$warn: 0
@ -212,25 +212,25 @@ set<long long int> scan_contained_in_product_indices(const instruction& inst, se
:(scenario immutability_infects_contained_in_variables)
% Hide_warnings = true;
container test-list [
next:address:test-list
next:address:shared:test-list
]
recipe main [
local-scope
p:address:test-list <- new test-list:type
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:test-list [ # p is immutable
recipe foo p:address:shared:test-list [ # p is immutable
local-scope
load-ingredients
p2:address:test-list <- test-next p # p2 is immutable
p3:address:address:test-list <- get-address *p2, next:offset # signal modification of p2
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:test-list -> y:address:test-list/contained-in:x [
recipe test-next x:address:shared:test-list -> y:address:shared:test-list/contained-in:x [
local-scope
load-ingredients
y <- get *x, next:offset
]
+warn: foo: cannot modify p2 after instruction 'p3:address:address:test-list <- get-address *p2, next:offset' because that would modify ingredient p which is not also a product of foo
+warn: foo: cannot modify p2 after instruction 'p3:address:address:shared:test-list <- get-address *p2, next:offset' because that would modify ingredient p which is not also a product of foo
:(code)
void check_immutable_ingredient_in_instruction(const instruction& inst, const set<string>& current_ingredient_and_aliases, const string& original_ingredient_name, const recipe& caller) {
@ -315,28 +315,28 @@ set<long long int> ingredient_indices(const instruction& inst, const set<string>
:(scenario can_modify_contained_in_addresses)
% Hide_warnings = true;
container test-list [
next:address:test-list
next:address:shared:test-list
]
recipe main [
local-scope
p:address:test-list <- new test-list:type
p:address:shared:test-list <- new test-list:type
foo p
]
recipe foo p:address:test-list -> p:address:test-list [
recipe foo p:address:shared:test-list -> p:address:shared:test-list [
local-scope
load-ingredients
p2:address:test-list <- test-next p
p2:address:shared:test-list <- test-next p
p <- test-remove p2, p
]
recipe test-next x:address:test-list -> y:address:test-list [
recipe 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:test-list/contained-in:from, from:address:test-list -> from:address:test-list [
recipe 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:test-list <- get-address *x, next:offset # pretend modification
x2:address:address:shared:test-list <- get-address *x, next:offset # pretend modification
]
$warn: 0

View File

@ -517,16 +517,16 @@ case LIMIT_TIME: {
:(scenario new_concurrent)
recipe f1 [
start-running f2
1:address:number/raw <- new number:type
1:address:shared:number/raw <- new number:type
# wait for f2 to complete
{
loop-unless 4:number/raw
}
]
recipe f2 [
2:address:number/raw <- new number:type
2:address:shared:number/raw <- new number:type
# hack: assumes scheduler implementation
3:boolean/raw <- equal 1:address:number/raw, 2:address:number/raw
3:boolean/raw <- equal 1:address:shared:number/raw, 2:address:shared:number/raw
# signal f2 complete
4:number/raw <- copy 1
]

File diff suppressed because it is too large Load Diff

View File

@ -10,9 +10,9 @@
scenario channel [
run [
1:address:channel <- new-channel 3/capacity
1:address:channel <- write 1:address:channel, 34
2:character, 1:address:channel <- read 1:address:channel
1:address:shared:channel <- new-channel 3/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
2:character, 1:address:shared:channel <- read 1:address:shared:channel
]
memory-should-contain [
2 <- 34
@ -28,11 +28,10 @@ container channel [
# A circular buffer contains values from index first-full up to (but not
# including) index first-empty. The reader always modifies it at first-full,
# while the writer always modifies it at first-empty.
data:address:array:character
data:address:shared:array:character
]
# result:address:channel <- new-channel capacity:number
recipe new-channel capacity:number -> result:address:channel [
recipe new-channel capacity:number -> result:address:shared:channel [
local-scope
load-ingredients
result <- new channel:type
@ -44,11 +43,11 @@ recipe new-channel capacity:number -> result:address:channel [
*free <- copy 0
# result.data = new location[ingredient+1]
capacity <- add capacity, 1 # unused slot for 'full?' below
dest:address:address:array:character <- get-address *result, data:offset
dest:address:address:shared:array:character <- get-address *result, data:offset
*dest <- new character:type, capacity
]
recipe write chan:address:channel, val:character -> chan:address:channel [
recipe write chan:address:shared:channel, val:character -> chan:address:shared:channel [
local-scope
load-ingredients
{
@ -59,7 +58,7 @@ recipe write chan:address:channel, val:character -> chan:address:channel [
wait-for-location *full-address
}
# store val
circular-buffer:address:array:character <- get *chan, data:offset
circular-buffer:address:shared:array:character <- get *chan, data:offset
free:address:number <- get-address *chan, first-free:offset
dest:address:character <- index-address *circular-buffer, *free
*dest <- copy val
@ -74,7 +73,7 @@ recipe write chan:address:channel, val:character -> chan:address:channel [
}
]
recipe read chan:address:channel -> result:character, chan:address:channel [
recipe read chan:address:shared:channel -> result:character, chan:address:shared:channel [
local-scope
load-ingredients
{
@ -86,7 +85,7 @@ recipe read chan:address:channel -> result:character, chan:address:channel [
}
# read result
full:address:number <- get-address *chan, first-full:offset
circular-buffer:address:array:character <- get *chan, data:offset
circular-buffer:address:shared:array:character <- get *chan, data:offset
result <- index *circular-buffer, *full
# mark its slot as empty
*full <- add *full, 1
@ -99,7 +98,7 @@ recipe read chan:address:channel -> result:character, chan:address:channel [
}
]
recipe clear-channel chan:address:channel -> chan:address:channel [
recipe clear-channel chan:address:shared:channel -> chan:address:shared:channel [
local-scope
load-ingredients
{
@ -111,9 +110,9 @@ recipe clear-channel chan:address:channel -> chan:address:channel [
scenario channel-initialization [
run [
1:address:channel <- new-channel 3/capacity
2:number <- get *1:address:channel, first-full:offset
3:number <- get *1:address:channel, first-free:offset
1:address:shared:channel <- new-channel 3/capacity
2:number <- get *1:address:shared:channel, first-full:offset
3:number <- get *1:address:shared:channel, first-free:offset
]
memory-should-contain [
2 <- 0 # first-full
@ -123,10 +122,10 @@ scenario channel-initialization [
scenario channel-write-increments-free [
run [
1:address:channel <- new-channel 3/capacity
1:address:channel <- write 1:address:channel, 34
2:number <- get *1:address:channel, first-full:offset
3:number <- get *1:address:channel, first-free:offset
1:address:shared:channel <- new-channel 3/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
2:number <- get *1:address:shared:channel, first-full:offset
3:number <- get *1:address:shared:channel, first-free:offset
]
memory-should-contain [
2 <- 0 # first-full
@ -136,11 +135,11 @@ scenario channel-write-increments-free [
scenario channel-read-increments-full [
run [
1:address:channel <- new-channel 3/capacity
1:address:channel <- write 1:address:channel, 34
_, 1:address:channel <- read 1:address:channel
2:number <- get *1:address:channel, first-full:offset
3:number <- get *1:address:channel, first-free:offset
1:address:shared:channel <- new-channel 3/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
_, 1:address:shared:channel <- read 1:address:shared:channel
2:number <- get *1:address:shared:channel, first-full:offset
3:number <- get *1:address:shared:channel, first-free:offset
]
memory-should-contain [
2 <- 1 # first-full
@ -151,19 +150,19 @@ scenario channel-read-increments-full [
scenario channel-wrap [
run [
# channel with just 1 slot
1:address:channel <- new-channel 1/capacity
1:address:shared:channel <- new-channel 1/capacity
# write and read a value
1:address:channel <- write 1:address:channel, 34
_, 1:address:channel <- read 1:address:channel
1:address:shared:channel <- write 1:address:shared:channel, 34
_, 1:address:shared:channel <- read 1:address:shared:channel
# first-free will now be 1
2:number <- get *1:address:channel, first-free:offset
3:number <- get *1:address:channel, first-free:offset
2:number <- get *1:address:shared:channel, first-free:offset
3:number <- get *1:address:shared:channel, first-free:offset
# write second value, verify that first-free wraps
1:address:channel <- write 1:address:channel, 34
4:number <- get *1:address:channel, first-free:offset
1:address:shared:channel <- write 1:address:shared:channel, 34
4:number <- get *1:address:shared:channel, first-free:offset
# read second value, verify that first-full wraps
_, 1:address:channel <- read 1:address:channel
5:number <- get *1:address:channel, first-full:offset
_, 1:address:shared:channel <- read 1:address:shared:channel
5:number <- get *1:address:shared:channel, first-full:offset
]
memory-should-contain [
2 <- 1 # first-free after first write
@ -176,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:channel -> result:boolean [
recipe channel-empty? chan:address:shared:channel -> result:boolean [
local-scope
load-ingredients
# return chan.first-full == chan.first-free
@ -187,7 +186,7 @@ recipe channel-empty? chan:address: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:channel -> result:boolean [
recipe channel-full? chan:address:shared:channel -> result:boolean [
local-scope
load-ingredients
# tmp = chan.first-free + 1
@ -205,19 +204,18 @@ recipe channel-full? chan:address:channel -> result:boolean [
result <- equal full, tmp
]
# result:number <- channel-capacity chan:address:channel
recipe channel-capacity chan:address:channel -> result:number [
recipe channel-capacity chan:address:shared:channel -> result:number [
local-scope
load-ingredients
q:address:array:character <- get *chan, data:offset
q:address:shared:array:character <- get *chan, data:offset
result <- length *q
]
scenario channel-new-empty-not-full [
run [
1:address:channel <- new-channel 3/capacity
2:boolean <- channel-empty? 1:address:channel
3:boolean <- channel-full? 1:address:channel
1:address:shared:channel <- new-channel 3/capacity
2:boolean <- channel-empty? 1:address:shared:channel
3:boolean <- channel-full? 1:address:shared:channel
]
memory-should-contain [
2 <- 1 # empty?
@ -227,10 +225,10 @@ scenario channel-new-empty-not-full [
scenario channel-write-not-empty [
run [
1:address:channel <- new-channel 3/capacity
1:address:channel <- write 1:address:channel, 34
2:boolean <- channel-empty? 1:address:channel
3:boolean <- channel-full? 1:address:channel
1:address:shared:channel <- new-channel 3/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
2:boolean <- channel-empty? 1:address:shared:channel
3:boolean <- channel-full? 1:address:shared:channel
]
memory-should-contain [
2 <- 0 # empty?
@ -240,10 +238,10 @@ scenario channel-write-not-empty [
scenario channel-write-full [
run [
1:address:channel <- new-channel 1/capacity
1:address:channel <- write 1:address:channel, 34
2:boolean <- channel-empty? 1:address:channel
3:boolean <- channel-full? 1:address:channel
1:address:shared:channel <- new-channel 1/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
2:boolean <- channel-empty? 1:address:shared:channel
3:boolean <- channel-full? 1:address:shared:channel
]
memory-should-contain [
2 <- 0 # empty?
@ -253,11 +251,11 @@ scenario channel-write-full [
scenario channel-read-not-full [
run [
1:address:channel <- new-channel 1/capacity
1:address:channel <- write 1:address:channel, 34
_, 1:address:channel <- read 1:address:channel
2:boolean <- channel-empty? 1:address:channel
3:boolean <- channel-full? 1:address:channel
1:address:shared:channel <- new-channel 1/capacity
1:address:shared:channel <- write 1:address:shared:channel, 34
_, 1:address:shared:channel <- read 1:address:shared:channel
2:boolean <- channel-empty? 1:address:shared:channel
3:boolean <- channel-full? 1:address:shared:channel
]
memory-should-contain [
2 <- 1 # empty?
@ -266,12 +264,12 @@ scenario channel-read-not-full [
]
# helper for channels of characters in particular
recipe buffer-lines in:address:channel, out:address:channel -> out:address:channel, in:address:channel [
recipe buffer-lines in:address:shared:channel, out:address:shared:channel -> out:address:shared:channel, in:address:shared:channel [
local-scope
load-ingredients
# repeat forever
{
line:address:buffer <- new-buffer, 30
line:address:shared:buffer <- new-buffer 30
# read characters from 'in' until newline, copy into line
{
+next-character
@ -302,7 +300,7 @@ recipe buffer-lines in:address:channel, out:address:channel -> out:address:chann
}
# copy line into 'out'
i:number <- copy 0
line-contents:address:array:character <- get *line, data:offset
line-contents:address:shared:array:character <- get *line, data:offset
max:number <- get *line, length:offset
{
done?:boolean <- greater-or-equal i, max
@ -318,36 +316,36 @@ recipe buffer-lines in:address:channel, out:address:channel -> out:address:chann
scenario buffer-lines-blocks-until-newline [
run [
1:address:channel/stdin <- new-channel 10/capacity
2:address:channel/buffered-stdin <- new-channel 10/capacity
3:boolean <- channel-empty? 2:address:channel/buffered-stdin
1:address:shared:channel/stdin <- new-channel 10/capacity
2:address:shared:channel/buffered-stdin <- new-channel 10/capacity
3:boolean <- channel-empty? 2:address:shared:channel/buffered-stdin
assert 3:boolean, [
F buffer-lines-blocks-until-newline: channel should be empty after init]
# buffer stdin into buffered-stdin, try to read from buffered-stdin
4:number/buffer-routine <- start-running buffer-lines, 1:address:channel/stdin, 2:address:channel/buffered-stdin
4:number/buffer-routine <- start-running buffer-lines, 1:address:shared:channel/stdin, 2:address:shared:channel/buffered-stdin
wait-for-routine 4:number/buffer-routine
5:boolean <- channel-empty? 2:address:channel/buffered-stdin
5:boolean <- channel-empty? 2:address:shared:channel/buffered-stdin
assert 5:boolean, [
F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up]
# write 'a'
1:address:channel <- write 1:address:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 97/a
restart 4:number/buffer-routine
wait-for-routine 4:number/buffer-routine
6:boolean <- channel-empty? 2:address:channel/buffered-stdin
6:boolean <- channel-empty? 2:address:shared:channel/buffered-stdin
assert 6:boolean, [
F buffer-lines-blocks-until-newline: channel should be empty after writing 'a']
# write 'b'
1:address:channel <- write 1:address:channel, 98/b
1:address:shared:channel <- write 1:address:shared:channel, 98/b
restart 4:number/buffer-routine
wait-for-routine 4:number/buffer-routine
7:boolean <- channel-empty? 2:address:channel/buffered-stdin
7:boolean <- channel-empty? 2:address:shared:channel/buffered-stdin
assert 7:boolean, [
F buffer-lines-blocks-until-newline: channel should be empty after writing 'b']
# write newline
1:address:channel <- write 1:address:channel, 10/newline
1:address:shared:channel <- write 1:address:shared:channel, 10/newline
restart 4:number/buffer-routine
wait-for-routine 4:number/buffer-routine
8:boolean <- channel-empty? 2:address:channel/buffered-stdin
8:boolean <- channel-empty? 2:address:shared:channel/buffered-stdin
9:boolean/completed? <- not 8:boolean
assert 9:boolean/completed?, [
F buffer-lines-blocks-until-newline: channel should contain data after writing newline]

View File

@ -1,7 +1,7 @@
scenario array-from-args [
run [
1:address:array:character <- new-array 0, 1, 2
2:array:character <- copy *1:address:array:character
1:address:shared:array:character <- new-array 0, 1, 2
2:array:character <- copy *1:address:shared:array:character
]
memory-should-contain [
2 <- 3 # array length
@ -12,7 +12,7 @@ scenario array-from-args [
]
# create an array out of a list of scalar args
recipe new-array [
recipe new-array -> result:address:shared:array:character [
local-scope
capacity:number <- copy 0
{
@ -22,7 +22,7 @@ recipe new-array [
capacity <- add capacity, 1
loop
}
result:address:array:character <- new character:type, capacity
result <- new character:type, capacity
rewind-ingredients
i:number <- copy 0
{

View File

@ -5,27 +5,27 @@
container list:_elem [
value:_elem
next:address:list:_elem
next:address:shared:list:_elem
]
recipe push x:_elem, in:address:list:_elem -> in:address:list:_elem [
recipe push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
local-scope
load-ingredients
result:address:list:_elem <- new {(list _elem): type}
result:address:shared:list:_elem <- new {(list _elem): type}
val:address:_elem <- get-address *result, value:offset
*val <- copy x
next:address:address:list:_elem <- get-address *result, next:offset
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'
]
recipe first in:address:list:_elem -> result:_elem [
recipe first in:address:shared:list:_elem -> result:_elem [
local-scope
load-ingredients
result <- get *in, value:offset
]
recipe rest in:address:list:_elem -> result:address:list:_elem/contained-in:in [
recipe rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
local-scope
load-ingredients
result <- get *in, next:offset
@ -33,15 +33,15 @@ recipe rest in:address:list:_elem -> result:address:list:_elem/contained-in:in [
scenario list-handling [
run [
1:address:list:number <- push 3, 0
1:address:list:number <- push 4, 1:address:list:number
1:address:list:number <- push 5, 1:address:list:number
2:number <- first 1:address:list:number
1:address:list:number <- rest 1:address:list:number
3:number <- first 1:address:list:number
1:address:list:number <- rest 1:address:list:number
4:number <- first 1:address:list:number
1:address:list:number <- rest 1:address:list:number
1:address:shared:list:number <- push 3, 0
1:address:shared:list:number <- push 4, 1:address:shared:list:number
1:address:shared:list:number <- push 5, 1:address:shared:list:number
2:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
3:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
4:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
]
memory-should-contain [
1 <- 0 # empty to empty, dust to dust..
@ -51,26 +51,26 @@ scenario list-handling [
]
]
recipe to-text in:address:list:_elem -> result:address:array:character [
recipe to-text in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
#? $print [to text: list], 10/newline
load-ingredients
buf:address:buffer <- new-buffer 80
buf:address:shared:buffer <- new-buffer 80
buf <- to-buffer in, buf
result <- buffer-to-array buf
]
# variant of 'to-text' which stops printing after a few elements (and so is robust to cycles)
recipe to-text-line in:address:list:_elem -> result:address:array:character [
recipe to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
#? $print [to text line: list], 10/newline
load-ingredients
buf:address:buffer <- new-buffer 80
buf:address:shared:buffer <- new-buffer 80
buf <- to-buffer in, buf, 6 # max elements to display
result <- buffer-to-array buf
]
recipe to-buffer in:address:list:_elem, buf:address:buffer -> buf:address:buffer [
recipe to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
local-scope
#? $print [to buffer: list], 10/newline
load-ingredients
@ -83,13 +83,13 @@ recipe to-buffer in:address:list:_elem, buf:address:buffer -> buf:address:buffer
val:_elem <- get *in, value:offset
buf <- append buf, val
# now prepare next
next:address:list:_elem <- rest in
next:address:shared:list:_elem <- rest in
nextn:number <- copy next
#? buf <- append buf, nextn
reply-unless next
space:character <- copy 32/space
buf <- append buf, space:character
s:address:array:character <- new [-> ]
s:address:shared:array:character <- new [-> ]
n:number <- length *s
buf <- append buf, s
# and recurse
@ -108,13 +108,13 @@ recipe to-buffer in:address:list:_elem, buf:address:buffer -> buf:address:buffer
reply
}
# past recursion depth; insert ellipses and stop
s:address:array:character <- new [...]
s:address:shared:array:character <- new [...]
append buf, s
]
scenario stash-on-list-converts-to-text [
run [
x:address:list:number <- push 4, 0
x:address:shared:list:number <- push 4, 0
x <- push 5, x
x <- push 6, x
stash [foo foo], x
@ -126,8 +126,8 @@ scenario stash-on-list-converts-to-text [
scenario stash-handles-list-with-cycle [
run [
x:address:list:number <- push 4, 0
y:address:address:list:number <- get-address *x, next:offset
x:address:shared:list:number <- push 4, 0
y:address:address:shared:list:number <- get-address *x, next:offset
*y <- copy x
stash [foo foo], x
]

View File

@ -2,42 +2,42 @@
container duplex-list:_elem [
value:_elem
next:address:duplex-list:_elem
prev:address:duplex-list:_elem
next:address:shared:duplex-list:_elem
prev:address:shared:duplex-list:_elem
]
# should I say in/contained-in:result, allow ingredients to refer to products?
recipe push x:_elem, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
recipe push x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
result:address:duplex-list:_elem <- new {(duplex-list _elem): type}
result:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
val:address:_elem <- get-address *result, value:offset
*val <- copy x
next:address:address:duplex-list:_elem <- get-address *result, next:offset
next:address:address:shared:duplex-list:_elem <- get-address *result, next:offset
*next <- copy in
{
break-unless in
prev:address:address:duplex-list:_elem <- get-address *in, prev:offset
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'
]
recipe first in:address:duplex-list:_elem -> result:_elem [
recipe first in:address:shared:duplex-list:_elem -> result:_elem [
local-scope
load-ingredients
reply-unless in, 0
result <- get *in, value:offset
]
recipe next in:address:duplex-list:_elem -> result:address:duplex-list:_elem/contained-in:in [
recipe next in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
local-scope
load-ingredients
reply-unless in, 0
result <- get *in, next:offset
]
recipe prev in:address:duplex-list:_elem -> result:address:duplex-list:_elem/contained-in:in [
recipe prev in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem/contained-in:in [
local-scope
load-ingredients
reply-unless in, 0
@ -50,24 +50,24 @@ scenario duplex-list-handling [
# reserve locations 0, 1 and 2 to check for missing null check
1:number <- copy 34
2:number <- copy 35
3:address:duplex-list:character <- push 3, 0
3:address:duplex-list:character <- push 4, 3:address:duplex-list:character
3:address:duplex-list:character <- push 5, 3:address:duplex-list:character
4:address:duplex-list:character <- copy 3:address:duplex-list:character
5:character <- first 4:address:duplex-list:character
4:address:duplex-list:character <- next 4:address:duplex-list:character
6:character <- first 4:address:duplex-list:character
4:address:duplex-list:character <- next 4:address:duplex-list:character
7:character <- first 4:address:duplex-list:character
8:address:duplex-list:character <- next 4:address:duplex-list:character
9:character <- first 8:address:duplex-list:character
10:address:duplex-list:character <- next 8:address:duplex-list:character
11:address:duplex-list:character <- prev 8:address:duplex-list:character
4:address:duplex-list:character <- prev 4:address:duplex-list:character
12:character <- first 4:address:duplex-list:character
4:address:duplex-list:character <- prev 4:address:duplex-list:character
13:character <- first 4:address:duplex-list:character
14:boolean <- equal 3:address:duplex-list:character, 4:address:duplex-list:character
3:address:shared:duplex-list:character <- push 3, 0
3:address:shared:duplex-list:character <- push 4, 3:address:shared:duplex-list:character
3:address:shared:duplex-list:character <- push 5, 3:address:shared:duplex-list:character
4:address:shared:duplex-list:character <- copy 3:address:shared:duplex-list:character
5:character <- first 4:address:shared:duplex-list:character
4:address:shared:duplex-list:character <- next 4:address:shared:duplex-list:character
6:character <- first 4:address:shared:duplex-list:character
4:address:shared:duplex-list:character <- next 4:address:shared:duplex-list:character
7:character <- first 4:address:shared:duplex-list:character
8:address:shared:duplex-list:character <- next 4:address:shared:duplex-list:character
9:character <- first 8:address:shared:duplex-list:character
10:address:shared:duplex-list:character <- next 8:address:shared:duplex-list:character
11:address:shared:duplex-list:character <- prev 8:address:shared:duplex-list:character
4:address:shared:duplex-list:character <- prev 4:address:shared:duplex-list:character
12:character <- first 4:address:shared:duplex-list:character
4:address:shared:duplex-list:character <- prev 4:address:shared:duplex-list:character
13:character <- first 4:address:shared:duplex-list:character
14:boolean <- equal 3:address:shared:duplex-list:character, 4:address:shared:duplex-list:character
]
memory-should-contain [
0 <- 0 # no modifications to null pointers
@ -87,15 +87,15 @@ scenario duplex-list-handling [
]
# insert 'x' after 'in'
recipe insert x:_elem, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
recipe insert x:_elem, in:address:shared:duplex-list:_elem -> in:address:shared:duplex-list:_elem [
local-scope
load-ingredients
new-node:address:duplex-list:_elem <- new {(duplex-list _elem): type}
new-node:address:shared:duplex-list:_elem <- new {(duplex-list _elem): type}
val:address:_elem <- get-address *new-node, value:offset
*val <- copy x
next-node:address:duplex-list:_elem <- get *in, next:offset
next-node:address:shared:duplex-list:_elem <- get *in, next:offset
# in.next = new-node
y:address:address:duplex-list:_elem <- get-address *in, next:offset
y:address:address:shared:duplex-list:_elem <- get-address *in, next:offset
*y <- copy new-node
# new-node.prev = in
y <- get-address *new-node, prev:offset
@ -112,27 +112,27 @@ recipe insert x:_elem, in:address:duplex-list:_elem -> in:address:duplex-list:_e
scenario inserting-into-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
2:address:duplex-list:character <- next 1:address:duplex-list:character # 2 points inside list
2:address:duplex-list:character <- insert 6, 2:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character # 2 points inside list
2:address:shared:duplex-list:character <- insert 6, 2:address:shared:duplex-list:character
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
3:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
5:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
6:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
7:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
8:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
9:character <- first 2:address:duplex-list:character
10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
3:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
5:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
6:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
7:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
8:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
9:character <- first 2:address:shared:duplex-list:character
10:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 5 # scanning next
@ -148,28 +148,28 @@ scenario inserting-into-duplex-list [
scenario inserting-at-end-of-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
2:address:duplex-list:character <- next 1:address:duplex-list:character # 2 points inside list
2:address:duplex-list:character <- next 2:address:duplex-list:character # now at end of list
2:address:duplex-list:character <- insert 6, 2:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character # 2 points inside list
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character # now at end of list
2:address:shared:duplex-list:character <- insert 6, 2:address:shared:duplex-list:character
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
3:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
5:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
6:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
7:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
8:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
9:character <- first 2:address:duplex-list:character
10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
3:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
5:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
6:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
7:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
8:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
9:character <- first 2:address:shared:duplex-list:character
10:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 5 # scanning next
@ -185,26 +185,26 @@ scenario inserting-at-end-of-duplex-list [
scenario inserting-after-start-of-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
1:address:duplex-list:character <- insert 6, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- insert 6, 1:address:shared:duplex-list:character
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
3:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
5:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
6:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
7:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
8:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
9:character <- first 2:address:duplex-list:character
10:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
3:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
5:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
6:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
7:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
8:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
9:character <- first 2:address:shared:duplex-list:character
10:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 5 # scanning next
@ -222,15 +222,15 @@ 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:duplex-list:_elem/contained-in:in, in:address:duplex-list:_elem -> in:address:duplex-list:_elem [
recipe 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
next-node:address:duplex-list:_elem <- get *x, next:offset
prev-node:address:duplex-list:_elem <- get *x, prev:offset
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
tmp:address:address:duplex-list:_elem <- get-address *x, next:offset
tmp:address:address:shared:duplex-list:_elem <- get-address *x, next:offset
*tmp <- copy 0
tmp <- get-address *x, prev:offset
*tmp <- copy 0
@ -254,21 +254,21 @@ recipe remove x:address:duplex-list:_elem/contained-in:in, in:address:duplex-lis
scenario removing-from-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
2:address:duplex-list:character <- next 1:address:duplex-list:character # 2 points at second element
1:address:duplex-list:character <- remove 2:address:duplex-list:character, 1:address:duplex-list:character
3:boolean <- equal 2:address:duplex-list:character, 0
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character # 2 points at second element
1:address:shared:duplex-list:character <- remove 2:address:shared:duplex-list:character, 1:address:shared:duplex-list:character
3:boolean <- equal 2:address:shared:duplex-list:character, 0
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
5:character <- first 2:address:duplex-list:character
6:address:duplex-list:character <- next 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
7:character <- first 2:address:duplex-list:character
8:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
5:character <- first 2:address:shared:duplex-list:character
6:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
7:character <- first 2:address:shared:duplex-list:character
8:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 0 # remove returned non-null
@ -282,19 +282,19 @@ scenario removing-from-duplex-list [
scenario removing-from-start-of-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
1:address:duplex-list:character <- remove 1:address:duplex-list:character, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- remove 1:address:shared:duplex-list:character, 1:address:shared:duplex-list:character
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
3:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
5:address:duplex-list:character <- next 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
6:character <- first 2:address:duplex-list:character
7:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
3:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
5:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
6:character <- first 2:address:shared:duplex-list:character
7:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 4 # scanning next, skipping deleted element
@ -307,23 +307,23 @@ scenario removing-from-start-of-duplex-list [
scenario removing-from-end-of-duplex-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- push 4, 1:address:duplex-list:character
1:address:duplex-list:character <- push 5, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- push 4, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 5, 1:address:shared:duplex-list:character
# delete last element
2:address:duplex-list:character <- next 1:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
1:address:duplex-list:character <- remove 2:address:duplex-list:character, 1:address:duplex-list:character
3:boolean <- equal 2:address:duplex-list:character, 0
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- remove 2:address:shared:duplex-list:character, 1:address:shared:duplex-list:character
3:boolean <- equal 2:address:shared:duplex-list:character, 0
# check structure like before
2:address:duplex-list:character <- copy 1:address:duplex-list:character
4:character <- first 2:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
5:character <- first 2:address:duplex-list:character
6:address:duplex-list:character <- next 2:address:duplex-list:character
2:address:duplex-list:character <- prev 2:address:duplex-list:character
7:character <- first 2:address:duplex-list:character
8:boolean <- equal 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- copy 1:address:shared:duplex-list:character
4:character <- first 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
5:character <- first 2:address:shared:duplex-list:character
6:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- prev 2:address:shared:duplex-list:character
7:character <- first 2:address:shared:duplex-list:character
8:boolean <- equal 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
]
memory-should-contain [
3 <- 0 # remove returned non-null
@ -337,8 +337,8 @@ scenario removing-from-end-of-duplex-list [
scenario removing-from-singleton-list [
run [
1:address:duplex-list:character <- push 3, 0
1:address:duplex-list:character <- remove 1:address:duplex-list:character, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 3, 0
1:address:shared:duplex-list:character <- remove 1:address:shared:duplex-list:character, 1:address:shared:duplex-list:character
]
memory-should-contain [
1 <- 0 # back to an empty list
@ -347,16 +347,16 @@ 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:duplex-list:_elem, end:address:duplex-list:_elem/contained-in:start -> start:address:duplex-list:_elem [
recipe 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
# start->next->prev = 0
# start->next = end
next:address:address:duplex-list:_elem <- get-address *start, next:offset
next:address:address:shared:duplex-list:_elem <- get-address *start, next:offset
nothing-to-delete?:boolean <- equal *next, end
reply-if nothing-to-delete?
prev:address:address:duplex-list:_elem <- get-address **next, prev:offset
prev:address:address:shared:duplex-list:_elem <- get-address **next, prev:offset
*prev <- copy 0
*next <- copy end
reply-unless end
@ -370,25 +370,25 @@ recipe remove-between start:address:duplex-list:_elem, end:address:duplex-list:_
scenario remove-range [
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
1:address:duplex-list:character <- push 18, 0
1:address:duplex-list:character <- push 17, 1:address:duplex-list:character
1:address:duplex-list:character <- push 16, 1:address:duplex-list:character
1:address:duplex-list:character <- push 15, 1:address:duplex-list:character
1:address:duplex-list:character <- push 14, 1:address:duplex-list:character
1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 18, 0
1:address:shared:duplex-list:character <- push 17, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 16, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 15, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 14, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 13, 1:address:shared:duplex-list:character
run [
# delete 16 onwards
# first pointer: to the third element
2:address:duplex-list:character <- next 1:address:duplex-list:character
2:address:duplex-list:character <- next 2:address:duplex-list:character
2:address:duplex-list:character <- remove-between 2:address:duplex-list:character, 0
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
2:address:shared:duplex-list:character <- remove-between 2:address:shared:duplex-list:character, 0
# now check the list
4:character <- get *1:address:duplex-list:character, value:offset
5:address:duplex-list:character <- next 1:address:duplex-list:character
6:character <- get *5:address:duplex-list:character, value:offset
7:address:duplex-list:character <- next 5:address:duplex-list:character
8:character <- get *7:address:duplex-list:character, value:offset
9:address:duplex-list:character <- next 7:address:duplex-list:character
4:character <- get *1:address:shared:duplex-list:character, value:offset
5:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
6:character <- get *5:address:shared:duplex-list:character, value:offset
7:address:shared:duplex-list:character <- next 5:address:shared:duplex-list:character
8:character <- get *7:address:shared:duplex-list:character, value:offset
9:address:shared:duplex-list:character <- next 7:address:shared:duplex-list:character
]
memory-should-contain [
4 <- 13
@ -400,29 +400,29 @@ scenario remove-range [
scenario remove-range-to-end [
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
1:address:duplex-list:character <- push 18, 0
1:address:duplex-list:character <- push 17, 1:address:duplex-list:character
1:address:duplex-list:character <- push 16, 1:address:duplex-list:character
1:address:duplex-list:character <- push 15, 1:address:duplex-list:character
1:address:duplex-list:character <- push 14, 1:address:duplex-list:character
1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 18, 0
1:address:shared:duplex-list:character <- push 17, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 16, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 15, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 14, 1:address:shared:duplex-list:character
1:address:shared:duplex-list:character <- push 13, 1:address:shared:duplex-list:character
run [
# delete 15, 16 and 17
# first pointer: to the third element
2:address:duplex-list:character <- next 1:address:duplex-list:character
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
# second pointer: to the fifth element
3:address:duplex-list:character <- next 2:address:duplex-list:character
3:address:duplex-list:character <- next 3:address:duplex-list:character
3:address:duplex-list:character <- next 3:address:duplex-list:character
3:address:duplex-list:character <- next 3:address:duplex-list:character
remove-between 2:address:duplex-list:character, 3:address:duplex-list:character
3:address:shared:duplex-list:character <- next 2:address:shared:duplex-list:character
3:address:shared:duplex-list:character <- next 3:address:shared:duplex-list:character
3:address:shared:duplex-list:character <- next 3:address:shared:duplex-list:character
3:address:shared:duplex-list:character <- next 3:address:shared:duplex-list:character
remove-between 2:address:shared:duplex-list:character, 3:address:shared:duplex-list:character
# now check the list
4:character <- get *1:address:duplex-list:character, value:offset
5:address:duplex-list:character <- next 1:address:duplex-list:character
6:character <- get *5:address:duplex-list:character, value:offset
7:address:duplex-list:character <- next 5:address:duplex-list:character
8:character <- get *7:address:duplex-list:character, value:offset
9:address:duplex-list:character <- next 7:address:duplex-list:character
4:character <- get *1:address:shared:duplex-list:character, value:offset
5:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
6:character <- get *5:address:shared:duplex-list:character, value:offset
7:address:shared:duplex-list:character <- next 5:address:shared:duplex-list:character
8:character <- get *7:address:shared:duplex-list:character, value:offset
9:address:shared:duplex-list:character <- next 7:address:shared:duplex-list:character
]
memory-should-contain [
4 <- 13
@ -434,18 +434,18 @@ scenario remove-range-to-end [
scenario remove-range-empty [
# construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
1:address:duplex-list:character <- push 14, 0
1:address:duplex-list:character <- push 13, 1:address:duplex-list:character
1:address:shared:duplex-list:character <- push 14, 0
1:address:shared:duplex-list:character <- push 13, 1:address:shared:duplex-list:character
run [
# delete 16 onwards
# first pointer: to the third element
2:address:duplex-list:character <- next 1:address:duplex-list:character
remove-between 1:address:duplex-list:character, 2:address:duplex-list:character
2:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
remove-between 1:address:shared:duplex-list:character, 2:address:shared:duplex-list:character
# now check the list
4:character <- get *1:address:duplex-list:character, value:offset
5:address:duplex-list:character <- next 1:address:duplex-list:character
6:character <- get *5:address:duplex-list:character, value:offset
7:address:duplex-list:character <- next 5:address:duplex-list:character
4:character <- get *1:address:shared:duplex-list:character, value:offset
5:address:shared:duplex-list:character <- next 1:address:shared:duplex-list:character
6:character <- get *5:address:shared:duplex-list:character, value:offset
7:address:shared:duplex-list:character <- next 5:address:shared:duplex-list:character
]
memory-should-contain [
4 <- 13
@ -455,20 +455,20 @@ scenario remove-range-empty [
]
# insert list beginning at 'new' after 'in'
recipe insert-range in:address:duplex-list:_elem, start:address:duplex-list:_elem/contained-in:in -> in:address:duplex-list:_elem [
recipe 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
end:address:duplex-list:_elem <- copy start
end:address:shared:duplex-list:_elem <- copy start
{
next:address:duplex-list:_elem <- next end/insert-range
next:address:shared:duplex-list:_elem <- next end/insert-range
break-unless next
end <- copy next
loop
}
next:address:duplex-list:_elem <- next in
dest:address:address:duplex-list:_elem <- get-address *end, next:offset
next:address:shared:duplex-list:_elem <- next in
dest:address:address:shared:duplex-list:_elem <- get-address *end, next:offset
*dest <- copy next
{
break-unless next
@ -481,23 +481,23 @@ recipe insert-range in:address:duplex-list:_elem, start:address:duplex-list:_ele
*dest <- copy in
]
recipe append in:address:duplex-list:_elem, new:address:duplex-list:_elem/contained-in:in -> in:address:duplex-list:_elem [
recipe 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:duplex-list:_elem <- last in
dest:address:address:duplex-list:_elem <- get-address *last, next:offset
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
dest <- get-address *new, prev:offset
*dest <- copy last
]
recipe last in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
recipe last in:address:shared:duplex-list:_elem -> result:address:shared:duplex-list:_elem [
local-scope
load-ingredients
result <- copy in
{
next:address:duplex-list:_elem <- next result
next:address:shared:duplex-list:_elem <- next result
break-unless next
result <- copy next
loop
@ -505,7 +505,7 @@ recipe last in:address:duplex-list:_elem -> result:address:duplex-list:_elem [
]
# helper for debugging
recipe dump-from x:address:duplex-list:_elem [
recipe dump-from x:address:shared:duplex-list:_elem [
local-scope
load-ingredients
$print x, [: ]

View File

@ -1,41 +1,41 @@
# new type to help incrementally read texts (arrays of characters)
container stream [
index:number
data:address:array:character
data:address:shared:array:character
]
recipe new-stream s:address:array:character -> result:address:stream [
recipe new-stream s:address:shared:array:character -> result:address:shared:stream [
local-scope
load-ingredients
result <- new stream:type
i:address:number <- get-address *result, index:offset
*i <- copy 0
d:address:address:array:character <- get-address *result, data:offset
d:address:address:shared:array:character <- get-address *result, data:offset
*d <- copy s
]
recipe rewind-stream in:address:stream -> in:address:stream [
recipe 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:stream -> result:address:array:character, in:address:stream [
recipe 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
s:address:array:character <- get *in, data:offset
s:address:shared:array:character <- get *in, data:offset
next-idx:number <- find-next s, 10/newline, *idx
result <- copy-range s, *idx, next-idx
*idx <- add next-idx, 1 # skip newline
]
recipe end-of-stream? in:address:stream -> result:boolean [
recipe end-of-stream? in:address:shared:stream -> result:boolean [
local-scope
load-ingredients
idx:number <- get *in, index:offset
s:address:array:character <- get *in, data:offset
s:address:shared:array:character <- get *in, data:offset
len:number <- length *s
result <- greater-or-equal idx, len
]

View File

@ -6,7 +6,7 @@ container screen [
num-columns:number
cursor-row:number
cursor-column:number
data:address:array:screen-cell
data:address:shared:array:screen-cell
]
container screen-cell [
@ -14,7 +14,7 @@ container screen-cell [
color:number
]
recipe new-fake-screen w:number, h:number -> result:address:screen [
recipe new-fake-screen w:number, h:number -> result:address:shared:screen [
local-scope
load-ingredients
result <- new screen:type
@ -27,19 +27,19 @@ recipe new-fake-screen w:number, h:number -> result:address:screen [
column:address:number <- get-address *result, cursor-column:offset
*column <- copy 0
bufsize:number <- multiply *width, *height
buf:address:address:array:screen-cell <- get-address *result, data:offset
buf:address:address:shared:array:screen-cell <- get-address *result, data:offset
*buf <- new screen-cell:type, bufsize
result <- clear-screen result
]
recipe clear-screen screen:address:screen -> screen:address:screen [
recipe clear-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists
{
break-unless screen
# clear fake screen
buf:address:array:screen-cell <- get *screen, data:offset
buf:address:shared:array:screen-cell <- get *screen, data:offset
max:number <- length *buf
i:number <- copy 0
{
@ -64,7 +64,7 @@ recipe clear-screen screen:address:screen -> screen:address:screen [
clear-display
]
recipe sync-screen screen:address:screen -> screen:address:screen [
recipe sync-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
{
@ -74,11 +74,11 @@ recipe sync-screen screen:address:screen -> screen:address:screen [
# do nothing for fake screens
]
recipe fake-screen-is-empty? screen:address:screen -> result:boolean [
recipe fake-screen-is-empty? screen:address:shared:screen -> result:boolean [
local-scope
load-ingredients
reply-unless screen, 1/true
buf:address:array:screen-cell <- get *screen, data:offset
buf:address:shared:array:screen-cell <- get *screen, data:offset
i:number <- copy 0
len:number <- length *buf
{
@ -94,7 +94,7 @@ recipe fake-screen-is-empty? screen:address:screen -> result:boolean [
reply 1/true
]
recipe print screen:address:screen, c:character -> screen:address:screen [
recipe print screen:address:shared:screen, c:character -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -145,7 +145,7 @@ recipe print screen:address:screen, c:character -> screen:address:screen [
# save character in fake screen
index:number <- multiply *row, width
index <- add index, *column
buf:address:array:screen-cell <- get *screen, data:offset
buf:address:shared:array:screen-cell <- get *screen, data:offset
len:number <- length *buf
# special-case: backspace
{
@ -186,11 +186,11 @@ recipe print screen:address:screen, c:character -> screen:address:screen [
scenario print-character-at-top-left [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
2:address:array:screen-cell <- get *1:address:screen, data:offset
3:array:screen-cell <- copy *2:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
2:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
3:array:screen-cell <- copy *2:address:shared:array:screen-cell
]
memory-should-contain [
3 <- 6 # width*height
@ -202,11 +202,11 @@ scenario print-character-at-top-left [
scenario print-character-in-color [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a, 1/red
2:address:array:screen-cell <- get *1:address:screen, data:offset
3:array:screen-cell <- copy *2:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a, 1/red
2:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
3:array:screen-cell <- copy *2:address:shared:array:screen-cell
]
memory-should-contain [
3 <- 6 # width*height
@ -218,14 +218,14 @@ scenario print-character-in-color [
scenario print-backspace-character [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
12:character <- copy 8/backspace
1:address:screen <- print 1:address:screen, 12:character/backspace
2:number <- get *1:address:screen, cursor-column:offset
3:address:array:screen-cell <- get *1:address:screen, data:offset
4:array:screen-cell <- copy *3:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 12:character/backspace
2:number <- get *1:address:shared:screen, cursor-column:offset
3:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
4:array:screen-cell <- copy *3:address:shared:array:screen-cell
]
memory-should-contain [
2 <- 0 # cursor column
@ -238,16 +238,16 @@ scenario print-backspace-character [
scenario print-extra-backspace-character [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
12:character <- copy 8/backspace
1:address:screen <- print 1:address:screen, 12:character/backspace
1:address:shared:screen <- print 1:address:shared:screen, 12:character/backspace
12:character <- copy 8/backspace
1:address:screen <- print 1:address:screen, 12:character/backspace
2:number <- get *1:address:screen, cursor-column:offset
3:address:array:screen-cell <- get *1:address:screen, data:offset
4:array:screen-cell <- copy *3:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 12:character/backspace
2:number <- get *1:address:shared:screen, cursor-column:offset
3:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
4:array:screen-cell <- copy *3:address:shared:array:screen-cell
]
memory-should-contain [
2 <- 0 # cursor column
@ -260,16 +260,16 @@ scenario print-extra-backspace-character [
scenario print-character-at-right-margin [
run [
1:address:screen <- new-fake-screen 2/width, 2/height
1:address:shared:screen <- new-fake-screen 2/width, 2/height
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
12:character <- copy 98/b
1:address:screen <- print 1:address:screen, 12:character/b
1:address:shared:screen <- print 1:address:shared:screen, 12:character/b
13:character <- copy 99/b
1:address:screen <- print 1:address:screen, 13:character/c
2:number <- get *1:address:screen, cursor-column:offset
3:address:array:screen-cell <- get *1:address:screen, data:offset
4:array:screen-cell <- copy *3:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 13:character/c
2:number <- get *1:address:shared:screen, cursor-column:offset
3:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
4:array:screen-cell <- copy *3:address:shared:array:screen-cell
]
memory-should-contain [
2 <- 1 # cursor column
@ -284,15 +284,15 @@ scenario print-character-at-right-margin [
scenario print-newline-character [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
10:character <- copy 10/newline
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
1:address:screen <- print 1:address:screen, 10:character/newline
2:number <- get *1:address:screen, cursor-row:offset
3:number <- get *1:address:screen, cursor-column:offset
4:address:array:screen-cell <- get *1:address:screen, data:offset
5:array:screen-cell <- copy *4:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
2:number <- get *1:address:shared:screen, cursor-row:offset
3:number <- get *1:address:shared:screen, cursor-column:offset
4:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
5:array:screen-cell <- copy *4:address:shared:array:screen-cell
]
memory-should-contain [
2 <- 1 # cursor row
@ -306,13 +306,13 @@ scenario print-newline-character [
scenario print-newline-at-bottom-line [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
10:character <- copy 10/newline
1:address:screen <- print 1:address:screen, 10:character/newline
1:address:screen <- print 1:address:screen, 10:character/newline
1:address:screen <- print 1:address:screen, 10:character/newline
2:number <- get *1:address:screen, cursor-row:offset
3:number <- get *1:address:screen, cursor-column:offset
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
2:number <- get *1:address:shared:screen, cursor-row:offset
3:number <- get *1:address:shared:screen, cursor-column:offset
]
memory-should-contain [
2 <- 1 # cursor row
@ -322,22 +322,22 @@ scenario print-newline-at-bottom-line [
scenario print-character-at-bottom-right [
run [
1:address:screen <- new-fake-screen 2/width, 2/height
1:address:shared:screen <- new-fake-screen 2/width, 2/height
10:character <- copy 10/newline
1:address:screen <- print 1:address:screen, 10:character/newline
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
11:character <- copy 97/a
1:address:screen <- print 1:address:screen, 11:character/a
1:address:shared:screen <- print 1:address:shared:screen, 11:character/a
12:character <- copy 98/b
1:address:screen <- print 1:address:screen, 12:character/b
1:address:shared:screen <- print 1:address:shared:screen, 12:character/b
13:character <- copy 99/c
1:address:screen <- print 1:address:screen, 13:character/c
1:address:screen <- print 1:address:screen, 10:character/newline
1:address:shared:screen <- print 1:address:shared:screen, 13:character/c
1:address:shared:screen <- print 1:address:shared:screen, 10:character/newline
14:character <- copy 100/d
1:address:screen <- print 1:address:screen, 14:character/d
2:number <- get *1:address:screen, cursor-row:offset
3:number <- get *1:address:screen, cursor-column:offset
4:address:array:screen-cell <- get *1:address:screen, data:offset
20:array:screen-cell <- copy *4:address:array:screen-cell
1:address:shared:screen <- print 1:address:shared:screen, 14:character/d
2:number <- get *1:address:shared:screen, cursor-row:offset
3:number <- get *1:address:shared:screen, cursor-column:offset
4:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
20:array:screen-cell <- copy *4:address:shared:array:screen-cell
]
memory-should-contain [
2 <- 1 # cursor row
@ -355,7 +355,7 @@ scenario print-character-at-bottom-right [
]
]
recipe clear-line screen:address:screen -> screen:address:screen [
recipe clear-line screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 0/nul
@ -381,7 +381,7 @@ recipe clear-line screen:address:screen -> screen:address:screen [
clear-line-on-display
]
recipe cursor-position screen:address:screen -> row:number, column:number [
recipe cursor-position screen:address:shared:screen -> row:number, column:number [
local-scope
load-ingredients
# if x exists, lookup cursor in fake screen
@ -394,7 +394,7 @@ recipe cursor-position screen:address:screen -> row:number, column:number [
row, column <- cursor-position-on-display
]
recipe move-cursor screen:address:screen, new-row:number, new-column:number -> screen:address:screen [
recipe 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
@ -412,16 +412,16 @@ recipe move-cursor screen:address:screen, new-row:number, new-column:number -> s
scenario clear-line-erases-printed-characters [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
1:address:shared:screen <- new-fake-screen 3/width, 2/height
# print a character
10:character <- copy 97/a
1:address:screen <- print 1:address:screen, 10:character/a
1:address:shared:screen <- print 1:address:shared:screen, 10:character/a
# move cursor to start of line
1:address:screen <- move-cursor 1:address:screen, 0/row, 0/column
1:address:shared:screen <- move-cursor 1:address:shared:screen, 0/row, 0/column
# clear line
1:address:screen <- clear-line 1:address:screen
2:address:array:screen-cell <- get *1:address:screen, data:offset
20:array:screen-cell <- copy *2:address:array:screen-cell
1:address:shared:screen <- clear-line 1:address:shared:screen
2:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
20:array:screen-cell <- copy *2:address:shared:array:screen-cell
]
# screen should be blank
memory-should-contain [
@ -441,7 +441,7 @@ scenario clear-line-erases-printed-characters [
]
]
recipe cursor-down screen:address:screen -> screen:address:screen [
recipe cursor-down screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -462,7 +462,7 @@ recipe cursor-down screen:address:screen -> screen:address:screen [
move-cursor-down-on-display
]
recipe cursor-up screen:address:screen -> screen:address:screen [
recipe cursor-up screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -481,7 +481,7 @@ recipe cursor-up screen:address:screen -> screen:address:screen [
move-cursor-up-on-display
]
recipe cursor-right screen:address:screen -> screen:address:screen [
recipe cursor-right screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -502,7 +502,7 @@ recipe cursor-right screen:address:screen -> screen:address:screen [
move-cursor-right-on-display
]
recipe cursor-left screen:address:screen -> screen:address:screen [
recipe cursor-left screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -521,7 +521,7 @@ recipe cursor-left screen:address:screen -> screen:address:screen [
move-cursor-left-on-display
]
recipe cursor-to-start-of-line screen:address:screen -> screen:address:screen [
recipe cursor-to-start-of-line screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
row:number <- cursor-position screen
@ -529,14 +529,14 @@ recipe cursor-to-start-of-line screen:address:screen -> screen:address:screen [
screen <- move-cursor screen, row, column
]
recipe cursor-to-next-line screen:address:screen -> screen:address:screen [
recipe 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:screen -> width:number [
recipe screen-width screen:address:shared:screen -> width:number [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -549,7 +549,7 @@ recipe screen-width screen:address:screen -> width:number [
width <- display-width
]
recipe screen-height screen:address:screen -> height:number [
recipe screen-height screen:address:shared:screen -> height:number [
local-scope
load-ingredients
# if x exists, move cursor in fake screen
@ -562,7 +562,7 @@ recipe screen-height screen:address:screen -> height:number [
height <- display-height
]
recipe hide-cursor screen:address:screen -> screen:address:screen [
recipe hide-cursor screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
@ -574,7 +574,7 @@ recipe hide-cursor screen:address:screen -> screen:address:screen [
hide-cursor-on-display
]
recipe show-cursor screen:address:screen -> screen:address:screen [
recipe show-cursor screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
@ -586,7 +586,7 @@ recipe show-cursor screen:address:screen -> screen:address:screen [
show-cursor-on-display
]
recipe hide-screen screen:address:screen -> screen:address:screen [
recipe hide-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
@ -599,7 +599,7 @@ recipe hide-screen screen:address:screen -> screen:address:screen [
hide-display
]
recipe show-screen screen:address:screen -> screen:address:screen [
recipe show-screen screen:address:shared:screen -> screen:address:shared:screen [
local-scope
load-ingredients
# if x exists (not real display), do nothing
@ -612,7 +612,7 @@ recipe show-screen screen:address:screen -> screen:address:screen [
show-display
]
recipe print screen:address:screen, s:address:array:character -> screen:address:screen [
recipe 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
@ -641,11 +641,11 @@ recipe print screen:address:screen, s:address:array:character -> screen:address:
scenario print-text-stops-at-right-margin [
run [
1:address:screen <- new-fake-screen 3/width, 2/height
2:address:array:character <- new [abcd]
1:address:screen <- print 1:address:screen, 2:address:array:character
3:address:array:screen-cell <- get *1:address:screen, data:offset
4:array:screen-cell <- copy *3:address:array:screen-cell
1:address:shared:screen <- new-fake-screen 3/width, 2/height
2:address:shared:array:character <- new [abcd]
1:address:shared:screen <- print 1:address:shared:screen, 2:address:shared:array:character
3:address:shared:array:screen-cell <- get *1:address:shared:screen, data:offset
4:array:screen-cell <- copy *3:address:shared:array:screen-cell
]
memory-should-contain [
4 <- 6 # width*height
@ -659,7 +659,7 @@ scenario print-text-stops-at-right-margin [
]
]
recipe print-integer screen:address:screen, n:number -> screen:address:screen [
recipe print-integer screen:address:shared:screen, n:number -> screen:address:shared:screen [
local-scope
load-ingredients
color:number, color-found?:boolean <- next-ingredient
@ -675,12 +675,12 @@ recipe print-integer screen:address:screen, n:number -> screen:address:screen [
bg-color <- copy 0/black
}
# todo: other bases besides decimal
s:address:array:character <- to-text n
s:address:shared:array:character <- to-text n
screen <- print screen, s, color, bg-color
]
# for now, we can only print integers
recipe print screen:address:screen, n:number -> screen:address:screen [
recipe print screen:address:shared:screen, n:number -> screen:address:shared:screen [
local-scope
load-ingredients
screen <- print-integer screen, n

View File

@ -10,7 +10,7 @@ scenario screen-in-scenario [
assume-screen 5/width, 3/height
run [
1:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 1:character/a
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/a
]
screen-should-contain [
# 01234
@ -25,9 +25,9 @@ scenario screen-in-scenario-unicode-color [
assume-screen 5/width, 3/height
run [
1:character <- copy 955/greek-small-lambda
screen:address:screen <- print screen:address:screen, 1:character/lambda, 1/red
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/lambda, 1/red
2:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 2:character/a
screen:address:shared:screen <- print screen:address:shared:screen, 2:character/a
]
screen-should-contain [
# 01234
@ -43,9 +43,9 @@ scenario screen-in-scenario-color [
assume-screen 5/width, 3/height
run [
1:character <- copy 955/greek-small-lambda
screen:address:screen <- print screen:address:screen, 1:character/lambda, 1/red
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/lambda, 1/red
2:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 2:character/a, 7/white
screen:address:shared:screen <- print screen:address:shared:screen, 2:character/a, 7/white
]
# screen-should-contain shows everything
screen-should-contain [
@ -78,7 +78,7 @@ scenario screen-in-scenario-error [
assume-screen 5/width, 3/height
run [
1:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 1:character/a
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/a
]
screen-should-contain [
# 01234
@ -97,7 +97,7 @@ scenario screen-in-scenario-color [
assume-screen 5/width, 3/height
run [
1:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 1:character/a, 1/red
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/a, 1/red
]
screen-should-contain-in-color 2/green, [
# 01234
@ -146,11 +146,11 @@ Name[r]["screen"] = SCREEN;
:(before "End Rewrite Instruction(curr, recipe result)")
// rewrite `assume-screen width, height` to
// `screen:address:screen <- new-fake-screen width, height`
// `screen:address:shared:screen <- new-fake-screen width, height`
if (curr.name == "assume-screen") {
curr.name = "new-fake-screen";
assert(curr.products.empty());
curr.products.push_back(reagent("screen:address:screen"));
curr.products.push_back(reagent("screen:address:shared:screen"));
curr.products.at(0).set_value(SCREEN);
}
@ -210,7 +210,7 @@ void check_screen(const string& expected_contents, const int color) {
long long int screen_location = get_or_insert(Memory, SCREEN);
int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", "");
assert(data_offset >= 0);
long long int screen_data_location = screen_location+data_offset; // type: address:array:character
long long int screen_data_location = screen_location+data_offset; // type: address:shared:array:character
long long int screen_data_start = get_or_insert(Memory, screen_data_location); // type: array:character
int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", "");
long long int screen_width = get_or_insert(Memory, screen_location+width_offset);
@ -349,7 +349,7 @@ void dump_screen() {
long long int screen_height = get_or_insert(Memory, screen_location+height_offset);
int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", "");
assert(data_offset >= 0);
long long int screen_data_location = screen_location+data_offset; // type: address:array:character
long long int screen_data_location = screen_location+data_offset; // type: address:shared:array:character
long long int screen_data_start = get_or_insert(Memory, screen_data_location); // type: array:character
assert(get_or_insert(Memory, screen_data_start) == screen_width*screen_height);
long long int curr = screen_data_start+1; // skip length

View File

@ -4,7 +4,7 @@ scenario print-character-at-top-left-2 [
assume-screen 3/width, 2/height
run [
1:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 1:character/a
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/a
]
screen-should-contain [
.a .
@ -17,11 +17,11 @@ scenario clear-line-erases-printed-characters-2 [
run [
# print a character
1:character <- copy 97/a
screen:address:screen <- print screen:address:screen, 1:character/a
screen:address:shared:screen <- print screen:address:shared:screen, 1:character/a
# move cursor to start of line
screen:address:screen <- move-cursor screen:address:screen, 0/row, 0/column
screen:address:shared:screen <- move-cursor screen:address:shared:screen, 0/row, 0/column
# clear line
screen:address:screen <- clear-line screen:address:screen
screen:address:shared:screen <- clear-line screen:address:shared:screen
]
screen-should-contain [
. .

View File

@ -22,31 +22,31 @@ container resize-event [
container console [
current-event-index:number
events:address:array:event
events:address:shared:array:event
]
recipe new-fake-console events:address:array:event -> result:address:console [
recipe new-fake-console events:address:shared:array:event -> result:address:shared:console [
local-scope
load-ingredients
result:address:console <- new console:type
buf:address:address:array:event <- get-address *result, events:offset
result:address:shared:console <- new console:type
buf:address:address:shared:array:event <- get-address *result, events:offset
*buf <- copy events
idx:address:number <- get-address *result, current-event-index:offset
*idx <- copy 0
]
recipe read-event console:address:console -> result:event, console:address:console, found?:boolean, quit?:boolean [
recipe read-event console:address:shared:console -> result:event, console:address:shared:console, found?:boolean, quit?:boolean [
local-scope
load-ingredients
{
break-unless console
current-event-index:address:number <- get-address *console, current-event-index:offset
buf:address:array:event <- get *console, events:offset
buf:address:shared:array:event <- get *console, events:offset
{
max:number <- length *buf
done?:boolean <- greater-or-equal *current-event-index, max
break-unless done?
dummy:address:event <- new event:type
dummy:address:shared:event <- new event:type
reply *dummy, console/same-as-ingredient:0, 1/found, 1/quit
}
result <- index *buf, *current-event-index
@ -61,7 +61,7 @@ recipe read-event console:address:console -> result:event, console:address:conso
# 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:console -> result:character, console:address:console, found?:boolean, quit?:boolean [
recipe 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
@ -72,7 +72,7 @@ recipe read-key console:address:console -> result:character, console:address:con
reply *c, console/same-as-ingredient:0, 1/found, 0/quit
]
recipe send-keys-to-channel console:address:console, chan:address:channel, screen:address:screen -> console:address:console, chan:address:channel, screen:address:screen [
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 [
local-scope
load-ingredients
{
@ -86,7 +86,7 @@ recipe send-keys-to-channel console:address:console, chan:address:channel, scree
}
]
recipe wait-for-event console:address:console -> console:address:console [
recipe wait-for-event console:address:shared:console -> console:address:shared:console [
local-scope
load-ingredients
{
@ -96,7 +96,7 @@ recipe wait-for-event console:address:console -> console:address:console [
]
# use this helper to skip rendering if there's lots of other events queued up
recipe has-more-events? console:address:console -> result:boolean [
recipe has-more-events? console:address:shared:console -> result:boolean [
local-scope
load-ingredients
{

View File

@ -11,10 +11,10 @@ scenario keyboard-in-scenario [
type [abc]
]
run [
1:character, console:address:console, 2:boolean <- read-key console:address:console
3:character, console:address:console, 4:boolean <- read-key console:address:console
5:character, console:address:console, 6:boolean <- read-key console:address:console
7:character, console:address:console, 8:boolean, 9:boolean <- read-key console:address:console
1:character, console:address:shared:console, 2:boolean <- read-key console:address:shared:console
3:character, console:address:shared:console, 4:boolean <- read-key console:address:shared:console
5:character, console:address:shared:console, 6:boolean <- read-key console:address:shared:console
7:character, console:address:shared:console, 8:boolean, 9:boolean <- read-key console:address:shared:console
]
memory-should-contain [
1 <- 97 # 'a'
@ -184,15 +184,15 @@ scenario events-in-scenario [
]
run [
# 3 keyboard events; each event occupies 4 locations
1:event <- read-event console:address:console
5:event <- read-event console:address:console
9:event <- read-event console:address:console
1:event <- read-event console:address:shared:console
5:event <- read-event console:address:shared:console
9:event <- read-event console:address:shared:console
# mouse click
13:event <- read-event console:address:console
13:event <- read-event console:address:shared:console
# non-character keycode
17:event <- read-event console:address:console
17:event <- read-event console:address:shared:console
# final keyboard event
21:event <- read-event console:address:console
21:event <- read-event console:address:shared:console
]
memory-should-contain [
1 <- 0 # 'text'

View File

@ -7,10 +7,10 @@ scenario read-key-in-mu [
type [abc]
]
run [
1:character, console:address:console, 2:boolean <- read-key console:address:console
3:character, console:address:console, 4:boolean <- read-key console:address:console
5:character, console:address:console, 6:boolean <- read-key console:address:console
7:character, console:address:console, 8:boolean <- read-key console:address:console
1:character, console:address:shared:console, 2:boolean <- read-key console:address:shared:console
3:character, console:address:shared:console, 4:boolean <- read-key console:address:shared:console
5:character, console:address:shared:console, 6:boolean <- read-key console:address:shared:console
7:character, console:address:shared:console, 8:boolean <- read-key console:address:shared:console
]
memory-should-contain [
1 <- 97 # 'a'

View File

@ -4,16 +4,16 @@
:(scenario run_interactive_code)
recipe main [
1:number/raw <- copy 0
2:address:array:character <- new [1:number/raw <- copy 34]
run-interactive 2:address:array:character
2:address:shared:array:character <- new [1:number/raw <- copy 34]
run-interactive 2:address:shared:array:character
3:number/raw <- copy 1:number/raw
]
+mem: storing 34 in location 3
:(scenario run_interactive_empty)
recipe main [
1:address:array:character <- copy 0/unsafe
2:address:array:character <- run-interactive 1:address:array:character
1:address:shared:array:character <- copy 0/unsafe
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
]
# result is null
+mem: storing 0 in location 2
@ -88,7 +88,7 @@ bool run_interactive(long long int address) {
// call run(string) but without the scheduling
load(string("recipe! interactive [\n") +
"local-scope\n" +
"screen:address:screen <- next-ingredient\n" +
"screen:address:shared:screen <- next-ingredient\n" +
"$start-tracking-products\n" +
command + "\n" +
"$stop-tracking-products\n" +
@ -153,15 +153,15 @@ load(string(
"]\n" +
"recipe sandbox [\n" +
"local-scope\n" +
"screen:address:screen/shared <- new-fake-screen 30, 5\n" +
"screen:address:shared:screen <- new-fake-screen 30, 5\n" +
"r:number/routine_id <- start-running interactive, screen\n" +
"limit-time r, 100000/instructions\n" +
"wait-for-routine r\n" +
"sandbox-state:number <- routine-state r/routine_id\n" +
"completed?:boolean <- equal sandbox-state, 1/completed\n" +
"output:address:array:character <- $most-recent-products\n" +
"warnings:address:array:character <- save-errors-warnings\n" +
"stashes:address:array:character <- save-app-trace\n" +
"output:address:shared:array:character <- $most-recent-products\n" +
"warnings:address:shared:array:character <- save-errors-warnings\n" +
"stashes:address:shared:array:character <- save-app-trace\n" +
"$cleanup-run-interactive\n" +
"reply output, warnings, screen, stashes, completed?\n" +
"]\n");
@ -174,10 +174,10 @@ Recently_added_recipes.clear();
:(scenario run_interactive_comments)
recipe main [
1:address:array:character <- new [# ab
1:address:shared:array:character <- new [# ab
add 2, 2]
2:address:array:character <- run-interactive 1:address:array:character
3:array:character <- copy *2:address:array:character
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
3:array:character <- copy *2:address:shared:array:character
]
+mem: storing 52 in location 4
@ -271,9 +271,9 @@ case _CLEANUP_RUN_INTERACTIVE: {
:(scenario "run_interactive_converts_result_to_text")
recipe main [
# try to interactively add 2 and 2
1:address:array:character <- new [add 2, 2]
2:address:array:character <- run-interactive 1:address:array:character
10:array:character <- copy 2:address:array:character/lookup
1:address:shared:array:character <- new [add 2, 2]
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
10:array:character <- copy 2:address:shared:array:character/lookup
]
# first letter in the output should be '4' in unicode
+mem: storing 52 in location 11
@ -281,13 +281,13 @@ recipe main [
:(scenario "run_interactive_returns_text")
recipe main [
# try to interactively add 2 and 2
1:address:array:character <- new [
x:address:array:character <- new [a]
y:address:array:character <- new [b]
z:address:array:character <- append x:address:array:character, y:address:array:character
1:address:shared:array:character <- new [
x:address:shared:array:character <- new [a]
y:address:shared:array:character <- new [b]
z:address:shared:array:character <- append x:address:shared:array:character, y:address:shared:array:character
]
2:address:array:character <- run-interactive 1:address:array:character
10:array:character <- copy 2:address:array:character/lookup
2:address:shared:array:character <- run-interactive 1:address:shared:array:character
10:array:character <- copy 2:address:shared:array:character/lookup
]
# output contains "ab"
+mem: storing 97 in location 11
@ -296,10 +296,10 @@ recipe main [
:(scenario "run_interactive_returns_errors")
recipe main [
# run a command that generates an error
1:address:array:character <- new [x:number <- copy 34
1:address:shared:array:character <- new [x:number <- copy 34
get x:number, foo:offset]
2:address:array:character, 3:address:array:character <- run-interactive 1:address:array:character
10:array:character <- copy 3:address:array:character/lookup
2:address:shared:array:character, 3:address:shared:array:character <- run-interactive 1:address:shared:array:character
10:array:character <- copy 3:address:shared:array:character/lookup
]
# error should be "unknown element foo in container number"
+mem: storing 117 in location 11
@ -311,10 +311,10 @@ get x:number, foo:offset]
:(scenario run_interactive_with_comment)
recipe main [
# 2 instructions, with a comment after the first
1:address:array:number <- new [a:number <- copy 0 # abc
1:address:shared:array:number <- new [a:number <- copy 0 # abc
b:number <- copy 0
]
2:address:array:character, 3:address:array:character <- run-interactive 1:address:array:character
2:address:shared:array:character, 3:address:shared:array:character <- run-interactive 1:address:shared:array:character
]
# no errors
+mem: storing 0 in location 3
@ -331,8 +331,8 @@ void test_run_interactive_cleans_up_any_created_specializations() {
// run-interactive a call that specializes this recipe
run("recipe main [\n"
" 1:number/raw <- copy 0\n"
" 2:address:array:character <- new [foo 1:number/raw]\n"
" run-interactive 2:address:array:character\n"
" 2:address:shared:array:character <- new [foo 1:number/raw]\n"
" run-interactive 2:address:shared:array:character\n"
"]\n");
assert(SIZE(Recently_added_recipes) == 2); // foo, main
// check that number of variants doesn't change
@ -504,7 +504,7 @@ case RELOAD: {
:(scenario reload_continues_past_error)
recipe main [
local-scope
x:address:array:character <- new [recipe foo [
x:address:shared:array:character <- new [recipe foo [
get 1234:number, foo:offset
]]
reload x
@ -520,7 +520,7 @@ void test_reload_cleans_up_any_created_specializations() {
// a call that specializes this recipe
run("recipe main [\n"
" local-scope\n"
" x:address:array:character <- new [recipe foo x:_elem -> n:number [\n"
" x:address:shared:array:character <- new [recipe foo x:_elem -> n:number [\n"
"local-scope\n"
"load-ingredients\n"
"reply 34\n"

View File

@ -1,6 +1,6 @@
# example program: communicating between routines using channels
recipe producer chan:address:channel -> chan:address:channel [
recipe producer chan:address:shared:channel -> chan:address:shared:channel [
# produce characters 1 to 5 on a channel
local-scope
load-ingredients
@ -12,19 +12,19 @@ recipe producer chan:address:channel -> chan:address:channel [
# other threads might get between these prints
$print [produce: ], n, [
]
chan:address:channel <- write chan, n
chan:address:shared:channel <- write chan, n
n <- add n, 1
loop
}
]
recipe consumer chan:address:channel -> chan:address:channel [
recipe consumer chan:address:shared:channel -> chan:address:shared:channel [
# consume and print integers from a channel
local-scope
load-ingredients
{
# read an integer from the channel
n:character, chan:address:channel <- read chan
n:character, chan:address:shared:channel <- read chan
# other threads might get between these prints
$print [consume: ], n:character, [
]
@ -34,7 +34,7 @@ recipe consumer chan:address:channel -> chan:address:channel [
recipe main [
local-scope
chan:address:channel <- new-channel 3
chan:address:shared:channel <- new-channel 3
# create two background 'routines' that communicate by a channel
routine1:number <- start-running producer, chan
routine2:number <- start-running consumer, chan

View File

@ -34,7 +34,7 @@ scenario print-board-and-read-move [
]
]
run [
screen:address:screen, console:address:console <- chessboard screen:address:screen, console:address:console
screen:address:shared:screen, console:address:shared:console <- chessboard screen:address:shared:screen, console:address:shared:console
# icon for the cursor
screen <- print screen, 9251/␣
]
@ -66,18 +66,18 @@ scenario print-board-and-read-move [
## Here's how 'chessboard' is implemented.
recipe chessboard screen:address:screen, console:address:console -> screen:address:screen, console:address:console [
recipe chessboard screen:address:shared:screen, console:address:shared:console -> screen:address:shared:screen, console:address:shared:console [
local-scope
load-ingredients
board:address:array:address:array:character <- initial-position
board:address:shared:array:address:shared:array:character <- initial-position
# hook up stdin
stdin:address:channel <- new-channel 10/capacity
stdin:address:shared:channel <- new-channel 10/capacity
start-running send-keys-to-channel, console, stdin, screen
# buffer lines in stdin
buffered-stdin:address:channel <- new-channel 10/capacity
buffered-stdin:address:shared:channel <- new-channel 10/capacity
start-running buffer-lines, stdin, buffered-stdin
{
msg:address:array:character <- new [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves.
msg:address:shared:array:character <- new [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves.
]
print screen, msg
cursor-to-next-line screen
@ -94,7 +94,7 @@ recipe chessboard screen:address:screen, console:address:console -> screen:addre
cursor-to-next-line screen
msg <- new [move: ]
screen <- print screen, msg
m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin, screen
m:address:shared:move, quit:boolean, error:boolean <- read-move buffered-stdin, screen
break-if quit, +quit:label
buffered-stdin <- clear-channel buffered-stdin # cleanup after error. todo: test this?
loop-if error
@ -103,12 +103,13 @@ recipe chessboard screen:address:screen, console:address:console -> screen:addre
screen <- clear-screen screen
loop
}
msg <- copy 0
+quit
]
## a board is an array of files, a file is an array of characters (squares)
recipe new-board initial-position:address:array:character -> board:address:array:address:array:character [
recipe 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)
@ -116,19 +117,19 @@ recipe new-board initial-position:address:array:character -> board:address:array
correct-length?:boolean <- equal len, 64
assert correct-length?, [chessboard had incorrect size]
# board is an array of pointers to files; file is an array of characters
board <- new {(address array character): type}, 8
board <- new {(address shared array character): type}, 8
col:number <- copy 0
{
done?:boolean <- equal col, 8
break-if done?
file:address:address:array:character <- index-address *board, col
file:address:address:shared:array:character <- index-address *board, col
*file <- new-file initial-position, col
col <- add col, 1
loop
}
]
recipe new-file position:address:array:character, index:number -> result:address:array:character [
recipe new-file position:address:shared:array:character, index:number -> result:address:shared:array:character [
local-scope
load-ingredients
index <- multiply index, 8
@ -145,7 +146,7 @@ recipe new-file position:address:array:character, index:number -> result:address
}
]
recipe print-board screen:address:screen, board:address:array:address:array:character -> screen:address:screen [
recipe 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
@ -157,14 +158,14 @@ recipe print-board screen:address:screen, board:address:array:address:array:char
# print rank number as a legend
rank:number <- add row, 1
print-integer screen, rank
s:address:array:character <- new [ | ]
s:address:shared:array:character <- new [ | ]
print screen, s
# print each square in the row
col:number <- copy 0
{
done?:boolean <- equal col:number, 8
break-if done?:boolean
f:address:array:character <- index *board, col
f:address:shared:array:character <- index *board, col
c:character <- index *f, row
print screen, c
print screen, space
@ -184,7 +185,7 @@ recipe print-board screen:address:screen, board:address:array:address:array:char
screen <- cursor-to-next-line screen
]
recipe initial-position -> board:address:array:address:array:character [
recipe initial-position -> board:address:shared:array:address:shared:array:character [
local-scope
# layout in memory (in raster order):
# R P _ _ _ _ p r
@ -195,7 +196,7 @@ recipe initial-position -> board:address:array:address:array:character [
# B P _ _ _ _ p B
# N P _ _ _ _ p n
# R P _ _ _ _ p r
initial-position:address:array:character <- new-array 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r
initial-position:address:shared:array:character <- new-array 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r
#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r,
#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n,
#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b,
@ -210,8 +211,8 @@ recipe initial-position -> board:address:array:address:array:character [
scenario printing-the-board [
assume-screen 30/width, 12/height
run [
1:address:array:address:array:character/board <- initial-position
screen:address:screen <- print-board screen:address:screen, 1:address:array:address:array:character/board
1:address:shared:array:address:shared:array:character/board <- initial-position
screen:address:shared:screen <- print-board screen:address:shared:screen, 1:address:shared:array:address:shared:array:character/board
]
screen-should-contain [
# 012345678901234567890123456789
@ -241,14 +242,14 @@ container move [
]
# prints only error messages to screen
recipe read-move stdin:address:channel, screen:address:screen -> result:address:move, quit?:boolean, error?:boolean, stdin:address:channel, screen:address: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 [
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?
# construct the move object
result:address:move <- new move:type
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
@ -271,7 +272,7 @@ recipe read-move stdin:address:channel, screen:address:screen -> result:address:
]
# valid values for file: 0-7
recipe read-file stdin:address:channel, screen:address:screen -> file:number, quit:boolean, error:boolean, stdin:address:channel, screen:address:screen [
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 [
local-scope
load-ingredients
c:character, stdin <- read stdin
@ -293,7 +294,7 @@ recipe read-file stdin:address:channel, screen:address:screen -> file:number, qu
{
newline?:boolean <- equal c, 10/newline
break-unless newline?
error-message:address:array:character <- new [that's not enough]
error-message:address:shared:array:character <- new [that's not enough]
print screen, error-message
reply 0/dummy, 0/quit, 1/error
}
@ -302,7 +303,7 @@ recipe read-file stdin:address:channel, screen:address:screen -> file:number, qu
{
above-min:boolean <- greater-or-equal file, 0
break-if above-min
error-message:address:array:character <- new [file too low: ]
error-message:address:shared:array:character <- new [file too low: ]
print screen, error-message
print screen, c
cursor-to-next-line screen
@ -320,7 +321,7 @@ recipe read-file stdin:address:channel, screen:address:screen -> file:number, qu
]
# valid values: 0-7, -1 (quit), -2 (error)
recipe read-rank stdin:address:channel, screen:address:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:channel, screen:address:screen [
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 [
local-scope
load-ingredients
c:character, stdin <- read stdin
@ -337,7 +338,7 @@ recipe read-rank stdin:address:channel, screen:address:screen -> rank:number, qu
{
newline?:boolean <- equal c, 10 # newline
break-unless newline?
error-message:address:array:character <- new [that's not enough]
error-message:address:shared:array:character <- new [that's not enough]
print screen, error-message
reply 0/dummy, 0/quit, 1/error
}
@ -364,14 +365,14 @@ recipe read-rank stdin:address:channel, screen:address:screen -> rank:number, qu
# 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:channel, expected:character, screen:address:screen -> result:boolean, stdin:address:channel, screen:address:screen [
recipe 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
{
match?:boolean <- equal c, expected
break-if match?
s:address:array:character <- new [expected character not found]
s:address:shared:array:character <- new [expected character not found]
print screen, s
}
result <- not match?
@ -380,8 +381,8 @@ recipe expect-from-channel stdin:address:channel, expected:character, screen:add
scenario read-move-blocking [
assume-screen 20/width, 2/height
run [
1:address:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:channel, screen:address:screen
1:address:shared:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:shared:channel, screen:address:shared:screen
# 'read-move' is waiting for input
wait-for-routine 2:number
3:number <- routine-state 2:number/id
@ -389,7 +390,7 @@ scenario read-move-blocking [
assert 4:boolean/waiting?, [
F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)]
# press 'a'
1:address:channel <- write 1:address:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 97/a
restart 2:number/routine
# 'read-move' still waiting for input
wait-for-routine 2:number
@ -398,7 +399,7 @@ F read-move-blocking: routine failed to pause after coming up (before any keys w
assert 4:boolean/waiting?, [
F read-move-blocking: routine failed to pause after rank 'a']
# press '2'
1:address:channel <- write 1:address:channel, 50/'2'
1:address:shared:channel <- write 1:address:shared:channel, 50/'2'
restart 2:number/routine
# 'read-move' still waiting for input
wait-for-routine 2:number
@ -407,7 +408,7 @@ F read-move-blocking: routine failed to pause after rank 'a']
assert 4:boolean/waiting?, [
F read-move-blocking: routine failed to pause after file 'a2']
# press '-'
1:address:channel <- write 1:address:channel, 45/'-'
1:address:shared:channel <- write 1:address:shared:channel, 45/'-'
restart 2:number/routine
# 'read-move' still waiting for input
wait-for-routine 2:number
@ -416,7 +417,7 @@ F read-move-blocking: routine failed to pause after file 'a2']
assert 4:boolean/waiting?/routine-state, [
F read-move-blocking: routine failed to pause after hyphen 'a2-']
# press 'a'
1:address:channel <- write 1:address:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 97/a
restart 2:number/routine
# 'read-move' still waiting for input
wait-for-routine 2:number
@ -425,7 +426,7 @@ F read-move-blocking: routine failed to pause after hyphen 'a2-']
assert 4:boolean/waiting?/routine-state, [
F read-move-blocking: routine failed to pause after rank 'a2-a']
# press '4'
1:address:channel <- write 1:address:channel, 52/'4'
1:address:shared:channel <- write 1:address:shared:channel, 52/'4'
restart 2:number/routine
# 'read-move' still waiting for input
wait-for-routine 2:number
@ -434,7 +435,7 @@ F read-move-blocking: routine failed to pause after rank 'a2-a']
assert 4:boolean/waiting?, [
F read-move-blocking: routine failed to pause after file 'a2-a4']
# press 'newline'
1:address:channel <- write 1:address:channel, 10 # newline
1:address:shared:channel <- write 1:address:shared:channel, 10 # newline
restart 2:number/routine
# 'read-move' now completes
wait-for-routine 2:number
@ -452,8 +453,8 @@ F read-move-blocking: routine failed to terminate on newline]
scenario read-move-quit [
assume-screen 20/width, 2/height
run [
1:address:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:channel, screen:address:screen
1:address:shared:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:shared:channel, screen:address:shared:screen
# 'read-move' is waiting for input
wait-for-routine 2:number
3:number <- routine-state 2:number/id
@ -461,7 +462,7 @@ scenario read-move-quit [
assert 4:boolean/waiting?, [
F read-move-quit: routine failed to pause after coming up (before any keys were pressed)]
# press 'q'
1:address:channel <- write 1:address:channel, 113/q
1:address:shared:channel <- write 1:address:shared:channel, 113/q
restart 2:number/routine
# 'read-move' completes
wait-for-routine 2:number
@ -479,15 +480,15 @@ F read-move-quit: routine failed to terminate on 'q']
scenario read-move-illegal-file [
assume-screen 20/width, 2/height
run [
1:address:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:channel, screen:address:screen
1:address:shared:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:shared:channel, screen:address:shared:screen
# 'read-move' is waiting for input
wait-for-routine 2:number
3:number <- routine-state 2:number/id
4:boolean/waiting? <- equal 3:number/routine-state, 3/waiting
assert 4:boolean/waiting?, [
F read-move-file: routine failed to pause after coming up (before any keys were pressed)]
1:address:channel <- write 1:address:channel, 50/'2'
1:address:shared:channel <- write 1:address:shared:channel, 50/'2'
restart 2:number/routine
wait-for-routine 2:number
]
@ -500,16 +501,16 @@ F read-move-file: routine failed to pause after coming up (before any keys were
scenario read-move-illegal-rank [
assume-screen 20/width, 2/height
run [
1:address:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:channel, screen:address:screen
1:address:shared:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:shared:channel, screen:address:shared:screen
# 'read-move' is waiting for input
wait-for-routine 2:number
3:number <- routine-state 2:number/id
4:boolean/waiting? <- equal 3:number/routine-state, 3/waiting
assert 4:boolean/waiting?, [
F read-move-file: routine failed to pause after coming up (before any keys were pressed)]
1:address:channel <- write 1:address:channel, 97/a
1:address:channel <- write 1:address:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 97/a
restart 2:number/routine
wait-for-routine 2:number
]
@ -522,16 +523,16 @@ F read-move-file: routine failed to pause after coming up (before any keys were
scenario read-move-empty [
assume-screen 20/width, 2/height
run [
1:address:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:channel, screen:address:screen
1:address:shared:channel <- new-channel 2
2:number/routine <- start-running read-move, 1:address:shared:channel, screen:address:shared:screen
# 'read-move' is waiting for input
wait-for-routine 2:number
3:number <- routine-state 2:number/id
4:boolean/waiting? <- equal 3:number/routine-state, 3/waiting
assert 4:boolean/waiting?, [
F read-move-file: routine failed to pause after coming up (before any keys were pressed)]
1:address:channel <- write 1:address:channel, 10/newline
1:address:channel <- write 1:address:channel, 97/a
1:address:shared:channel <- write 1:address:shared:channel, 10/newline
1:address:shared:channel <- write 1:address:shared:channel, 97/a
restart 2:number/routine
wait-for-routine 2:number
]
@ -541,14 +542,14 @@ F read-move-file: routine failed to pause after coming up (before any keys were
]
]
recipe make-move board:address:array:address:array:character, m:address:move -> board:address:array:address:array:character [
recipe 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
from-rank:number <- get *m, from-rank:offset
to-file:number <- get *m, to-file:offset
to-rank:number <- get *m, to-rank:offset
f:address:array:character <- index *board, from-file
f:address:shared:array:character <- index *board, from-file
src:address:character/square <- index-address *f, from-rank
f <- index *board, to-file
dest:address:character/square <- index-address *f, to-rank
@ -559,18 +560,18 @@ recipe make-move board:address:array:address:array:character, m:address:move ->
scenario making-a-move [
assume-screen 30/width, 12/height
run [
2:address:array:address:array:character/board <- initial-position
3:address:move <- new move:type
4:address:number <- get-address *3:address:move, from-file:offset
2:address:shared:array:address:shared:array:character/board <- initial-position
3:address:shared:move <- new move:type
4:address:number <- get-address *3:address:shared:move, from-file:offset
*4:address:number <- copy 6/g
5:address:number <- get-address *3:address:move, from-rank:offset
5:address:number <- get-address *3:address:shared:move, from-rank:offset
*5:address:number <- copy 1/'2'
6:address:number <- get-address *3:address:move, to-file:offset
6:address:number <- get-address *3:address:shared:move, to-file:offset
*6:address:number <- copy 6/g
7:address:number <- get-address *3:address:move, to-rank:offset
7:address:number <- get-address *3:address:shared:move, to-rank:offset
*7:address:number <- copy 3/'4'
2:address:array:address:array:character/board <- make-move 2:address:array:address:array:character/board, 3:address:move
screen:address:screen <- print-board screen:address:screen, 2:address:array:address:array:character/board
2:address:shared:array:address:shared:array:character/board <- make-move 2:address:shared:array:address:shared:array:character/board, 3:address:shared:move
screen:address:shared:screen <- print-board screen:address:shared:screen, 2:address:shared:array:address:shared:array:character/board
]
screen-should-contain [
# 012345678901234567890123456789

View File

@ -1,24 +1,24 @@
# example program: maintain multiple counters with isolated lexical scopes
# (spaces)
recipe new-counter n:number -> default-space:address:array:location [
recipe new-counter n:number -> default-space:address:shared:array:location [
default-space <- new location:type, 30
load-ingredients
]
recipe increment-counter outer:address:array:location/names:new-counter, x:number -> n:number/space:1 [
recipe increment-counter outer:address:shared:array:location/names:new-counter, x:number -> n:number/space:1 [
local-scope
load-ingredients
0:address:array:location/names:new-counter <- copy outer # setup outer space; it *must* come from 'new-counter'
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 [
local-scope
# counter A
a:address:array:location <- new-counter 34
a:address:shared:array:location <- new-counter 34
# counter B
b:address:array:location <- new-counter 23
b:address:shared:array:location <- new-counter 23
# increment both by 2 but in different ways
increment-counter a, 1
b-value:number <- increment-counter b, 2

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:array:character [
recipe! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -16,8 +16,8 @@ recipe! main text:address:array:character [
scenario editor-initially-prints-text-to-screen [
assume-screen 10/width, 5/height
run [
1:address:array:character <- new [abc]
new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
]
screen-should-contain [
# top line of screen reserved for menu
@ -29,11 +29,11 @@ scenario editor-initially-prints-text-to-screen [
container editor-data [
# editable text: doubly linked list of characters (head contains a special sentinel)
data:address:duplex-list:character
top-of-screen:address:duplex-list:character
bottom-of-screen:address:duplex-list:character
data:address:shared:duplex-list:character
top-of-screen:address:shared:duplex-list:character
bottom-of-screen:address:shared:duplex-list:character
# location before cursor inside data
before-cursor:address:duplex-list:character
before-cursor:address:shared:duplex-list:character
# raw bounds of display area on screen
# always displays from row 1 (leaving row 0 for a menu) and at most until bottom of screen
@ -47,7 +47,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:array:character, screen:address:screen, left:number, right:number -> result:address:editor-data, screen:address:screen [
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 [
local-scope
load-ingredients
# no clipping of bounds
@ -63,11 +63,11 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
*x <- copy 1/top
x <- get-address *result, cursor-column:offset
*x <- copy left
init:address:address:duplex-list:character <- get-address *result, data:offset
init:address:address:shared:duplex-list:character <- get-address *result, data:offset
*init <- push 167/§, 0/tail
top-of-screen:address:address:duplex-list:character <- get-address *result, top-of-screen:offset
top-of-screen:address:address:shared:duplex-list:character <- get-address *result, top-of-screen:offset
*top-of-screen <- copy *init
y:address:address:duplex-list:character <- get-address *result, before-cursor:offset
y:address:address:shared:duplex-list:character <- get-address *result, before-cursor:offset
*y <- copy *init
result <- insert-text result, s
# initialize cursor to top of screen
@ -78,7 +78,7 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
<editor-initialization>
]
recipe insert-text editor:address:editor-data, text:address:array:character -> editor:address:editor-data [
recipe 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
@ -87,7 +87,7 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
reply-unless len, editor/same-as-ingredient:0
idx:number <- copy 0
# now we can start appending the rest, character by character
curr:address:duplex-list:character <- get *editor, data:offset
curr:address:shared:duplex-list:character <- get *editor, data:offset
{
done?:boolean <- greater-or-equal idx, len
break-if done?
@ -104,8 +104,8 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
scenario editor-initializes-without-data [
assume-screen 5/width, 3/height
run [
1:address:editor-data <- new-editor 0/data, screen:address:screen, 2/left, 5/right
2:editor-data <- copy *1:address:editor-data
1:address:shared:editor-data <- new-editor 0/data, screen:address:shared:screen, 2/left, 5/right
2:editor-data <- copy *1:address:shared:editor-data
]
memory-should-contain [
# 2 (data) <- just the § sentinel
@ -127,7 +127,7 @@ 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:screen, editor:address:editor-data -> last-row:number, last-column:number, screen:address:screen, editor:address:editor-data [
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 [
local-scope
load-ingredients
reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
@ -135,8 +135,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
screen-height:number <- screen-height screen
right:number <- get *editor, right:offset
# traversing editor
curr:address:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr:address:shared:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:shared:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr <- next curr
# traversing screen
+render-loop-initialization
@ -145,7 +145,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
column:number <- copy left
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
screen <- move-cursor screen, row, column
{
+next-character
@ -208,7 +208,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
loop
}
# save first character off-screen
bottom-of-screen:address:address:duplex-list:character <- get-address *editor, bottom-of-screen:offset
bottom-of-screen:address:address:shared:duplex-list:character <- get-address *editor, bottom-of-screen:offset
*bottom-of-screen <- copy curr
# is cursor to the right of the last line? move to end
{
@ -225,7 +225,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
]
recipe clear-line-delimited screen:address:screen, column:number, right:number -> screen:address:screen [
recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 32/space
@ -238,7 +238,7 @@ recipe clear-line-delimited screen:address:screen, column:number, right:number -
}
]
recipe clear-screen-from screen:address:screen, row:number, column:number, left:number, right:number -> screen:address:screen [
recipe 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
@ -254,7 +254,7 @@ recipe clear-screen-from screen:address:screen, row:number, column:number, left:
reply screen/same-as-ingredient:0
]
recipe clear-rest-of-screen screen:address:screen, row:number, left:number, right:number -> screen:address:screen [
recipe 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
@ -273,9 +273,9 @@ recipe clear-rest-of-screen screen:address:screen, row:number, left:number, righ
scenario editor-initially-prints-multiple-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
def]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -288,8 +288,8 @@ def]
scenario editor-initially-handles-offsets [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc]
new-editor s:address:array:character, screen:address:screen, 1/left, 5/right
s:address:shared:array:character <- new [abc]
new-editor s:address:shared:array:character, screen:address:shared:screen, 1/left, 5/right
]
screen-should-contain [
. .
@ -301,9 +301,9 @@ scenario editor-initially-handles-offsets [
scenario editor-initially-prints-multiple-lines-at-offset [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
def]
new-editor s:address:array:character, screen:address:screen, 1/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 1/left, 5/right
]
screen-should-contain [
. .
@ -316,8 +316,8 @@ def]
scenario editor-initially-wraps-long-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc def]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
s:address:shared:array:character <- new [abc def]
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -336,8 +336,8 @@ scenario editor-initially-wraps-long-lines [
scenario editor-initially-wraps-barely-long-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abcde]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
s:address:shared:array:character <- new [abcde]
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
# still wrap, even though the line would fit. We need room to click on the
# end of the line
@ -358,10 +358,10 @@ scenario editor-initially-wraps-barely-long-lines [
scenario editor-initializes-empty-text [
assume-screen 5/width, 5/height
run [
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
1:address:shared:array:character <- new []
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -379,10 +379,10 @@ scenario editor-initializes-empty-text [
scenario render-colors-comments [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
# de
f]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -460,10 +460,10 @@ recipe get-color color:number, c:character -> color:number [
scenario render-colors-assignment [
assume-screen 8/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
d <- e
f]
new-editor s:address:array:character, screen:address:screen, 0/left, 8/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 8/right
]
screen-should-contain [
. .

View File

@ -2,16 +2,16 @@
# temporary main: interactive editor
# hit ctrl-c to exit
recipe! main text:address:array:character [
recipe! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
editor:address:editor-data <- new-editor text, 0/screen, 5/left, 45/right
editor:address:shared:editor-data <- new-editor text, 0/screen, 5/left, 45/right
editor-event-loop 0/screen, 0/console, editor
close-console
]
recipe editor-event-loop screen:address:screen, console:address:console, editor:address:editor-data -> screen:address:screen, console:address:console, editor:address:editor-data [
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 [
local-scope
load-ingredients
{
@ -20,7 +20,7 @@ recipe editor-event-loop screen:address:screen, console:address:console, editor:
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
screen <- move-cursor screen, cursor-row, cursor-column
e:event, console:address:console, found?:boolean, quit?:boolean <- read-event console
e:event, console:address:shared:console, found?:boolean, quit?:boolean <- read-event console
loop-unless found?
break-if quit? # only in tests
trace 10, [app], [next-event]
@ -45,7 +45,7 @@ recipe editor-event-loop screen:address:screen, console:address:console, editor:
]
# process click, return if it was on current editor
recipe move-cursor-in-editor screen:address:screen, editor:address:editor-data, t:touch-event -> in-focus?:boolean, editor:address:editor-data [
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 [
local-scope
load-ingredients
reply-unless editor, 0/false
@ -70,7 +70,7 @@ recipe move-cursor-in-editor screen:address:screen, editor:address:editor-data,
# 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:screen, editor:address:editor-data, target-row:number, target-column:number -> editor:address:editor-data [
recipe 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
@ -78,8 +78,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
# count newlines until screen row
curr:address:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr:address:shared:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:shared:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr <- next curr
row:number <- copy 1/top
column:number <- copy left
@ -87,7 +87,7 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
*cursor-row <- copy target-row
cursor-column:address:number <- get-address *editor, cursor-column:offset
*cursor-column <- copy target-column
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
{
+next-character
break-unless curr
@ -155,7 +155,7 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
# 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:screen, editor:address:editor-data, e:event -> screen:address:screen, editor:address:editor-data, go-render?:boolean [
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 [
local-scope
load-ingredients
go-render? <- copy 0/false
@ -164,7 +164,7 @@ recipe handle-keyboard-event screen:address:screen, editor:address:editor-data,
screen-height:number <- screen-height screen
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
save-row:number <- copy *cursor-row
@ -195,10 +195,10 @@ recipe handle-keyboard-event screen:address:screen, editor:address:editor-data,
reply
]
recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [
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 [
local-scope
load-ingredients
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
insert c, *before-cursor
*before-cursor <- next *before-cursor
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -213,7 +213,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
<insert-character-special-case>
# but mostly we'll just move the cursor right
*cursor-column <- add *cursor-column, 1
next:address:duplex-list:character <- next *before-cursor
next:address:shared:duplex-list:character <- next *before-cursor
{
# at end of all text? no need to scroll? just print the character and leave
at-end?:boolean <- equal next, 0/null
@ -233,7 +233,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
break-unless next
at-right?:boolean <- greater-or-equal *cursor-column, screen-width
break-if at-right?
curr:address:duplex-list:character <- copy *before-cursor
curr:address:shared:duplex-list:character <- copy *before-cursor
move-cursor screen, save-row, save-column
curr-column:number <- copy save-column
{
@ -259,7 +259,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
]
# helper for tests
recipe editor-render screen:address:screen, editor:address:editor-data -> screen:address:screen, editor:address:editor-data [
recipe 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
@ -274,12 +274,12 @@ recipe editor-render screen:address:screen, editor:address:editor-data -> screen
scenario editor-handles-empty-event-queue [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
assume-console []
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -291,17 +291,17 @@ scenario editor-handles-empty-event-queue [
scenario editor-handles-mouse-clicks [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 1 # on the 'b'
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -318,16 +318,16 @@ scenario editor-handles-mouse-clicks [
scenario editor-handles-mouse-clicks-outside-text [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 1, 7 # last line, to the right of text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 1 # cursor row
@ -338,17 +338,17 @@ scenario editor-handles-mouse-clicks-outside-text [
scenario editor-handles-mouse-clicks-outside-text-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
def]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 1, 7 # interior line, to the right of text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 1 # cursor row
@ -359,17 +359,17 @@ def]
scenario editor-handles-mouse-clicks-outside-text-3 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
def]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 3, 7 # below text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2 # cursor row
@ -380,19 +380,19 @@ def]
scenario editor-handles-mouse-clicks-outside-column [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
1:address:shared:array:character <- new [abc]
# editor occupies only left half of screen
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
# click on right half of screen
left-click 3, 8
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -409,18 +409,18 @@ scenario editor-handles-mouse-clicks-outside-column [
scenario editor-handles-mouse-clicks-in-menu-area [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
# click on first, 'menu' row
left-click 0, 3
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# no change to cursor
memory-should-contain [
@ -431,15 +431,15 @@ scenario editor-handles-mouse-clicks-in-menu-area [
scenario editor-inserts-characters-into-empty-editor [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new []
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
type [abc]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -452,9 +452,9 @@ scenario editor-inserts-characters-into-empty-editor [
scenario editor-inserts-characters-at-cursor [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
# type two letters at different places
assume-console [
@ -463,7 +463,7 @@ scenario editor-inserts-characters-at-cursor [
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -476,16 +476,16 @@ scenario editor-inserts-characters-at-cursor [
scenario editor-inserts-characters-at-cursor-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 5 # right of last line
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -498,17 +498,17 @@ scenario editor-inserts-characters-at-cursor-2 [
scenario editor-inserts-characters-at-cursor-5 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 5 # right of non-last line
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -522,16 +522,16 @@ d]
scenario editor-inserts-characters-at-cursor-3 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -544,17 +544,17 @@ scenario editor-inserts-characters-at-cursor-3 [
scenario editor-inserts-characters-at-cursor-4 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -568,17 +568,17 @@ d]
scenario editor-inserts-characters-at-cursor-6 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [ef]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -592,14 +592,14 @@ d]
scenario editor-moves-cursor-after-inserting-characters [
assume-screen 10/width, 5/height
1:address:array:character <- new [ab]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [ab]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
assume-console [
type [01]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -613,15 +613,15 @@ scenario editor-moves-cursor-after-inserting-characters [
scenario editor-wraps-line-on-insert [
assume-screen 5/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
# type a letter
assume-console [
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# no wrap yet
screen-should-contain [
@ -636,7 +636,7 @@ scenario editor-wraps-line-on-insert [
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# now wrap
screen-should-contain [
@ -651,19 +651,19 @@ scenario editor-wraps-line-on-insert [
scenario editor-wraps-line-on-insert-2 [
# create an editor with some text
assume-screen 10/width, 5/height
1:address:array:character <- new [abcdefg
1:address:shared:array:character <- new [abcdefg
defg]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
# type more text at the start
assume-console [
left-click 3, 0
type [abc]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor is not wrapped
memory-should-contain [
@ -703,16 +703,16 @@ after <insert-character-special-case> [
scenario editor-wraps-cursor-after-inserting-characters [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
left-click 1, 4 # line is full; no wrap icon yet
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -729,16 +729,16 @@ scenario editor-wraps-cursor-after-inserting-characters [
scenario editor-wraps-cursor-after-inserting-characters-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
left-click 1, 3 # right before the wrap icon
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -755,16 +755,16 @@ scenario editor-wraps-cursor-after-inserting-characters-2 [
scenario editor-wraps-cursor-to-left-margin [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 2/left, 7/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 2/left, 7/right
assume-console [
left-click 1, 5 # line is full; no wrap icon yet
type [01]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -792,14 +792,14 @@ after <editor-initialization> [
scenario editor-moves-cursor-down-after-inserting-newline [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
assume-console [
type [0
1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -822,12 +822,12 @@ after <handle-special-character> [
}
]
recipe insert-new-line-and-indent editor:address:editor-data, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [
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 [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
@ -847,8 +847,8 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
# indent if necessary
indent?:boolean <- get *editor, indent?:offset
reply-unless indent?
d:address:duplex-list:character <- get *editor, data:offset
end-of-previous-line:address:duplex-list:character <- prev *before-cursor
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
i:number <- copy 0
{
@ -862,7 +862,7 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
# 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:duplex-list:character, start:address:duplex-list:character -> result:number [
recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
@ -894,14 +894,14 @@ recipe line-indent curr:address:duplex-list:character, start:address:duplex-list
scenario editor-moves-cursor-down-after-inserting-newline-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 1/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 1/left, 10/right
assume-console [
type [0
1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -914,8 +914,8 @@ scenario editor-moves-cursor-down-after-inserting-newline-2 [
scenario editor-clears-previous-line-completely-after-inserting-newline [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
press enter
]
@ -927,7 +927,7 @@ scenario editor-clears-previous-line-completely-after-inserting-newline [
. .
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# line should be fully cleared
screen-should-contain [
@ -941,10 +941,10 @@ scenario editor-clears-previous-line-completely-after-inserting-newline [
scenario editor-inserts-indent-after-newline [
assume-screen 10/width, 10/height
1:address:array:character <- new [ab
1:address:shared:array:character <- new [ab
cd
ef]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
# position cursor after 'cd' and hit 'newline'
assume-console [
left-click 2, 8
@ -952,9 +952,9 @@ ef]
]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor should be below start of previous line
memory-should-contain [
@ -965,10 +965,10 @@ ef]
scenario editor-skips-indent-around-paste [
assume-screen 10/width, 10/height
1:address:array:character <- new [ab
1:address:shared:array:character <- new [ab
cd
ef]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
# position cursor after 'cd' and hit 'newline' surrounded by paste markers
assume-console [
left-click 2, 8
@ -977,9 +977,9 @@ ef]
press 65506 # end paste
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor should be below start of previous line
memory-should-contain [
@ -1012,7 +1012,7 @@ after <handle-special-key> [
## helpers
recipe draw-horizontal screen:address:screen, row:number, x:number, right:number -> screen:address:screen [
recipe 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

File diff suppressed because it is too large Load Diff

View File

@ -6,22 +6,22 @@
recipe! main [
local-scope
open-console
initial-recipe:address:array:character <- restore [recipes.mu]
initial-sandbox:address:array:character <- new []
initial-recipe:address:shared:array:character <- restore [recipes.mu]
initial-sandbox:address:shared:array:character <- new []
hide-screen 0/screen
env:address:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
env:address:shared:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
render-all 0/screen, env
event-loop 0/screen, 0/console, env
# never gets here
]
container programming-environment-data [
recipes:address:editor-data
current-sandbox:address:editor-data
recipes:address:shared:editor-data
current-sandbox:address:shared:editor-data
sandbox-in-focus?:boolean # false => cursor in recipes; true => cursor in current-sandbox
]
recipe new-programming-environment screen:address:screen, initial-recipe-contents:address:array:character, initial-sandbox-contents:address:array:character -> result:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
width:number <- screen-width screen
@ -33,25 +33,25 @@ recipe new-programming-environment screen:address:screen, initial-recipe-content
button-on-screen?:boolean <- greater-or-equal button-start, 0
assert button-on-screen?, [screen too narrow for menu]
screen <- move-cursor screen, 0/row, button-start
run-button:address:array:character <- new [ run (F4) ]
run-button:address:shared:array:character <- new [ run (F4) ]
print screen, run-button, 255/white, 161/reddish
# dotted line down the middle
divider:number, _ <- divide-with-remainder width, 2
draw-vertical screen, divider, 1/top, height, 9482/vertical-dotted
# recipe editor on the left
recipes:address:address:editor-data <- get-address *result, recipes:offset
recipes:address:address:shared:editor-data <- get-address *result, recipes:offset
*recipes <- new-editor initial-recipe-contents, screen, 0/left, divider/right
# sandbox editor on the right
new-left:number <- add divider, 1
current-sandbox:address:address:editor-data <- get-address *result, current-sandbox:offset
current-sandbox:address:address:shared:editor-data <- get-address *result, current-sandbox:offset
*current-sandbox <- new-editor initial-sandbox-contents, screen, new-left, width/right
]
recipe event-loop screen:address:screen, console:address:console, env:address:programming-environment-data -> screen:address:screen, console:address:console, env:address:programming-environment-data [
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 [
local-scope
load-ingredients
recipes:address:editor-data <- get *env, recipes:offset
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
recipes:address:shared:editor-data <- get *env, recipes:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
sandbox-in-focus?:address:boolean <- get-address *env, sandbox-in-focus?:offset
# if we fall behind we'll stop updating the screen, but then we have to
# render the entire screen when we catch up.
@ -179,14 +179,14 @@ recipe event-loop screen:address:screen, console:address:console, env:address:pr
}
]
recipe resize screen:address:screen, env:address:programming-environment-data -> env:address:programming-environment-data, screen:address:screen [
recipe 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
width:number <- screen-width screen
divider:number, _ <- divide-with-remainder width, 2
# update recipe editor
recipes:address:editor-data <- get *env, recipes:offset
recipes:address:shared:editor-data <- get *env, recipes:offset
right:address:number <- get-address *recipes, right:offset
*right <- subtract divider, 1
# reset cursor (later we'll try to preserve its position)
@ -195,7 +195,7 @@ recipe resize screen:address:screen, env:address:programming-environment-data ->
cursor-column:address:number <- get-address *recipes, cursor-column:offset
*cursor-column <- copy 0
# update sandbox editor
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
left:address:number <- get-address *current-sandbox, left:offset
right:address:number <- get-address *current-sandbox, right:offset
*left <- add divider, 1
@ -211,9 +211,9 @@ scenario point-at-multiple-editors [
trace-until 100/app # trace too long
assume-screen 30/width, 5/height
# initialize both halves of screen
1:address:array:character <- new [abc]
2:address:array:character <- new [def]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
1:address:shared:array:character <- new [abc]
2:address:shared:array:character <- new [def]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# focus on both sides
assume-console [
left-click 1, 1
@ -221,11 +221,11 @@ scenario point-at-multiple-editors [
]
# check cursor column in each
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
4:address:editor-data <- get *3:address:programming-environment-data, recipes:offset
5:number <- get *4:address:editor-data, cursor-column:offset
6:address:editor-data <- get *3:address:programming-environment-data, current-sandbox:offset
7:number <- get *6:address:editor-data, cursor-column:offset
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:address:shared:editor-data <- get *3:address:shared:programming-environment-data, recipes:offset
5:number <- get *4:address:shared:editor-data, cursor-column:offset
6:address:shared:editor-data <- get *3:address:shared:programming-environment-data, current-sandbox:offset
7:number <- get *6:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
5 <- 1
@ -237,10 +237,10 @@ scenario edit-multiple-editors [
trace-until 100/app # trace too long
assume-screen 30/width, 5/height
# initialize both halves of screen
1:address:array:character <- new [abc]
2:address:array:character <- new [def]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
render-all screen, 3:address:programming-environment-data
1:address:shared:array:character <- new [abc]
2:address:shared:array:character <- new [def]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
render-all screen, 3:address:shared:programming-environment-data
# type one letter in each of them
assume-console [
left-click 1, 1
@ -249,11 +249,11 @@ scenario edit-multiple-editors [
type [1]
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
4:address:editor-data <- get *3:address:programming-environment-data, recipes:offset
5:number <- get *4:address:editor-data, cursor-column:offset
6:address:editor-data <- get *3:address:programming-environment-data, current-sandbox:offset
7:number <- get *6:address:editor-data, cursor-column:offset
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:address:shared:editor-data <- get *3:address:shared:programming-environment-data, recipes:offset
5:number <- get *4:address:shared:editor-data, cursor-column:offset
6:address:shared:editor-data <- get *3:address:shared:programming-environment-data, current-sandbox:offset
7:number <- get *6:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. run (F4) . # this line has a different background, but we don't test that yet
@ -268,7 +268,7 @@ scenario edit-multiple-editors [
# show the cursor at the right window
run [
8:character/cursor <- copy 9251/␣
print screen:address:screen, 8:character/cursor
print screen:address:shared:screen, 8:character/cursor
]
screen-should-contain [
. run (F4) .
@ -282,10 +282,10 @@ scenario multiple-editors-cover-only-their-own-areas [
trace-until 100/app # trace too long
assume-screen 60/width, 10/height
run [
1:address:array:character <- new [abc]
2:address:array:character <- new [def]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
render-all screen, 3:address:programming-environment-data
1:address:shared:array:character <- new [abc]
2:address:shared:array:character <- new [def]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
render-all screen, 3:address:shared:programming-environment-data
]
# divider isn't messed up
screen-should-contain [
@ -300,16 +300,16 @@ scenario multiple-editors-cover-only-their-own-areas [
scenario editor-in-focus-keeps-cursor [
trace-until 100/app # trace too long
assume-screen 30/width, 5/height
1:address:array:character <- new [abc]
2:address:array:character <- new [def]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
render-all screen, 3:address:programming-environment-data
1:address:shared:array:character <- new [abc]
2:address:shared:array:character <- new [def]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
render-all screen, 3:address:shared:programming-environment-data
# initialize programming environment and highlight cursor
assume-console []
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:character/cursor <- copy 9251/␣
print screen:address:screen, 4:character/cursor
print screen:address:shared:screen, 4:character/cursor
]
# is cursor at the right place?
screen-should-contain [
@ -323,9 +323,9 @@ scenario editor-in-focus-keeps-cursor [
type [z]
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:character/cursor <- copy 9251/␣
print screen:address:screen, 4:character/cursor
print screen:address:shared:screen, 4:character/cursor
]
# cursor should still be right
screen-should-contain [
@ -340,11 +340,11 @@ scenario backspace-in-sandbox-editor-joins-lines [
trace-until 100/app # trace too long
assume-screen 30/width, 5/height
# initialize sandbox side with two lines
1:address:array:character <- new []
2:address:array:character <- new [abc
1:address:shared:array:character <- new []
2:address:shared:array:character <- new [abc
def]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
render-all screen, 3:address:programming-environment-data
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
render-all screen, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊abc .
@ -358,9 +358,9 @@ def]
press backspace
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:character/cursor <- copy 9251/␣
print screen:address:screen, 4:character/cursor
print screen:address:shared:screen, 4:character/cursor
]
# cursor moves to end of old line
screen-should-contain [
@ -371,7 +371,7 @@ def]
]
]
recipe render-all screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
trace 10, [app], [render all]
@ -384,7 +384,7 @@ recipe render-all screen:address:screen, env:address:programming-environment-dat
button-on-screen?:boolean <- greater-or-equal button-start, 0
assert button-on-screen?, [screen too narrow for menu]
screen <- move-cursor screen, 0/row, button-start
run-button:address:array:character <- new [ run (F4) ]
run-button:address:shared:array:character <- new [ run (F4) ]
print screen, run-button, 255/white, 161/reddish
# dotted line down the middle
trace 11, [app], [render divider]
@ -396,19 +396,19 @@ recipe render-all screen:address:screen, env:address:programming-environment-dat
screen <- render-sandbox-side screen, env
<render-components-end>
#
recipes:address:editor-data <- get *env, recipes:offset
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
recipes:address:shared:editor-data <- get *env, recipes:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
sandbox-in-focus?:boolean <- get *env, sandbox-in-focus?:offset
screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?
#
show-screen screen
]
recipe render-recipes screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe render-recipes screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
trace 11, [app], [render recipes]
recipes:address:editor-data <- get *env, recipes:offset
recipes:address:shared:editor-data <- get *env, recipes:offset
# render recipes
left:number <- get *recipes, left:offset
right:number <- get *recipes, right:offset
@ -423,10 +423,10 @@ recipe render-recipes screen:address:screen, env:address:programming-environment
]
# replaced in a later layer
recipe render-sandbox-side screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
left:number <- get *current-sandbox, left:offset
right:number <- get *current-sandbox, right:offset
row:number, column:number, screen, current-sandbox <- render screen, current-sandbox
@ -438,7 +438,7 @@ recipe render-sandbox-side screen:address:screen, env:address:programming-enviro
clear-screen-from screen, row, left, left, right
]
recipe update-cursor screen:address:screen, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:boolean -> screen:address:screen [
recipe update-cursor screen:address:shared:screen, recipes:address:shared:editor-data, current-sandbox:address:shared:editor-data, sandbox-in-focus?:boolean -> screen:address:shared:screen [
local-scope
load-ingredients
{
@ -456,7 +456,7 @@ recipe update-cursor screen:address:screen, recipes:address:editor-data, current
# 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:screen, s:address:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [
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 [
local-scope
load-ingredients
reply-unless s
@ -517,7 +517,7 @@ recipe render screen:address:screen, s:address:array:character, left:number, rig
]
# like 'render' for texts, but with colorization for comments like in the editor
recipe render-code screen:address:screen, s:address:array:character, left:number, right:number, row:number -> row:number, screen:address:screen [
recipe 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
@ -585,7 +585,7 @@ after <global-type> [
{
redraw-screen?:boolean <- equal *c, 12/ctrl-l
break-unless redraw-screen?
screen <- render-all screen, env:address:programming-environment-data
screen <- render-all screen, env:address:shared:programming-environment-data
sync-screen screen
loop +next-event:label
}
@ -606,7 +606,7 @@ after <global-type> [
## helpers
recipe draw-vertical screen:address:screen, col:number, y:number, bottom:number -> screen:address:screen [
recipe 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

@ -7,10 +7,10 @@
recipe! main [
local-scope
open-console
initial-recipe:address:array:character <- restore [recipes.mu]
initial-sandbox:address:array:character <- new []
initial-recipe:address:shared:array:character <- restore [recipes.mu]
initial-sandbox:address:shared:array:character <- new []
hide-screen 0/screen
env:address:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
env:address:shared:programming-environment-data <- new-programming-environment 0/screen, initial-recipe, initial-sandbox
env <- restore-sandboxes env
render-all 0/screen, env
event-loop 0/screen, 0/console, env
@ -18,35 +18,35 @@ recipe! main [
]
container programming-environment-data [
sandbox:address:sandbox-data # list of sandboxes, from top to bottom
sandbox:address:shared:sandbox-data # list of sandboxes, from top to bottom
]
container sandbox-data [
data:address:array:character
response:address:array:character
expected-response:address:array:character
data:address:shared:array:character
response:address:shared:array:character
expected-response:address:shared:array:character
# coordinates to track clicks
starting-row-on-screen:number
code-ending-row-on-screen:number # past end of code
response-starting-row-on-screen:number
screen:address:screen # prints in the sandbox go here
next-sandbox:address:sandbox-data
screen:address:shared:screen # prints in the sandbox go here
next-sandbox:address:shared:sandbox-data
]
scenario run-and-show-results [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
# recipe editor is empty
1:address:array:character <- new []
1:address:shared:array:character <- new []
# sandbox editor contains an instruction without storing outputs
2:address:array:character <- new [divide-with-remainder 11, 3]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [divide-with-remainder 11, 3]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the code in the editors
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that screen prints the results
screen-should-contain [
@ -89,7 +89,7 @@ scenario run-and-show-results [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that screen prints the results
screen-should-contain [
@ -115,14 +115,14 @@ after <global-keypress> [
do-run?:boolean <- equal *k, 65532/F4
break-unless do-run?
#? $log [F4 pressed]
status:address:array:character <- new [running... ]
status:address:shared:array:character <- new [running... ]
screen <- update-status screen, status, 245/grey
error?:boolean, env, screen <- run-sandboxes env, screen
# F4 might update warnings and results on both sides
screen <- render-all screen, env
{
break-if error?
status:address:array:character <- new [ ]
status:address:shared:array:character <- new [ ]
screen <- update-status screen, status, 245/grey
}
screen <- update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?
@ -130,36 +130,36 @@ after <global-keypress> [
}
]
recipe run-sandboxes env:address:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
errors-found?:boolean, env, screen <- update-recipes env, screen
reply-if errors-found?
# check contents of right editor (sandbox)
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
{
sandbox-contents:address:array:character <- editor-contents current-sandbox
sandbox-contents:address:shared:array:character <- editor-contents current-sandbox
break-unless sandbox-contents
# if contents exist, first save them
# run them and turn them into a new sandbox-data
new-sandbox:address:sandbox-data <- new sandbox-data:type
data:address:address:array:character <- get-address *new-sandbox, data:offset
new-sandbox:address:shared:sandbox-data <- new sandbox-data:type
data:address:address:shared:array:character <- get-address *new-sandbox, data:offset
*data <- copy sandbox-contents
# push to head of sandbox list
dest:address:address:sandbox-data <- get-address *env, sandbox:offset
next:address:address:sandbox-data <- get-address *new-sandbox, next-sandbox:offset
dest:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
next:address:address:shared:sandbox-data <- get-address *new-sandbox, next-sandbox:offset
*next <- copy *dest
*dest <- copy new-sandbox
# clear sandbox editor
init:address:address:duplex-list:character <- get-address *current-sandbox, data:offset
init:address:address:shared:duplex-list:character <- get-address *current-sandbox, data:offset
*init <- push 167/§, 0/tail
top-of-screen:address:address:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
top-of-screen:address:address:shared:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
*top-of-screen <- copy *init
}
# save all sandboxes before running, just in case we die when running
save-sandboxes env
# run all sandboxes
curr:address:sandbox-data <- get *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
{
break-unless curr
curr <- update-sandbox curr
@ -171,49 +171,49 @@ recipe run-sandboxes env:address:programming-environment-data, screen:address:sc
# 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:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
recipes:address:editor-data <- get *env, recipes:offset
in:address:array:character <- editor-contents recipes
recipes:address:shared:editor-data <- get *env, recipes:offset
in:address:shared:array:character <- editor-contents recipes
save [recipes.mu], in # newlayer: persistence
reload in
errors-found? <- copy 0/false
]
# replaced in a later layer
recipe update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe update-sandbox sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
*response, _, *fake-screen <- run-interactive data
]
recipe update-status screen:address:screen, msg:address:array:character, color:number -> screen:address:screen [
recipe 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:programming-environment-data [
recipe save-sandboxes env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
# first clear previous versions, in case we deleted some sandbox
$system [rm lesson/[0-9]* >/dev/null 2>/dev/null] # some shells can't handle '>&'
curr:address:sandbox-data <- get *env, sandbox:offset
suffix:address:array:character <- new [.out]
curr:address:shared:sandbox-data <- get *env, sandbox:offset
suffix:address:shared:array:character <- new [.out]
idx:number <- copy 0
{
break-unless curr
data:address:array:character <- get *curr, data:offset
filename:address:array:character <- to-text idx
data:address:shared:array:character <- get *curr, data:offset
filename:address:shared:array:character <- to-text idx
save filename, data
{
expected-response:address:array:character <- get *curr, expected-response:offset
expected-response:address:shared:array:character <- get *curr, expected-response:offset
break-unless expected-response
filename <- append filename, suffix
save filename, expected-response
@ -224,24 +224,24 @@ recipe save-sandboxes env:address:programming-environment-data [
}
]
recipe! render-sandbox-side screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
#? $log [render sandbox side]
trace 11, [app], [render sandbox side]
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
left:number <- get *current-sandbox, left:offset
right:number <- get *current-sandbox, right:offset
row:number, column:number, screen, current-sandbox <- render screen, current-sandbox
clear-screen-from screen, row, column, left, right
row <- add row, 1
draw-horizontal screen, row, left, right, 9473/horizontal-double
sandbox:address:sandbox-data <- get *env, sandbox:offset
sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
row, screen <- render-sandboxes screen, sandbox, left, right, row
clear-rest-of-screen screen, row, left, left, right
]
recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, left:number, right:number, row:number -> row:number, screen:address:screen, sandbox:address:sandbox-data [
recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
#? $log [render sandbox]
@ -261,16 +261,16 @@ recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, lef
# render sandbox contents
row <- add row, 1
screen <- move-cursor screen, row, left
sandbox-data:address:array:character <- get *sandbox, data:offset
sandbox-data:address:shared:array:character <- get *sandbox, data:offset
row, screen <- render-code screen, sandbox-data, left, right, row
code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset
*code-ending-row <- copy row
# render sandbox warnings, screen or response, in that order
response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset
sandbox-response:address:array:character <- get *sandbox, response:offset
sandbox-response:address:shared:array:character <- get *sandbox, response:offset
<render-sandbox-results>
{
sandbox-screen:address:screen <- get *sandbox, screen:offset
sandbox-screen:address:shared:screen <- get *sandbox, screen:offset
empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen
break-if empty-screen?
row, screen <- render-screen screen, sandbox-screen, left, right, row
@ -287,32 +287,32 @@ recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, lef
# draw solid line after sandbox
draw-horizontal screen, row, left, right, 9473/horizontal-double
# draw next sandbox
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
row, screen <- render-sandboxes screen, next-sandbox, left, right, row
]
# assumes programming environment has no sandboxes; restores them from previous session
recipe restore-sandboxes env:address:programming-environment-data -> env:address:programming-environment-data [
recipe 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
suffix:address:array:character <- new [.out]
suffix:address:shared:array:character <- new [.out]
idx:number <- copy 0
curr:address:address:sandbox-data <- get-address *env, sandbox:offset
curr:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
{
filename:address:array:character <- to-text idx
contents:address:array:character <- restore filename
filename:address:shared:array:character <- to-text idx
contents:address:shared:array:character <- restore filename
break-unless contents # stop at first error; assuming file didn't exist
# create new sandbox for file
*curr <- new sandbox-data:type
data:address:address:array:character <- get-address **curr, data:offset
data:address:address:shared:array:character <- get-address **curr, data:offset
*data <- copy contents
# restore expected output for sandbox if it exists
{
filename <- append filename, suffix
contents <- restore filename
break-unless contents
expected-response:address:address:array:character <- get-address **curr, expected-response:offset
expected-response:address:address:shared:array:character <- get-address **curr, expected-response:offset
*expected-response <- copy contents
}
+continue
@ -324,19 +324,19 @@ recipe restore-sandboxes env:address:programming-environment-data -> env:address
# print the fake sandbox screen to 'screen' with appropriate delimiters
# leave cursor at start of next line
recipe render-screen screen:address:screen, sandbox-screen:address:screen, left:number, right:number, row:number -> row:number, screen:address:screen [
recipe 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
# print 'screen:'
header:address:array:character <- new [screen:]
header:address:shared:array:character <- new [screen:]
row <- render screen, header, left, right, 245/grey, row
screen <- move-cursor screen, row, left
# start printing sandbox-screen
column:number <- copy left
s-width:number <- screen-width sandbox-screen
s-height:number <- screen-height sandbox-screen
buf:address:array:screen-cell <- get *sandbox-screen, data:offset
buf:address:shared:array:screen-cell <- get *sandbox-screen, data:offset
stop-printing:number <- add left, s-width, 3
max-column:number <- min stop-printing, right
i:number <- copy 0
@ -394,19 +394,19 @@ scenario run-updates-results [
trace-until 100/app # trace too long
assume-screen 100/width, 12/height
# define a recipe (no indent for the 'add' line below so column numbers are more obvious)
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
z:number <- add 2, 2
reply z
]]
# sandbox editor contains an instruction without storing outputs
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the code in the editors
assume-console [
press F4
]
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -425,7 +425,7 @@ reply z
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that screen updates the result on the right
screen-should-contain [
@ -444,16 +444,16 @@ scenario run-instruction-manages-screen-per-sandbox [
trace-until 100/app # trace too long
assume-screen 100/width, 20/height
# left editor is empty
1:address:array:character <- new []
1:address:shared:array:character <- new []
# right editor contains an instruction
2:address:array:character <- new [print-integer screen, 4]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [print-integer screen, 4]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the code in the editor
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that it prints a little toy screen
screen-should-contain [
@ -473,11 +473,11 @@ scenario run-instruction-manages-screen-per-sandbox [
]
]
recipe editor-contents editor:address:editor-data -> result:address:array:character [
recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:buffer <- new-buffer 80
curr:address:duplex-list:character <- get *editor, data:offset
buf:address:shared:buffer <- new-buffer 80
curr:address:shared:duplex-list:character <- get *editor, data:offset
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
@ -494,16 +494,16 @@ recipe editor-contents editor:address:editor-data -> result:address:array:charac
scenario editor-provides-edited-contents [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
assume-console [
left-click 1, 2
type [def]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:address:array:character <- editor-contents 2:address:editor-data
4:array:character <- copy *3:address:array:character
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:address:shared:array:character <- editor-contents 2:address:shared:editor-data
4:array:character <- copy *3:address:shared:array:character
]
memory-should-contain [
4:array:character <- [abdefc]

View File

@ -4,17 +4,17 @@ scenario clicking-on-a-sandbox-moves-it-to-editor [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# basic recipe
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
reply 4
]]
# run it
2:address:array:character <- new [foo]
2:address:shared:array:character <- new [foo]
assume-console [
press F4
]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -30,7 +30,7 @@ recipe foo [
left-click 3, 30
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# it pops back into editor
screen-should-contain [
@ -48,7 +48,7 @@ recipe foo [
type [0]
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -69,7 +69,7 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
@ -78,8 +78,8 @@ after <global-touch> [
empty-sandbox-editor?:boolean <- empty-editor? current-sandbox
break-unless empty-sandbox-editor? # don't clobber existing contents
# identify the sandbox to edit and remove it from the sandbox list
sandbox:address:sandbox-data <- extract-sandbox env, click-row
text:address:array:character <- get *sandbox, data:offset
sandbox:address:shared:sandbox-data <- extract-sandbox env, click-row
text:address:shared:array:character <- get *sandbox, data:offset
current-sandbox <- insert-text current-sandbox, text
hide-screen screen
screen <- render-sandbox-side screen, env
@ -89,24 +89,24 @@ after <global-touch> [
}
]
recipe empty-editor? editor:address:editor-data -> result:boolean [
recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
local-scope
load-ingredients
head:address:duplex-list:character <- get *editor, data:offset
first:address:duplex-list:character <- next head
head:address:shared:duplex-list:character <- get *editor, data:offset
first:address:shared:duplex-list:character <- next head
result <- not first
]
recipe extract-sandbox env:address:programming-environment-data, click-row:number -> result:address:sandbox-data, env:address:programming-environment-data [
recipe 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
# assert click-row >= sandbox.starting-row-on-screen
sandbox:address:address:sandbox-data <- get-address *env, sandbox:offset
sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
start:number <- get **sandbox, starting-row-on-screen:offset
clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
{
next-sandbox:address:sandbox-data <- get **sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
break-unless next-sandbox
# if click-row < sandbox.next-sandbox.starting-row-on-screen, break
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
@ -127,15 +127,15 @@ scenario sandbox-with-print-can-be-edited [
trace-until 100/app # trace too long
assume-screen 100/width, 20/height
# left editor is empty
1:address:array:character <- new []
1:address:shared:array:character <- new []
# right editor contains an instruction
2:address:array:character <- new [print-integer screen, 4]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [print-integer screen, 4]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the sandbox
assume-console [
press F4
]
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -156,7 +156,7 @@ scenario sandbox-with-print-can-be-edited [
left-click 3, 70
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .

View File

@ -3,9 +3,9 @@
scenario deleting-sandboxes [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new []
2:address:array:character <- new []
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
1:address:shared:array:character <- new []
2:address:shared:array:character <- new []
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run a few commands
assume-console [
left-click 1, 80
@ -14,7 +14,7 @@ scenario deleting-sandboxes [
type [add 2, 2]
press F4
]
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -35,7 +35,7 @@ scenario deleting-sandboxes [
left-click 7, 99
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -53,7 +53,7 @@ scenario deleting-sandboxes [
left-click 3, 99
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -77,17 +77,17 @@ after <global-touch> [
}
]
recipe delete-sandbox t:touch-event, env:address:programming-environment-data -> was-delete?:boolean, env:address:programming-environment-data [
recipe 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:editor-data <- get *env, current-sandbox: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
click-row:number <- get t, row:offset
prev:address:address:sandbox-data <- get-address *env, sandbox:offset
curr:address:sandbox-data <- get *env, sandbox:offset
prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
{
break-unless curr
# more sandboxes to check

View File

@ -4,17 +4,17 @@ scenario sandbox-click-on-result-toggles-color-to-green [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# basic recipe
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
reply 4
]]
# run it
2:address:array:character <- new [foo]
2:address:shared:array:character <- new [foo]
assume-console [
press F4
]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -30,7 +30,7 @@ recipe foo [
left-click 5, 21
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# color toggles to green
screen-should-contain-in-color 2/green, [
@ -46,7 +46,7 @@ recipe foo [
# cursor should remain unmoved
run [
4:character/cursor <- copy 9251/␣
print screen:address:screen, 4:character/cursor
print screen:address:shared:screen, 4:character/cursor
]
screen-should-contain [
. run (F4) .
@ -67,7 +67,7 @@ recipe foo [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# result turns red
screen-should-contain-in-color 1/red, [
@ -90,14 +90,14 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
break-unless below-sandbox-editor?
# identify the sandbox whose output is being clicked on
sandbox:address:sandbox-data <- find-click-in-sandbox-output env, click-row
sandbox:address:shared:sandbox-data <- find-click-in-sandbox-output env, click-row
break-unless sandbox
# toggle its expected-response, and save session
sandbox <- toggle-expected-response sandbox
@ -111,17 +111,17 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-output env:address:programming-environment-data, click-row:number -> sandbox:address:sandbox-data [
recipe 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
sandbox:address:sandbox-data <- get *env, sandbox:offset
sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
start:number <- get *sandbox, starting-row-on-screen:offset
clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
# while click-row < sandbox.next-sandbox.starting-row-on-screen
{
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
break-unless next-sandbox
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
found?:boolean <- lesser-than click-row, next-start
@ -137,10 +137,10 @@ recipe find-click-in-sandbox-output env:address:programming-environment-data, cl
reply sandbox
]
recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
expected-response:address:address:array:character <- get-address *sandbox, expected-response:offset
expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
{
# if expected-response is set, reset
break-unless *expected-response
@ -148,7 +148,7 @@ recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:
reply sandbox/same-as-ingredient:0
}
# if not, current response is the expected response
response:address:array:character <- get *sandbox, response:offset
response:address:shared:array:character <- get *sandbox, response:offset
*expected-response <- copy response
]
@ -156,7 +156,7 @@ recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:
after <render-sandbox-response> [
{
break-unless sandbox-response
expected-response:address:array:character <- get *sandbox, expected-response:offset
expected-response:address:shared:array:character <- get *sandbox, expected-response:offset
break-unless expected-response # fall-through to print in grey
response-is-expected?:boolean <- equal expected-response, sandbox-response
{

View File

@ -4,17 +4,17 @@ scenario sandbox-click-on-code-toggles-app-trace [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# basic recipe
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
stash [abc]
]]
# run it
2:address:array:character <- new [foo]
2:address:shared:array:character <- new [foo]
assume-console [
press F4
]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -29,9 +29,9 @@ recipe foo [
left-click 4, 21
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
4:character/cursor-icon <- copy 9251/␣
print screen:address:screen, 4:character/cursor-icon
print screen:address:shared:screen, 4:character/cursor-icon
]
# trace now printed and cursor shouldn't have budged
screen-should-contain [
@ -59,8 +59,8 @@ recipe foo [
left-click 4, 25
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
print screen:address:screen, 4:character/cursor-icon
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
print screen:address:shared:screen, 4:character/cursor-icon
]
# trace hidden again
screen-should-contain [
@ -78,18 +78,18 @@ scenario sandbox-shows-app-trace-and-result [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# basic recipe
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
stash [abc]
reply 4
]]
# run it
2:address:array:character <- new [foo]
2:address:shared:array:character <- new [foo]
assume-console [
press F4
]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. ┊ .
@ -105,7 +105,7 @@ recipe foo [
left-click 4, 21
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# trace now printed above result
screen-should-contain [
@ -122,18 +122,18 @@ recipe foo [
]
container sandbox-data [
trace:address:array:character
trace:address:shared:array:character
display-trace?:boolean
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe! update-sandbox sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
trace:address:address:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
trace:address:address:shared:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
*response, _, *fake-screen, *trace <- run-interactive data
]
@ -145,14 +145,14 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
break-unless below-sandbox-editor?
# identify the sandbox whose code is being clicked on
sandbox:address:sandbox-data <- find-click-in-sandbox-code env, click-row
sandbox:address:shared:sandbox-data <- find-click-in-sandbox-code env, click-row
break-unless sandbox
# toggle its display-trace? property
x:address:boolean <- get-address *sandbox, display-trace?:offset
@ -166,7 +166,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-code env:address:programming-environment-data, click-row:number -> sandbox:address:sandbox-data [
recipe 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
@ -176,7 +176,7 @@ recipe find-click-in-sandbox-code env:address:programming-environment-data, clic
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
# while click-row < sandbox.next-sandbox.starting-row-on-screen
{
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
break-unless next-sandbox
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
found?:boolean <- lesser-than click-row, next-start
@ -202,7 +202,7 @@ after <render-sandbox-results> [
{
display-trace?:boolean <- get *sandbox, display-trace?:offset
break-unless display-trace?
sandbox-trace:address:array:character <- get *sandbox, trace:offset
sandbox-trace:address:shared:array:character <- get *sandbox, trace:offset
break-unless sandbox-trace # nothing to print; move on
row, screen <- render screen, sandbox-trace, left, right, 245/grey, row
}

View File

@ -1,23 +1,23 @@
## handling malformed programs
container programming-environment-data [
recipe-warnings:address:array:character
recipe-warnings:address:shared:array:character
]
# copy code from recipe editor, persist, load into mu, save any warnings
recipe! update-recipes env:address:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
#? $log [update recipes]
recipes:address:editor-data <- get *env, recipes:offset
in:address:array:character <- editor-contents recipes
recipes:address:shared:editor-data <- get *env, recipes:offset
in:address:shared:array:character <- editor-contents recipes
save [recipes.mu], in
recipe-warnings:address:address:array:character <- get-address *env, recipe-warnings:offset
recipe-warnings:address:address:shared:array:character <- get-address *env, recipe-warnings:offset
*recipe-warnings <- reload in
# if recipe editor has errors, stop
{
break-unless *recipe-warnings
status:address:array:character <- new [errors found]
status:address:shared:array:character <- new [errors found]
update-status screen, status, 1/red
errors-found? <- copy 1/true
reply
@ -27,35 +27,35 @@ recipe! update-recipes env:address:programming-environment-data, screen:address:
before <render-components-end> [
trace 11, [app], [render status]
recipe-warnings:address:array:character <- get *env, recipe-warnings:offset
recipe-warnings:address:shared:array:character <- get *env, recipe-warnings:offset
{
break-unless recipe-warnings
status:address:array:character <- new [errors found]
status:address:shared:array:character <- new [errors found]
update-status screen, status, 1/red
}
]
before <render-recipe-components-end> [
{
recipe-warnings:address:array:character <- get *env, recipe-warnings:offset
recipe-warnings:address:shared:array:character <- get *env, recipe-warnings:offset
break-unless recipe-warnings
row, screen <- render screen, recipe-warnings, left, right, 1/red, row
}
]
container sandbox-data [
warnings:address:array:character
warnings:address:shared:array:character
]
recipe! update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe! update-sandbox sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
#? $log [update sandbox]
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
warnings:address:address:array:character <- get-address *sandbox, warnings:offset
trace:address:address:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
warnings:address:address:shared:array:character <- get-address *sandbox, warnings:offset
trace:address:address:shared:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
#? $print [run-interactive], 10/newline
*response, *warnings, *fake-screen, *trace, completed?:boolean <- run-interactive data
{
@ -70,7 +70,7 @@ recipe! update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-d
# make sure we render any trace
after <render-sandbox-trace-done> [
{
sandbox-warnings:address:array:character <- get *sandbox, warnings:offset
sandbox-warnings:address:shared:array:character <- get *sandbox, warnings:offset
break-unless sandbox-warnings
*response-starting-row <- copy 0 # no response
row, screen <- render screen, sandbox-warnings, left, right, 1/red, row
@ -82,17 +82,17 @@ after <render-sandbox-trace-done> [
scenario run-shows-warnings-in-get [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
get 123:number, foo:offset
]]
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
@ -122,14 +122,14 @@ recipe foo [
scenario run-hides-warnings-from-past-sandboxes [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new []
2:address:array:character <- new [get foo, x:offset] # invalid
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
1:address:shared:array:character <- new []
2:address:shared:array:character <- new [get foo, x:offset] # invalid
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4 # generate error
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
assume-console [
left-click 3, 80
@ -138,7 +138,7 @@ scenario run-hides-warnings-from-past-sandboxes [
press F4 # error should disappear
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -156,18 +156,18 @@ scenario run-updates-warnings-for-shape-shifting-recipes [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
# define a shape-shifting recipe with an error
1:address:array:character <- new [recipe foo x:_elem -> z:_elem [
1:address:shared:array:character <- new [recipe foo x:_elem -> z:_elem [
local-scope
load-ingredients
z <- add x, [a]
]]
2:address:array:character <- new [foo 2]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo 2]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -185,7 +185,7 @@ z <- add x, [a]
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# error should remain unchanged
screen-should-contain [
@ -205,24 +205,24 @@ scenario run-avoids-spurious-warnings-on-reloading-shape-shifting-recipes [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
# overload a well-known shape-shifting recipe
1:address:array:character <- new [recipe length l:address:list:_elem -> n:number [
1:address:shared:array:character <- new [recipe length l:address:shared:list:_elem -> n:number [
]]
# call code that uses other variants of it, but not it itself
2:address:array:character <- new [x:address:list:number <- copy 0
2:address:shared:array:character <- new [x:address:shared:list:number <- copy 0
to-text x]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run it once
assume-console [
press F4
]
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
# no errors anywhere on screen (can't check anything else, since to-text will return an address)
screen-should-contain-in-color 1/red, [
. .
. .
. .
. .
. <- .
. <- .
. .
. .
. .
@ -239,7 +239,7 @@ to-text x]
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# still no errors
screen-should-contain-in-color 1/red, [
@ -247,7 +247,7 @@ to-text x]
. .
. .
. .
. <- .
. <- .
. .
. .
. .
@ -264,17 +264,17 @@ to-text x]
scenario run-shows-missing-type-warnings [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
x <- copy 0
]]
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
@ -290,18 +290,18 @@ scenario run-shows-unbalanced-bracket-warnings [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
# recipe is incomplete (unbalanced '[')
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo «
x <- copy 0
]
replace 1:address:array:character, 171/«, 91 # '['
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
replace 1:address:shared:array:character, 171/«, 91 # '['
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
@ -318,28 +318,28 @@ recipe foo «
scenario run-shows-get-on-non-container-warnings [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
x:address:point <- new point:type
get x:address:point, 1:offset
x:address:shared:point <- new point:type
get x:address:shared:point, 1:offset
]]
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
. ┊foo .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. x:address:point <- new point:type ┊ .
. get x:address:point, 1:offset ┊ .
. x:address:shared:point <- new point:type ┊ .
. get x:address:shared:point, 1:offset ┊ .
.] ┊ .
.foo: first ingredient of 'get' should be a contai↩┊ .
.ner, but got x:address:point ┊ .
.ner, but got x:address:shared:point ┊ .
.┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .
. ┊ .
]
@ -348,27 +348,27 @@ recipe foo [
scenario run-shows-non-literal-get-argument-warnings [
trace-until 100/app # trace too long
assume-screen 100/width, 15/height
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
x:number <- copy 0
y:address:point <- new point:type
get *y:address:point, x:number
y:address:shared:point <- new point:type
get *y:address:shared:point, x:number
]]
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
. ┊foo .
.recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. x:number <- copy 0 ┊ .
. y:address:point <- new point:type ┊ .
. get *y:address:point, x:number ┊ .
. y:address:shared:point <- new point:type ┊ .
. get *y:address:shared:point, x:number ┊ .
.] ┊ .
.foo: expected ingredient 1 of 'get' to have type ↩┊ .
.'offset'; got x:number ┊ .
@ -383,17 +383,17 @@ scenario run-shows-warnings-everytime [
trace-until 100/app # trace too long
# try to run a file with an error
assume-screen 100/width, 15/height
1:address:array:character <- new [
1:address:shared:array:character <- new [
recipe foo [
x:number <- copy y:number
]]
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
@ -410,7 +410,7 @@ recipe foo [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. errors found run (F4) .
@ -428,16 +428,16 @@ scenario run-instruction-and-print-warnings [
trace-until 100/app # trace too long
assume-screen 100/width, 10/height
# left editor is empty
1:address:array:character <- new []
1:address:shared:array:character <- new []
# right editor contains an illegal instruction
2:address:array:character <- new [get 1234:number, foo:offset]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [get 1234:number, foo:offset]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the code in the editors
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that screen prints error message in red
screen-should-contain [
@ -491,17 +491,17 @@ scenario run-instruction-and-print-warnings-only-once [
trace-until 100/app # trace too long
assume-screen 100/width, 10/height
# left editor is empty
1:address:array:character <- new []
1:address:shared:array:character <- new []
# right editor contains an illegal instruction
2:address:array:character <- new [get 1234:number, foo:offset]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [get 1234:number, foo:offset]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the code in the editors multiple times
assume-console [
press F4
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# check that screen prints error message just once
screen-should-contain [
@ -522,20 +522,20 @@ scenario sandbox-can-handle-infinite-loop [
trace-until 100/app # trace too long
assume-screen 100/width, 20/height
# left editor is empty
1:address:array:character <- new [recipe foo [
1:address:shared:array:character <- new [recipe foo [
{
loop
}
]]
# right editor contains an instruction
2:address:array:character <- new [foo]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run the sandbox
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -553,7 +553,7 @@ scenario sandbox-with-warnings-shows-trace [
trace-until 100/app # trace too long
assume-screen 100/width, 10/height
# generate a stash and a warning
1:address:array:character <- new [recipe foo [
1:address:shared:array:character <- new [recipe foo [
local-scope
a:number <- next-ingredient
b:number <- next-ingredient
@ -561,13 +561,13 @@ stash [dividing by], b
_, c:number <- divide-with-remainder a, b
reply b
]]
2:address:array:character <- new [foo 4, 0]
3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
2:address:shared:array:character <- new [foo 4, 0]
3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character
# run
assume-console [
press F4
]
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
# screen prints error message
screen-should-contain [
. run (F4) .
@ -585,7 +585,7 @@ reply b
left-click 4, 55
]
run [
event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data
]
# screen should expand trace
screen-should-contain [

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
recipe main [
# allocate 5 locations for globals
global-space:address:array:location <- new location:type, 5
global-space:address:shared:array:location <- new location:type, 5
# read to globals by using /space:global
1:number/space:global <- copy 3
foo
@ -10,5 +10,5 @@ recipe main [
recipe foo [
# ditto for writing to globals
$print 1:number/space:global
$print 1:number/space:global, 10/newline
]

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:array:character [
recipe! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
@ -16,8 +16,8 @@ recipe! main text:address:array:character [
scenario editor-initially-prints-text-to-screen [
assume-screen 10/width, 5/height
run [
1:address:array:character <- new [abc]
new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
]
screen-should-contain [
# top line of screen reserved for menu
@ -29,11 +29,11 @@ scenario editor-initially-prints-text-to-screen [
container editor-data [
# editable text: doubly linked list of characters (head contains a special sentinel)
data:address:duplex-list:character
top-of-screen:address:duplex-list:character
bottom-of-screen:address:duplex-list:character
data:address:shared:duplex-list:character
top-of-screen:address:shared:duplex-list:character
bottom-of-screen:address:shared:duplex-list:character
# location before cursor inside data
before-cursor:address:duplex-list:character
before-cursor:address:shared:duplex-list:character
# raw bounds of display area on screen
# always displays from row 1 (leaving row 0 for a menu) and at most until bottom of screen
@ -47,7 +47,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:array:character, screen:address:screen, left:number, right:number -> result:address:editor-data, screen:address:screen [
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 [
local-scope
load-ingredients
# no clipping of bounds
@ -63,11 +63,11 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
*x <- copy 1/top
x <- get-address *result, cursor-column:offset
*x <- copy left
init:address:address:duplex-list:character <- get-address *result, data:offset
init:address:address:shared:duplex-list:character <- get-address *result, data:offset
*init <- push 167/§, 0/tail
top-of-screen:address:address:duplex-list:character <- get-address *result, top-of-screen:offset
top-of-screen:address:address:shared:duplex-list:character <- get-address *result, top-of-screen:offset
*top-of-screen <- copy *init
y:address:address:duplex-list:character <- get-address *result, before-cursor:offset
y:address:address:shared:duplex-list:character <- get-address *result, before-cursor:offset
*y <- copy *init
result <- insert-text result, s
# initialize cursor to top of screen
@ -78,7 +78,7 @@ recipe new-editor s:address:array:character, screen:address:screen, left:number,
<editor-initialization>
]
recipe insert-text editor:address:editor-data, text:address:array:character -> editor:address:editor-data [
recipe 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
@ -87,7 +87,7 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
reply-unless len, editor/same-as-ingredient:0
idx:number <- copy 0
# now we can start appending the rest, character by character
curr:address:duplex-list:character <- get *editor, data:offset
curr:address:shared:duplex-list:character <- get *editor, data:offset
{
done?:boolean <- greater-or-equal idx, len
break-if done?
@ -104,8 +104,8 @@ recipe insert-text editor:address:editor-data, text:address:array:character -> e
scenario editor-initializes-without-data [
assume-screen 5/width, 3/height
run [
1:address:editor-data <- new-editor 0/data, screen:address:screen, 2/left, 5/right
2:editor-data <- copy *1:address:editor-data
1:address:shared:editor-data <- new-editor 0/data, screen:address:shared:screen, 2/left, 5/right
2:editor-data <- copy *1:address:shared:editor-data
]
memory-should-contain [
# 2 (data) <- just the § sentinel
@ -127,7 +127,7 @@ 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:screen, editor:address:editor-data -> last-row:number, last-column:number, screen:address:screen, editor:address:editor-data [
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 [
local-scope
load-ingredients
reply-unless editor, 1/top, 0/left, screen/same-as-ingredient:0, editor/same-as-ingredient:1
@ -135,8 +135,8 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
screen-height:number <- screen-height screen
right:number <- get *editor, right:offset
# traversing editor
curr:address:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr:address:shared:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:shared:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr <- next curr
# traversing screen
+render-loop-initialization
@ -145,7 +145,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
column:number <- copy left
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
screen <- move-cursor screen, row, column
{
+next-character
@ -208,7 +208,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
loop
}
# save first character off-screen
bottom-of-screen:address:address:duplex-list:character <- get-address *editor, bottom-of-screen:offset
bottom-of-screen:address:address:shared:duplex-list:character <- get-address *editor, bottom-of-screen:offset
*bottom-of-screen <- copy curr
# is cursor to the right of the last line? move to end
{
@ -225,7 +225,7 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb
reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1
]
recipe clear-line-delimited screen:address:screen, column:number, right:number -> screen:address:screen [
recipe clear-line-delimited screen:address:shared:screen, column:number, right:number -> screen:address:shared:screen [
local-scope
load-ingredients
space:character <- copy 32/space
@ -238,7 +238,7 @@ recipe clear-line-delimited screen:address:screen, column:number, right:number -
}
]
recipe clear-screen-from screen:address:screen, row:number, column:number, left:number, right:number -> screen:address:screen [
recipe 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
@ -254,7 +254,7 @@ recipe clear-screen-from screen:address:screen, row:number, column:number, left:
reply screen/same-as-ingredient:0
]
recipe clear-rest-of-screen screen:address:screen, row:number, left:number, right:number -> screen:address:screen [
recipe 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
@ -273,9 +273,9 @@ recipe clear-rest-of-screen screen:address:screen, row:number, left:number, righ
scenario editor-initially-prints-multiple-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
def]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -288,8 +288,8 @@ def]
scenario editor-initially-handles-offsets [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc]
new-editor s:address:array:character, screen:address:screen, 1/left, 5/right
s:address:shared:array:character <- new [abc]
new-editor s:address:shared:array:character, screen:address:shared:screen, 1/left, 5/right
]
screen-should-contain [
. .
@ -301,9 +301,9 @@ scenario editor-initially-handles-offsets [
scenario editor-initially-prints-multiple-lines-at-offset [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
def]
new-editor s:address:array:character, screen:address:screen, 1/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 1/left, 5/right
]
screen-should-contain [
. .
@ -316,8 +316,8 @@ def]
scenario editor-initially-wraps-long-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc def]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
s:address:shared:array:character <- new [abc def]
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -336,8 +336,8 @@ scenario editor-initially-wraps-long-lines [
scenario editor-initially-wraps-barely-long-lines [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abcde]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
s:address:shared:array:character <- new [abcde]
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
# still wrap, even though the line would fit. We need room to click on the
# end of the line
@ -358,10 +358,10 @@ scenario editor-initially-wraps-barely-long-lines [
scenario editor-initializes-empty-text [
assume-screen 5/width, 5/height
run [
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
1:address:shared:array:character <- new []
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -379,10 +379,10 @@ scenario editor-initializes-empty-text [
scenario render-colors-comments [
assume-screen 5/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
# de
f]
new-editor s:address:array:character, screen:address:screen, 0/left, 5/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
]
screen-should-contain [
. .
@ -460,10 +460,10 @@ recipe get-color color:number, c:character -> color:number [
scenario render-colors-assignment [
assume-screen 8/width, 5/height
run [
s:address:array:character <- new [abc
s:address:shared:array:character <- new [abc
d <- e
f]
new-editor s:address:array:character, screen:address:screen, 0/left, 8/right
new-editor s:address:shared:array:character, screen:address:shared:screen, 0/left, 8/right
]
screen-should-contain [
. .

View File

@ -2,16 +2,16 @@
# temporary main: interactive editor
# hit ctrl-c to exit
recipe! main text:address:array:character [
recipe! main text:address:shared:array:character [
local-scope
load-ingredients
open-console
editor:address:editor-data <- new-editor text, 0/screen, 5/left, 45/right
editor:address:shared:editor-data <- new-editor text, 0/screen, 5/left, 45/right
editor-event-loop 0/screen, 0/console, editor
close-console
]
recipe editor-event-loop screen:address:screen, console:address:console, editor:address:editor-data -> screen:address:screen, console:address:console, editor:address:editor-data [
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 [
local-scope
load-ingredients
{
@ -20,7 +20,7 @@ recipe editor-event-loop screen:address:screen, console:address:console, editor:
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
screen <- move-cursor screen, cursor-row, cursor-column
e:event, console:address:console, found?:boolean, quit?:boolean <- read-event console
e:event, console:address:shared:console, found?:boolean, quit?:boolean <- read-event console
loop-unless found?
break-if quit? # only in tests
trace 10, [app], [next-event]
@ -45,7 +45,7 @@ recipe editor-event-loop screen:address:screen, console:address:console, editor:
]
# process click, return if it was on current editor
recipe move-cursor-in-editor screen:address:screen, editor:address:editor-data, t:touch-event -> in-focus?:boolean, editor:address:editor-data [
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 [
local-scope
load-ingredients
reply-unless editor, 0/false
@ -70,7 +70,7 @@ recipe move-cursor-in-editor screen:address:screen, editor:address:editor-data,
# 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:screen, editor:address:editor-data, target-row:number, target-column:number -> editor:address:editor-data [
recipe 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
@ -78,8 +78,8 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
# count newlines until screen row
curr:address:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr:address:shared:duplex-list:character <- get *editor, top-of-screen:offset
prev:address:shared:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev
curr <- next curr
row:number <- copy 1/top
column:number <- copy left
@ -87,7 +87,7 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
*cursor-row <- copy target-row
cursor-column:address:number <- get-address *editor, cursor-column:offset
*cursor-column <- copy target-column
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
{
+next-character
break-unless curr
@ -155,7 +155,7 @@ recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row
# 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:screen, editor:address:editor-data, e:event -> screen:address:screen, editor:address:editor-data, go-render?:boolean [
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 [
local-scope
load-ingredients
go-render? <- copy 0/false
@ -164,7 +164,7 @@ recipe handle-keyboard-event screen:address:screen, editor:address:editor-data,
screen-height:number <- screen-height screen
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
save-row:number <- copy *cursor-row
@ -195,10 +195,10 @@ recipe handle-keyboard-event screen:address:screen, editor:address:editor-data,
reply
]
recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [
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 [
local-scope
load-ingredients
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
insert c, *before-cursor
*before-cursor <- next *before-cursor
cursor-row:address:number <- get-address *editor, cursor-row:offset
@ -213,7 +213,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
<insert-character-special-case>
# but mostly we'll just move the cursor right
*cursor-column <- add *cursor-column, 1
next:address:duplex-list:character <- next *before-cursor
next:address:shared:duplex-list:character <- next *before-cursor
{
# at end of all text? no need to scroll? just print the character and leave
at-end?:boolean <- equal next, 0/null
@ -233,7 +233,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
break-unless next
at-right?:boolean <- greater-or-equal *cursor-column, screen-width
break-if at-right?
curr:address:duplex-list:character <- copy *before-cursor
curr:address:shared:duplex-list:character <- copy *before-cursor
move-cursor screen, save-row, save-column
curr-column:number <- copy save-column
{
@ -259,7 +259,7 @@ recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:
]
# helper for tests
recipe editor-render screen:address:screen, editor:address:editor-data -> screen:address:screen, editor:address:editor-data [
recipe 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
@ -274,12 +274,12 @@ recipe editor-render screen:address:screen, editor:address:editor-data -> screen
scenario editor-handles-empty-event-queue [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
assume-console []
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -291,17 +291,17 @@ scenario editor-handles-empty-event-queue [
scenario editor-handles-mouse-clicks [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 1 # on the 'b'
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -318,16 +318,16 @@ scenario editor-handles-mouse-clicks [
scenario editor-handles-mouse-clicks-outside-text [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 1, 7 # last line, to the right of text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 1 # cursor row
@ -338,17 +338,17 @@ scenario editor-handles-mouse-clicks-outside-text [
scenario editor-handles-mouse-clicks-outside-text-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
def]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 1, 7 # interior line, to the right of text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 1 # cursor row
@ -359,17 +359,17 @@ def]
scenario editor-handles-mouse-clicks-outside-text-3 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
def]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
$clear-trace
assume-console [
left-click 3, 7 # below text
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2 # cursor row
@ -380,19 +380,19 @@ def]
scenario editor-handles-mouse-clicks-outside-column [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
1:address:shared:array:character <- new [abc]
# editor occupies only left half of screen
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
# click on right half of screen
left-click 3, 8
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -409,18 +409,18 @@ scenario editor-handles-mouse-clicks-outside-column [
scenario editor-handles-mouse-clicks-in-menu-area [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
# click on first, 'menu' row
left-click 0, 3
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# no change to cursor
memory-should-contain [
@ -431,15 +431,15 @@ scenario editor-handles-mouse-clicks-in-menu-area [
scenario editor-inserts-characters-into-empty-editor [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new []
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
type [abc]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -452,9 +452,9 @@ scenario editor-inserts-characters-into-empty-editor [
scenario editor-inserts-characters-at-cursor [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
# type two letters at different places
assume-console [
@ -463,7 +463,7 @@ scenario editor-inserts-characters-at-cursor [
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -476,16 +476,16 @@ scenario editor-inserts-characters-at-cursor [
scenario editor-inserts-characters-at-cursor-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 5 # right of last line
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -498,17 +498,17 @@ scenario editor-inserts-characters-at-cursor-2 [
scenario editor-inserts-characters-at-cursor-5 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 1, 5 # right of non-last line
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -522,16 +522,16 @@ d]
scenario editor-inserts-characters-at-cursor-3 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [d]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -544,17 +544,17 @@ scenario editor-inserts-characters-at-cursor-3 [
scenario editor-inserts-characters-at-cursor-4 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -568,17 +568,17 @@ d]
scenario editor-inserts-characters-at-cursor-6 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
1:address:shared:array:character <- new [abc
d]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
editor-render screen, 2:address:shared:editor-data
$clear-trace
assume-console [
left-click 3, 5 # below all text
type [ef]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -592,14 +592,14 @@ d]
scenario editor-moves-cursor-after-inserting-characters [
assume-screen 10/width, 5/height
1:address:array:character <- new [ab]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [ab]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
assume-console [
type [01]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -613,15 +613,15 @@ scenario editor-moves-cursor-after-inserting-characters [
scenario editor-wraps-line-on-insert [
assume-screen 5/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
# type a letter
assume-console [
type [e]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# no wrap yet
screen-should-contain [
@ -636,7 +636,7 @@ scenario editor-wraps-line-on-insert [
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# now wrap
screen-should-contain [
@ -651,19 +651,19 @@ scenario editor-wraps-line-on-insert [
scenario editor-wraps-line-on-insert-2 [
# create an editor with some text
assume-screen 10/width, 5/height
1:address:array:character <- new [abcdefg
1:address:shared:array:character <- new [abcdefg
defg]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
editor-render screen, 2:address:editor-data
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
editor-render screen, 2:address:shared:editor-data
# type more text at the start
assume-console [
left-click 3, 0
type [abc]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor is not wrapped
memory-should-contain [
@ -703,16 +703,16 @@ after <insert-character-special-case> [
scenario editor-wraps-cursor-after-inserting-characters [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
left-click 1, 4 # line is full; no wrap icon yet
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -729,16 +729,16 @@ scenario editor-wraps-cursor-after-inserting-characters [
scenario editor-wraps-cursor-after-inserting-characters-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
left-click 1, 3 # right before the wrap icon
type [f]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -755,16 +755,16 @@ scenario editor-wraps-cursor-after-inserting-characters-2 [
scenario editor-wraps-cursor-to-left-margin [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 2/left, 7/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 2/left, 7/right
assume-console [
left-click 1, 5 # line is full; no wrap icon yet
type [01]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
screen-should-contain [
. .
@ -792,14 +792,14 @@ after <editor-initialization> [
scenario editor-moves-cursor-down-after-inserting-newline [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
assume-console [
type [0
1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -822,12 +822,12 @@ after <handle-special-character> [
}
]
recipe insert-new-line-and-indent editor:address:editor-data, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [
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 [
local-scope
load-ingredients
cursor-row:address:number <- get-address *editor, cursor-row:offset
cursor-column:address:number <- get-address *editor, cursor-column:offset
before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset
before-cursor:address:address:shared:duplex-list:character <- get-address *editor, before-cursor:offset
left:number <- get *editor, left:offset
right:number <- get *editor, right:offset
screen-height:number <- screen-height screen
@ -847,8 +847,8 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
# indent if necessary
indent?:boolean <- get *editor, indent?:offset
reply-unless indent?
d:address:duplex-list:character <- get *editor, data:offset
end-of-previous-line:address:duplex-list:character <- prev *before-cursor
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
i:number <- copy 0
{
@ -862,7 +862,7 @@ recipe insert-new-line-and-indent editor:address:editor-data, screen:address:scr
# 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:duplex-list:character, start:address:duplex-list:character -> result:number [
recipe line-indent curr:address:shared:duplex-list:character, start:address:shared:duplex-list:character -> result:number [
local-scope
load-ingredients
result:number <- copy 0
@ -894,14 +894,14 @@ recipe line-indent curr:address:duplex-list:character, start:address:duplex-list
scenario editor-moves-cursor-down-after-inserting-newline-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 1/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 1/left, 10/right
assume-console [
type [0
1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
screen-should-contain [
. .
@ -914,8 +914,8 @@ scenario editor-moves-cursor-down-after-inserting-newline-2 [
scenario editor-clears-previous-line-completely-after-inserting-newline [
assume-screen 10/width, 5/height
1:address:array:character <- new [abcde]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
1:address:shared:array:character <- new [abcde]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 5/right
assume-console [
press enter
]
@ -927,7 +927,7 @@ scenario editor-clears-previous-line-completely-after-inserting-newline [
. .
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
]
# line should be fully cleared
screen-should-contain [
@ -941,10 +941,10 @@ scenario editor-clears-previous-line-completely-after-inserting-newline [
scenario editor-inserts-indent-after-newline [
assume-screen 10/width, 10/height
1:address:array:character <- new [ab
1:address:shared:array:character <- new [ab
cd
ef]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
# position cursor after 'cd' and hit 'newline'
assume-console [
left-click 2, 8
@ -952,9 +952,9 @@ ef]
]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor should be below start of previous line
memory-should-contain [
@ -965,10 +965,10 @@ ef]
scenario editor-skips-indent-around-paste [
assume-screen 10/width, 10/height
1:address:array:character <- new [ab
1:address:shared:array:character <- new [ab
cd
ef]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
# position cursor after 'cd' and hit 'newline' surrounded by paste markers
assume-console [
left-click 2, 8
@ -977,9 +977,9 @@ ef]
press 65506 # end paste
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:number <- get *2:address:shared:editor-data, cursor-row:offset
4:number <- get *2:address:shared:editor-data, cursor-column:offset
]
# cursor should be below start of previous line
memory-should-contain [
@ -1012,7 +1012,7 @@ after <handle-special-key> [
## helpers
recipe draw-horizontal screen:address:screen, row:number, x:number, right:number -> screen:address:screen [
recipe 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

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,12 @@
recipe! main [
local-scope
open-console
initial-sandbox:address:array:character <- new []
initial-sandbox:address:shared:array:character <- new []
hide-screen 0/screen
env:address:programming-environment-data <- new-programming-environment 0/screen, initial-sandbox
env:address:shared:programming-environment-data <- new-programming-environment 0/screen, initial-sandbox
env <- restore-sandboxes env
render-sandbox-side 0/screen, env
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
update-cursor 0/screen, current-sandbox
show-screen 0/screen
event-loop 0/screen, 0/console, env
@ -16,10 +16,10 @@ recipe! main [
]
container programming-environment-data [
current-sandbox:address:editor-data
current-sandbox:address:shared:editor-data
]
recipe new-programming-environment screen:address:screen, initial-sandbox-contents:address:array:character -> result:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
width:number <- screen-width screen
@ -31,17 +31,17 @@ recipe new-programming-environment screen:address:screen, initial-sandbox-conten
button-on-screen?:boolean <- greater-or-equal button-start, 0
assert button-on-screen?, [screen too narrow for menu]
screen <- move-cursor screen, 0/row, button-start
run-button:address:array:character <- new [ run (F4) ]
run-button:address:shared:array:character <- new [ run (F4) ]
print screen, run-button, 255/white, 161/reddish
# sandbox editor
current-sandbox:address:address:editor-data <- get-address *result, current-sandbox:offset
current-sandbox:address:address:shared:editor-data <- get-address *result, current-sandbox:offset
*current-sandbox <- new-editor initial-sandbox-contents, screen, 0, width/right
]
recipe event-loop screen:address:screen, console:address:console, env:address:programming-environment-data -> screen:address:screen, console:address:console, env:address:programming-environment-data [
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 [
local-scope
load-ingredients
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
# if we fall behind we'll stop updating the screen, but then we have to
# render the entire screen when we catch up.
# todo: test this
@ -56,18 +56,18 @@ recipe event-loop screen:address:screen, console:address:console, env:address:pr
<handle-event>
# check for global events that will trigger regardless of which editor has focus
{
k:address:number <- maybe-convert e:event, keycode:variant
k:address:shared:number <- maybe-convert e:event, keycode:variant
break-unless k
<global-keypress>
}
{
c:address:character <- maybe-convert e:event, text:variant
c:address:shared:character <- maybe-convert e:event, text:variant
break-unless c
<global-type>
}
# 'touch' event
{
t:address:touch-event <- maybe-convert e:event, touch:variant
t:address:shared:touch-event <- maybe-convert e:event, touch:variant
break-unless t
# ignore all but 'left-click' events for now
# todo: test this
@ -83,7 +83,7 @@ recipe event-loop screen:address:screen, console:address:console, env:address:pr
# 'resize' event - redraw editor
# todo: test this after supporting resize in assume-console
{
r:address:resize-event <- maybe-convert e:event, resize:variant
r:address:shared:resize-event <- maybe-convert e:event, resize:variant
break-unless r
# if more events, we're still resizing; wait until we stop
more-events?:boolean <- has-more-events? console
@ -135,13 +135,13 @@ recipe event-loop screen:address:screen, console:address:console, env:address:pr
}
]
recipe resize screen:address:screen, env:address:programming-environment-data -> env:address:programming-environment-data, screen:address:screen [
recipe 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
width:number <- screen-width screen
# update sandbox editor
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
right:address:number <- get-address *current-sandbox, right:offset
*right <- subtract width, 1
# reset cursor
@ -151,7 +151,7 @@ recipe resize screen:address:screen, env:address:programming-environment-data ->
*cursor-column <- copy 0
]
recipe render-all screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe render-all screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
trace 10, [app], [render all]
@ -164,23 +164,23 @@ recipe render-all screen:address:screen, env:address:programming-environment-dat
button-on-screen?:boolean <- greater-or-equal button-start, 0
assert button-on-screen?, [screen too narrow for menu]
screen <- move-cursor screen, 0/row, button-start
run-button:address:array:character <- new [ run (F4) ]
run-button:address:shared:array:character <- new [ run (F4) ]
print screen, run-button, 255/white, 161/reddish
#
screen <- render-sandbox-side screen, env
<render-components-end>
#
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
screen <- update-cursor screen, current-sandbox
#
show-screen screen
]
# replaced in a later layer
recipe render-sandbox-side screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
left:number <- get *current-sandbox, left:offset
right:number <- get *current-sandbox, right:offset
row:number, column:number, screen, current-sandbox <- render screen, current-sandbox
@ -192,7 +192,7 @@ recipe render-sandbox-side screen:address:screen, env:address:programming-enviro
clear-screen-from screen, row, left, left, right
]
recipe update-cursor screen:address:screen, current-sandbox:address:editor-data -> screen:address:screen [
recipe update-cursor screen:address:shared:screen, current-sandbox:address:shared:editor-data -> screen:address:shared:screen [
local-scope
load-ingredients
cursor-row:number <- get *current-sandbox, cursor-row:offset
@ -202,7 +202,7 @@ recipe update-cursor screen:address:screen, current-sandbox:address:editor-data
# 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:screen, s:address:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [
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 [
local-scope
load-ingredients
reply-unless s
@ -263,7 +263,7 @@ recipe render screen:address:screen, s:address:array:character, left:number, rig
]
# like 'render' for texts, but with colorization for comments like in the editor
recipe render-code screen:address:screen, s:address:array:character, left:number, right:number, row:number -> row:number, screen:address:screen [
recipe 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
@ -331,8 +331,13 @@ after <global-type> [
{
redraw-screen?:boolean <- equal *c, 12/ctrl-l
break-unless redraw-screen?
screen <- render-all screen, env:address:programming-environment-data
screen <- render-all screen, env:address:shared:programming-environment-data
sync-screen screen
loop +next-event:label
}
]
# dummy
recipe restore-sandboxes env:address:shared:programming-environment-data -> env:address:shared:programming-environment-data [
# do nothing; redefined later
]

View File

@ -5,33 +5,33 @@
# few other things.
container programming-environment-data [
sandbox:address:sandbox-data # list of sandboxes, from top to bottom
sandbox:address:shared:sandbox-data # list of sandboxes, from top to bottom
]
container sandbox-data [
data:address:array:character
response:address:array:character
expected-response:address:array:character
data:address:shared:array:character
response:address:shared:array:character
expected-response:address:shared:array:character
# coordinates to track clicks
starting-row-on-screen:number
code-ending-row-on-screen:number # past end of code
response-starting-row-on-screen:number
screen:address:screen # prints in the sandbox go here
next-sandbox:address:sandbox-data
screen:address:shared:screen # prints in the sandbox go here
next-sandbox:address:shared:sandbox-data
]
scenario run-and-show-results [
trace-until 100/app # trace too long
assume-screen 50/width, 15/height
# sandbox editor contains an instruction without storing outputs
1:address:array:character <- new [divide-with-remainder 11, 3]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new [divide-with-remainder 11, 3]
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run the code in the editors
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# check that screen prints the results
screen-should-contain [
@ -74,7 +74,7 @@ scenario run-and-show-results [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# check that screen prints both sandboxes
screen-should-contain [
@ -99,14 +99,14 @@ after <global-keypress> [
{
do-run?:boolean <- equal *k, 65532/F4
break-unless do-run?
status:address:array:character <- new [running... ]
status:address:shared:array:character <- new [running... ]
screen <- update-status screen, status, 245/grey
error?:boolean, env, screen <- run-sandboxes env, screen
# F4 might update warnings and results on both sides
screen <- render-all screen, env
{
break-if error?
status:address:array:character <- new [ ]
status:address:shared:array:character <- new [ ]
screen <- update-status screen, status, 245/grey
}
screen <- update-cursor screen, current-sandbox
@ -114,36 +114,36 @@ after <global-keypress> [
}
]
recipe run-sandboxes env:address:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
errors-found?:boolean, env, screen <- update-recipes env, screen
reply-if errors-found?
# check contents of editor
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
{
sandbox-contents:address:array:character <- editor-contents current-sandbox
sandbox-contents:address:shared:array:character <- editor-contents current-sandbox
break-unless sandbox-contents
# if contents exist, first save them
# run them and turn them into a new sandbox-data
new-sandbox:address:sandbox-data <- new sandbox-data:type
data:address:address:array:character <- get-address *new-sandbox, data:offset
new-sandbox:address:shared:sandbox-data <- new sandbox-data:type
data:address:address:shared:array:character <- get-address *new-sandbox, data:offset
*data <- copy sandbox-contents
# push to head of sandbox list
dest:address:address:sandbox-data <- get-address *env, sandbox:offset
next:address:address:sandbox-data <- get-address *new-sandbox, next-sandbox:offset
dest:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
next:address:address:shared:sandbox-data <- get-address *new-sandbox, next-sandbox:offset
*next <- copy *dest
*dest <- copy new-sandbox
# clear sandbox editor
init:address:address:duplex-list:character <- get-address *current-sandbox, data:offset
init:address:address:shared:duplex-list:character <- get-address *current-sandbox, data:offset
*init <- push 167/§, 0/tail
top-of-screen:address:address:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
top-of-screen:address:address:shared:duplex-list:character <- get-address *current-sandbox, top-of-screen:offset
*top-of-screen <- copy *init
}
# save all sandboxes before running, just in case we die when running
save-sandboxes env
# run all sandboxes
curr:address:sandbox-data <- get *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
{
break-unless curr
curr <- update-sandbox curr, env
@ -155,47 +155,47 @@ recipe run-sandboxes env:address:programming-environment-data, screen:address:sc
# load code from recipes.mu
# replaced in a later layer (whereupon errors-found? will actually be set)
recipe update-recipes env:address:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
in:address:array:character <- restore [recipes.mu] # newlayer: persistence
in:address:shared:array:character <- restore [recipes.mu] # newlayer: persistence
reload in
errors-found? <- copy 0/false
]
# replaced in a later layer
recipe update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe update-sandbox sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
*response, _, *fake-screen <- run-interactive data
]
recipe update-status screen:address:screen, msg:address:array:character, color:number -> screen:address:screen [
recipe 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:programming-environment-data [
recipe save-sandboxes env:address:shared:programming-environment-data [
local-scope
load-ingredients
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
# first clear previous versions, in case we deleted some sandbox
$system [rm lesson/[0-9]* >/dev/null 2>/dev/null] # some shells can't handle '>&'
curr:address:sandbox-data <- get *env, sandbox:offset
suffix:address:array:character <- new [.out]
curr:address:shared:sandbox-data <- get *env, sandbox:offset
suffix:address:shared:array:character <- new [.out]
idx:number <- copy 0
{
break-unless curr
data:address:array:character <- get *curr, data:offset
filename:address:array:character <- to-text idx
data:address:shared:array:character <- get *curr, data:offset
filename:address:shared:array:character <- to-text idx
save filename, data
{
expected-response:address:array:character <- get *curr, expected-response:offset
expected-response:address:shared:array:character <- get *curr, expected-response:offset
break-unless expected-response
filename <- append filename, suffix
save filename, expected-response
@ -206,26 +206,26 @@ recipe save-sandboxes env:address:programming-environment-data [
}
]
recipe! render-sandbox-side screen:address:screen, env:address:programming-environment-data -> screen:address:screen [
recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:programming-environment-data -> screen:address:shared:screen [
local-scope
load-ingredients
trace 11, [app], [render sandbox side]
current-sandbox:address:editor-data <- get *env, current-sandbox:offset
current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset
left:number <- get *current-sandbox, left:offset
right:number <- get *current-sandbox, right:offset
row:number, column:number, screen, current-sandbox <- render screen, current-sandbox
clear-screen-from screen, row, column, left, right
row <- add row, 1
draw-horizontal screen, row, left, right, 9473/horizontal-double
sandbox:address:sandbox-data <- get *env, sandbox:offset
sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
row, screen <- render-sandboxes screen, sandbox, left, right, row, env
clear-rest-of-screen screen, row, left, left, right
]
recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, left:number, right:number, row:number -> row:number, screen:address:screen, sandbox:address:sandbox-data [
recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
env:address:programming-environment-data, _/optional <- next-ingredient
env:address:shared:programming-environment-data, _/optional <- next-ingredient
reply-unless sandbox
screen-height:number <- screen-height screen
at-bottom?:boolean <- greater-or-equal row, screen-height
@ -242,16 +242,16 @@ recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, lef
# render sandbox contents
row <- add row, 1
screen <- move-cursor screen, row, left
sandbox-data:address:array:character <- get *sandbox, data:offset
sandbox-data:address:shared:array:character <- get *sandbox, data:offset
row, screen <- render-code screen, sandbox-data, left, right, row
code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset
*code-ending-row <- copy row
# render sandbox warnings, screen or response, in that order
response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset
sandbox-response:address:array:character <- get *sandbox, response:offset
sandbox-response:address:shared:array:character <- get *sandbox, response:offset
<render-sandbox-results>
{
sandbox-screen:address:screen <- get *sandbox, screen:offset
sandbox-screen:address:shared:screen <- get *sandbox, screen:offset
empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen
break-if empty-screen?
row, screen <- render-screen screen, sandbox-screen, left, right, row
@ -268,32 +268,32 @@ recipe render-sandboxes screen:address:screen, sandbox:address:sandbox-data, lef
# draw solid line after sandbox
draw-horizontal screen, row, left, right, 9473/horizontal-double
# draw next sandbox
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
row, screen <- render-sandboxes screen, next-sandbox, left, right, row
]
# assumes programming environment has no sandboxes; restores them from previous session
recipe restore-sandboxes env:address:programming-environment-data -> env:address:programming-environment-data [
recipe! 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
suffix:address:array:character <- new [.out]
suffix:address:shared:array:character <- new [.out]
idx:number <- copy 0
curr:address:address:sandbox-data <- get-address *env, sandbox:offset
curr:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
{
filename:address:array:character <- to-text idx
contents:address:array:character <- restore filename
filename:address:shared:array:character <- to-text idx
contents:address:shared:array:character <- restore filename
break-unless contents # stop at first error; assuming file didn't exist
# create new sandbox for file
*curr <- new sandbox-data:type
data:address:address:array:character <- get-address **curr, data:offset
data:address:address:shared:array:character <- get-address **curr, data:offset
*data <- copy contents
# restore expected output for sandbox if it exists
{
filename <- append filename, suffix
contents <- restore filename
break-unless contents
expected-response:address:address:array:character <- get-address **curr, expected-response:offset
expected-response:address:address:shared:array:character <- get-address **curr, expected-response:offset
*expected-response <- copy contents
}
+continue
@ -305,19 +305,19 @@ recipe restore-sandboxes env:address:programming-environment-data -> env:address
# print the fake sandbox screen to 'screen' with appropriate delimiters
# leave cursor at start of next line
recipe render-screen screen:address:screen, sandbox-screen:address:screen, left:number, right:number, row:number -> row:number, screen:address:screen [
recipe 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
# print 'screen:'
header:address:array:character <- new [screen:]
header:address:shared:array:character <- new [screen:]
row <- render screen, header, left, right, 245/grey, row
screen <- move-cursor screen, row, left
# start printing sandbox-screen
column:number <- copy left
s-width:number <- screen-width sandbox-screen
s-height:number <- screen-height sandbox-screen
buf:address:array:screen-cell <- get *sandbox-screen, data:offset
buf:address:shared:array:screen-cell <- get *sandbox-screen, data:offset
stop-printing:number <- add left, s-width, 3
max-column:number <- min stop-printing, right
i:number <- copy 0
@ -375,14 +375,14 @@ scenario run-instruction-manages-screen-per-sandbox [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
# editor contains an instruction
1:address:array:character <- new [print-integer screen, 4]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new [print-integer screen, 4]
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run the code in the editor
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# check that it prints a little toy screen
screen-should-contain [
@ -402,11 +402,11 @@ scenario run-instruction-manages-screen-per-sandbox [
]
]
recipe editor-contents editor:address:editor-data -> result:address:array:character [
recipe editor-contents editor:address:shared:editor-data -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:buffer <- new-buffer 80
curr:address:duplex-list:character <- get *editor, data:offset
buf:address:shared:buffer <- new-buffer 80
curr:address:shared:duplex-list:character <- get *editor, data:offset
# skip § sentinel
assert curr, [editor without data is illegal; must have at least a sentinel]
curr <- next curr
@ -423,16 +423,16 @@ recipe editor-contents editor:address:editor-data -> result:address:array:charac
scenario editor-provides-edited-contents [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
1:address:shared:array:character <- new [abc]
2:address:shared:editor-data <- new-editor 1:address:shared:array:character, screen:address:shared:screen, 0/left, 10/right
assume-console [
left-click 1, 2
type [def]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:address:array:character <- editor-contents 2:address:editor-data
4:array:character <- copy *3:address:array:character
editor-event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:editor-data
3:address:shared:array:character <- editor-contents 2:address:shared:editor-data
4:array:character <- copy *3:address:shared:array:character
]
memory-should-contain [
4:array:character <- [abdefc]

View File

@ -4,12 +4,12 @@ scenario clicking-on-a-sandbox-moves-it-to-editor [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# run something
1:address:array:character <- new [add 2, 2]
1:address:shared:array:character <- new [add 2, 2]
assume-console [
press F4
]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. .
@ -27,7 +27,7 @@ scenario clicking-on-a-sandbox-moves-it-to-editor [
left-click 3, 0
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# it pops back into editor
screen-should-contain [
@ -47,7 +47,7 @@ scenario clicking-on-a-sandbox-moves-it-to-editor [
type [0]
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -70,7 +70,7 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
@ -79,8 +79,8 @@ after <global-touch> [
empty-sandbox-editor?:boolean <- empty-editor? current-sandbox
break-unless empty-sandbox-editor? # make the user hit F4 before editing a new sandbox
# identify the sandbox to edit and remove it from the sandbox list
sandbox:address:sandbox-data <- extract-sandbox env, click-row
text:address:array:character <- get *sandbox, data:offset
sandbox:address:shared:sandbox-data <- extract-sandbox env, click-row
text:address:shared:array:character <- get *sandbox, data:offset
current-sandbox <- insert-text current-sandbox, text
hide-screen screen
screen <- render-sandbox-side screen, env
@ -90,24 +90,24 @@ after <global-touch> [
}
]
recipe empty-editor? editor:address:editor-data -> result:boolean [
recipe empty-editor? editor:address:shared:editor-data -> result:boolean [
local-scope
load-ingredients
head:address:duplex-list:character <- get *editor, data:offset
first:address:duplex-list:character <- next head
head:address:shared:duplex-list:character <- get *editor, data:offset
first:address:shared:duplex-list:character <- next head
result <- not first
]
recipe extract-sandbox env:address:programming-environment-data, click-row:number -> result:address:sandbox-data, env:address:programming-environment-data [
recipe 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
# assert click-row >= sandbox.starting-row-on-screen
sandbox:address:address:sandbox-data <- get-address *env, sandbox:offset
sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
start:number <- get **sandbox, starting-row-on-screen:offset
clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
{
next-sandbox:address:sandbox-data <- get **sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset
break-unless next-sandbox
# if click-row < sandbox.next-sandbox.starting-row-on-screen, break
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
@ -125,14 +125,14 @@ scenario sandbox-with-print-can-be-edited [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
# run a print instruction
1:address:array:character <- new [print-integer screen, 4]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new [print-integer screen, 4]
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run the sandbox
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -161,7 +161,7 @@ scenario sandbox-with-print-can-be-edited [
left-click 3, 70
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .

View File

@ -3,8 +3,8 @@
scenario deleting-sandboxes [
trace-until 100/app # trace too long
assume-screen 50/width, 15/height
1:address:array:character <- new []
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new []
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run a few commands
assume-console [
left-click 1, 0
@ -13,7 +13,7 @@ scenario deleting-sandboxes [
type [add 2, 2]
press F4
]
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. .
@ -34,7 +34,7 @@ scenario deleting-sandboxes [
left-click 7, 49
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -52,7 +52,7 @@ scenario deleting-sandboxes [
left-click 3, 49
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
@ -76,17 +76,17 @@ after <global-touch> [
}
]
recipe delete-sandbox t:touch-event, env:address:programming-environment-data -> was-delete?:boolean, env:address:programming-environment-data [
recipe 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:editor-data <- get *env, current-sandbox: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
click-row:number <- get t, row:offset
prev:address:address:sandbox-data <- get-address *env, sandbox:offset
curr:address:sandbox-data <- get *env, sandbox:offset
prev:address:address:shared:sandbox-data <- get-address *env, sandbox:offset
curr:address:shared:sandbox-data <- get *env, sandbox:offset
{
break-unless curr
# more sandboxes to check

View File

@ -10,14 +10,14 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
break-unless below-sandbox-editor?
# identify the sandbox whose output is being clicked on
sandbox:address:sandbox-data <- find-click-in-sandbox-output env, click-row
sandbox:address:shared:sandbox-data <- find-click-in-sandbox-output env, click-row
break-unless sandbox
# toggle its expected-response, and save session
sandbox <- toggle-expected-response sandbox
@ -31,17 +31,17 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-output env:address:programming-environment-data, click-row:number -> sandbox:address:sandbox-data [
recipe 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
sandbox:address:sandbox-data <- get *env, sandbox:offset
sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
start:number <- get *sandbox, starting-row-on-screen:offset
clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
# while click-row < sandbox.next-sandbox.starting-row-on-screen
{
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
break-unless next-sandbox
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
found?:boolean <- lesser-than click-row, next-start
@ -57,10 +57,10 @@ recipe find-click-in-sandbox-output env:address:programming-environment-data, cl
reply sandbox
]
recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe toggle-expected-response sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
expected-response:address:address:array:character <- get-address *sandbox, expected-response:offset
expected-response:address:address:shared:array:character <- get-address *sandbox, expected-response:offset
{
# if expected-response is set, reset
break-unless *expected-response
@ -68,7 +68,7 @@ recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:
reply sandbox/same-as-ingredient:0
}
# if not, current response is the expected response
response:address:array:character <- get *sandbox, response:offset
response:address:shared:array:character <- get *sandbox, response:offset
*expected-response <- copy response
]
@ -76,7 +76,7 @@ recipe toggle-expected-response sandbox:address:sandbox-data -> sandbox:address:
after <render-sandbox-response> [
{
break-unless sandbox-response
expected-response:address:array:character <- get *sandbox, expected-response:offset
expected-response:address:shared:array:character <- get *sandbox, expected-response:offset
break-unless expected-response # fall-through to print in grey
response-is-expected?:boolean <- equal expected-response, sandbox-response
{

View File

@ -4,12 +4,12 @@ scenario sandbox-click-on-code-toggles-app-trace [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# run a stash instruction
1:address:array:character <- new [stash [abc]]
1:address:shared:array:character <- new [stash [abc]]
assume-console [
press F4
]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. .
@ -24,9 +24,9 @@ scenario sandbox-click-on-code-toggles-app-trace [
left-click 4, 21
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
4:character/cursor-icon <- copy 9251/␣
print screen:address:screen, 4:character/cursor-icon
print screen:address:shared:screen, 4:character/cursor-icon
]
# trace now printed and cursor shouldn't have budged
screen-should-contain [
@ -54,8 +54,8 @@ scenario sandbox-click-on-code-toggles-app-trace [
left-click 4, 25
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
print screen:address:screen, 4:character/cursor-icon
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
print screen:address:shared:screen, 4:character/cursor-icon
]
# trace hidden again
screen-should-contain [
@ -73,13 +73,13 @@ scenario sandbox-shows-app-trace-and-result [
trace-until 100/app # trace too long
assume-screen 40/width, 10/height
# run a stash instruction and some code
1:address:array:character <- new [stash [abc]
1:address:shared:array:character <- new [stash [abc]
add 2, 2]
assume-console [
press F4
]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
screen-should-contain [
. run (F4) .
. .
@ -96,7 +96,7 @@ add 2, 2]
left-click 4, 21
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# trace now printed above result
screen-should-contain [
@ -114,18 +114,18 @@ add 2, 2]
]
container sandbox-data [
trace:address:array:character
trace:address:shared:array:character
display-trace?:boolean
]
# replaced in a later layer
recipe! update-sandbox sandbox:address:sandbox-data -> sandbox:address:sandbox-data [
recipe! update-sandbox sandbox:address:shared:sandbox-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
trace:address:address:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
trace:address:address:shared:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
*response, _, *fake-screen, *trace <- run-interactive data
]
@ -137,14 +137,14 @@ after <global-touch> [
click-column:number <- get *t, column:offset
on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
break-unless on-sandbox-side?
first-sandbox:address:sandbox-data <- get *env, sandbox:offset
first-sandbox:address:shared:sandbox-data <- get *env, sandbox:offset
break-unless first-sandbox
first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
click-row:number <- get *t, row:offset
below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
break-unless below-sandbox-editor?
# identify the sandbox whose code is being clicked on
sandbox:address:sandbox-data <- find-click-in-sandbox-code env, click-row
sandbox:address:shared:sandbox-data <- find-click-in-sandbox-code env, click-row
break-unless sandbox
# toggle its display-trace? property
x:address:boolean <- get-address *sandbox, display-trace?:offset
@ -158,7 +158,7 @@ after <global-touch> [
}
]
recipe find-click-in-sandbox-code env:address:programming-environment-data, click-row:number -> sandbox:address:sandbox-data [
recipe 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
@ -168,7 +168,7 @@ recipe find-click-in-sandbox-code env:address:programming-environment-data, clic
assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
# while click-row < sandbox.next-sandbox.starting-row-on-screen
{
next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset
break-unless next-sandbox
next-start:number <- get *next-sandbox, starting-row-on-screen:offset
found?:boolean <- lesser-than click-row, next-start
@ -194,7 +194,7 @@ after <render-sandbox-results> [
{
display-trace?:boolean <- get *sandbox, display-trace?:offset
break-unless display-trace?
sandbox-trace:address:array:character <- get *sandbox, trace:offset
sandbox-trace:address:shared:array:character <- get *sandbox, trace:offset
break-unless sandbox-trace # nothing to print; move on
row, screen <- render screen, sandbox-trace, left, right, 245/grey, row
}

View File

@ -1,20 +1,20 @@
## handling malformed programs
container programming-environment-data [
recipe-warnings:address:array:character
recipe-warnings:address:shared:array:character
]
# copy code from recipe editor, persist, load into mu, save any warnings
recipe! update-recipes env:address:programming-environment-data, screen:address:screen -> errors-found?:boolean, env:address:programming-environment-data, screen:address:screen [
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 [
local-scope
load-ingredients
in:address:array:character <- restore [recipes.mu]
recipe-warnings:address:address:array:character <- get-address *env, recipe-warnings:offset
in:address:shared:array:character <- restore [recipes.mu]
recipe-warnings:address:address:shared:array:character <- get-address *env, recipe-warnings:offset
*recipe-warnings <- reload in
# if recipe editor has errors, stop
{
break-unless *recipe-warnings
status:address:array:character <- new [errors found]
status:address:shared:array:character <- new [errors found]
update-status screen, status, 1/red
}
errors-found? <- copy 0/false
@ -22,27 +22,27 @@ recipe! update-recipes env:address:programming-environment-data, screen:address:
before <render-components-end> [
trace 11, [app], [render status]
recipe-warnings:address:array:character <- get *env, recipe-warnings:offset
recipe-warnings:address:shared:array:character <- get *env, recipe-warnings:offset
{
break-unless recipe-warnings
status:address:array:character <- new [errors found]
status:address:shared:array:character <- new [errors found]
update-status screen, status, 1/red
}
]
container sandbox-data [
warnings:address:array:character
warnings:address:shared:array:character
]
recipe! update-sandbox sandbox:address:sandbox-data, env:address:programming-environment-data -> sandbox:address:sandbox-data [
recipe! update-sandbox sandbox:address:shared:sandbox-data, env:address:shared:programming-environment-data -> sandbox:address:shared:sandbox-data [
local-scope
load-ingredients
data:address:array:character <- get *sandbox, data:offset
response:address:address:array:character <- get-address *sandbox, response:offset
warnings:address:address:array:character <- get-address *sandbox, warnings:offset
trace:address:address:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:screen <- get-address *sandbox, screen:offset
recipe-warnings:address:array:character <- get *env, recipe-warnings:offset
data:address:shared:array:character <- get *sandbox, data:offset
response:address:address:shared:array:character <- get-address *sandbox, response:offset
warnings:address:address:shared:array:character <- get-address *sandbox, warnings:offset
trace:address:address:shared:array:character <- get-address *sandbox, trace:offset
fake-screen:address:address:shared:screen <- get-address *sandbox, screen:offset
recipe-warnings:address:shared:array:character <- get *env, recipe-warnings:offset
{
break-unless recipe-warnings
*warnings <- copy recipe-warnings
@ -60,12 +60,12 @@ recipe! update-sandbox sandbox:address:sandbox-data, env:address:programming-env
# make sure we render any trace
after <render-sandbox-trace-done> [
{
sandbox-warnings:address:array:character <- get *sandbox, warnings:offset
sandbox-warnings:address:shared:array:character <- get *sandbox, warnings:offset
break-unless sandbox-warnings
*response-starting-row <- copy 0 # no response
{
break-unless env
recipe-warnings:address:array:character <- get *env, recipe-warnings:offset
recipe-warnings:address:shared:array:character <- get *env, recipe-warnings:offset
row, screen <- render screen, recipe-warnings, left, right, 1/red, row
}
row, screen <- render screen, sandbox-warnings, left, right, 1/red, row
@ -77,22 +77,22 @@ after <render-sandbox-trace-done> [
scenario run-instruction-and-print-warnings [
trace-until 100/app # trace too long
assume-screen 50/width, 15/height
1:address:array:character <- new [get 1:address:point, 1:offset]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new [get 1:address:shared:point, 1:offset]
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .
. .
.━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. x.
.get 1:address:point, 1:offset .
.get 1:address:shared:point, 1:offset .
.first ingredient of 'get' should be a container, ↩.
.but got 1:address:point .
.but got 1:address:shared:point .
.━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
. .
]
@ -103,7 +103,7 @@ scenario run-instruction-and-print-warnings [
. .
. .
.first ingredient of 'get' should be a container, .
.but got 1:address:point .
.but got 1:address:shared:point .
. .
. .
]
@ -115,15 +115,15 @@ scenario run-instruction-and-print-warnings-only-once [
trace-until 100/app # trace too long
assume-screen 50/width, 10/height
# editor contains an illegal instruction
1:address:array:character <- new [get 1234:number, foo:offset]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
1:address:shared:array:character <- new [get 1234:number, foo:offset]
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run the code in the editors multiple times
assume-console [
press F4
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
# check that screen prints error message just once
screen-should-contain [
@ -144,16 +144,16 @@ scenario sandbox-can-handle-infinite-loop [
trace-until 100/app # trace too long
assume-screen 50/width, 20/height
# editor contains an infinite loop
1:address:array:character <- new [{
1:address:shared:array:character <- new [{
loop
}]
2:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character
2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character
# run the sandbox
assume-console [
press F4
]
run [
event-loop screen:address:screen, console:address:console, 2:address:programming-environment-data
event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data
]
screen-should-contain [
. run (F4) .

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,8 @@ recipe main [
wait-for-event 0/console
clear-screen 0/screen
move-cursor 0/screen, 0/row, 4/column
print 0/screen, 98/b
10:character <- copy 98/b
print 0/screen, 10:character
wait-for-event 0/console
move-cursor 0/screen, 0/row, 0/column
clear-line 0/screen