From e46306432ddb75a89f69d92ccc175a23f0b72072 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 25 Jul 2015 14:19:28 -0700 Subject: 1848 - core instructions now check for ingredients Also standardized warnings. --- 021arithmetic.cc | 12 +++++++++ 022boolean.cc | 2 +- 023jump.cc | 40 +++++++++++++++++++++------ 024compare.cc | 44 +++++++++++++++++++++++++++--- 027trace.cc | 4 +++ 028assert.cc | 15 ++++++++--- 030container.cc | 10 +++---- 031address.cc | 10 +++++-- 032array.cc | 19 ++++++++----- 033exclusive_container.cc | 16 +++++------ 034call.cc | 2 +- 035call_ingredient.cc | 15 +++++++++-- 036call_reply.cc | 69 +++++++++++++++++++++++++---------------------- 037recipe.cc | 12 +++++++-- 038scheduler.cc | 27 ++++++++++++++++--- 039wait.cc | 22 ++++++++------- 041jump_label.cc | 12 ++++----- 042name.cc | 13 +++++---- 043new.cc | 34 +++++++++++++---------- 044space.cc | 12 ++++----- 045space_surround.cc | 3 ++- 046closure_name.cc | 9 ++++--- 047global.cc | 4 +-- 049continuation.cc | 24 ++++++++++++----- 064random.cc | 9 ++++++- 070display.cc | 40 ++++++++++++++++++--------- 081run_interactive.cc | 19 ++++++++++--- 082persist.cc | 14 +++++++--- 28 files changed, 358 insertions(+), 154 deletions(-) diff --git a/021arithmetic.cc b/021arithmetic.cc index 0701e82a..51df6f46 100644 --- a/021arithmetic.cc +++ b/021arithmetic.cc @@ -43,6 +43,10 @@ SUBTRACT, Recipe_ordinal["subtract"] = SUBTRACT; :(before "End Primitive Recipe Implementations") case SUBTRACT: { + if (ingredients.empty()) { + raise << current_recipe_name() << ": 'subtract' has no ingredients\n" << end(); + break; + } assert(scalar(ingredients.at(0))); double result = ingredients.at(0).at(0); for (long long int i = 1; i < SIZE(ingredients); ++i) { @@ -116,6 +120,10 @@ DIVIDE, Recipe_ordinal["divide"] = DIVIDE; :(before "End Primitive Recipe Implementations") case DIVIDE: { + if (ingredients.empty()) { + raise << current_recipe_name() << ": 'divide' has no ingredients\n" << end(); + break; + } assert(scalar(ingredients.at(0))); double result = ingredients.at(0).at(0); for (long long int i = 1; i < SIZE(ingredients); ++i) { @@ -155,6 +163,10 @@ DIVIDE_WITH_REMAINDER, Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER; :(before "End Primitive Recipe Implementations") case DIVIDE_WITH_REMAINDER: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'divide-with-remainder' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); + break; + } long long int quotient = ingredients.at(0).at(0) / ingredients.at(1).at(0); long long int remainder = static_cast(ingredients.at(0).at(0)) % static_cast(ingredients.at(1).at(0)); products.resize(2); diff --git a/022boolean.cc b/022boolean.cc index 86b2f16d..bebe2204 100644 --- a/022boolean.cc +++ b/022boolean.cc @@ -90,7 +90,7 @@ NOT, Recipe_ordinal["not"] = NOT; :(before "End Primitive Recipe Implementations") case NOT: { - products.resize(ingredients.size()); + products.resize(SIZE(ingredients)); for (long long int i = 0; i < SIZE(ingredients); ++i) { assert(scalar(ingredients.at(i))); products.at(i).push_back(!ingredients.at(i).at(0)); diff --git a/023jump.cc b/023jump.cc index edccf207..af713628 100644 --- a/023jump.cc +++ b/023jump.cc @@ -16,9 +16,15 @@ JUMP, Recipe_ordinal["jump"] = JUMP; :(before "End Primitive Recipe Implementations") case JUMP: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'jump' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'jump' should be a label or offset, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } assert(current_instruction().ingredients.at(0).initialized); - assert(SIZE(ingredients) == 1); - assert(scalar(ingredients.at(0))); current_step_index() += ingredients.at(0).at(0)+1; trace(Primitive_recipe_depth, "run") << "jumping to instruction " << current_step_index() << end(); continue; // skip rest of this instruction @@ -45,14 +51,23 @@ JUMP_IF, Recipe_ordinal["jump-if"] = JUMP_IF; :(before "End Primitive Recipe Implementations") case JUMP_IF: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'jump-if' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": 'jump-if' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } + if (!scalar(ingredients.at(1))) { + raise << current_recipe_name() << ": 'jump-if' requires a label or offset for its second ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } assert(current_instruction().ingredients.at(1).initialized); - assert(SIZE(ingredients) == 2); - assert(scalar(ingredients.at(0))); if (!ingredients.at(0).at(0)) { trace(Primitive_recipe_depth, "run") << "jump-if fell through" << end(); break; } - assert(scalar(ingredients.at(1))); current_step_index() += ingredients.at(1).at(0)+1; trace(Primitive_recipe_depth, "run") << "jumping to instruction " << current_step_index() << end(); continue; // skip rest of this instruction @@ -84,14 +99,23 @@ JUMP_UNLESS, Recipe_ordinal["jump-unless"] = JUMP_UNLESS; :(before "End Primitive Recipe Implementations") case JUMP_UNLESS: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'jump-unless' requires exactly two ingredients, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": 'jump-unless' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } + if (!scalar(ingredients.at(1))) { + raise << current_recipe_name() << ": 'jump-unless' requires a label or offset for its second ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } assert(current_instruction().ingredients.at(1).initialized); - assert(SIZE(ingredients) == 2); - assert(scalar(ingredients.at(0))); if (ingredients.at(0).at(0)) { trace(Primitive_recipe_depth, "run") << "jump-unless fell through" << end(); break; } - assert(scalar(ingredients.at(1))); current_step_index() += ingredients.at(1).at(0)+1; trace(Primitive_recipe_depth, "run") << "jumping to instruction " << current_step_index() << end(); continue; // skip rest of this instruction diff --git a/024compare.cc b/024compare.cc index c037c381..cd31065b 100644 --- a/024compare.cc +++ b/024compare.cc @@ -6,6 +6,10 @@ EQUAL, Recipe_ordinal["equal"] = EQUAL; :(before "End Primitive Recipe Implementations") case EQUAL: { + if (SIZE(ingredients) <= 1) { + raise << current_recipe_name() << ": 'equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); + break; + } vector& exemplar = ingredients.at(0); bool result = true; for (long long int i = 1; i < SIZE(ingredients); ++i) { @@ -58,14 +62,22 @@ Recipe_ordinal["greater-than"] = GREATER_THAN; :(before "End Primitive Recipe Implementations") case GREATER_THAN: { bool result = true; + if (SIZE(ingredients) <= 1) { + raise << current_recipe_name() << ": 'greater-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); + break; + } for (long long int i = 0; i < SIZE(ingredients); ++i) { - assert(scalar(ingredients.at(i))); + if (!scalar(ingredients.at(i))) { + raise << current_recipe_name() << ": 'greater-than' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); + goto finish_greater_than; + } } for (long long int i = /**/1; i < SIZE(ingredients); ++i) { if (ingredients.at(i-1).at(0) <= ingredients.at(i).at(0)) { result = false; } } + finish_greater_than: products.resize(1); products.at(0).push_back(result); break; @@ -106,14 +118,22 @@ Recipe_ordinal["lesser-than"] = LESSER_THAN; :(before "End Primitive Recipe Implementations") case LESSER_THAN: { bool result = true; + if (SIZE(ingredients) <= 1) { + raise << current_recipe_name() << ": 'lesser-than' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); + break; + } for (long long int i = 0; i < SIZE(ingredients); ++i) { - assert(scalar(ingredients.at(i))); + if (!scalar(ingredients.at(i))) { + raise << current_recipe_name() << ": 'lesser-than' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); + goto finish_lesser_than; + } } for (long long int i = /**/1; i < SIZE(ingredients); ++i) { if (ingredients.at(i-1).at(0) >= ingredients.at(i).at(0)) { result = false; } } + finish_lesser_than: products.resize(1); products.at(0).push_back(result); break; @@ -154,14 +174,22 @@ Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL; :(before "End Primitive Recipe Implementations") case GREATER_OR_EQUAL: { bool result = true; + if (SIZE(ingredients) <= 1) { + raise << current_recipe_name() << ": 'greater-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); + break; + } for (long long int i = 0; i < SIZE(ingredients); ++i) { - assert(scalar(ingredients.at(i))); + if (!scalar(ingredients.at(i))) { + raise << current_recipe_name() << ": 'greater-or-equal' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); + goto finish_greater_or_equal; + } } for (long long int i = /**/1; i < SIZE(ingredients); ++i) { if (ingredients.at(i-1).at(0) < ingredients.at(i).at(0)) { result = false; } } + finish_greater_or_equal: products.resize(1); products.at(0).push_back(result); break; @@ -210,14 +238,22 @@ Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL; :(before "End Primitive Recipe Implementations") case LESSER_OR_EQUAL: { bool result = true; + if (SIZE(ingredients) <= 1) { + raise << current_recipe_name() << ": 'lesser-or-equal' needs at least two ingredients to compare in '" << current_instruction().to_string() << "'\n" << end(); + break; + } for (long long int i = 0; i < SIZE(ingredients); ++i) { - assert(scalar(ingredients.at(i))); + if (!scalar(ingredients.at(i))) { + raise << current_recipe_name() << ": 'lesser-or-equal' can only compare numbers; got " << current_instruction().ingredients.at(i).original_string << '\n' << end(); + goto finish_lesser_or_equal; + } } for (long long int i = /**/1; i < SIZE(ingredients); ++i) { if (ingredients.at(i-1).at(0) > ingredients.at(i).at(0)) { result = false; } } + finish_lesser_or_equal: products.resize(1); products.at(0).push_back(result); break; diff --git a/027trace.cc b/027trace.cc index 12cc7ca3..742432fa 100644 --- a/027trace.cc +++ b/027trace.cc @@ -12,6 +12,10 @@ TRACE, Recipe_ordinal["trace"] = TRACE; :(before "End Primitive Recipe Implementations") case TRACE: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'trace' takes exactly two ingredients rather than '" << current_instruction().to_string() << "'\n" << end(); + break; + } assert(is_literal(current_instruction().ingredients.at(0))); string label = current_instruction().ingredients.at(0).name; assert(is_literal(current_instruction().ingredients.at(1))); diff --git a/028assert.cc b/028assert.cc index 07f68cc8..6cdb2ba0 100644 --- a/028assert.cc +++ b/028assert.cc @@ -11,10 +11,19 @@ ASSERT, Recipe_ordinal["assert"] = ASSERT; :(before "End Primitive Recipe Implementations") case ASSERT: { - assert(SIZE(ingredients) == 2); - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'assert' takes exactly two ingredients rather than '" << current_instruction().to_string() << "'\n" << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": 'assert' requires a boolean for its first ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } + if (!scalar(ingredients.at(1))) { + raise << current_recipe_name() << ": 'assert' requires a literal string for its second ingredient, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); + break; + } if (!ingredients.at(0).at(0)) { - assert(is_literal(current_instruction().ingredients.at(1))); raise << current_instruction().ingredients.at(1).name << '\n' << end(); } break; diff --git a/030container.cc b/030container.cc index 79ab71e1..76f05d05 100644 --- a/030container.cc +++ b/030container.cc @@ -107,7 +107,7 @@ GET, Recipe_ordinal["get"] = GET; :(before "End Primitive Recipe Implementations") case GET: { - if (ingredients.size() != 2) { + if (SIZE(ingredients) != 2) { raise << current_recipe_name() << ": 'get' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); break; } @@ -115,11 +115,11 @@ case GET: { long long int base_address = base.value; type_ordinal base_type = base.types.at(0); if (Type[base_type].kind != container) { - raise << current_recipe_name () << ": 'get' on a non-container " << base.original_string << '\n' << end(); + raise << current_recipe_name () << ": first ingredient of 'get' should be a container, but got " << base.original_string << '\n' << end(); break; } if (!is_literal(current_instruction().ingredients.at(1))) { - raise << current_recipe_name() << ": expected ingredient 1 of 'get' to have type 'offset', got '" << current_instruction().ingredients.at(1).original_string << "'\n" << end(); + raise << current_recipe_name() << ": second ingredient of 'get' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } assert(scalar(ingredients.at(1))); @@ -192,11 +192,11 @@ case GET_ADDRESS: { long long int base_address = base.value; type_ordinal base_type = base.types.at(0); if (Type[base_type].kind != container) { - raise << current_recipe_name () << ": 'get-address' on a non-container " << base.original_string << '\n' << end(); + raise << current_recipe_name () << ": first ingredient of 'get-address' should be a container, but got " << base.original_string << '\n' << end(); break; } if (!is_literal(current_instruction().ingredients.at(1))) { - raise << current_recipe_name() << ": expected ingredient 1 of 'get-address' to have type 'offset', got '" << current_instruction().ingredients.at(1).original_string << "'\n" << end(); + raise << current_recipe_name() << ": second ingredient of 'get-address' should have type 'offset', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } assert(scalar(ingredients.at(1))); diff --git a/031address.cc b/031address.cc index 0e2a4f0f..51a6a960 100644 --- a/031address.cc +++ b/031address.cc @@ -40,9 +40,15 @@ reagent deref(reagent x) { //? cout << "deref: " << x.to_string() << "\n"; //? 2 static const type_ordinal ADDRESS = Type_ordinal["address"]; reagent result; - assert(x.types.at(0) == ADDRESS); - + if (x.types.at(0) != ADDRESS) { + raise << current_recipe_name() << ": tried to /deref " << x.original_string << " but it isn't an address\n" << end(); + return result; + } // compute value + if (x.value == 0) { + raise << current_recipe_name() << ": tried to /deref 0\n" << end(); + return result; + } result.set_value(Memory[x.value]); trace(Primitive_recipe_depth, "mem") << "location " << x.value << " is " << result.value << end(); diff --git a/032array.cc b/032array.cc index f9134e87..a9274b49 100644 --- a/032array.cc +++ b/032array.cc @@ -79,20 +79,19 @@ INDEX, Recipe_ordinal["index"] = INDEX; :(before "End Primitive Recipe Implementations") case INDEX: { -//? if (Trace_stream) Trace_stream->dump_layer = "run"; //? 1 + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'index' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); + break; + } reagent base = canonize(current_instruction().ingredients.at(0)); -//? trace(Primitive_recipe_depth, "run") << "ingredient 0 after canonize: " << base.to_string() << end(); //? 1 long long int base_address = base.value; if (base.types.at(0) != Type_ordinal["array"]) { raise << current_recipe_name () << ": 'index' on a non-array " << base.original_string << '\n' << end(); break; } reagent offset = canonize(current_instruction().ingredients.at(1)); -//? trace(Primitive_recipe_depth, "run") << "ingredient 1 after canonize: " << offset.to_string() << end(); //? 1 vector offset_val(read_memory(offset)); vector element_type = array_element(base.types); -//? trace(Primitive_recipe_depth, "run") << "offset: " << offset_val.at(0) << end(); //? 1 -//? trace(Primitive_recipe_depth, "run") << "size of elements: " << size_of(element_type) << end(); //? 1 if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) { raise << current_recipe_name() << ": invalid index " << offset_val.at(0) << '\n' << end(); products.resize(1); @@ -172,6 +171,10 @@ INDEX_ADDRESS, Recipe_ordinal["index-address"] = INDEX_ADDRESS; :(before "End Primitive Recipe Implementations") case INDEX_ADDRESS: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'index-address' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); + break; + } reagent base = canonize(current_instruction().ingredients.at(0)); long long int base_address = base.value; if (base.types.at(0) != Type_ordinal["array"]) { @@ -240,9 +243,13 @@ LENGTH, Recipe_ordinal["length"] = LENGTH; :(before "End Primitive Recipe Implementations") case LENGTH: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'length' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); + break; + } reagent x = canonize(current_instruction().ingredients.at(0)); if (x.types.at(0) != Type_ordinal["array"]) { - raise << "tried to calculate length of non-array " << x.to_string() << '\n' << end(); + raise << "tried to calculate length of non-array " << x.original_string << '\n' << end(); break; } products.resize(1); diff --git a/033exclusive_container.cc b/033exclusive_container.cc index c212be79..804d649f 100644 --- a/033exclusive_container.cc +++ b/033exclusive_container.cc @@ -11,16 +11,12 @@ type_ordinal tmp = Type_ordinal["number-or-point"] = Next_type_ordinal++; Type[tmp].size = 2; Type[tmp].kind = exclusive_container; Type[tmp].name = "number-or-point"; -//? cout << tmp << ": " << SIZE(Type[tmp].elements) << '\n'; //? 1 vector t1; t1.push_back(number); Type[tmp].elements.push_back(t1); -//? cout << SIZE(Type[tmp].elements) << '\n'; //? 1 vector t2; t2.push_back(point); Type[tmp].elements.push_back(t2); -//? cout << SIZE(Type[tmp].elements) << '\n'; //? 1 -//? cout << "point: " << point << '\n'; //? 1 Type[tmp].element_names.push_back("i"); Type[tmp].element_names.push_back("p"); } @@ -44,13 +40,9 @@ recipe main [ if (t.kind == exclusive_container) { // size of an exclusive container is the size of its largest variant // (So like containers, it can't contain arrays.) -//? cout << "--- " << types.at(0) << ' ' << t.size << '\n'; //? 1 -//? cout << "point: " << Type_ordinal["point"] << " " << Type[Type_ordinal["point"]].name << " " << Type[Type_ordinal["point"]].size << '\n'; //? 1 -//? cout << t.name << ' ' << t.size << ' ' << SIZE(t.elements) << '\n'; //? 1 long long int result = 0; for (long long int i = 0; i < t.size; ++i) { long long int tmp = size_of(t.elements.at(i)); -//? cout << i << ": " << t.elements.at(i).at(0) << ' ' << tmp << ' ' << result << '\n'; //? 1 if (tmp > result) result = tmp; } // ...+1 for its tag. @@ -91,15 +83,19 @@ MAYBE_CONVERT, Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT; :(before "End Primitive Recipe Implementations") case MAYBE_CONVERT: { + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'maybe-convert' expects exactly 2 ingredients in '" << current_instruction().to_string() << "'\n" << end(); + break; + } reagent base = canonize(current_instruction().ingredients.at(0)); long long int base_address = base.value; type_ordinal base_type = base.types.at(0); if (Type[base_type].kind != exclusive_container) { - raise << current_recipe_name () << ": 'maybe-convert' on a non-exclusive-container " << base.original_string << '\n' << end(); + raise << current_recipe_name () << ": first ingredient of 'maybe-convert' should be an exclusive-container, but got " << base.original_string << '\n' << end(); break; } if (!is_literal(current_instruction().ingredients.at(1))) { - raise << current_recipe_name() << ": expected ingredient 1 of 'get' to have type 'variant', got '" << current_instruction().ingredients.at(1).original_string << "'\n" << end(); + raise << current_recipe_name() << ": second ingredient of 'maybe-convert' should have type 'variant', but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); break; } long long int tag = current_instruction().ingredients.at(1).value; diff --git a/034call.cc b/034call.cc index cafabd53..16b6ca41 100644 --- a/034call.cc +++ b/034call.cc @@ -85,7 +85,7 @@ default: { break; } Current_routine->calls.push_front(call(current_instruction().operation)); -complete_call: + call_housekeeping: ++Callstack_depth; assert(Callstack_depth < 9000); // 9998-101 plus cushion continue; // not done with caller; don't increment current_step_index() diff --git a/035call_ingredient.cc b/035call_ingredient.cc index fa8e012e..7ffa1207 100644 --- a/035call_ingredient.cc +++ b/035call_ingredient.cc @@ -26,7 +26,7 @@ long long int next_ingredient_to_process; :(before "End call Constructor") next_ingredient_to_process = 0; -:(after "complete_call:") +:(after "call_housekeeping:") for (long long int i = 0; i < SIZE(ingredients); ++i) { Current_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i)); } @@ -37,6 +37,10 @@ NEXT_INGREDIENT, Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT; :(before "End Primitive Recipe Implementations") case NEXT_INGREDIENT: { + if (!ingredients.empty()) { + raise << current_recipe_name() << ": 'next-ingredient' didn't expect any ingredients in '" << current_instruction().to_string() << "'\n" << end(); + break; + } assert(!Current_routine->calls.empty()); if (Current_routine->calls.front().next_ingredient_to_process < SIZE(Current_routine->calls.front().ingredient_atoms)) { products.push_back( @@ -95,7 +99,14 @@ INGREDIENT, Recipe_ordinal["ingredient"] = INGREDIENT; :(before "End Primitive Recipe Implementations") case INGREDIENT: { - assert(is_literal(current_instruction().ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'ingredient' expects exactly one ingredient, but got '" << current_instruction().to_string() << "'\n" << end(); + break; + } + if (!is_literal(current_instruction().ingredients.at(0))) { + raise << current_recipe_name() << ": 'ingredient' expects a literal ingredient, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } assert(scalar(ingredients.at(0))); if (static_cast(ingredients.at(0).at(0)) < SIZE(Current_routine->calls.front().ingredient_atoms)) { Current_routine->calls.front().next_ingredient_to_process = ingredients.at(0).at(0); diff --git a/036call_reply.cc b/036call_reply.cc index 75587351..a5f265a2 100644 --- a/036call_reply.cc +++ b/036call_reply.cc @@ -22,10 +22,6 @@ case REPLY: { const instruction& reply_inst = current_instruction(); // save pointer into recipe before pop const string& callee = current_recipe_name(); --Callstack_depth; -//? if (tb_is_active()) { //? 1 -//? tb_clear(); //? 1 -//? cerr << Recipe[Current_routine->calls.front().running_recipe].name << ' ' << current_step_index() << '\n'; //? 1 -//? } //? 1 Current_routine->calls.pop_front(); // just in case 'main' returns a value, drop it for now if (Current_routine->calls.empty()) goto stop_running_current_routine; @@ -37,21 +33,22 @@ case REPLY: { if (SIZE(caller_instruction.products) > SIZE(ingredients)) raise << "too few values replied from " << callee << '\n' << end(); for (long long int i = 0; i < SIZE(caller_instruction.products); ++i) { -//? cerr << Recipe[Current_routine->calls.front().running_recipe].name << '\n'; //? 1 trace(Primitive_recipe_depth, "run") << "result " << i << " is " << to_string(ingredients.at(i)) << end(); if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) { vector tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient"); - assert(SIZE(tmp) == 1); + if (SIZE(tmp) != 1) { + raise << current_recipe_name() << ": 'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end(); + goto finish_reply; + } long long int ingredient_index = to_integer(tmp.at(0)); if (ingredient_index >= SIZE(caller_instruction.ingredients)) raise << current_recipe_name() << ": 'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end(); -//? cerr << caller_instruction.products.size() << ' ' << i << ' ' << caller_instruction.ingredients.size() << ' ' << ingredient_index << '\n'; //? 1 -//? cerr << caller_instruction.to_string() << '\n'; //? 1 if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value) raise << current_recipe_name() << ": 'same-as-ingredient' result " << caller_instruction.products.at(i).value << " from call to " << callee << " must be location " << caller_instruction.ingredients.at(ingredient_index).value << '\n' << end(); } } // End Reply + finish_reply: break; // continue to process rest of *caller* instruction } @@ -144,18 +141,22 @@ recipe test1 [ // reply b, c, ... // ``` if (curr.name == "reply-if") { - assert(curr.products.empty()); - curr.operation = Recipe_ordinal["jump-unless"]; - curr.name = "jump-unless"; - vector results; - copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end())); - curr.ingredients.resize(1); - curr.ingredients.push_back(reagent("1:offset")); - result.steps.push_back(curr); - curr.clear(); - curr.operation = Recipe_ordinal["reply"]; - curr.name = "reply"; - curr.ingredients.swap(results); + if (curr.products.empty()) { + curr.operation = Recipe_ordinal["jump-unless"]; + curr.name = "jump-unless"; + vector results; + copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end())); + curr.ingredients.resize(1); + curr.ingredients.push_back(reagent("1:offset")); + result.steps.push_back(curr); + curr.clear(); + curr.operation = Recipe_ordinal["reply"]; + curr.name = "reply"; + curr.ingredients.swap(results); + } + else { + raise << "'reply-if' never yields any products\n" << end(); + } } // rewrite `reply-unless a, b, c, ...` to // ``` @@ -163,16 +164,20 @@ if (curr.name == "reply-if") { // reply b, c, ... // ``` if (curr.name == "reply-unless") { - assert(curr.products.empty()); - curr.operation = Recipe_ordinal["jump-if"]; - curr.name = "jump-if"; - vector results; - copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end())); - curr.ingredients.resize(1); - curr.ingredients.push_back(reagent("1:offset")); - result.steps.push_back(curr); - curr.clear(); - curr.operation = Recipe_ordinal["reply"]; - curr.name = "reply"; - curr.ingredients.swap(results); + if (curr.products.empty()) { + curr.operation = Recipe_ordinal["jump-if"]; + curr.name = "jump-if"; + vector results; + copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end())); + curr.ingredients.resize(1); + curr.ingredients.push_back(reagent("1:offset")); + result.steps.push_back(curr); + curr.clear(); + curr.operation = Recipe_ordinal["reply"]; + curr.name = "reply"; + curr.ingredients.swap(results); + } + else { + raise << "'reply-unless' never yields any products\n" << end(); + } } diff --git a/037recipe.cc b/037recipe.cc index 95e61073..41c688f5 100644 --- a/037recipe.cc +++ b/037recipe.cc @@ -43,11 +43,19 @@ CALL, Recipe_ordinal["call"] = CALL; :(before "End Primitive Recipe Implementations") case CALL: { - assert(scalar(ingredients.at(0))); + if (ingredients.empty()) { + raise << current_recipe_name() << ": 'call' requires at least one ingredient (the recipe to call)\n" << end(); + break; + } + // Begin Call + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'call' should be a recipe, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } // todo: when we start doing type checking this will be a prime point of // attention, so we don't accidentally allow external data to a program to // run as code. Current_routine->calls.push_front(call(ingredients.at(0).at(0))); ingredients.erase(ingredients.begin()); // drop the callee - goto complete_call; + goto call_housekeeping; } diff --git a/038scheduler.cc b/038scheduler.cc index 5334009c..a218799c 100644 --- a/038scheduler.cc +++ b/038scheduler.cc @@ -304,7 +304,14 @@ ROUTINE_STATE, Recipe_ordinal["routine-state"] = ROUTINE_STATE; :(before "End Primitive Recipe Implementations") case ROUTINE_STATE: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'routine-state' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } long long int id = ingredients.at(0).at(0); long long int result = -1; for (long long int i = 0; i < SIZE(Routines); ++i) { @@ -326,7 +333,14 @@ RESTART, Recipe_ordinal["restart"] = RESTART; :(before "End Primitive Recipe Implementations") case RESTART: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'restart' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } long long int id = ingredients.at(0).at(0); for (long long int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->id == id) { @@ -343,7 +357,14 @@ STOP, Recipe_ordinal["stop"] = STOP; :(before "End Primitive Recipe Implementations") case STOP: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'stop' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } long long int id = ingredients.at(0).at(0); for (long long int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->id == id) { diff --git a/039wait.cc b/039wait.cc index 8a40dc8a..5b589d6a 100644 --- a/039wait.cc +++ b/039wait.cc @@ -41,7 +41,6 @@ case WAIT_FOR_LOCATION: { Current_routine->waiting_on_location = loc.value; Current_routine->old_value_of_waiting_location = Memory[loc.value]; trace(Primitive_recipe_depth, "run") << "waiting for location " << loc.value << " to change from " << Memory[loc.value] << end(); -//? trace("schedule") << Current_routine->id << ": waiting for location " << loc.value << " to change from " << Memory[loc.value] << end(); //? 2 break; } @@ -49,12 +48,7 @@ case WAIT_FOR_LOCATION: { :(before "End Scheduler State Transitions") for (long long int i = 0; i < SIZE(Routines); ++i) { -//? trace("schedule") << "wake up loop 1: routine " << Routines.at(i)->id << " has state " << Routines.at(i)->state << end(); //? 1 if (Routines.at(i)->state != WAITING) continue; -//? trace("schedule") << "waiting on location: " << Routines.at(i)->waiting_on_location << end(); //? 1 -//? if (Routines.at(i)->waiting_on_location) //? 2 -//? trace("schedule") << "checking routine " << Routines.at(i)->id << " waiting on location " //? 2 -//? << Routines.at(i)->waiting_on_location << ": " << Memory[Routines.at(i)->waiting_on_location] << " vs " << Routines.at(i)->old_value_of_waiting_location; //? 2 if (Routines.at(i)->waiting_on_location && Memory[Routines.at(i)->waiting_on_location] != Routines.at(i)->old_value_of_waiting_location) { trace("schedule") << "waking up routine\n" << end(); @@ -96,8 +90,19 @@ WAIT_FOR_ROUTINE, Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE; :(before "End Primitive Recipe Implementations") case WAIT_FOR_ROUTINE: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'wait-for-routine' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } + if (ingredients.at(0).at(0) == Current_routine->id) { + raise << current_recipe_name() << ": routine can't wait for itself! " << current_instruction().to_string() << '\n' << end(); + break; + } Current_routine->state = WAITING; - assert(scalar(ingredients.at(0))); Current_routine->waiting_on_routine = ingredients.at(0).at(0); trace(Primitive_recipe_depth, "run") << "waiting for routine " << ingredients.at(0).at(0) << end(); break; @@ -111,7 +116,7 @@ for (long long int i = 0; i < SIZE(Routines); ++i) { if (Routines.at(i)->state != WAITING) continue; if (!Routines.at(i)->waiting_on_routine) continue; long long int id = Routines.at(i)->waiting_on_routine; - assert(id != Routines.at(i)->id); + assert(id != Routines.at(i)->id); // routine can't wait on itself for (long long int j = 0; j < SIZE(Routines); ++j) { if (Routines.at(j)->id == id && Routines.at(j)->state != RUNNING) { trace("schedule") << "waking up routine " << Routines.at(i)->id << end(); @@ -130,7 +135,6 @@ case SWITCH: { long long int id = some_other_running_routine(); if (id) { assert(id != Current_routine->id); -//? cerr << "waiting on " << id << " from " << Current_routine->id << '\n'; //? 1 Current_routine->state = WAITING; Current_routine->waiting_on_routine = id; } diff --git a/041jump_label.cc b/041jump_label.cc index 2527e813..a24970d5 100644 --- a/041jump_label.cc +++ b/041jump_label.cc @@ -26,7 +26,6 @@ void transform_labels(const recipe_ordinal r) { for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) { instruction& inst = Recipe[r].steps.at(i); if (inst.operation == Recipe_ordinal["jump"]) { -//? cerr << inst.to_string() << '\n'; //? 1 replace_offset(inst.ingredients.at(0), offset, i, r); } if (inst.operation == Recipe_ordinal["jump-if"] || inst.operation == Recipe_ordinal["jump-unless"]) { @@ -46,15 +45,14 @@ void transform_labels(const recipe_ordinal r) { :(code) void replace_offset(reagent& x, /*const*/ map& offset, const long long int current_offset, const recipe_ordinal r) { -//? cerr << "AAA " << x.to_string() << '\n'; //? 1 - assert(is_literal(x)); -//? cerr << "BBB " << x.to_string() << '\n'; //? 1 + if (!is_literal(x)) { + raise << Recipe[r].name << ": jump target must be offset or label but is " << x.original_string << '\n' << end(); + return; + } assert(!x.initialized); -//? cerr << "CCC " << x.to_string() << '\n'; //? 1 if (is_integer(x.name)) return; // non-labels will be handled like other number operands -//? cerr << "DDD " << x.to_string() << '\n'; //? 1 if (offset.find(x.name) == offset.end()) - raise << "can't find label " << x.name << " in routine " << Recipe[r].name << '\n' << end(); + raise << Recipe[r].name << ": can't find label " << x.name << '\n' << end(); x.set_value(offset[x.name]-current_offset); } diff --git a/042name.cc b/042name.cc index 283bcbd7..9e2d75b2 100644 --- a/042name.cc +++ b/042name.cc @@ -219,9 +219,10 @@ recipe main [ // replace element names of containers with offsets if (inst.operation == Recipe_ordinal["get"] || inst.operation == Recipe_ordinal["get-address"]) { - // at least 2 args, and second arg is offset - assert(SIZE(inst.ingredients) >= 2); -//? cout << inst.ingredients.at(1).to_string() << '\n'; //? 1 + if (SIZE(inst.ingredients) != 2) { + raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end(); + break; + } if (!is_literal(inst.ingredients.at(1))) raise << Recipe[r].name << ": expected ingredient 1 of " << (inst.operation == Recipe_ordinal["get"] ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end(); if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) { @@ -258,8 +259,10 @@ recipe main [ :(after "Per-recipe Transforms") // convert variant names of exclusive containers if (inst.operation == Recipe_ordinal["maybe-convert"]) { - // at least 2 args, and second arg is offset - assert(SIZE(inst.ingredients) >= 2); + if (SIZE(inst.ingredients) != 2) { + raise << Recipe[r].name << ": exactly 2 ingredients expected in '" << current_instruction().to_string() << "'\n" << end(); + break; + } assert(is_literal(inst.ingredients.at(1))); if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) { // since first non-address in base type must be an exclusive container, we don't have to canonize diff --git a/043new.cc b/043new.cc index 08c68eec..5fb62ed3 100644 --- a/043new.cc +++ b/043new.cc @@ -34,14 +34,14 @@ Type_ordinal["type"] = 0; if (inst.operation == Recipe_ordinal["new"]) { // End NEW Transform Special-cases // first arg must be of type 'type' - assert(SIZE(inst.ingredients) >= 1); - if (!is_literal(inst.ingredients.at(0))) - raise << "expected literal, got " << inst.ingredients.at(0).original_string << '\n' << end(); - if (inst.ingredients.at(0).properties.at(0).second.at(0) != "type") - raise << "tried to allocate non-type " << inst.ingredients.at(0).to_string() << " in recipe " << Recipe[r].name << '\n' << end(); + if (inst.ingredients.empty()) + raise << Recipe[r].name << ": 'new' expects one or two ingredients\n" << end(); + if (inst.ingredients.at(0).properties.empty() + || inst.ingredients.at(0).properties.at(0).second.empty() + || inst.ingredients.at(0).properties.at(0).second.at(0) != "type") + raise << Recipe[r].name << ": first ingredient of 'new' should be a type, but got " << inst.ingredients.at(0).original_string << '\n' << end(); if (Type_ordinal.find(inst.ingredients.at(0).name) == Type_ordinal.end()) - raise << "unknown type " << inst.ingredients.at(0).name << " in recipe " << Recipe[r].name << '\n' << end(); -//? cerr << "type " << inst.ingredients.at(0).name << " => " << Type_ordinal[inst.ingredients.at(0).name] << '\n'; //? 1 + raise << Recipe[r].name << ": unknown type " << inst.ingredients.at(0).name << '\n' << end(); inst.ingredients.at(0).set_value(Type_ordinal[inst.ingredients.at(0).name]); trace(Primitive_recipe_depth, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end(); end_new_transform:; @@ -56,14 +56,19 @@ NEW, Recipe_ordinal["new"] = NEW; :(before "End Primitive Recipe Implementations") case NEW: { + if (ingredients.empty() || SIZE(ingredients) > 2) { + raise << current_recipe_name() << ": 'new' requires one or two ingredients, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'new' should be a type, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + } // compute the space we need long long int size = 0; long long int array_length = 0; { vector type; - assert(is_literal(current_instruction().ingredients.at(0))); type.push_back(current_instruction().ingredients.at(0).value); -//? trace(Primitive_recipe_depth, "mem") << "type " << current_instruction().ingredients.at(0).to_string() << ' ' << type.size() << ' ' << type.back() << " has size " << size_of(type) << end(); //? 1 if (SIZE(current_instruction().ingredients) > 1) { // array array_length = ingredients.at(1).at(0); @@ -82,7 +87,6 @@ case NEW: { ensure_space(size); const long long int result = Current_routine->alloc; trace(Primitive_recipe_depth, "mem") << "new alloc: " << result << end(); -//? trace(Primitive_recipe_depth, "mem") << "size: " << size << " locations" << end(); //? 1 // save result products.resize(1); products.at(0).push_back(result); @@ -115,7 +119,6 @@ case NEW: { :(code) void ensure_space(long long int size) { assert(size <= Initial_memory_per_routine); -//? cout << Current_routine->alloc << " " << Current_routine->alloc_max << " " << size << '\n'; //? 1 if (Current_routine->alloc + size > Current_routine->alloc_max) { // waste the remaining space and create a new chunk Current_routine->alloc = Memory_allocated_until; @@ -208,14 +211,18 @@ ABANDON, Recipe_ordinal["abandon"] = ABANDON; :(before "End Primitive Recipe Implementations") case ABANDON: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'abandon' requires one ingredient, but got '" << current_instruction().to_string() << "'\n" << end(); + break; + } if (!scalar(ingredients.at(0))) { - raise << "abandon's ingredient should be scalar\n" << end(); + raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } long long int address = ingredients.at(0).at(0); reagent types = canonize(current_instruction().ingredients.at(0)); if (types.types.at(0) != Type_ordinal["address"]) { - raise << "abandon's ingredient should be an address\n" << end(); + raise << current_recipe_name() << ": first ingredient of 'abandon' should be an address, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); break; } reagent target_type = deref(types); @@ -322,7 +329,6 @@ long long int new_mu_string(const string& contents) { //? Num_alloc++; //? 1 ensure_space(string_length+1); // don't forget the extra location for array size // initialize string -//? cout << "new string literal: " << current_instruction().ingredients.at(0).name << '\n'; //? 1 long long int result = Current_routine->alloc; Memory[Current_routine->alloc++] = string_length; long long int curr = 0; diff --git a/044space.cc b/044space.cc index 17ca4d2a..31fca4ec 100644 --- a/044space.cc +++ b/044space.cc @@ -138,8 +138,7 @@ if (curr.name == "new-default-space") { } :(after "void write_memory(reagent x, vector data)") if (x.name == "number-of-locals") { - assert(scalar(data)); - raise << "can't write to special variable number-of-locals\n" << end(); + raise << current_recipe_name() << ": can't write to special name 'number-of-locals'\n" << end(); return; } @@ -176,11 +175,9 @@ if (curr.name == "local-scope") { void try_reclaim_locals() { // only reclaim routines starting with 'local-scope' const recipe_ordinal r = Recipe_ordinal[current_recipe_name()]; + if (Recipe[r].steps.empty()) return; const instruction& inst = Recipe[r].steps.at(0); - if (inst.name != "local-scope") - return; -//? cerr << inst.to_string() << '\n'; //? 1 -//? cerr << current_recipe_name() << ": abandon " << Current_routine->calls.front().default_space << '\n'; //? 1 + if (inst.name != "local-scope") return; abandon(Current_routine->calls.front().default_space, /*array length*/1+/*number-of-locals*/Name[r][""]); } @@ -215,7 +212,8 @@ long long int address(long long int offset, long long int base) { :(after "void write_memory(reagent x, vector data)") if (x.name == "default-space") { - assert(scalar(data)); + if (!scalar(data)) + raise << current_recipe_name() << ": 'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end(); Current_routine->calls.front().default_space = data.at(0); return; } diff --git a/045space_surround.cc b/045space_surround.cc index b90d464f..1ab41c91 100644 --- a/045space_surround.cc +++ b/045space_surround.cc @@ -41,7 +41,8 @@ long long int space_base(const reagent& x, long long int space_index, long long long long int space_index(const reagent& x) { for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) { if (x.properties.at(i).first == "space") { - assert(SIZE(x.properties.at(i).second) == 1); + if (SIZE(x.properties.at(i).second) != 1) + raise << current_recipe_name() << ": /space metadata should take exactly one value in " << x.original_string << '\n' << end(); return to_integer(x.properties.at(i).second.at(0)); } } diff --git a/046closure_name.cc b/046closure_name.cc index bc7460f5..dc2c4b61 100644 --- a/046closure_name.cc +++ b/046closure_name.cc @@ -7,8 +7,6 @@ recipe main [ default-space:address:array:location <- new location:type, 30:literal 1:address:array:location/names:new-counter <- new-counter -#? $print [AAAAAAAAAAAAAAAA] -#? $print 1:address:array:location 2:number/raw <- increment-counter 1:address:array:location/names:new-counter 3:number/raw <- increment-counter 1:address:array:location/names:new-counter ] @@ -60,7 +58,7 @@ void collect_surrounding_spaces(const recipe_ordinal r) { raise << "slot 0 requires a /names property in recipe " << Recipe[r].name << end(); continue; } - if (SIZE(s) > 1) raise << "slot 0 should have a single value in /names, got " << inst.products.at(j).to_string() << '\n' << end(); + if (SIZE(s) > 1) raise << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end(); string surrounding_recipe_name = s.at(0); if (Surrounding_space.find(r) != Surrounding_space.end() && Surrounding_space[r] != Recipe_ordinal[surrounding_recipe_name]) { @@ -128,7 +126,10 @@ recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, long long int n bool already_transformed(const reagent& r, const map& names) { if (has_property(r, "space")) { vector p = property(r, "space"); - assert(SIZE(p) == 1); + if (SIZE(p) != 1) { + raise << "/space property should have exactly one (non-negative integer) value in " << r.original_string << '\n' << end(); + return false; + } if (p.at(0) != "0") return true; } return names.find(r.name) != names.end(); diff --git a/047global.cc b/047global.cc index 6ce4b78f..39be9bc2 100644 --- a/047global.cc +++ b/047global.cc @@ -31,7 +31,8 @@ long long int global_space; global_space = 0; :(after "void write_memory(reagent x, vector data)") if (x.name == "global-space") { - assert(scalar(data)); + if (!scalar(data)) + raise << current_recipe_name() << ": 'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end(); if (Current_routine->global_space) raise << "routine already has a global-space; you can't over-write your globals" << end(); Current_routine->global_space = data.at(0); @@ -66,7 +67,6 @@ $warn: 0 :(code) bool is_global(const reagent& x) { -//? cerr << x.to_string() << '\n'; //? 1 for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) { if (x.properties.at(i).first == "space") return !x.properties.at(i).second.empty() && x.properties.at(i).second.at(0) == "global"; diff --git a/049continuation.cc b/049continuation.cc index e625e7b7..c79db298 100644 --- a/049continuation.cc +++ b/049continuation.cc @@ -40,7 +40,10 @@ CONTINUE_FROM, Recipe_ordinal["continue-from"] = CONTINUE_FROM; :(before "End Primitive Recipe Implementations") case CONTINUE_FROM: { - assert(scalar(ingredients.at(0))); + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'continue-from' should be a continuation id generated by 'current-continuation', but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } long long int c = ingredients.at(0).at(0); Current_routine->calls = Continuation[c]; // deep copy; calls have no pointers continue; // skip rest of this instruction @@ -171,7 +174,7 @@ case CREATE_DELIMITED_CONTINUATION: { Current_routine->calls.front().is_reset = true; Current_routine->calls.push_front(call(Recipe_ordinal[current_instruction().ingredients.at(0).name])); ingredients.erase(ingredients.begin()); // drop the callee - goto complete_call; + goto call_housekeeping; } //: save the slice of current call stack until the 'create-delimited-continuation' @@ -197,7 +200,10 @@ case REPLY_DELIMITED_CONTINUATION: { // copy the current call stack until the most recent 'reset' call call_stack::iterator find_reset(call_stack& c); // manual prototype containing '::' call_stack::iterator reset = find_reset(Current_routine->calls); - assert(reset != Current_routine->calls.end()); + if (reset == Current_routine->calls.end()) { + raise << current_recipe_name() << ": couldn't find a 'reset' call to jump out to\n" << end(); + break; + } Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), reset); while (Current_routine->calls.begin() != reset) { --Callstack_depth; @@ -218,15 +224,19 @@ call_stack::iterator find_reset(call_stack& c) { } //: overload 'call' for continuations -:(after "case CALL:") - if (current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") { +:(after "Begin Call") + if (!current_instruction().ingredients.at(0).properties.empty() + && !current_instruction().ingredients.at(0).properties.at(0).second.empty() + && current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") { // copy multiple calls on to current call stack assert(scalar(ingredients.at(0))); - assert(Delimited_continuation.find(ingredients.at(0).at(0)) != Delimited_continuation.end()); + if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) { + raise << current_recipe_name() << ": no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + } const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)]; for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p) Current_routine->calls.push_front(*p); ++current_step_index(); // skip past the reply-delimited-continuation ingredients.erase(ingredients.begin()); // drop the callee - goto complete_call; + goto call_housekeeping; } diff --git a/064random.cc b/064random.cc index 6fadeb40..bd171132 100644 --- a/064random.cc +++ b/064random.cc @@ -27,7 +27,14 @@ ROUND, Recipe_ordinal["round"] = ROUND; :(before "End Primitive Recipe Implementations") case ROUND: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'round' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'round' should be a number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } products.resize(1); products.at(0).push_back(rint(ingredients.at(0).at(0))); break; diff --git a/070display.cc b/070display.cc index 335a3e55..976be637 100644 --- a/070display.cc +++ b/070display.cc @@ -14,7 +14,6 @@ bool Autodisplay = true; OPEN_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["open-console"] = OPEN_CONSOLE; -//? cerr << "open-console: " << OPEN_CONSOLE << '\n'; //? 1 :(before "End Primitive Recipe Implementations") case OPEN_CONSOLE: { tb_init(); @@ -71,22 +70,29 @@ case PRINT_CHARACTER_TO_DISPLAY: { int h=tb_height(), w=tb_width(); long long int height = (h >= 0) ? h : 0; long long int width = (w >= 0) ? w : 0; - assert(scalar(ingredients.at(0))); + if (ingredients.empty()) { + raise << current_recipe_name() << ": 'print-character-to-display' requires at least one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'print-character-to-display' should be a character, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } long long int c = ingredients.at(0).at(0); -//? tb_shutdown(); //? 1 -//? cerr << "AAA " << c << ' ' << (int)'\n' << ' ' << (int)'\r' << '\n'; //? 1 -//? exit(1); //? 1 int color = TB_BLACK; if (SIZE(ingredients) > 1) { - assert(scalar(ingredients.at(1))); + if (!scalar(ingredients.at(1))) { + raise << current_recipe_name() << ": second ingredient of 'print-character-to-display' should be a foreground color number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); + break; + } color = ingredients.at(1).at(0); -//? tb_shutdown(); //? 1 -//? cerr << "AAA " << color << '\n'; //? 1 -//? exit(1); //? 1 } int bg_color = TB_BLACK; if (SIZE(ingredients) > 2) { - assert(scalar(ingredients.at(2))); + if (!scalar(ingredients.at(2))) { + raise << current_recipe_name() << ": third ingredient of 'print-character-to-display' should be a background color number, but got " << current_instruction().ingredients.at(2).original_string << '\n' << end(); + break; + } bg_color = ingredients.at(2).at(0); if (bg_color == 0) bg_color = TB_BLACK; } @@ -135,9 +141,19 @@ MOVE_CURSOR_ON_DISPLAY, Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY; :(before "End Primitive Recipe Implementations") case MOVE_CURSOR_ON_DISPLAY: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 2) { + raise << current_recipe_name() << ": 'move-cursor-on-display' requires two ingredients, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'move-cursor-on-display' should be a row number, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } Display_row = ingredients.at(0).at(0); - assert(scalar(ingredients.at(1))); + if (!scalar(ingredients.at(1))) { + raise << current_recipe_name() << ": second ingredient of 'move-cursor-on-display' should be a column number, but got " << current_instruction().ingredients.at(1).original_string << '\n' << end(); + break; + } Display_column = ingredients.at(1).at(0); tb_set_cursor(Display_column, Display_row); if (Autodisplay) tb_present(); diff --git a/081run_interactive.cc b/081run_interactive.cc index bbb49a97..75e58012 100644 --- a/081run_interactive.cc +++ b/081run_interactive.cc @@ -26,7 +26,14 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE; //? cerr << "run-interactive: " << RUN_INTERACTIVE << '\n'; //? 1 :(before "End Primitive Recipe Implementations") case RUN_INTERACTIVE: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'run-interactive' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'run-interactive' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } products.resize(3); bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); if (!new_code_pushed_to_stack) { @@ -170,7 +177,6 @@ if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction() } if (SIZE(current_instruction().products) >= 3) { vector screen; -//? cerr << "returning screen " << Memory[SCREEN] << " to " << current_instruction().products.at(2).to_string() << " value " << current_instruction().products.at(2).value << '\n'; //? 1 screen.push_back(Memory[SCREEN]); write_memory(current_instruction().products.at(2), screen); } @@ -263,7 +269,14 @@ RELOAD, Recipe_ordinal["reload"] = RELOAD; :(before "End Primitive Recipe Implementations") case RELOAD: { - assert(scalar(ingredients.at(0))); + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'reload' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } + if (!scalar(ingredients.at(0))) { + raise << current_recipe_name() << ": first ingredient of 'reload' should be a literal string, but got " << current_instruction().ingredients.at(0).original_string << '\n' << end(); + break; + } if (!Trace_stream) { Trace_file = ""; // if there wasn't already a stream we don't want to save it Trace_stream = new trace_stream; diff --git a/082persist.cc b/082persist.cc index 9d1fa8b2..00d81c53 100644 --- a/082persist.cc +++ b/082persist.cc @@ -8,8 +8,12 @@ RESTORE, Recipe_ordinal["restore"] = RESTORE; :(before "End Primitive Recipe Implementations") case RESTORE: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'restore' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } if (!scalar(ingredients.at(0))) - raise << "restore: illegal operand " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); + raise << current_recipe_name() << ": first ingredient of 'restore' should be a literal string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); products.resize(1); string filename = current_instruction().ingredients.at(0).name; if (!is_literal(current_instruction().ingredients.at(0))) @@ -47,14 +51,18 @@ SAVE, Recipe_ordinal["save"] = SAVE; :(before "End Primitive Recipe Implementations") case SAVE: { + if (SIZE(ingredients) != 1) { + raise << current_recipe_name() << ": 'save' requires exactly one ingredient, but got " << current_instruction().to_string() << '\n' << end(); + break; + } if (!scalar(ingredients.at(0))) - raise << "save: illegal operand 0 " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); + raise << current_recipe_name() << ": first ingredient of 'save' should be a literal string, but got " << current_instruction().ingredients.at(0).to_string() << '\n' << end(); string filename = current_instruction().ingredients.at(0).name; if (!is_literal(current_instruction().ingredients.at(0))) filename = to_string(ingredients.at(0).at(0)); ofstream fout(("lesson/"+filename).c_str()); if (!scalar(ingredients.at(1))) - raise << "save: illegal operand 1 " << current_instruction().ingredients.at(1).to_string() << '\n' << end(); + raise << current_recipe_name() << ": second ingredient of 'save' should be an address:array:character, but got " << current_instruction().ingredients.at(1).to_string() << '\n' << end(); string contents = read_mu_string(ingredients.at(1).at(0)); fout << contents; fout.close(); -- cgit 1.4.1-2-gfad0