//: Phase 3: Start running a loaded and transformed recipe. //: //: So far we've seen recipes as lists of instructions, and instructions point //: at other recipes. To kick things off mu needs to know how to run certain //: 'primitive' recipes. That will then give the ability to run recipes //: containing these primitives. //: //: This layer defines a skeleton with just two primitive recipes: IDLE which //: does nothing, and COPY, which can copy numbers from one memory location to //: another. Later layers will add more primitives. :(scenario copy_literal) def main [ 1:number <- copy 23 ] +run: {1: "number"} <- copy {23: "literal"} +mem: storing 23 in location 1 :(scenario copy) def main [ 1:number <- copy 23 2:number <- copy 1:number ] +run: {2: "number"} <- copy {1: "number"} +mem: location 1 is 23 +mem: storing 23 in location 2 :(scenario copy_multiple) def main [ 1:number, 2:number <- copy 23, 24 ] +mem: storing 23 in location 1 +mem: storing 24 in location 2 :(before "End Types") // Book-keeping while running a recipe. //: Later layers will replace this. struct routine { recipe_ordinal running_recipe; int running_step_index; routine(recipe_ordinal r) :running_recipe(r), running_step_index(0) {} bool completed() const; const vector& steps() const; }; :(before "End Globals") routine* Current_routine = NULL; map Instructions_running; map Locations_read; map Locations_read_by_instruction; :(code) void run(recipe_ordinal r) { routine rr(r); Current_routine = &rr; run_current_routine(); } void run_current_routine() { // curly on a separate line, because later layers will modify header while (!Current_routine->completed()) // later layers will modify condition { // Running One Instruction if (current_instruction().is_label) { ++current_step_index(); continue; } trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << to_string(current_instruction()) << end(); if (get_or_insert(Memory, 0) != 0) { raise << "something wrote to location 0; this should never happen\n" << end(); put(Memory, 0, 0); } // read all ingredients from memory, each potentially spanning multiple locations vector > ingredients; if (should_copy_ingredients()) { for (int i = 0; i < SIZE(current_instruction().ingredients); ++i) ingredients.push_back(read_memory(current_instruction().ingredients.at(i))); } // instructions below will write to 'products' vector > products; switch (current_instruction().operation) { // Primitive Recipe Implementations case COPY: { copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); break; } // End Primitive Recipe Implementations default: { cout << "not a primitive op: " << current_instruction().operation << '\n'; } } if (SIZE(products) < SIZE(current_instruction().products)) { raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products! " << to_original_string(current_instruction()) << '\n' << end(); } else { for (int i = 0; i < SIZE(current_instruction().products); ++i) { write_memory(current_instruction().products.at(i), products.at(i)); } } // End of Instruction finish_instruction:; ++current_step_index(); } stop_running_current_routine:; } bool should_copy_ingredients() { // End should_copy_ingredients Special-cases return true; } //: Some helpers. //: We'll need to override these later as we change the definition of routine. //: Important that they return referrences into the routine. inline int& current_step_index() { return Current_routine->running_step_index; } inline const string& current_recipe_name() { return get(Recipe, Current_rou
c{0: 0 (((test1))) -- nil
c{1: 0 ✓ (((test1)))
c{0: 0 (((1 integer)) <- ((copy)) ((1 literal))) -- nil
c{1: 0 ✓ (((1 integer)) <- ((copy)) ((1 literal)))
cn0: convert-names in main
cn0: (((test1))) nil nil
cn0: convert-names in test1
cn0: (((1 integer)) <- ((copy)) ((1 literal))) nil nil
cn0: checking arg ((1 literal))
cn0: checking oarg ((1 integer))
maybe-add: ((1 integer))
cn1: (((test1)))
cn1: (((1 integer)) <- ((copy)) ((1 literal)))
schedule: main
run: main 0: (((test1)))
run: test1/main 0: (((1 integer)) <- ((copy)) ((1 literal)))
run: test1/main 0: 1 => ((1 integer))
mem: ((1 integer)): 1 <= 1
schedule: done with routine nil
y {0: "literal"} :(scenario write_to_0_disallowed) % Hide_errors = true; def main [ 0:number <- copy 34 ] -mem: storing 34 in location 0 //: mu is robust to various combinations of commas and spaces. You just have //: to put spaces around the '<-'. :(scenario comma_without_space) def main [ 1:number, 2:number <- copy 2,2 ] +mem: storing 2 in location 1 :(scenario space_without_comma) def main [ 1:number, 2:number <- copy 2 2 ] +mem: storing 2 in location 1 :(scenario comma_before_space) def main [ 1:number, 2:number <- copy 2, 2 ] +mem: storing 2 in location 1 :(scenario comma_after_space) def main [ 1:number, 2:number <- copy 2 ,2 ] +mem: storing 2 in location 1