diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-04 12:25:39 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-11-04 12:27:15 -0800 |
commit | ff8d96ae16d6ef9c901ea8ee6c045319ae0f1187 (patch) | |
tree | 085c63dc394ef941015e4b5a51602914d20448bc /043new.cc | |
parent | bc6fcd0fcb56df5e12ace096a66d56badb97cdfc (diff) | |
download | mu-ff8d96ae16d6ef9c901ea8ee6c045319ae0f1187.tar.gz |
2351 - support arbitrary type trees in 'new'
In the process we also convert types to sizes before we start running.
Diffstat (limited to '043new.cc')
-rw-r--r-- | 043new.cc | 116 |
1 files changed, 65 insertions, 51 deletions
diff --git a/043new.cc b/043new.cc index 72f3491b..70cac35b 100644 --- a/043new.cc +++ b/043new.cc @@ -24,29 +24,11 @@ Memory_allocated_until += Initial_memory_per_routine; alloc_max = Memory_allocated_until; trace(9999, "new") << "routine allocated memory from " << alloc << " to " << alloc_max << end(); -//:: First handle 'type' operands. - +//:: 'new' takes a weird 'type' as its first ingredient; don't error on it :(before "End Mu Types Initialization") Type_ordinal["type"] = 0; -:(before "End transform_names(inst) Special-cases") -// replace type names with type_ordinals -if (inst.name == "new") { - // End NEW Transform Special-cases - // first arg must be of type 'type' - if (inst.ingredients.empty()) - raise_error << maybe(Recipe[r].name) << "'new' expects one or two ingredients\n" << end(); - if (!is_mu_type_literal(inst.ingredients.at(0))) - raise_error << maybe(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_error << maybe(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(9999, "new") << inst.ingredients.at(0).name << " -> " << inst.ingredients.at(0).name << end(); - end_new_transform:; -} - -//:: Now implement the primitive recipe. -//: todo: build 'new' in mu itself +//:: typecheck 'new' instructions :(before "End Primitive Recipe Declarations") NEW, :(before "End Primitive Recipe Numbers") @@ -57,7 +39,7 @@ case NEW: { raise_error << maybe(Recipe[r].name) << "'new' requires one or two ingredients, but got " << inst.to_string() << '\n' << end(); break; } - // End NEW Checks + // End NEW Check Special-cases reagent type = inst.ingredients.at(0); if (!is_mu_type_literal(type)) { raise_error << maybe(Recipe[r].name) << "first ingredient of 'new' should be a type, but got " << type.original_string << '\n' << end(); @@ -65,24 +47,48 @@ case NEW: { } break; } + +//:: translate 'new' to 'alloc' instructions that take a size instead of a type +:(after "Transform.push_back(check_instruction)" following "Transform.push_back(check_invalid_types)") // so that all types are defined + Transform.push_back(transform_new_to_allocate); + +:(code) +void transform_new_to_allocate(recipe_ordinal r) { + trace(9991, "transform") << "--- convert 'new' to 'allocate' for recipe " << Recipe[r].name << end(); + for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) { + instruction& inst = Recipe[r].steps.at(i); + // Convert 'new' To 'allocate' + if (inst.name == "new") { + inst.operation = ALLOCATE; +//? istringstream in(inst.ingredients.at(0).name); +//? in >> std::noskipws; + string_tree* type_name = new string_tree(inst.ingredients.at(0).name); + // End Post-processing(type_name) When Converting 'new' + type_tree* type = new_type_tree(type_name); + inst.ingredients.at(0).set_value(size_of(type)); + ostringstream out; + dump_property(type_name, out); + trace(9992, "new") << "size of " << out.str() << " is " << inst.ingredients.at(0).value << end(); + delete type; + delete type_name; + } + } +} + +//:: implement 'allocate' based on size + +:(before "End Primitive Recipe Declarations") +ALLOCATE, +:(before "End Primitive Recipe Numbers") +Recipe_ordinal["allocate"] = ALLOCATE; :(before "End Primitive Recipe Implementations") -case NEW: { +case ALLOCATE: { // compute the space we need - long long int size = 0; - long long int array_length = 0; - { - type_tree* type = new type_tree(current_instruction().ingredients.at(0).value); - if (SIZE(current_instruction().ingredients) > 1) { - // array - array_length = ingredients.at(1).at(0); - trace(9999, "mem") << "array size is " << array_length << end(); - size = array_length*size_of(type) + /*space for length*/1; - } - else { - // scalar - size = size_of(type); - } - delete type; + long long int size = ingredients.at(0).at(0); + if (SIZE(ingredients) > 1) { + // array + trace(9999, "mem") << "array size is " << ingredients.at(1).at(0) << end(); + size = /*space for length*/1 + size*ingredients.at(1).at(0); } //? Total_alloc += size; //? Num_alloc++; @@ -99,7 +105,7 @@ case NEW: { Memory[address] = 0; } if (SIZE(current_instruction().ingredients) > 1) { - Memory[result] = array_length; + Memory[result] = ingredients.at(1).at(0); // array length } // bump Current_routine->alloc += size; @@ -108,6 +114,20 @@ case NEW: { break; } +//:: ensure we never call 'allocate' directly; its types are not checked +:(before "End Primitive Recipe Checks") +case ALLOCATE: { + raise << "never call 'allocate' directly'; always use 'new'\n" << end(); + break; +} + +//:: ensure we never call 'new' without translating it (unless we add special-cases later) +:(before "End Primitive Recipe Implementations") +case NEW: { + raise << "no implementation for 'new'; why wasn't it translated to 'allocate'?\n" << end(); + break; +} + //? :(before "End Globals") //? long long int Total_alloc = 0; //? long long int Num_alloc = 0; @@ -257,7 +277,7 @@ void abandon(long long int address, long long int size) { Free_list[size] = address; } -:(before "ensure_space(size)" following "case NEW") +:(before "ensure_space(size)" following "case ALLOCATE") if (Free_list[size]) { long long int result = Free_list[size]; Free_list[size] = Memory[result]; @@ -268,7 +288,7 @@ if (Free_list[size]) { } } if (SIZE(current_instruction().ingredients) > 1) - Memory[result] = array_length; + Memory[result] = ingredients.at(1).at(0); else Memory[result] = 0; products.resize(1); @@ -316,18 +336,10 @@ recipe main [ # unicode for '«' +mem: storing 171 in location 3 -:(before "End NEW Transform Special-cases") - if (!inst.ingredients.empty() - && !inst.ingredients.at(0).properties.empty() - && inst.ingredients.at(0).properties.at(0).second - && inst.ingredients.at(0).properties.at(0).second->value == "literal-string") { - // skip transform - inst.ingredients.at(0).initialized = true; - goto end_new_transform; - } - -:(before "End NEW Checks") +:(before "End NEW Check Special-cases") if (is_literal_string(inst.ingredients.at(0))) break; +:(before "Convert 'new' To 'allocate'") +if (inst.name == "new" && is_literal_string(inst.ingredients.at(0))) continue; :(after "case NEW" following "Primitive Recipe Implementations") if (is_literal_string(current_instruction().ingredients.at(0))) { products.resize(1); @@ -437,5 +449,7 @@ string read_mu_string(long long int address) { } bool is_mu_type_literal(reagent r) { +//? if (!r.properties.empty()) +//? dump_property(r.properties.at(0).second, cerr); return is_literal(r) && !r.properties.empty() && r.properties.at(0).second && r.properties.at(0).second->value == "type"; } |