diff options
author | Kartik Agaram <vc@akkartik.com> | 2018-06-15 22:16:09 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2018-06-15 22:16:09 -0700 |
commit | ce9b2b0515eaf92a9c68c8608fd9bf392c941d50 (patch) | |
tree | eb1899f86308c712e54ef94a1c85243c26621c45 | |
parent | 0edd9b9fc60440213e4df926ea511419ee291f1e (diff) | |
download | mu-ce9b2b0515eaf92a9c68c8608fd9bf392c941d50.tar.gz |
4258 - undo 4257
38 files changed, 381 insertions, 757 deletions
diff --git a/020run.cc b/020run.cc index 0bba6bb2..3739ad2c 100644 --- a/020run.cc +++ b/020run.cc @@ -87,12 +87,6 @@ void run_current_routine() { // Primitive Recipe Implementations case COPY: { copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); - for (int i = 0; i < SIZE(current_instruction().products); ++i) { - if (is_mu_scalar(current_instruction().products.at(i)) && is_mu_address(current_instruction().ingredients.at(i))) - products.at(i).erase(products.at(i).begin()); // ignore alloc id - if (is_mu_address(current_instruction().products.at(i)) && is_mu_scalar(current_instruction().ingredients.at(i))) - products.at(i).insert(products.at(i).begin(), /*alloc id*/0); - } break; } // End Primitive Recipe Implementations @@ -202,7 +196,7 @@ if (argc > 1) { } transform_all(); //? cerr << to_original_string(get(Type_ordinal, "editor")) << '\n'; -//? cerr << to_original_string(get(Recipe, get(Recipe_ordinal, "handle-keyboard-event"))) << '\n'; +//? cerr << to_original_string(get(Recipe, get(Recipe_ordinal, "event-loop"))) << '\n'; //? DUMP(""); //? exit(0); if (trace_contains_errors()) { @@ -347,9 +341,8 @@ void write_memory(reagent/*copy*/ x, const vector<double>& data) { } :(code) -int size_of(reagent/*copy*/ r) { +int size_of(const reagent& r) { if (!r.type) return 0; - // Begin size_of(reagent r) Special-cases // End size_of(reagent r) Special-cases return size_of(r.type); } @@ -358,7 +351,6 @@ int size_of(const type_tree* type) { if (type->atom) { if (type->value == -1) return 1; // error value, but we'll raise it elsewhere if (type->value == 0) return 1; -//? if (type->value == Address_type_ordinal) return 2; // address and alloc id // End size_of(type) Atom Special-cases } else { @@ -366,7 +358,7 @@ int size_of(const type_tree* type) { raise << "invalid type " << to_string(type) << '\n' << end(); return 0; } - if (type->left->value == Address_type_ordinal) return 2; // address and alloc id + if (type->left->value == Address_type_ordinal) return 1; // End size_of(type) Non-atom Special-cases } // End size_of(type) Special-cases diff --git a/021check_instruction.cc b/021check_instruction.cc index 4bba31e5..d7628008 100644 --- a/021check_instruction.cc +++ b/021check_instruction.cc @@ -112,9 +112,8 @@ def main [ :(code) // types_match with some leniency -bool types_coercible(reagent/*copy*/ to, reagent/*copy*/ from) { - // Begin types_coercible(reagent to, reagent from) - if (types_match_sub(to, from)) return true; +bool types_coercible(const reagent& to, const reagent& from) { + if (types_match(to, from)) return true; if (is_mu_address(from) && is_real_mu_number(to)) return true; if (is_mu_boolean(from) && is_real_mu_number(to)) return true; if (is_real_mu_number(from) && is_mu_character(to)) return true; @@ -122,11 +121,10 @@ bool types_coercible(reagent/*copy*/ to, reagent/*copy*/ from) { return false; } -bool types_match_sub(const reagent& to, const reagent& from) { +bool types_match(const reagent& to, const reagent& from) { // to sidestep type-checking, use /unsafe in the source. // this will be highlighted in red inside vim. just for setting up some tests. if (is_unsafe(from)) return true; - if (is_literal(from)) { if (is_mu_array(to)) return false; // End Matching Types For Literal(to) @@ -136,16 +134,12 @@ bool types_match_sub(const reagent& to, const reagent& from) { if (is_mu_boolean(to)) return from.name == "0" || from.name == "1"; return size_of(to) == 1; // literals are always scalars } - return types_strictly_match_sub(to, from); -} -// variant for others to call -bool types_match(reagent/*copy*/ to, reagent/*copy*/ from) { - // Begin types_match(reagent to, reagent from) - return types_match_sub(to, from); + return types_strictly_match(to, from); } //: copy arguments for later layers -bool types_strictly_match_sub(const reagent& to, const reagent& from) { +bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) { + // End Preprocess types_strictly_match(reagent to, reagent from) if (to.type == NULL) return false; // error if (is_literal(from) && to.type->value == Number_type_ordinal) return true; // to sidestep type-checking, use /unsafe in the source. @@ -156,11 +150,6 @@ bool types_strictly_match_sub(const reagent& to, const reagent& from) { if (!to.type) return !from.type; return types_strictly_match(to.type, from.type); } -// variant for others to call -bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) { - // Begin types_strictly_match(reagent to, reagent from) - return types_strictly_match_sub(to, from); -} bool types_strictly_match(const type_tree* to, const type_tree* from) { if (from == to) return true; @@ -279,7 +268,7 @@ bool is_mu_scalar(reagent/*copy*/ r) { } bool is_mu_scalar(const type_tree* type) { if (!type) return false; - if (is_mu_address(type)) return false; + if (is_mu_address(type)) return true; if (!type->atom) return false; if (is_literal(type)) return type->name != "literal-string"; diff --git a/022arithmetic.cc b/022arithmetic.cc index 50a54578..530541aa 100644 --- a/022arithmetic.cc +++ b/022arithmetic.cc @@ -95,25 +95,18 @@ case SUBTRACT: { } break; } -:(code) -bool is_raw(const reagent& r) { - return has_property(r, "raw"); -} - :(before "End Primitive Recipe Implementations") case SUBTRACT: { - double result = scalar_ingredient(ingredients, 0); + double result = ingredients.at(0).at(0); for (int i = 1; i < SIZE(ingredients); ++i) - result -= scalar_ingredient(ingredients, i); + result -= ingredients.at(i).at(0); products.resize(1); products.at(0).push_back(result); break; } :(code) -double scalar_ingredient(const vector<vector<double> >& ingredients, int i) { - if (is_mu_address(current_instruction().ingredients.at(i))) - return ingredients.at(i).at(1); // skip alloc id - return ingredients.at(i).at(0); +bool is_raw(const reagent& r) { + return has_property(r, "raw"); } :(scenario subtract_literal) diff --git a/023boolean.cc b/023boolean.cc index 976cbff9..3d51fd7a 100644 --- a/023boolean.cc +++ b/023boolean.cc @@ -26,7 +26,7 @@ case AND: { case AND: { bool result = true; for (int i = 0; i < SIZE(ingredients); ++i) - result = result && scalar_ingredient(ingredients, i); + result = result && ingredients.at(i).at(0); products.resize(1); products.at(0).push_back(result); break; @@ -84,7 +84,7 @@ case OR: { case OR: { bool result = false; for (int i = 0; i < SIZE(ingredients); ++i) - result = result || scalar_ingredient(ingredients, i); + result = result || ingredients.at(i).at(0); products.resize(1); products.at(0).push_back(result); break; @@ -127,8 +127,8 @@ case NOT: { break; } for (int i = 0; i < SIZE(inst.ingredients); ++i) { - if (!is_mu_scalar(inst.ingredients.at(i)) && !is_mu_address(inst.ingredients.at(i))) { - raise << maybe(get(Recipe, r).name) << "'not' requires ingredients that can be interpreted as boolean, but got '" << inst.ingredients.at(i).original_string << "'\n" << end(); + if (!is_mu_scalar(inst.ingredients.at(i))) { + raise << maybe(get(Recipe, r).name) << "'not' requires boolean ingredients, but got '" << inst.ingredients.at(i).original_string << "'\n" << end(); goto finish_checking_instruction; } } @@ -145,7 +145,7 @@ case NOT: { case NOT: { products.resize(SIZE(ingredients)); for (int i = 0; i < SIZE(ingredients); ++i) { - products.at(i).push_back(!scalar_ingredient(ingredients, i)); + products.at(i).push_back(!ingredients.at(i).at(0)); } break; } diff --git a/024jump.cc b/024jump.cc index b7011c09..37011290 100644 --- a/024jump.cc +++ b/024jump.cc @@ -72,7 +72,7 @@ case JUMP_IF: { raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end(); break; } - if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) { + if (!is_mu_scalar(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end(); break; } @@ -90,7 +90,7 @@ case JUMP_IF: { :(before "End Primitive Recipe Implementations") case JUMP_IF: { assert(current_instruction().ingredients.at(1).initialized); - if (!scalar_ingredient(ingredients, 0)) { + if (!ingredients.at(0).at(0)) { trace(9998, "run") << "jump-if fell through" << end(); break; } @@ -109,7 +109,7 @@ def main [ ] +run: jump-if {999: "literal"}, {1: "offset"} +run: jumping to instruction 2 --run: {123: "number"} <- copy {1: "literal"} +-run: {1: "number"} <- copy {1: "literal"} -mem: storing 1 in location 123 :(scenario jump_if_fallthrough) @@ -122,17 +122,6 @@ def main [ +run: {123: "number"} <- copy {1: "literal"} +mem: storing 1 in location 123 -:(scenario jump_if_on_address) -def main [ - 10:&:num <- copy 999/unsafe - jump-if 10:&:number, 1:offset - 123:num <- copy 1 -] -+run: jump-if {10: ("address" "number")}, {1: "offset"} -+run: jumping to instruction 3 --run: {123: "number"} <- copy {1: "literal"} --mem: storing 1 in location 123 - :(before "End Primitive Recipe Declarations") JUMP_UNLESS, :(before "End Primitive Recipe Numbers") @@ -143,7 +132,7 @@ case JUMP_UNLESS: { raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' should get exactly two ingredients\n" << end(); break; } - if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) { + if (!is_mu_scalar(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "'" << to_original_string(inst) << "' requires a boolean for its first ingredient, but '" << inst.ingredients.at(0).name << "' has type '" << names_to_string_without_quotes(inst.ingredients.at(0).type) << "'\n" << end(); break; } @@ -161,7 +150,7 @@ case JUMP_UNLESS: { :(before "End Primitive Recipe Implementations") case JUMP_UNLESS: { assert(current_instruction().ingredients.at(1).initialized); - if (scalar_ingredient(ingredients, 0)) { + if (ingredients.at(0).at(0)) { trace(9998, "run") << "jump-unless fell through" << end(); break; } diff --git a/025compare.cc b/025compare.cc index c82f3578..92878208 100644 --- a/025compare.cc +++ b/025compare.cc @@ -29,8 +29,6 @@ case EQUAL: { } :(before "End Primitive Recipe Implementations") case EQUAL: { - // todo: keep the address exception from slowing down the common case - drop_alloc_ids_if_comparing_address_to_literal_0(ingredients); vector<double>& exemplar = ingredients.at(0); bool result = true; for (int i = /*skip exemplar*/1; i < SIZE(ingredients); ++i) { @@ -43,23 +41,6 @@ case EQUAL: { products.at(0).push_back(result); break; } -:(code) -void drop_alloc_ids_if_comparing_address_to_literal_0(vector<vector<double> >& ingredients) { - bool any_ingredient_is_null = false; - bool any_ingredient_is_address = false; - for (int i = 0; i < SIZE(current_instruction().ingredients); ++i) { - if (current_instruction().ingredients.at(i).name == "0") - any_ingredient_is_null = true; - if (is_mu_address(current_instruction().ingredients.at(i))) - any_ingredient_is_address = true; - } - if (any_ingredient_is_null && any_ingredient_is_address) { - for (int i = 0; i < SIZE(ingredients); ++i) { - if (is_mu_address(current_instruction().ingredients.at(i))) - ingredients.at(i).erase(ingredients.at(i).begin()); - } - } -} :(scenario equal) def main [ @@ -93,42 +74,6 @@ def main [ ] +mem: storing 0 in location 1 -:(scenario equal_address_null) -def main [ - 1:&:num <- copy 0 - 10:bool <- equal 1:&:num, 0 -] -+mem: storing 1 in location 10 - -:(scenario equal_address_null_2) -def main [ - 1:&:num <- copy 0 - 10:bool <- equal 0, 1:&:num -] -+mem: storing 1 in location 10 - -:(scenario equal_address_null_3) -def main [ - 1:&:num <- new num:type - 10:bool <- equal 1:&:num, 0 -] -+mem: storing 0 in location 10 - -:(scenario equal_address_null_multiple) -def main [ - 1:&:num <- copy 0 - 10:bool <- equal 0, 1:&:num, 0 -] -+mem: storing 1 in location 10 - -:(scenario equal_address_null_multiple_2) -def main [ - 1:&:num <- copy 0 - 3:&:num <- copy 0 - 10:bool <- equal 0, 1:&:num, 0, 3:&:num -] -+mem: storing 1 in location 10 - :(before "End Primitive Recipe Declarations") NOT_EQUAL, :(before "End Primitive Recipe Numbers") @@ -156,8 +101,6 @@ case NOT_EQUAL: { } :(before "End Primitive Recipe Implementations") case NOT_EQUAL: { - // todo: keep the address exception from slowing down the common case - drop_alloc_ids_if_comparing_address_to_literal_0(ingredients); vector<double>& exemplar = ingredients.at(0); products.resize(1); bool equal_ingredients = equal(ingredients.at(1).begin(), ingredients.at(1).end(), exemplar.begin()); diff --git a/027call_ingredient.cc b/027call_ingredient.cc index 00e44ea3..46fafe7e 100644 --- a/027call_ingredient.cc +++ b/027call_ingredient.cc @@ -68,9 +68,6 @@ case NEXT_INGREDIENT: { } products.push_back( current_call().ingredient_atoms.at(current_call().next_ingredient_to_process)); - if (is_mu_scalar(current_call().ingredients.at(current_call().next_ingredient_to_process)) - && is_mu_address(current_instruction().products.at(0))) - products.at(0).insert(products.at(0).begin(), /*alloc id*/0); assert(SIZE(products) == 1); products.resize(2); // push a new vector products.at(1).push_back(1); ++current_call().next_ingredient_to_process; @@ -97,18 +94,6 @@ def f [ ] +error: f: no ingredient to save in '11:num' -:(scenario pass_null_ingredient_for_address) -def main [ - f 0 -] -def f [ - 1:address:num <- next-ingredient -] -+mem: storing 0 in location 2 -$error: 0 - -//: another primitive: 'rewind-ingredients' to rescan ingredients from the start - :(scenario rewind_ingredients) def main [ f 2 @@ -139,8 +124,6 @@ case REWIND_INGREDIENTS: { break; } -//: another primitive: 'ingredient' for random access - :(scenario ingredient) def main [ f 1, 2 diff --git a/028call_return.cc b/028call_return.cc index aa5cb584..c8c1bca6 100644 --- a/028call_return.cc +++ b/028call_return.cc @@ -52,10 +52,6 @@ case RETURN: { trace(9998, "run") << "result " << i << " is " << to_string(ingredients.at(i)) << end(); // make return products available to caller copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); - for (int i = 0; i < SIZE(current_instruction().products); ++i) { - if (is_mu_address(current_instruction().products.at(i)) && scalar(ingredients.at(i))) - products.at(i).insert(products.at(i).begin(), /*alloc id*/0); - } // End Return break; // continue to process rest of *caller* instruction } diff --git a/030container.cc b/030container.cc index b722e711..f4aaafd4 100644 --- a/030container.cc +++ b/030container.cc @@ -7,16 +7,14 @@ get_or_insert(Type, point); // initialize get(Type, point).kind = CONTAINER; get(Type, point).name = "point"; get(Type, point).elements.push_back(reagent("x:number")); -get(Type, point).elements.back().set_value(0); get(Type, point).elements.push_back(reagent("y:number")); -get(Type, point).elements.back().set_value(1); //: Containers can be copied around with a single instruction just like //: numbers, no matter how large they are. //: Tests in this layer often explicitly set up memory before reading it as a -//: container. Don't do this in general. I'm tagging exceptions with /unsafe to -//: skip later checks. +//: container. Don't do this in general. I'm tagging such cases with /unsafe; +//: they'll be exceptions to later checks. :(scenario copy_multiple_locations) def main [ 1:num <- copy 34 @@ -42,9 +40,7 @@ get_or_insert(Type, point_number); // initialize get(Type, point_number).kind = CONTAINER; get(Type, point_number).name = "point-number"; get(Type, point_number).elements.push_back(reagent("xy:point")); -get(Type, point_number).elements.back().set_value(0); get(Type, point_number).elements.push_back(reagent("z:number")); -get(Type, point_number).elements.back().set_value(1); :(scenario copy_handles_nested_container_elements) def main [ @@ -131,10 +127,6 @@ def main [ //: 'get' takes a 'base' container and an 'offset' into it and returns the //: appropriate element of the container value. -//: The offset is different from the distance (in memory locations) an element -//: is at from the start. This is because elements can occupy multiple memory -//: locations in the container. - :(scenario get) def main [ 12:num <- copy 34 @@ -203,7 +195,9 @@ case GET: { // Update GET base_type in Run int offset = ingredients.at(1).at(0); if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break; // copied from Check above - int src = element_location(base_address, offset, base.type); + int src = base_address; + for (int i = 0; i < offset; ++i) + src += size_of(element_type(base.type, i)); trace(9998, "run") << "address to copy is " << src << end(); //: use base.type rather than base_type because later layers will introduce compound types reagent/*copy*/ element = element_type(base.type, offset); @@ -228,12 +222,6 @@ const reagent element_type(const type_tree* type, int offset_value) { // End element_type Special-cases return element; } -int element_location(int base_address, int offset, const type_tree* type) { - int result = base_address; - for (int i = 0; i < offset; ++i) - result += size_of(element_type(type, i)); - return result; -} :(scenario get_handles_nested_container_elements) def main [ @@ -364,17 +352,14 @@ case PUT: { // Update PUT base_type in Run int offset = ingredients.at(1).at(0); if (offset < 0 || offset >= SIZE(get(Type, base_type->value).elements)) break; // copied from Check above - int address = element_location(base_address, offset, base.type); + int address = base_address; + for (int i = 0; i < offset; ++i) + address += size_of(element_type(base.type, i)); trace(9998, "run") << "address to copy to is " << address << end(); // optimization: directly write the element rather than updating 'product' // and writing the entire container // Write Memory in PUT in Run write_products = false; - if (is_mu_address(element_type(base.type, offset)) && is_literal(current_instruction().ingredients.at(2)) && current_instruction().ingredients.at(2).name == "0") { - trace("mem") << "storing 0 in location " << address << end(); - put(Memory, address, /*alloc id*/0); - ++address; - } for (int i = 0; i < SIZE(ingredients.at(2)); ++i) { trace("mem") << "storing " << no_scientific(ingredients.at(2).at(i)) << " in location " << address+i << end(); put(Memory, address+i, ingredients.at(2).at(i)); @@ -392,23 +377,6 @@ def main [ ] +error: main: product of 'put' must be first ingredient '1:point', but got '3:point' -:(scenario put_null_address) -container foo [ - x:num - y:&:num - z:num -] -def main [ - 1:num <- copy 34 - 2:num <- copy 0 # alloc id - 3:num <- copy 1000 # pretend address - 4:num <- copy 36 - put 1:foo, y:offset, 0 -] -+run: put {1: "foo"}, {y: "offset"}, {0: "literal"} -+mem: storing 0 in location 2 -+mem: storing 0 in location 3 - //:: Allow containers to be defined in Mu code. :(scenarios load) @@ -522,7 +490,6 @@ void insert_container(const string& command, kind_of_type kind, istream& in) { break; } info.elements.push_back(reagent(element)); - info.elements.back().set_value(SIZE(info.elements)-1); expand_type_abbreviations(info.elements.back().type); // todo: use abbreviation before declaration replace_unknown_types_with_unique_ordinals(info.elements.back().type, info); trace(9993, "parse") << " element: " << to_string(info.elements.back()) << end(); diff --git a/032array.cc b/032array.cc index d893b529..3bde42fb 100644 --- a/032array.cc +++ b/032array.cc @@ -11,7 +11,7 @@ def main [ # create an array occupying locations 1 (for the size) and 2-4 (for the elements) 1:array:num:3 <- create-array ] -+run: creating array from 4 locations ++run: creating array of size 4 :(before "End Primitive Recipe Declarations") CREATE_ARRAY, @@ -60,7 +60,7 @@ case CREATE_ARRAY: { trace("mem") << "storing " << array_length << " in location " << base_address << end(); put(Memory, base_address, array_length); // in array elements int size = size_of(product); // in locations - trace(9998, "run") << "creating array from " << size << " locations" << end(); + trace(9998, "run") << "creating array of size " << size << end(); // initialize array for (int i = 1; i <= size_of(product); ++i) put(Memory, base_address+i, 0); @@ -208,23 +208,19 @@ def main [ 2:num <- copy 14 3:num <- copy 15 4:num <- copy 16 - 10:num <- index 1:array:num:3, 0/index # the index must be a non-negative whole number + 5:num <- index 1:array:num:3, 0/index # the index must be a non-negative whole number ] -+mem: storing 14 in location 10 ++mem: storing 14 in location 5 :(scenario index_compound_element) def main [ {1: (array (address number) 3)} <- create-array - # skip alloc id - 3:num <- copy 14 - # skip alloc id - 5:num <- copy 15 - # skip alloc id - 7:num <- copy 16 - 10:address:num <- index {1: (array (address number) 3)}, 0 + 2:num <- copy 14 + 3:num <- copy 15 + 4:num <- copy 16 + 5:address:num <- index {1: (array (address number) 3)}, 0 ] -# skip alloc id -+mem: storing 14 in location 11 ++mem: storing 14 in location 5 :(scenario index_direct_offset) def main [ @@ -232,10 +228,10 @@ def main [ 2:num <- copy 14 3:num <- copy 15 4:num <- copy 16 - 10:num <- copy 0 - 20:num <- index 1:array:num, 10:num + 5:num <- copy 0 + 6:num <- index 1:array:num, 5:num ] -+mem: storing 14 in location 20 ++mem: storing 14 in location 6 :(before "End Primitive Recipe Declarations") INDEX, @@ -350,38 +346,38 @@ def main [ 2:num <- copy 14 3:num <- copy 15 4:num <- copy 16 - 10:num <- index 1:array:num:3, 1.5 # non-whole number + 5:num <- index 1:array:num:3, 1.5 # non-whole number ] # fraction is truncated away -+mem: storing 15 in location 10 ++mem: storing 15 in location 5 :(scenario index_out_of_bounds) % Hide_errors = true; def main [ - 2:array:point:3 <- create-array - 3:num <- copy 14 - 4:num <- copy 15 - 5:num <- copy 16 - 6:num <- copy 17 - 7:num <- copy 18 - 8:num <- copy 19 - index 1:array:point:3/skip-alloc-id, 4 # less than size of array in locations, but larger than its length in elements + 1:array:num:3 <- create-array + 2:num <- copy 14 + 3:num <- copy 15 + 4:num <- copy 16 + 5:num <- copy 14 + 6:num <- copy 15 + 7:num <- copy 16 + index 1:array:num:3, 4 # less than size of array in locations, but larger than its length in elements ] -+error: main: invalid index 4 in 'index 1:array:point:3/skip-alloc-id, 4' ++error: main: invalid index 4 in 'index 1:array:num:3, 4' :(scenario index_out_of_bounds_2) % Hide_errors = true; def main [ - 2:array:point:3 <- create-array - 3:num <- copy 14 - 4:num <- copy 15 - 5:num <- copy 16 - 6:num <- copy 14 - 7:num <- copy 15 - 8:num <- copy 16 - index 1:array:point/skip-alloc-id, -1 + 1:array:point:3 <- create-array + 2:num <- copy 14 + 3:num <- copy 15 + 4:num <- copy 16 + 5:num <- copy 14 + 6:num <- copy 15 + 7:num <- copy 16 + index 1:array:point, -1 ] -+error: main: invalid index -1 in 'index 1:array:point/skip-alloc-id, -1' ++error: main: invalid index -1 in 'index 1:array:point, -1' :(scenario index_product_type_mismatch) % Hide_errors = true; diff --git a/033exclusive_container.cc b/033exclusive_container.cc index e4fa6398..44161d7c 100644 --- a/033exclusive_container.cc +++ b/033exclusive_container.cc @@ -12,14 +12,12 @@ get_or_insert(Type, tmp); // initialize get(Type, tmp).kind = EXCLUSIVE_CONTAINER; get(Type, tmp).name = "number-or-point"; get(Type, tmp).elements.push_back(reagent("i:number")); -get(Type, tmp).elements.back().set_value(0); get(Type, tmp).elements.push_back(reagent("p:point")); -get(Type, tmp).elements.back().set_value(1); } -//: Tests in this layer often explicitly set up memory before reading it as an -//: array. Don't do this in general. I'm tagging exceptions with /raw to keep -//: checks in future layers from flagging them. +//: Tests in this layer often explicitly set up memory before reading it as a +//: container. Don't do this in general. I'm tagging such cases with /unsafe; +//: they'll be exceptions to later checks. :(scenario copy_exclusive_container) # Copying exclusive containers copies all their contents and an extra location for the tag. def main [ diff --git a/034address.cc b/034address.cc index 94c930bd..bce51b2e 100644 --- a/034address.cc +++ b/034address.cc @@ -18,37 +18,6 @@ //: write to the payload of an ingredient rather than its value, simply add //: the /lookup property to it. Modern computers provide efficient support for //: addresses and lookups, making this a realistic feature. -//: -//: To create addresses and allocate memory exclusively for their use, use -//: 'new'. Memory is a finite resource so if the computer can't satisfy your -//: request, 'new' may return a 0 (null) address. -//: -//: Computers these days have lots of memory so in practice we can often -//: assume we'll never run out. If you start running out however, say in a -//: long-running program, you'll need to switch mental gears and start -//: husbanding our memory more carefully. The most important tool to avoid -//: wasting memory is to 'abandon' an address when you don't need it anymore. -//: That frees up the memory allocated to it to be reused in future calls to -//: 'new'. - -//: Since memory can be reused multiple times, it can happen that you have a -//: stale copy to an address that has since been abandoned and reused. Using -//: the stale address is almost never safe, but it can be very hard to track -//: down such copies because any errors caused by them may occur even millions -//: of instructions after the copy or abandon instruction. To help track down -//: such issues, Mu tracks an 'alloc id' for each allocation it makes. The -//: first call to 'new' has an alloc id of 1, the second gets 2, and so on. -//: The alloc id is never reused. -:(before "End Globals") -long long Next_alloc_id = 0; -:(before "End Reset") -Next_alloc_id = 0; - -//: The 'new' instruction records alloc ids both in the memory being allocated -//: and *also* in the address. The 'abandon' instruction clears alloc ids in -//: both places as well. Tracking alloc ids in this manner allows us to raise -//: errors about stale addresses much earlier: 'lookup' operations always -//: compare alloc ids between the address and its payload. //: todo: give 'new' a custodian ingredient. Following malloc/free is a temporary hack. @@ -57,30 +26,28 @@ Next_alloc_id = 0; # should get back different results def main [ 1:address:num/raw <- new number:type - 3:address:num/raw <- new number:type - 5:bool/raw <- equal 1:address:num/raw, 3:address:num/raw + 2:address:num/raw <- new number:type + 3:bool/raw <- equal 1:address:num/raw, 2:address:num/raw ] -+mem: storing 1000 in location 2 +mem: storing 0 in location 3 :(scenario new_array) # call 'new' with a second ingredient to allocate an array of some type rather than a single copy def main [ 1:address:array:num/raw <- new number:type, 5 - 3:address:num/raw <- new number:type - 5:num/raw <- subtract 3:address:num/raw, 1:address:array:num/raw + 2:address:num/raw <- new number:type + 3:num/raw <- subtract 2:address:num/raw, 1:address:array:num/raw ] +run: {1: ("address" "array" "number"), "raw": ()} <- new {number: "type"}, {5: "literal"} +mem: array length is 5 -+mem: storing 1000 in location 2 # don't forget the extra location for array length -+mem: storing 7 in location 5 ++mem: storing 6 in location 3 :(scenario dilated_reagent_with_new) def main [ 1:address:address:num <- new {(address number): type} ] -+new: size of '(address number)' is 2 ++new: size of '(address number)' is 1 //: 'new' takes a weird 'type' as its first ingredient; don't error on it :(before "End Mu Types Initialization") @@ -184,13 +151,6 @@ def main [ ] $error: 0 -:(scenario equal_result_of_new_with_null) -def main [ - 1:&:num <- new num:type - 10:bool <- equal 1:&:num, 0 -] -+mem: storing 0 in location 10 - //: To implement 'new', a Mu transform turns all 'new' instructions into //: 'allocate' instructions that precompute the amount of memory they want to //: allocate. @@ -261,18 +221,15 @@ case ALLOCATE: { int result = allocate(size); if (SIZE(current_instruction().ingredients) > 1) { // initialize array length - trace("mem") << "storing array length " << ingredients.at(1).at(0) << " in location " << result+/*skip alloc id*/1 << end(); - put(Memory, result+/*skip alloc id*/1, ingredients.at(1).at(0)); + trace("mem") << "storing " << ingredients.at(1).at(0) << " in location " << result << end(); + put(Memory, result, ingredients.at(1).at(0)); } products.resize(1); - products.at(0).push_back(0); products.at(0).push_back(result); break; } :(code) int allocate(int size) { - // include space for alloc id - ++size; trace("mem") << "allocating size " << size << end(); //? Total_alloc += size; //? ++Num_alloc; @@ -333,41 +290,41 @@ def main [ :(scenario new_size) def main [ 11:address:num/raw <- new number:type - 13:address:num/raw <- new number:type - 15:num/raw <- subtract 13:address:num/raw, 11:address:num/raw + 12:address:num/raw <- new number:type + 13:num/raw <- subtract 12:address:num/raw, 11:address:num/raw ] -# size of number + alloc id -+mem: storing 2 in location 15 +# size of number ++mem: storing 1 in location 13 :(scenario new_array_size) def main [ 1:address:array:num/raw <- new number:type, 5 - 3:address:num/raw <- new number:type - 5:num/raw <- subtract 3:address:num/raw, 1:address:array:num/raw + 2:address:num/raw <- new number:type + 3:num/raw <- subtract 2:address:num/raw, 1:address:array:num/raw ] # 5 locations for array contents + array length -+mem: storing 7 in location 5 ++mem: storing 6 in location 3 :(scenario new_empty_array) def main [ 1:address:array:num/raw <- new number:type, 0 - 3:address:num/raw <- new number:type - 5:num/raw <- subtract 3:address:num/raw, 1:address:array:num/raw + 2:address:num/raw <- new number:type + 3:num/raw <- subtract 2:address:num/raw, 1:address:array:num/raw ] +run: {1: ("address" "array" "number"), "raw": ()} <- new {number: "type"}, {0: "literal"} +mem: array length is 0 # one location for array length -+mem: storing 2 in location 5 ++mem: storing 1 in location 3 //: If a routine runs out of its initial allocation, it should allocate more. :(scenario new_overflow) -% Initial_memory_per_routine = 3; // barely enough room for point allocation below +% Initial_memory_per_routine = 2; // barely enough room for point allocation below def main [ 1:address:num/raw <- new number:type 2:address:point/raw <- new point:type # not enough room in initial page ] -+new: routine allocated memory from 1000 to 1003 -+new: routine allocated memory from 1003 to 1006 ++new: routine allocated memory from 1000 to 1002 ++new: routine allocated memory from 1002 to 1004 :(scenario new_without_ingredient) % Hide_errors = true; diff --git a/035lookup.cc b/035lookup.cc index 9708ce5b..a2647f5d 100644 --- a/035lookup.cc +++ b/035lookup.cc @@ -6,8 +6,7 @@ :(scenario copy_indirect) def main [ 1:address:num <- copy 10/unsafe - # skip alloc id - 11:num <- copy 34 + 10:num <- copy 34 # This loads location 1 as an address and looks up *that* location. 2:num <- copy 1:address:num/lookup ] @@ -23,7 +22,7 @@ def main [ 1:address:num <- copy 10/unsafe 1:address:num/lookup <- copy 34 ] -+mem: storing 34 in location 11 ++mem: storing 34 in location 10 :(before "End Preprocess write_memory(x, data)") canonize(x); @@ -36,7 +35,7 @@ def main [ 1:address:num/lookup <- copy 34 ] -mem: storing 34 in location 0 -+error: main: tried to lookup 0 in '1:address:num/lookup <- copy 34' ++error: can't write to location 0 in '1:address:num/lookup <- copy 34' //: attempts to /lookup address 0 always loudly fail :(scenario lookup_0_fails) @@ -83,7 +82,7 @@ void lookup_memory(reagent& x) { } void lookup_memory_core(reagent& x, bool check_for_null) { - double address = x.value + /*skip alloc id in address*/1; + double address = x.value; double new_value = get_or_insert(Memory, address); trace("mem") << "location " << address << " contains " << no_scientific(new_value) << end(); if (check_for_null && new_value == 0) { @@ -95,18 +94,12 @@ void lookup_memory_core(reagent& x, bool check_for_null) { raise << "tried to lookup 0\n" << end(); } } - x.set_value(new_value+/*skip alloc id in payload*/1); + x.set_value(new_value); drop_from_type(x, "address"); drop_one_lookup(x); } -:(after "Begin types_coercible(reagent to, reagent from)") -if (!canonize_type(to)) return false; -if (!canonize_type(from)) return false; -:(after "Begin types_match(reagent to, reagent from)") -if (!canonize_type(to)) return false; -if (!canonize_type(from)) return false; -:(after "Begin types_strictly_match(reagent to, reagent from)") +:(before "End Preprocess types_strictly_match(reagent to, reagent from)") if (!canonize_type(to)) return false; if (!canonize_type(from)) return false; @@ -164,33 +157,30 @@ void drop_one_lookup(reagent& r) { :(scenario get_indirect) def main [ 1:address:point <- copy 10/unsafe - # skip alloc id - 11:num <- copy 34 - 12:num <- copy 35 - 20:num <- get 1:address:point/lookup, 0:offset + 10:num <- copy 34 + 11:num <- copy 35 + 2:num <- get 1:address:point/lookup, 0:offset ] -+mem: storing 34 in location 20 ++mem: storing 34 in location 2 :(scenario get_indirect2) def main [ 1:address:point <- copy 10/unsafe - # skip alloc id - 11:num <- copy 94 - 12:num <- copy 95 - 20:address:num <- copy 30/unsafe - 20:address:num/lookup <- get 1:address:point/lookup, 0:offset + 10:num <- copy 34 + 11:num <- copy 35 + 2:address:num <- copy 20/unsafe + 2:address:num/lookup <- get 1:address:point/lookup, 0:offset ] -+mem: storing 94 in location 31 ++mem: storing 34 in location 20 :(scenario include_nonlookup_properties) def main [ 1:address:point <- copy 10/unsafe - # skip alloc id - 11:num <- copy 34 - 12:num <- copy 35 - 20:num <- get 1:address:point/lookup/foo, 0:offset + 10:num <- copy 34 + 11:num <- copy 35 + 2:num <- get 1:address:point/lookup/foo, 0:offset ] -+mem: storing 34 in location 20 ++mem: storing 34 in location 2 :(after "Update GET base in Check") if (!canonize_type(base)) break; @@ -202,12 +192,11 @@ canonize(base); :(scenario put_indirect) def main [ 1:address:point <- copy 10/unsafe - # skip alloc id - 11:num <- copy 34 - 12:num <- copy 35 + 10:num <- copy 34 + 11:num <- copy 35 1:address:point/lookup <- put 1:address:point/lookup, 0:offset, 36 ] -+mem: storing 36 in location 11 ++mem: storing 36 in location 10 :(after "Update PUT base in Check") if (!canonize_type(base)) break; @@ -252,7 +241,7 @@ def main [ 11:num <- copy 14 12:num <- copy 15 13:num <- copy 16 - 1:address:array:num <- copy 9/unsafe/skip-alloc-id + 1:address:array:num <- copy 10/unsafe 2:array:num <- copy 1:address:array:num/lookup ] +mem: storing 3 in location 2 @@ -265,7 +254,7 @@ def main [ 1:address:array:num:3 <- copy 1000/unsafe # pretend allocation 1:address:array:num:3/lookup <- create-array ] -+mem: storing 3 in location 1001 ++mem: storing 3 in location 1000 :(after "Update CREATE_ARRAY product in Check") if (!canonize_type(product)) break; @@ -278,7 +267,7 @@ def main [ 11:num <- copy 14 12:num <- copy 15 13:num <- copy 16 - 1:address:array:num <- copy 9/unsafe/skip-alloc-id + 1:address:array:num <- copy 10/unsafe 2:num <- index 1:address:array:num/lookup, 1 ] +mem: storing 15 in location 2 @@ -301,7 +290,7 @@ def main [ 11:num <- copy 14 12:num <- copy 15 13:num <- copy 16 - 1:address:array:num <- copy 9/unsafe/skip-alloc-id + 1:address:array:num <- copy 10/unsafe 1:address:array:num/lookup <- put-index 1:address:array:num/lookup, 1, 34 ] +mem: storing 34 in location 12 @@ -312,7 +301,7 @@ def main [ 2:num <- copy 14 3:num <- copy 15 4:num <- copy 16 - 5:address:num <- copy 9/unsafe/skip-alloc-id + 5:address:num <- copy 10/unsafe 10:num <- copy 1 1:array:num:3 <- put-index 1:array:num:3, 5:address:num/lookup, 34 ] @@ -325,7 +314,7 @@ def main [ 11:num <- copy 14 12:num <- copy 15 13:num <- copy 16 - 1:address:array:num <- copy 9/unsafe/skip-alloc-id + 1:address:array:num <- copy 10/unsafe 1:address:array:num <- put-index 1:address:array:num/lookup, 1, 34 ] +error: main: product of 'put-index' must be first ingredient '1:address:array:num/lookup', but got '1:address:array:num' @@ -348,7 +337,7 @@ def main [ *5:address:num <- copy 34 6:num <- copy *5:address:num ] -+run: creating array from 7 locations ++run: creating array of size 4 +mem: storing 34 in location 6 :(before "Update PUT_INDEX base in Check") @@ -369,7 +358,7 @@ def main [ 11:num <- copy 14 12:num <- copy 15 13:num <- copy 16 - 1:address:array:num <- copy 9/unsafe/skip-alloc-id + 1:address:array:num <- copy 10/unsafe 2:num <- length 1:address:array:num/lookup ] +mem: storing 3 in location 2 @@ -381,8 +370,8 @@ canonize(array); :(scenario maybe_convert_indirect) def main [ - 11:number-or-point <- merge 0/number, 34 - 1:address:number-or-point <- copy 10/unsafe/skip-alloc-id + 10:number-or-point <- merge 0/number, 34 + 1:address:number-or-point <- copy 10/unsafe 2:num, 3:bool <- maybe-convert 1:address:number-or-point/lookup, i:variant ] +mem: storing 1 in location 3 @@ -390,23 +379,23 @@ def main [ :(scenario maybe_convert_indirect_2) def main [ - 11:number-or-point <- merge 0/number, 34 - 1:address:number-or-point <- copy 10/unsafe/skip-alloc-id - 3:address:num <- copy 20/unsafe - 3:address:num/lookup, 5:bool <- maybe-convert 1:address:number-or-point/lookup, i:variant + 10:number-or-point <- merge 0/number, 34 + 1:address:number-or-point <- copy 10/unsafe + 2:address:num <- copy 20/unsafe + 2:address:num/lookup, 3:bool <- maybe-convert 1:address:number-or-point/lookup, i:variant ] -+mem: storing 1 in location 5 -+mem: storing 34 in location 21 ++mem: storing 1 in location 3 ++mem: storing 34 in location 20 :(scenario maybe_convert_indirect_3) def main [ - 11:number-or-point <- merge 0/number, 34 - 1:address:number-or-point <- copy 10/unsafe/skip-alloc-id - 3:address:bool <- copy 20/unsafe - 5:num, 3:address:bool/lookup <- maybe-convert 1:address:number-or-point/lookup, i:variant + 10:number-or-point <- merge 0/number, 34 + 1:address:number-or-point <- copy 10/unsafe + 2:address:bool <- copy 20/unsafe + 3:num, 2:address:bool/lookup <- maybe-convert 1:address:number-or-point/lookup, i:variant ] -+mem: storing 1 in location 21 -+mem: storing 34 in location 5 ++mem: storing 1 in location 20 ++mem: storing 34 in location 3 :(before "Update MAYBE_CONVERT base in Check") if (!canonize_type(base)) break; @@ -427,9 +416,8 @@ def main [ 1:address:number-or-point <- copy 10/unsafe 1:address:number-or-point/lookup <- merge 0/number, 34 ] -# skip alloc id -+mem: storing 0 in location 11 -+mem: storing 34 in location 12 ++mem: storing 0 in location 10 ++mem: storing 34 in location 11 :(before "Update size_mismatch Check for MERGE(x) canonize(x); @@ -439,7 +427,7 @@ canonize(x); :(scenario lookup_abbreviation) def main [ 1:address:number <- copy 10/unsafe - 11:number <- copy 34 + 10:number <- copy 34 3:number <- copy *1:address:number ] +parse: ingredient: {1: ("address" "number"), "lookup": ()} diff --git a/037abandon.cc b/037abandon.cc index 1c2bc395..5a4adbd1 100644 --- a/037abandon.cc +++ b/037abandon.cc @@ -3,14 +3,14 @@ :(scenario new_reclaim) def main [ 1:address:num <- new number:type - 3:num <- copy 1:address:num # because 1 will get reset during abandon below + 2:num <- copy 1:address:num # because 1 will get reset during abandon below abandon 1:address:num - 4:address:num <- new number:type # must be same size as abandoned memory to reuse - 6:num <- copy 4:address:num - 7:bool <- equal 3:num, 6:num + 3:address:num <- new number:type # must be same size as abandoned memory to reuse + 4:num <- copy 3:address:num + 5:bool <- equal 2:num, 4:num ] # both allocations should have returned the same address -+mem: storing 1 in location 7 ++mem: storing 1 in location 5 //: When abandoning addresses we'll save them to a 'free list', segregated by size. @@ -39,7 +39,7 @@ case ABANDON: { for (int i = 0; i < SIZE(current_instruction().ingredients); ++i) { reagent/*copy*/ ingredient = current_instruction().ingredients.at(i); canonize(ingredient); - abandon(get_or_insert(Memory, ingredient.value+/*skip alloc id*/1), payload_size(ingredient)); + abandon(get_or_insert(Memory, ingredient.value), payload_size(ingredient)); } break; } @@ -50,7 +50,7 @@ void abandon(int address, int payload_size) { for (int curr = address; curr < address+payload_size; ++curr) put(Memory, curr, 0); // append existing free list to address - trace("mem") << "saving " << address << " in free-list of size " << payload_size << end(); + trace("abandon") << "saving " << address << " in free-list of size " << payload_size << end(); put(Memory, address, get_or_insert(Current_routine->free_list, payload_size)); put(Current_routine->free_list, payload_size, address); } @@ -58,7 +58,7 @@ void abandon(int address, int payload_size) { int payload_size(reagent/*copy*/ x) { x.properties.push_back(pair<string, string_tree*>("lookup", NULL)); lookup_memory_core(x, /*check_for_null*/false); - return size_of(x) + /*alloc id*/1; + return size_of(x); } :(after "Allocate Special-cases") @@ -80,23 +80,23 @@ if (get_or_insert(Current_routine->free_list, size)) { :(scenario new_differing_size_no_reclaim) def main [ 1:address:num <- new number:type - 3:num <- copy 1:address:num + 2:num <- copy 1:address:num abandon 1:address:num - 4:address:array:num <- new number:type, 2 # different size - 6:num <- copy 4:address:array:num - 7:bool <- equal 3:num, 6:num + 3:address:array:num <- new number:type, 2 # different size + 4:num <- copy 3:address:array:num + 5:bool <- equal 2:num, 4:num ] # no reuse -+mem: storing 0 in location 7 ++mem: storing 0 in location 5 :(scenario new_reclaim_array) def main [ 1:address:array:num <- new number:type, 2 - 3:num <- copy 1:address:array:num + 2:num <- copy 1:address:array:num abandon 1:address:array:num - 4:address:array:num <- new number:type, 2 # same size - 6:num <- copy 4:address:array:num - 7:bool <- equal 3:num, 6:num + 3:address:array:num <- new number:type, 2 # same size + 4:num <- copy 3:address:array:num + 5:bool <- equal 2:num, 4:num ] # both calls to new returned identical addresses -+mem: storing 1 in location 7 ++mem: storing 1 in location 5 diff --git a/038new_text.cc b/038new_text.cc index b2a5db75..4b666f1c 100644 --- a/038new_text.cc +++ b/038new_text.cc @@ -4,25 +4,23 @@ :(before "End Mu Types Initialization") put(Type_abbreviations, "text", new_type_tree("address:array:character")); -:(scenario new_text) +:(scenario new_string) def main [ 1:text <- new [abc def] - # location 2 is part of 1:text - 3:char <- index *1:text, 5 + 2:char <- index *1:text, 5 ] # number code for 'e' -+mem: storing 101 in location 3 ++mem: storing 101 in location 2 -:(scenario new_text_handles_unicode) +:(scenario new_string_handles_unicode) def main [ 1:text <- new [a«c] - # location 2 is part of 1:text - 3:num <- length *1:text - 4:char <- index *1:text, 1 + 2:num <- length *1:text + 3:char <- index *1:text, 1 ] -+mem: storing 3 in location 3 ++mem: storing 3 in location 2 # unicode for '«' -+mem: storing 171 in location 4 ++mem: storing 171 in location 3 :(before "End NEW Check Special-cases") if (is_literal_text(inst.ingredients.at(0))) break; @@ -31,7 +29,6 @@ if (inst.name == "new" && !inst.ingredients.empty() && is_literal_text(inst.ingr :(after "case NEW" following "Primitive Recipe Implementations") if (is_literal_text(current_instruction().ingredients.at(0))) { products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(new_mu_text(current_instruction().ingredients.at(0).name)); trace("mem") << "new string alloc: " << products.at(0).at(0) << end(); break; @@ -43,9 +40,8 @@ int new_mu_text(const string& contents) { int string_length = unicode_length(contents); //? Total_alloc += string_length+1; //? ++Num_alloc; - int result = allocate(/*array length*/1 + string_length); + int result = allocate(string_length+/*array length*/1); int curr_address = result; - ++curr_address; // skip alloc id trace("mem") << "storing string length " << string_length << " in location " << curr_address << end(); put(Memory, curr_address, string_length); ++curr_address; // skip length @@ -66,16 +62,16 @@ int new_mu_text(const string& contents) { //: a new kind of typo -:(scenario literal_text_without_instruction) +:(scenario string_literal_without_instruction) % Hide_errors = true; def main [ [abc] ] +error: main: instruction '[abc]' has no recipe in '[abc]' -//: stash recognizes texts +//: stash recognizes strings -:(scenario stash_text) +:(scenario stash_string) def main [ 1:text <- new [abc] stash [foo:], 1:text @@ -84,29 +80,30 @@ def main [ :(before "End inspect Special-cases(r, data)") if (is_mu_text(r)) { - return read_mu_text(data.at(/*skip alloc id*/1)); + assert(scalar(data)); + return read_mu_text(data.at(0)); } :(before "End $print Special-cases") else if (is_mu_text(current_instruction().ingredients.at(i))) { - cout << read_mu_text(ingredients.at(i).at(/*skip alloc id*/1)); + cout << read_mu_text(ingredients.at(i).at(0)); } -:(scenario unicode_text) +:(scenario unicode_string) def main [ 1:text <- new [♠] stash [foo:], 1:text ] +app: foo: ♠ -:(scenario stash_space_after_text) +:(scenario stash_space_after_string) def main [ 1:text <- new [abc] stash 1:text, [foo] ] +app: abc foo -:(scenario stash_text_as_array) +:(scenario stash_string_as_array) def main [ 1:text <- new [abc] stash *1:text @@ -117,16 +114,15 @@ def main [ :(before "End Preprocess is_mu_text(reagent x)") if (!canonize_type(x)) return false; -//: Allocate more to routine when initializing a literal text -:(scenario new_text_overflow) -% Initial_memory_per_routine = 3; +//: Allocate more to routine when initializing a literal string +:(scenario new_string_overflow) +% Initial_memory_per_routine = 2; def main [ 1:address:num/raw <- new number:type - # location 2 is part of 1:address - 3:text/raw <- new [a] # not enough room in initial page, if you take the array length into account + 2:text/raw <- new [a] # not enough room in initial page, if you take the array length into account ] -+new: routine allocated memory from 1000 to 1003 -+new: routine allocated memory from 1003 to 1006 ++new: routine allocated memory from 1000 to 1002 ++new: routine allocated memory from 1002 to 1004 //: helpers :(code) @@ -144,9 +140,9 @@ int unicode_length(const string& s) { string read_mu_text(int address) { if (address == 0) return ""; - int length = get_or_insert(Memory, address+/*alloc id*/1); + int length = get_or_insert(Memory, address); if (length == 0) return ""; - return read_mu_characters(address+/*alloc id*/1+/*length*/1, length); + return read_mu_characters(address+1, length); } string read_mu_characters(int start, int length) { @@ -160,18 +156,10 @@ string read_mu_characters(int start, int length) { //: assert: perform sanity checks at runtime -:(scenario assert_literal) -% Hide_errors = true; // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line. -def main [ - assert 0, [this is an assert in Mu] -] -+error: this is an assert in Mu - :(scenario assert) % Hide_errors = true; // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line. def main [ - 1:text <- new [this is an assert in Mu] - assert 0, 1:text + assert 0, [this is an assert in Mu] ] +error: this is an assert in Mu @@ -185,7 +173,7 @@ case ASSERT: { raise << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << to_original_string(inst) << "'\n" << end(); break; } - if (!is_mu_address(inst.ingredients.at(0)) && !is_mu_scalar(inst.ingredients.at(0))) { + if (!is_mu_scalar(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "'assert' requires a boolean for its first ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end(); break; } @@ -197,11 +185,11 @@ case ASSERT: { } :(before "End Primitive Recipe Implementations") case ASSERT: { - if (!scalar_ingredient(ingredients, 0)) { + if (!ingredients.at(0).at(0)) { if (is_literal_text(current_instruction().ingredients.at(1))) raise << current_instruction().ingredients.at(1).name << '\n' << end(); else - raise << read_mu_text(ingredients.at(1).at(/*skip alloc id*/1)) << '\n' << end(); + raise << read_mu_text(ingredients.at(1).at(0)) << '\n' << end(); if (!Hide_errors) exit(1); } break; diff --git a/042name.cc b/042name.cc index e1f35136..f183962c 100644 --- a/042name.cc +++ b/042name.cc @@ -6,8 +6,8 @@ def main [ x:num <- copy 0 ] -+name: assign x 2 -+mem: storing 0 in location 2 ++name: assign x 1 ++mem: storing 0 in location 1 :(scenarios transform) :(scenario transform_names_fails_on_use_before_define) @@ -42,7 +42,7 @@ void transform_names(const recipe_ordinal r) { map<string, int>& names = Name[r]; // store the indices 'used' so far in the map int& curr_idx = names[""]; - curr_idx = 2; // reserve indices 0 and 1 for the chaining slot in a later layer + ++curr_idx; // avoid using index 0, benign skip in some other cases for (int i = 0; i < SIZE(caller.steps); ++i) { instruction& inst = caller.steps.at(i); // End transform_names(inst) Special-cases @@ -135,21 +135,13 @@ bool is_compound_type_starting_with(const type_tree* type, const string& expecte return type->left->value == get(Type_ordinal, expected_name); } -int find_element_offset(const type_ordinal t, const string& name, const string& recipe_name) { +int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) { const type_info& container = get(Type, t); for (int i = 0; i < SIZE(container.elements); ++i) if (container.elements.at(i).name == name) return i; raise << maybe(recipe_name) << "unknown element '" << name << "' in container '" << get(Type, t).name << "'\n" << end(); return -1; } -int find_element_location(int base_address, const string& name, const type_tree* type, const string& recipe_name) { - int offset = find_element_offset(get_base_type(type)->value, name, recipe_name); - if (offset == -1) return offset; - int result = base_address; - for (int i = 0; i < offset; ++i) - result += size_of(element_type(type, i)); - return result; -} bool is_numeric_location(const reagent& x) { if (is_literal(x)) return false; @@ -178,26 +170,26 @@ def main [ x:point <- merge 34, 35 y:num <- copy 3 ] -+name: assign x 2 ++name: assign x 1 # skip location 2 because x occupies two locations -+name: assign y 4 ++name: assign y 3 :(scenario transform_names_supports_static_arrays) def main [ x:@:num:3 <- create-array y:num <- copy 3 ] -+name: assign x 2 ++name: assign x 1 # skip locations 2, 3, 4 because x occupies four locations -+name: assign y 6 ++name: assign y 5 :(scenario transform_names_passes_dummy) # _ is just a dummy result that never gets consumed def main [ _, x:num <- copy 0, 1 ] -+name: assign x 2 --name: assign _ 2 ++name: assign x 1 +-name: assign _ 1 //: an escape hatch to suppress name conversion that we'll use later :(scenarios run) @@ -206,7 +198,7 @@ def main [ def main [ x:num/raw <- copy 0 ] --name: assign x 2 +-name: assign x 1 +error: can't write to location 0 in 'x:num/raw <- copy 0' :(scenarios transform) @@ -274,7 +266,7 @@ if (inst.name == "get" || inst.name == "get-location" || inst.name == "put") { // since first non-address in base type must be a container, we don't have to canonize type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type); if (contains_key(Type, base_type)) { // otherwise we'll raise an error elsewhere - inst.ingredients.at(1).set_value(find_element_offset(base_type, inst.ingredients.at(1).name, get(Recipe, r).name)); + inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name)); trace(9993, "name") << "element " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end(); } } @@ -294,8 +286,8 @@ def main [ a:point <- copy 0/unsafe b:num <- copy 0/unsafe ] -+name: assign a 2 -+name: assign b 4 ++name: assign a 1 ++name: assign b 3 //:: Support variant names for exclusive containers in 'maybe-convert'. @@ -324,7 +316,7 @@ if (inst.name == "maybe-convert") { // since first non-address in base type must be an exclusive container, we don't have to canonize type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type); if (contains_key(Type, base_type)) { // otherwise we'll raise an error elsewhere - inst.ingredients.at(1).set_value(find_element_offset(base_type, inst.ingredients.at(1).name, get(Recipe, r).name)); + inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name)); trace(9993, "name") << "variant " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end(); } } diff --git a/043space.cc b/043space.cc index e62e9285..f290a0b9 100644 --- a/043space.cc +++ b/043space.cc @@ -13,31 +13,25 @@ put(Type_abbreviations, "space", new_type_tree("address:array:location")); :(scenario set_default_space) -# if default-space is 10, then: -# 10: alloc id -# 11: array size -# 12: local 0 (space for the chaining slot; described later; often unused) -# 13: local 0 (space for the chaining slot; described later; often unused) -# 14: local 2 (assuming it is a scalar) -# 15: local 3 -# ..and so on +# if default-space is 10, and if an array of 5 locals lies from location 12 to 16 (inclusive), +# then local 0 is really location 12, local 1 is really location 13, and so on. def main [ # pretend address:array:location; in practice we'll use 'new' - 11:num <- copy 5 # length - default-space:space <- copy 10/unsafe/skip-alloc-id - 2:num <- copy 23 + 10:num <- copy 5 # length + default-space:space <- copy 10/unsafe + 1:num <- copy 23 ] -+mem: storing 23 in location 14 ++mem: storing 23 in location 12 :(scenario lookup_sidesteps_default_space) def main [ # pretend pointer from outside - 2001:num <- copy 34 + 2000:num <- copy 34 # pretend address:array:location; in practice we'll use 'new' - 1001:num <- copy 5 # length + 1000:num <- copy 5 # length # actual start of this recipe - default-space:space <- copy 1000/unsafe/skip-alloc-id - 1:&:num <- copy 2000/unsafe/skip-alloc-id # even local variables always contain raw addresses + default-space:space <- copy 1000/unsafe + 1:&:num <- copy 2000/unsafe # even local variables always contain raw addresses 8:num/raw <- copy *1:&:num ] +mem: storing 34 in location 8 @@ -49,9 +43,8 @@ def main [ def main [ default-space:num, x:num <- copy 0, 1 ] -+name: assign x 2 ++name: assign x 1 -name: assign default-space 1 --name: assign default-space 2 :(before "End is_disqualified Special-cases") if (x.name == "default-space") @@ -81,7 +74,7 @@ void absolutize(reagent& x) { //: hook replaced in a later layer int space_base(const reagent& x) { - return current_call().default_space ? (current_call().default_space + /*skip alloc id*/1) : 0; + return current_call().default_space ? current_call().default_space : 0; } int address(int offset, int base) { @@ -102,13 +95,9 @@ int address(int offset, int base) { :(after "Begin Preprocess write_memory(x, data)") if (x.name == "default-space") { - if (!is_mu_space(x)) { + if (!scalar(data) || !is_mu_space(x)) raise << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but is " << to_string(x.type) << '\n' << end(); - return; - } - double space_location = data.at(/*skip alloc id*/1); - trace("mem") << "storing " << no_scientific(space_location) << " to default_space" << end(); - current_call().default_space = space_location; + current_call().default_space = data.at(0); return; } :(code) @@ -126,13 +115,11 @@ def main [ default-space:space <- copy 10/unsafe 1:space/raw <- copy default-space:space ] -# skip alloc id -+mem: storing 10 in location 2 ++mem: storing 10 in location 1 :(after "Begin Preprocess read_memory(x)") if (x.name == "default-space") { vector<double> result; - result.push_back(/*alloc id*/0); result.push_back(current_call().default_space); return result; } @@ -142,13 +129,13 @@ if (x.name == "default-space") { :(scenario lookup_sidesteps_default_space_in_get) def main [ # pretend pointer to container from outside - 2001:num <- copy 34 - 2002:num <- copy 35 + 2000:num <- copy 34 + 2001:num <- copy 35 # pretend address:array:location; in practice we'll use 'new' - 1001:num <- copy 5 # length + 1000:num <- copy 5 # length # actual start of this recipe - default-space:space <- copy 1000/unsafe/skip-alloc-id - 1:&:point <- copy 2000/unsafe/skip-alloc-id + default-space:space <- copy 1000/unsafe + 1:&:point <- copy 2000/unsafe 9:num/raw <- get *1:&:point, 1:offset ] +mem: storing 35 in location 9 @@ -161,14 +148,14 @@ element.properties.push_back(pair<string, string_tree*>("raw", NULL)); :(scenario lookup_sidesteps_default_space_in_index) def main [ # pretend pointer to array from outside - 2001:num <- copy 2 # length - 2002:num <- copy 34 - 2003:num <- copy 35 + 2000:num <- copy 2 # length + 2001:num <- copy 34 + 2002:num <- copy 35 # pretend address:array:location; in practice we'll use 'new' - 1001:num <- copy 5 # length + 1000:num <- copy 5 # length # actual start of this recipe - default-space:space <- copy 1000/unsafe/skip-alloc-id - 1:&:@:num <- copy 2000/unsafe/skip-alloc-id + default-space:space <- copy 1000/unsafe + 1:&:@:num <- copy 2000/unsafe 9:num/raw <- index *1:&:@:num, 1 ] +mem: storing 35 in location 9 @@ -185,8 +172,8 @@ def main [ x:num <- copy 0 y:num <- copy 3 ] -# allocate space for x and y, as well as the chaining slot at indices 0 and 1 -+mem: array length is 4 +# allocate space for x and y, as well as the chaining slot at 0 ++mem: array length is 3 :(before "End is_disqualified Special-cases") if (x.name == "number-of-locals") diff --git a/044space_surround.cc b/044space_surround.cc index 8efda681..310672be 100644 --- a/044space_surround.cc +++ b/044space_surround.cc @@ -8,24 +8,24 @@ # location 1 in space 1 refers to the space surrounding the default space, here 20. def main [ # pretend address:array:location; in practice we'll use 'new' - 11:num <- copy 5 # length + 10:num <- copy 5 # length # pretend address:array:location; in practice we'll use 'new" - 21:num <- copy 5 # length + 20:num <- copy 5 # length # actual start of this recipe - default-space:space <- copy 10/unsafe/skip-alloc-id + default-space:space <- copy 10/unsafe #: later layers will explain the /names: property - 0:space/names:dummy <- copy 20/unsafe/skip-alloc-id - 2:num <- copy 32 - 2:num/space:1 <- copy 33 + 0:space/names:dummy <- copy 20/unsafe + 1:num <- copy 32 + 1:num/space:1 <- copy 33 ] def dummy [ # just for the /names: property above ] -# write chained space: 10 + (alloc id for default-space) 1 + (length) 1 + (alloc id for chained space) 1 -+mem: storing 20 in location 13 -# store to inside default space: 10 + (alloc id) 1 + (length) 1 + (index) 2 -+mem: storing 32 in location 14 -# store to inside chained space: (contents of location 12) 20 + (alloc id) 1 + (length) 1 + (index) 2 -+mem: storing 33 in location 24 +# chain space: 10 + (length) 1 ++mem: storing 20 in location 11 +# store to default space: 10 + (skip length) 1 + (index) 1 ++mem: storing 32 in location 12 +# store to chained space: (contents of location 12) 20 + (length) 1 + (index) 1 ++mem: storing 33 in location 22 //: If you think of a space as a collection of variables with a common //: lifetime, surrounding allows managing shorter lifetimes inside a longer @@ -33,17 +33,14 @@ def dummy [ # just for the /names: property above :(replace{} "int space_base(const reagent& x)") int space_base(const reagent& x) { - int base = current_call().default_space ? (current_call().default_space+/*skip alloc id*/1) : 0; + int base = current_call().default_space ? current_call().default_space : 0; return space_base(x, space_index(x), base); } int space_base(const reagent& x, int space_index, int base) { - trace("space") << "default_space is at location " << base << " with " << space_index << " chained spaces to go" << end(); if (space_index == 0) return base; - double chained_space_address = base+/*skip length*/1+/*skip alloc id of chaining slot*/1; - double chained_space_base = get_or_insert(Memory, chained_space_address) + /*skip alloc id of chained space*/1; - return space_base(x, space_index-1, chained_space_base); + return space_base(x, space_index-1, get_or_insert(Memory, base+/*skip length*/1)); } int space_index(const reagent& x) { diff --git a/045closure_name.cc b/045closure_name.cc index f5c8d2aa..e478337d 100644 --- a/045closure_name.cc +++ b/045closure_name.cc @@ -9,9 +9,9 @@ :(scenario closure) def main [ default-space:space <- new location:type, 30 - 2:space/names:new-counter <- new-counter - 10:num/raw <- increment-counter 2:space/names:new-counter - 11:num/raw <- increment-counter 2:space/names:new-counter + 1:space/names:new-counter <- new-counter + 2:num/raw <- increment-counter 1:space/names:new-counter + 3:num/raw <- increment-counter 1:space/names:new-counter ] def new-counter [ default-space:space <- new location:type, 30 @@ -27,7 +27,7 @@ def increment-counter [ return y:num/space:1 ] +name: lexically surrounding space for recipe increment-counter comes from new-counter -+mem: storing 5 in location 11 ++mem: storing 5 in location 3 //: To make this work, compute the recipe that provides names for the //: surrounding space of each recipe. diff --git a/046check_type_by_name.cc b/046check_type_by_name.cc index 8a023024..df5a2a6d 100644 --- a/046check_type_by_name.cc +++ b/046check_type_by_name.cc @@ -87,27 +87,27 @@ void check_type(set<reagent>& known, const reagent& x, const recipe& caller) { :(scenario transform_fills_in_missing_types) def main [ - x:num <- copy 10 + x:num <- copy 1 y:num <- add x, 1 ] -# x is in location 2, y in location 3 -+mem: storing 11 in location 3 +# x is in location 1, y in location 2 ++mem: storing 2 in location 2 :(scenario transform_fills_in_missing_types_in_product) def main [ - x:num <- copy 10 - x <- copy 11 + x:num <- copy 1 + x <- copy 2 ] -# x is in location 2 -+mem: storing 11 in location 2 +# x is in location 1 ++mem: storing 2 in location 1 :(scenario transform_fills_in_missing_types_in_product_and_ingredient) def main [ - x:num <- copy 10 + x:num <- copy 1 x <- add x, 1 ] # x is in location 1 -+mem: storing 11 in location 2 ++mem: storing 2 in location 1 :(scenario transform_fills_in_missing_label_type) def main [ diff --git a/050scenario.cc b/050scenario.cc index c4f2541b..e84a18e9 100644 --- a/050scenario.cc +++ b/050scenario.cc @@ -79,7 +79,6 @@ Scenario_names = Scenario_names_snapshot; :(before "End Command Handlers") else if (command == "scenario") { scenario result = parse_scenario(in); -//? result.name.clear(); // disable running scenarios if (!result.name.empty()) Scenarios.push_back(result); } diff --git a/053recipe_header.cc b/053recipe_header.cc index b948ce61..057234f9 100644 --- a/053recipe_header.cc +++ b/053recipe_header.cc @@ -207,9 +207,6 @@ case NEXT_INGREDIENT_WITHOUT_TYPECHECKING: { if (current_call().next_ingredient_to_process < SIZE(current_call().ingredient_atoms)) { products.push_back( current_call().ingredient_atoms.at(current_call().next_ingredient_to_process)); - if (is_mu_scalar(current_call().ingredients.at(current_call().next_ingredient_to_process)) - && is_mu_address(current_instruction().products.at(0))) - products.at(0).insert(products.at(0).begin(), /*alloc id*/0); assert(SIZE(products) == 1); products.resize(2); // push a new vector products.at(1).push_back(1); ++current_call().next_ingredient_to_process; diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc index 3bf1fe80..0e7409d8 100644 --- a/055shape_shifting_container.cc +++ b/055shape_shifting_container.cc @@ -295,12 +295,12 @@ container foo:_a:_b [ y:_b ] def main [ - 10:text <- new [abc] - {20: (foo number (address array character))} <- merge 34/x, 10:text/y - 30:text <- get {20: (foo number (address array character))}, y:offset - 40:bool <- equal 10:text, 30:text + 1:text <- new [abc] + {2: (foo number (address array character))} <- merge 34/x, 1:text/y + 3:text <- get {2: (foo number (address array character))}, y:offset + 4:bool <- equal 1:text, 3:text ] -+mem: storing 1 in location 40 ++mem: storing 1 in location 4 :(before "End element_type Special-cases") replace_type_ingredients(element, type, info, " while computing element type of container"); @@ -346,8 +346,8 @@ exclusive-container foo:_a [ ] def main [ 1:text <- new [abc] - 3:foo:point <- merge 0/variant, 34/xx, 35/xy - 10:point, 20:bool <- maybe-convert 3:foo:point, 0/variant + 2:foo:point <- merge 0/variant, 34/xx, 35/xy + 10:point, 20:bool <- maybe-convert 2:foo:point, 0/variant ] +mem: storing 1 in location 20 +mem: storing 35 in location 11 diff --git a/058to_text.cc b/058to_text.cc index 9cb14e14..8c86e36c 100644 --- a/058to_text.cc +++ b/058to_text.cc @@ -18,7 +18,6 @@ case TO_TEXT: { :(before "End Primitive Recipe Implementations") case TO_TEXT: { products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(new_mu_text(inspect(current_instruction().ingredients.at(0), ingredients.at(0)))); break; } diff --git a/060rewrite_literal_string.cc b/060rewrite_literal_string.cc index 95e38924..f4ed9b4c 100644 --- a/060rewrite_literal_string.cc +++ b/060rewrite_literal_string.cc @@ -19,7 +19,6 @@ Transform.push_back(rewrite_literal_string_to_text); // idempotent set<string> recipes_taking_literal_strings; :(code) void initialize_transform_rewrite_literal_string_to_text() { - recipes_taking_literal_strings.insert("assert"); recipes_taking_literal_strings.insert("$print"); recipes_taking_literal_strings.insert("$dump-trace"); recipes_taking_literal_strings.insert("$system"); diff --git a/065duplex_list.mu b/065duplex_list.mu index b299fda7..037cb923 100644 --- a/065duplex_list.mu +++ b/065duplex_list.mu @@ -393,17 +393,12 @@ def remove-between start:&:duplex-list:_elem, end:&:duplex-list:_elem/contained- # start->next = end *next <- put *next, prev:offset, 0 *start <- put *start, next:offset, end - { - break-if end - stash [spliced:] next - return - } + return-unless end # end->prev->next = 0 # end->prev = start prev:&:duplex-list:_elem <- get *end, prev:offset assert prev, [malformed duplex list - 2] *prev <- put *prev, next:offset, 0 - stash [spliced:] next *end <- put *end, prev:offset, start ] @@ -436,9 +431,6 @@ scenario remove-range [ 12 <- 15 20 <- 0 ] - trace-should-contain [ - app: spliced: 16 <-> 17 <-> 18 - ] ] scenario remove-range-to-final [ @@ -474,49 +466,6 @@ scenario remove-range-to-final [ 12 <- 18 20 <- 0 # no more elements ] - trace-should-contain [ - app: spliced: 15 <-> 16 <-> 17 - ] -] - -scenario remove-range-to-penultimate [ - local-scope - # construct a duplex list with six elements [13, 14, 15, 16, 17, 18] - list:&:duplex-list:num <- push 18, 0 - list <- push 17, list - list <- push 16, list - list <- push 15, list - list <- push 14, list - list <- push 13, list - run [ - # delete 15 and 16 - # start pointer: to the second element - list2:&:duplex-list:num <- next list - # end pointer: to the last (sixth) element - end:&:duplex-list:num <- next list2 - end <- next end - end <- next end - remove-between list2, end - # now check the list - 10:num/raw <- get *list, value:offset - list <- next list - 11:num/raw <- get *list, value:offset - list <- next list - 12:num/raw <- get *list, value:offset - list <- next list - 13:num/raw <- get *list, value:offset - 20:&:duplex-list:num/raw <- next list - ] - memory-should-contain [ - 10 <- 13 - 11 <- 14 - 12 <- 17 - 13 <- 18 - 20 <- 0 # no more elements - ] - trace-should-contain [ - app: spliced: 15 <-> 16 - ] ] scenario remove-range-empty [ diff --git a/069hash.cc b/069hash.cc index 1d2f706e..4400c1e8 100644 --- a/069hash.cc +++ b/069hash.cc @@ -62,7 +62,7 @@ size_t hash_mu_address(size_t h, reagent& r) { } size_t hash_mu_text(size_t h, const reagent& r) { - string input = read_mu_text(get_or_insert(Memory, r.value+/*skip alloc id*/1)); + string input = read_mu_text(get_or_insert(Memory, r.value)); for (int i = 0; i < SIZE(input); ++i) { h = hash_iter(h, static_cast<size_t>(input.at(i))); //? cerr << i << ": " << h << '\n'; @@ -319,11 +319,11 @@ def main [ :(scenario hash_matches_old_version) def main [ 1:text <- new [abc] - 3:num <- hash 1:text - 4:num <- hash_old 1:text - 5:bool <- equal 3:num, 4:num + 2:num <- hash 1:text + 3:num <- hash_old 1:text + 4:bool <- equal 2:num, 3:num ] -+mem: storing 1 in location 5 ++mem: storing 1 in location 4 :(before "End Primitive Recipe Declarations") HASH_OLD, @@ -343,7 +343,7 @@ case HASH_OLD: { } :(before "End Primitive Recipe Implementations") case HASH_OLD: { - string input = read_mu_text(ingredients.at(0).at(/*skip alloc id*/1)); + string input = read_mu_text(ingredients.at(0).at(0)); size_t h = 0 ; for (int i = 0; i < SIZE(input); ++i) { diff --git a/074wait.cc b/074wait.cc index 47bbb0cc..eb17c8aa 100644 --- a/074wait.cc +++ b/074wait.cc @@ -262,23 +262,22 @@ def main [ :(scenario get_location_indirect) # 'get-location' can read from container address def main [ - 1:&:point <- copy 10/unsafe - # skip alloc id - 11:num <- copy 34 - 12:num <- copy 35 + 1:num <- copy 10 + 10:num <- copy 34 + 11:num <- copy 35 4:location <- get-location 1:&:point/lookup, 0:offset ] -+mem: storing 11 in location 4 ++mem: storing 10 in location 4 :(scenario get_location_indirect_2) def main [ - 1:&:point <- copy 10/unsafe - 11:num <- copy 34 - 12:num <- copy 35 + 1:num <- copy 10 + 10:num <- copy 34 + 11:num <- copy 35 4:&:num <- copy 20/unsafe 4:&:location/lookup <- get-location 1:&:point/lookup, 0:offset ] -+mem: storing 11 in location 21 ++mem: storing 10 in location 20 //: allow waiting on a routine to complete diff --git a/082scenario_screen.cc b/082scenario_screen.cc index dc015fed..31cbfcc9 100644 --- a/082scenario_screen.cc +++ b/082scenario_screen.cc @@ -145,14 +145,8 @@ assert(Next_predefined_global_for_scenarios < Reserved_for_tests); :(before "End Globals") // Scenario Globals. -extern const int SCREEN = next_predefined_global_for_scenarios(/*size_of(address:screen)*/2); +extern const int SCREEN = Next_predefined_global_for_scenarios++; // End Scenario Globals. -:(code) -int next_predefined_global_for_scenarios(int size) { - int result = Next_predefined_global_for_scenarios; - Next_predefined_global_for_scenarios += size; - return result; -} //: give 'screen' a fixed location in scenarios :(before "End Special Scenario Variable Names(r)") @@ -256,27 +250,19 @@ struct raw_string_stream { :(code) void check_screen(const string& expected_contents, const int color) { - int screen_location = get_or_insert(Memory, SCREEN+/*skip address alloc id*/1) + /*skip payload alloc id*/1; - reagent screen("x:screen"); // just to ensure screen.type is reclaimed - int screen_data_location = find_element_location(screen_location, "data", screen.type, "check_screen"); // type: address:array:character - assert(screen_data_location >= 0); -//? cerr << "screen data is at location " << screen_data_location << '\n'; - int screen_data_start = get_or_insert(Memory, screen_data_location+/*skip address alloc id*/1) + /*skip payload alloc id*/1; // type: array:character -//? cerr << "screen data start is at " << screen_data_start << '\n'; - int screen_width_location = find_element_location(screen_location, "num-columns", screen.type, "check_screen"); -//? cerr << "screen width is at location " << screen_width_location << '\n'; - int screen_width = get_or_insert(Memory, screen_width_location); -//? cerr << "screen width: " << screen_width << '\n'; - int screen_height_location = find_element_location(screen_location, "num-rows", screen.type, "check_screen"); -//? cerr << "screen height is at location " << screen_height_location << '\n'; - int screen_height = get_or_insert(Memory, screen_height_location); -//? cerr << "screen height: " << screen_height << '\n'; - int top_index_location= find_element_location(screen_location, "top-idx", screen.type, "check_screen"); -//? cerr << "top of screen is at location " << top_index_location << '\n'; - int top_index = get_or_insert(Memory, top_index_location); -//? cerr << "top of screen is index " << top_index << '\n'; + int screen_location = get_or_insert(Memory, SCREEN); + int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", ""); + assert(data_offset >= 0); + int screen_data_location = screen_location+data_offset; // type: address:array:character + 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", ""); + int screen_width = get_or_insert(Memory, screen_location+width_offset); + int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", ""); + int screen_height = get_or_insert(Memory, screen_location+height_offset); raw_string_stream cursor(expected_contents); // todo: too-long expected_contents should fail + int top_index_offset = find_element_name(get(Type_ordinal, "screen"), "top-idx", ""); + int top_index = get_or_insert(Memory, screen_location+top_index_offset); for (int i=0, row=top_index/screen_width; i < screen_height; ++i, row=(row+1)%screen_height) { cursor.skip_whitespace_and_comments(); if (cursor.at_end()) break; @@ -399,25 +385,18 @@ case _DUMP_SCREEN: { :(code) void dump_screen() { - int screen_location = get_or_insert(Memory, SCREEN+/*skip address alloc id*/1) + /*skip payload alloc id*/1; - reagent screen("x:screen"); // just to ensure screen.type is reclaimed - int screen_data_location = find_element_location(screen_location, "data", screen.type, "check_screen"); // type: address:array:character - assert(screen_data_location >= 0); -//? cerr << "screen data is at location " << screen_data_location << '\n'; - int screen_data_start = get_or_insert(Memory, screen_data_location+/*skip address alloc id*/1) + /*skip payload alloc id*/1; // type: array:character -//? cerr << "screen data start is at " << screen_data_start << '\n'; - int screen_width_location = find_element_location(screen_location, "num-columns", screen.type, "check_screen"); -//? cerr << "screen width is at location " << screen_width_location << '\n'; - int screen_width = get_or_insert(Memory, screen_width_location); -//? cerr << "screen width: " << screen_width << '\n'; - int screen_height_location = find_element_location(screen_location, "num-rows", screen.type, "check_screen"); -//? cerr << "screen height is at location " << screen_height_location << '\n'; - int screen_height = get_or_insert(Memory, screen_height_location); -//? cerr << "screen height: " << screen_height << '\n'; - int top_index_location= find_element_location(screen_location, "top-idx", screen.type, "check_screen"); -//? cerr << "top of screen is at location " << top_index_location << '\n'; - int top_index = get_or_insert(Memory, top_index_location); -//? cerr << "top of screen is index " << top_index << '\n'; + int screen_location = get_or_insert(Memory, SCREEN); + int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", ""); + int screen_width = get_or_insert(Memory, screen_location+width_offset); + int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", ""); + 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); + int screen_data_location = screen_location+data_offset; // type: address:array:character + 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); + int top_index_offset = find_element_name(get(Type_ordinal, "screen"), "top-idx", ""); + int top_index = get_or_insert(Memory, screen_location+top_index_offset); for (int i=0, row=top_index/screen_width; i < screen_height; ++i, row=(row+1)%screen_height) { cerr << '.'; int curr = screen_data_start+/*length*/1+row*screen_width* /*size of screen-cell*/2; diff --git a/085scenario_console.cc b/085scenario_console.cc index 31aa4fe7..2c3ab4bc 100644 --- a/085scenario_console.cc +++ b/085scenario_console.cc @@ -34,7 +34,7 @@ scenario keyboard-in-scenario [ ] :(before "End Scenario Globals") -extern const int CONSOLE = next_predefined_global_for_scenarios(/*size_of(address:console)*/2); +extern const int CONSOLE = Next_predefined_global_for_scenarios++; //: give 'console' a fixed location in scenarios :(before "End Special Scenario Variable Names(r)") Name[r]["console"] = CONSOLE; @@ -61,8 +61,8 @@ case ASSUME_CONSOLE: { int size = /*length*/1 + num_events*size_of_event(); int event_data_address = allocate(size); // store length - put(Memory, event_data_address+/*skip alloc id*/1, num_events); - int curr_address = event_data_address + /*skip alloc id*/1 + /*skip length*/1; + put(Memory, event_data_address, num_events); + int curr_address = event_data_address + /*skip length*/1; for (int i = 0; i < SIZE(r.steps); ++i) { const instruction& inst = r.steps.at(i); if (inst.name == "left-click") { @@ -113,13 +113,13 @@ case ASSUME_CONSOLE: { } } } - assert(curr_address == event_data_address+/*skip alloc id*/1+size); + assert(curr_address == event_data_address+size); // wrap the array of events in a console object int console_address = allocate(size_of_console()); trace("mem") << "storing console in " << console_address << end(); - put(Memory, CONSOLE+/*skip alloc id*/1, console_address); + put(Memory, CONSOLE, console_address); trace("mem") << "storing console data in " << console_address+/*offset of 'data' in container 'events'*/1 << end(); - put(Memory, console_address+/*skip alloc id*/1+/*offset of 'data' in container 'events'*/1+/*skip alloc id of 'data'*/1, event_data_address); + put(Memory, console_address+/*offset of 'data' in container 'events'*/1, event_data_address); break; } diff --git a/087file.cc b/087file.cc index 9fd056db..44da9b02 100644 --- a/087file.cc +++ b/087file.cc @@ -35,7 +35,7 @@ case _OPEN_FILE_FOR_READING: { } :(before "End Primitive Recipe Implementations") case _OPEN_FILE_FOR_READING: { - string filename = read_mu_text(ingredients.at(0).at(/*skip alloc id*/1)); + string filename = read_mu_text(ingredients.at(0).at(0)); assert(sizeof(long long int) >= sizeof(FILE*)); FILE* f = fopen(filename.c_str(), "r"); long long int result = reinterpret_cast<long long int>(f); @@ -70,7 +70,7 @@ case _OPEN_FILE_FOR_WRITING: { } :(before "End Primitive Recipe Implementations") case _OPEN_FILE_FOR_WRITING: { - string filename = read_mu_text(ingredients.at(0).at(/*skip alloc id*/1)); + string filename = read_mu_text(ingredients.at(0).at(0)); assert(sizeof(long long int) >= sizeof(FILE*)); long long int result = reinterpret_cast<long long int>(fopen(filename.c_str(), "w")); products.resize(1); diff --git a/089scenario_filesystem.cc b/089scenario_filesystem.cc index bacb61be..f14534ac 100644 --- a/089scenario_filesystem.cc +++ b/089scenario_filesystem.cc @@ -71,7 +71,7 @@ scenario escaping-file-contents [ ] :(before "End Globals") -extern const int RESOURCES = next_predefined_global_for_scenarios(/*size_of(address:resources)*/2); +extern const int RESOURCES = Next_predefined_global_for_scenarios++; //: give 'resources' a fixed location in scenarios :(before "End Special Scenario Variable Names(r)") Name[r]["resources"] = RESOURCES; @@ -203,28 +203,26 @@ string munge_resources_contents(const string& data, const string& filename, cons } void construct_resources_object(const map<string, string>& contents) { - int resources_data_address = allocate(SIZE(contents) * /*size of resource*/4 + /*array length*/1); - int curr = resources_data_address + /*skip alloc id*/1 + /*skip array length*/1; + int resources_data_address = allocate(SIZE(contents)*2 + /*array length*/1); + int curr = resources_data_address + /*skip length*/1; for (map<string, string>::const_iterator p = contents.begin(); p != contents.end(); ++p) { - ++curr; // skip alloc id of resource.name put(Memory, curr, new_mu_text(p->first)); trace("mem") << "storing file name " << get(Memory, curr) << " in location " << curr << end(); ++curr; - ++curr; // skip alloc id of resource.contents put(Memory, curr, new_mu_text(p->second)); trace("mem") << "storing file contents " << get(Memory, curr) << " in location " << curr << end(); ++curr; } - curr = resources_data_address + /*skip alloc id of resources.data*/1; - put(Memory, curr, SIZE(contents)); // array length + curr = resources_data_address; + put(Memory, curr, SIZE(contents)); // size of array trace("mem") << "storing resources size " << get(Memory, curr) << " in location " << curr << end(); // wrap the resources data in a 'resources' object int resources_address = allocate(size_of_resources()); - curr = resources_address+/*alloc id*/1+/*offset of 'data' element*/1+/*skip alloc id of 'data' element*/1; + curr = resources_address+/*offset of 'data' element*/1; put(Memory, curr, resources_data_address); trace("mem") << "storing resources data address " << resources_data_address << " in location " << curr << end(); // save in product - put(Memory, RESOURCES+/*skip alloc id*/1, resources_address); + put(Memory, RESOURCES, resources_address); trace("mem") << "storing resources address " << resources_address << " in location " << RESOURCES << end(); } diff --git a/091socket.cc b/091socket.cc index a0f3b948..7b6ca5b1 100644 --- a/091socket.cc +++ b/091socket.cc @@ -40,7 +40,7 @@ case _OPEN_CLIENT_SOCKET: { } :(before "End Primitive Recipe Implementations") case _OPEN_CLIENT_SOCKET: { - string host = read_mu_text(ingredients.at(0).at(/*skip alloc id*/1)); + string host = read_mu_text(ingredients.at(0).at(0)); int port = ingredients.at(1).at(0); socket_t* client = client_socket(host, port); products.resize(1); diff --git a/101run_sandboxed.cc b/101run_sandboxed.cc index 6d866b60..a0b827e9 100644 --- a/101run_sandboxed.cc +++ b/101run_sandboxed.cc @@ -3,23 +3,20 @@ :(scenario run_interactive_code) def main [ - 1:num <- copy 0 # reserve space for the sandbox - 10:text <- new [1:num/raw <- copy 34] -#? $print 10:num [|] 11:num [: ] 1000:num [|] *10:text [ (] 10:text [)] 10/newline - run-sandboxed 10:text - 20:num <- copy 1:num + 1:num <- copy 0 + 2:text <- new [1:num/raw <- copy 34] + run-sandboxed 2:text + 3:num <- copy 1:num ] -#? ? -+mem: storing 34 in location 20 ++mem: storing 34 in location 3 :(scenario run_interactive_empty) def main [ - 10:text <- copy 0/unsafe - 20:text <- run-sandboxed 10:text + 1:text <- copy 0/unsafe + 2:text <- run-sandboxed 1:text ] # result is null -+mem: storing 0 in location 20 -+mem: storing 0 in location 21 ++mem: storing 0 in location 2 //: As the name suggests, 'run-sandboxed' will prevent certain operations that //: regular Mu code can perform. @@ -55,16 +52,12 @@ case RUN_SANDBOXED: { } :(before "End Primitive Recipe Implementations") case RUN_SANDBOXED: { - bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(/*skip alloc id*/1)); + bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); if (!new_code_pushed_to_stack) { products.resize(5); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(0); - products.at(1).push_back(/*alloc id*/0); products.at(1).push_back(trace_error_contents()); - products.at(2).push_back(/*alloc id*/0); products.at(2).push_back(0); - products.at(3).push_back(/*alloc id*/0); products.at(3).push_back(trace_app_contents()); products.at(4).push_back(1); // completed run_code_end(); @@ -97,7 +90,6 @@ string Save_trace_file; // all errors. // returns true if successfully called (no errors found during load and transform) bool run_interactive(int address) { -//? cerr << "run_interactive: " << address << '\n'; assert(contains_key(Recipe_ordinal, "interactive") && get(Recipe_ordinal, "interactive") != 0); // try to sandbox the run as best you can // todo: test this @@ -106,7 +98,6 @@ bool run_interactive(int address) { Memory.erase(i); } string command = trim(strip_comments(read_mu_text(address))); -//? cerr << "command: " << command << '\n'; Name[get(Recipe_ordinal, "interactive")].clear(); run_code_begin(/*should_stash_snapshots*/true); if (command.empty()) return false; @@ -222,20 +213,15 @@ load(string( "]\n" + "recipe sandbox [\n" + "local-scope\n" + -//? "$print [aaa] 10/newline\n" + "screen:&:screen <- new-fake-screen 30, 5\n" + "routine-id:num <- start-running interactive, screen\n" + "limit-time routine-id, 100000/instructions\n" + "wait-for-routine routine-id\n" + -//? "$print [bbb] 10/newline\n" + "instructions-run:num <- number-of-instructions routine-id\n" + "stash instructions-run [instructions run]\n" + "sandbox-state:num <- routine-state routine-id\n" + "completed?:bool <- equal sandbox-state, 1/completed\n" + -//? "$print [completed: ] completed? 10/newline\n" + "output:text <- $most-recent-products\n" + -//? "$print [zzz] 10/newline\n" + -//? "$print output\n" + "errors:text <- save-errors\n" + "stashes:text <- save-app-trace\n" + "$cleanup-run-sandboxed\n" + @@ -295,7 +281,6 @@ case _MOST_RECENT_PRODUCTS: { :(before "End Primitive Recipe Implementations") case _MOST_RECENT_PRODUCTS: { products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(new_mu_text(Most_recent_products)); break; } @@ -311,7 +296,6 @@ case SAVE_ERRORS: { :(before "End Primitive Recipe Implementations") case SAVE_ERRORS: { products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(trace_error_contents()); break; } @@ -327,7 +311,6 @@ case SAVE_APP_TRACE: { :(before "End Primitive Recipe Implementations") case SAVE_APP_TRACE: { products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(trace_app_contents()); break; } @@ -349,64 +332,64 @@ case _CLEANUP_RUN_SANDBOXED: { :(scenario "run_interactive_converts_result_to_text") def main [ # try to interactively add 2 and 2 - 10:text <- new [add 2, 2] - 20:text <- run-sandboxed 10:text - 30:@:char <- copy *20:text + 1:text <- new [add 2, 2] + 2:text <- run-sandboxed 1:text + 10:@:char <- copy *2:text ] # first letter in the output should be '4' in unicode -+mem: storing 52 in location 31 ++mem: storing 52 in location 11 :(scenario "run_interactive_ignores_products_in_nested_functions") def main [ - 10:text <- new [foo] - 20:text <- run-sandboxed 10:text - 30:@:char <- copy *20:text + 1:text <- new [foo] + 2:text <- run-sandboxed 1:text + 10:@:char <- copy *2:text ] def foo [ - 40:num <- copy 1234 + 20:num <- copy 1234 { break reply 5678 } ] # no product should have been tracked -+mem: storing 0 in location 30 ++mem: storing 0 in location 10 :(scenario "run_interactive_ignores_products_in_previous_instructions") def main [ - 10:text <- new [ + 1:text <- new [ add 1, 1 # generates a product foo] # no products - 20:text <- run-sandboxed 10:text - 30:@:char <- copy *20:text + 2:text <- run-sandboxed 1:text + 10:@:char <- copy *2:text ] def foo [ - 40:num <- copy 1234 + 20:num <- copy 1234 { break reply 5678 } ] # no product should have been tracked -+mem: storing 0 in location 30 ++mem: storing 0 in location 10 :(scenario "run_interactive_remembers_products_before_final_label") def main [ - 10:text <- new [ + 1:text <- new [ add 1, 1 # generates a product +foo] # no products - 20:text <- run-sandboxed 10:text - 30:@:char <- copy *20:text + 2:text <- run-sandboxed 1:text + 10:@:char <- copy *2:text ] def foo [ - 40:num <- copy 1234 + 20:num <- copy 1234 { break reply 5678 } ] # product tracked -+mem: storing 50 in location 31 ++mem: storing 50 in location 11 :(scenario "run_interactive_returns_text") def main [ @@ -416,42 +399,38 @@ def main [ y:text <- new [b] z:text <- append x:text, y:text ] - 10:text <- run-sandboxed 1:text -#? $print 10:text 10/newline - 20:@:char <- copy *10:text + 2:text <- run-sandboxed 1:text + 10:@:char <- copy *2:text ] # output contains "ab" -#? ? -+mem: storing 97 in location 21 -+mem: storing 98 in location 22 ++mem: storing 97 in location 11 ++mem: storing 98 in location 12 :(scenario "run_interactive_returns_errors") def main [ # run a command that generates an error - 10:text <- new [x:num <- copy 34 + 1:text <- new [x:num <- copy 34 get x:num, foo:offset] - 20:text, 30:text <- run-sandboxed 10:text - 40:@:char <- copy *30:text + 2:text, 3:text <- run-sandboxed 1:text + 10:@:char <- copy *3:text ] # error should be "unknown element foo in container number" -+mem: storing 117 in location 41 -+mem: storing 110 in location 42 -+mem: storing 107 in location 43 -+mem: storing 110 in location 44 ++mem: storing 117 in location 11 ++mem: storing 110 in location 12 ++mem: storing 107 in location 13 ++mem: storing 110 in location 14 # ... :(scenario run_interactive_with_comment) def main [ # 2 instructions, with a comment after the first - 10:text <- new [a:num <- copy 0 # abc + 1:&:@:num <- new [a:num <- copy 0 # abc b:num <- copy 0 ] - 20:text, 30:text <- run-sandboxed 10:text + 2:text, 3:text <- run-sandboxed 1:text ] # no errors -# skip alloc id -+mem: storing 0 in location 30 -+mem: storing 0 in location 31 ++mem: storing 0 in location 3 :(after "Running One Instruction") if (Track_most_recent_products && SIZE(Current_routine->calls) == Call_depth_to_track_most_recent_products_at @@ -462,7 +441,6 @@ if (Track_most_recent_products && SIZE(Current_routine->calls) == Call_depth_to_ :(before "End Running One Instruction") if (Track_most_recent_products && SIZE(Current_routine->calls) == Call_depth_to_track_most_recent_products_at) { Most_recent_products = track_most_recent_products(current_instruction(), products); -//? cerr << "most recent products: " << Most_recent_products << '\n'; } :(code) string track_most_recent_products(const instruction& instruction, const vector<vector<double> >& products) { @@ -480,8 +458,8 @@ string track_most_recent_products(const instruction& instruction, const vector<v // => abc if (i < SIZE(instruction.products)) { if (is_mu_text(instruction.products.at(i))) { - if (SIZE(products.at(i)) != 2) continue; // weak silent check for address - out << read_mu_text(products.at(i).at(/*skip alloc id*/1)) << '\n'; + if (!scalar(products.at(i))) continue; // error handled elsewhere + out << read_mu_text(products.at(i).at(0)) << '\n'; continue; } } @@ -584,7 +562,6 @@ case RELOAD: { Sandbox_mode = false; Current_routine = save_current_routine; products.resize(1); - products.at(0).push_back(/*alloc id*/0); products.at(0).push_back(trace_error_contents()); run_code_end(); // wait until we're done with the trace contents break; diff --git a/edit/001-editor.mu b/edit/001-editor.mu index 036ef07a..8855395a 100644 --- a/edit/001-editor.mu +++ b/edit/001-editor.mu @@ -81,20 +81,18 @@ scenario editor-initializes-without-data [ assume-screen 5/width, 3/height run [ e:&:editor <- new-editor 0/data, 2/left, 5/right - 1:editor/raw <- copy *e + 2:editor/raw <- copy *e ] memory-should-contain [ - # 1,2 (data) <- just the § sentinel - # 3,4 (top of screen) <- the § sentinel - # 5 (bottom of screen) <- null since text fits on screen - 5 <- 0 - 6 <- 0 - # 7,8 (before cursor) <- the § sentinel - 9 <- 2 # left - 10 <- 4 # right (inclusive) - 11 <- 0 # bottom (not set until render) - 12 <- 1 # cursor row - 13 <- 2 # cursor column + # 2 (data) <- just the § sentinel + # 3 (top of screen) <- the § sentinel + 4 <- 0 # bottom-of-screen; null since text fits on screen + # 5 (before cursor) <- the § sentinel + 6 <- 2 # left + 7 <- 4 # right (inclusive) + 8 <- 0 # bottom (not set until render) + 9 <- 1 # cursor row + 10 <- 2 # cursor column ] screen-should-contain [ . . diff --git a/edit/002-typing.mu b/edit/002-typing.mu index 67fe76a0..47885c4f 100644 --- a/edit/002-typing.mu +++ b/edit/002-typing.mu @@ -280,11 +280,7 @@ scenario editor-handles-empty-event-queue [ assume-screen 10/width, 5/height e:&:editor <- new-editor [abc], 0/left, 10/right editor-render screen, e -#? x:num <- get *screen, num-rows:offset -#? $print [a: ] x 10/newline assume-console [] -#? x:num <- get *screen, num-rows:offset -#? $print [z: ] x 10/newline run [ editor-event-loop screen, console, e ] diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu index 78c6e49f..02ea77d0 100644 --- a/edit/003-shortcuts.mu +++ b/edit/003-shortcuts.mu @@ -2006,13 +2006,7 @@ after <handle-special-character> [ delete-to-start-of-line?:bool <- equal c, 21/ctrl-u break-unless delete-to-start-of-line? <begin-delete-to-start-of-line> - $print [before: ] cursor-row [ ] cursor-column 10/newline deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor - x:text <- to-text deleted-cells - $print x 10/newline - cursor-row <- get *editor, cursor-row:offset - cursor-column <- get *editor, cursor-column:offset - $print [after: ] cursor-row [ ] cursor-column 10/newline <end-delete-to-start-of-line> go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells return @@ -2022,7 +2016,6 @@ after <handle-special-character> [ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [ local-scope load-inputs - $print [minimal render for ctrl-u] 10/newline curr-column:num <- get *editor, cursor-column:offset # accumulate the current line as text and render it buf:&:buffer:char <- new-buffer 30 # accumulator for the text we need to render @@ -2032,7 +2025,6 @@ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&: { # if we have a wrapped line, give up and render the whole screen wrap?:bool <- greater-or-equal i, right - $print [wrap? ] wrap? 10/newline return-if wrap?, 1/go-render curr <- next curr break-unless curr @@ -2069,7 +2061,6 @@ def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor { at-start-of-text?:bool <- equal start, init break-if at-start-of-text? - $print [0] 10/newline curr:char <- get *start, value:offset at-start-of-line?:bool <- equal curr, 10/newline break-if at-start-of-line? @@ -2080,23 +2071,14 @@ def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor assert start, [delete-to-start-of-line tried to move before start of text] loop } - $print [1] 10/newline # snip it out result:&:duplex-list:char <- next start - x:text <- to-text start - $print [start: ] x 10/newline - x:text <- to-text end - $print [end: ] x 10/newline remove-between start, end - x:text <- to-text result - $print [snip: ] x 10/newline # update top-of-screen if it's just been invalidated { break-unless update-top-of-screen? - $print [2] 10/newline put *editor, top-of-screen:offset, start } - $print [3] 10/newline # adjust cursor before-cursor <- copy start *editor <- put *editor, before-cursor:offset, before-cursor @@ -2107,22 +2089,17 @@ def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor width:num <- subtract right, left num-deleted:num <- length result cursor-row-adjustment:num <- divide-with-remainder num-deleted, width - $print [adj ] num-deleted [/] width [=] cursor-row-adjustment 10/newline return-unless cursor-row-adjustment - $print [4] 10/newline cursor-row:num <- get *editor, cursor-row:offset cursor-row-in-editor:num <- subtract cursor-row, 1 # ignore menubar at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment { break-unless at-top? - $print [5] 10/newline cursor-row <- copy 1 # top of editor, below menubar } { break-if at-top? - $print [6] 10/newline cursor-row <- subtract cursor-row, cursor-row-adjustment - $print cursor-row 10/newline } put *editor, cursor-row:offset, cursor-row ] diff --git a/index.html b/index.html index dde93753..88e9b14a 100644 --- a/index.html +++ b/index.html @@ -158,16 +158,18 @@ for gradually constructing long strings in a piecemeal fashion. space at run-time as pointers or <em>addresses</em>. All Mu instructions can dereference or <a href='html/035lookup.cc.html'><em>lookup</em></a> addresses of values in addition to operating on regular values. These addresses are -manually managed like C, and can be reclaimed using the <a href='html/037abandon.cc.html'><tt>abandon</tt></a> -instruction. To ensure that stale addresses aren't used after being -abandoned/reused, each allocation gets a unique <em>alloc id</em> that is also -stored in the address returned. The lookup operation ensures that the alloc id -of an address matches that of its payload. This eliminates a whole class of -undefined behavior and security vulnerabilities that plague C. Compared to -Rust, Mu pays some additional runtime cost in exchange for C-like flexibility -(you can copy addresses around all you like, and write from any copy of an -address) and simpler implementation (no static analysis). Mu by convention -abbreviates type <tt>address</tt> to <tt>&</tt>. +manually managed like C. However, all allocations are transparently +reference-counted or <a href='html/036refcount.cc.html'><em>refcounted</em></a>, +with every copy of a pointer updating refcounts appropriately. When the +refcount of an allocation drops to zero it is transparently <a href='html/037abandon.cc.html'>reclaimed</a> +and made available to future allocations. By construction it is impossible to +reclaim memory prematurely, while some other part of a program is still +pointing to it. This eliminates a whole class of undefined behavior and +security vulnerabilities that plague C. Compared to Rust, Mu pays some +additional runtime cost in exchange for C-like flexibility (you can copy +addresses around all you like, and write from any copy of an address) and +simpler implementation (no static analysis). Mu by convention abbreviates type +<tt>address</tt> to <tt>&</tt>. <p/>Support for higher-order recipes that can pass <a href='html/072recipe.cc.html'>recipes</a> around like any other value. |