diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-07-03 19:38:21 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-07-03 19:38:21 -0700 |
commit | 7f73795cf5a5722dd6c05bee1e7c8c3f8eded8da (patch) | |
tree | 00871986797f79b9156c37dec25eb2071fda0d2c | |
parent | 608d5c9aa148801081d7dca80b6f3bfb5b285f08 (diff) | |
download | mu-7f73795cf5a5722dd6c05bee1e7c8c3f8eded8da.tar.gz |
1699 - first-class recipe types
It should now be easy to do dynamic dispatch, create higher-order functions, etc.
-rw-r--r-- | 012transform.cc | 1 | ||||
-rw-r--r-- | 020run.cc | 1 | ||||
-rw-r--r-- | 037call_variable.cc | 44 | ||||
-rw-r--r-- | 037recipe.cc | 51 | ||||
-rw-r--r-- | 038scheduler.cc | 8 |
5 files changed, 54 insertions, 51 deletions
diff --git a/012transform.cc b/012transform.cc index 7cd4d698..1a7415c8 100644 --- a/012transform.cc +++ b/012transform.cc @@ -47,6 +47,7 @@ void parse_int_reagents() { void populate_value(reagent& r) { if (r.initialized) return; + // End Reagent-parsing Exceptions if (!is_integer(r.name)) return; r.set_value(to_integer(r.name)); } diff --git a/020run.cc b/020run.cc index 2c069576..cecfd7b0 100644 --- a/020run.cc +++ b/020run.cc @@ -76,6 +76,7 @@ void run_current_routine() switch (current_instruction().operation) { // Primitive Recipe Implementations case COPY: { +//? if (!ingredients.empty()) cerr << current_instruction().ingredients.at(0).to_string() << ' ' << ingredients.at(0).at(0) << '\n'; //? 1 copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); break; } diff --git a/037call_variable.cc b/037call_variable.cc deleted file mode 100644 index 9514ed95..00000000 --- a/037call_variable.cc +++ /dev/null @@ -1,44 +0,0 @@ -//: push a variable recipe on the call stack - -:(scenario call_literal_recipe) -recipe main [ - 1:number <- call f:recipe, 34:literal -] -recipe f [ - 2:number <- next-ingredient - reply 2:number -] -+mem: storing 34 in location 1 - -:(scenario call_variable) -recipe main [ - 1:number/recipe <- copy 1001:literal/f # hack: assumes tests start recipes at 1000 - 2:number <- call 1:number/recipe, 34:literal -] -recipe f [ # recipe 1001 - 3:number <- next-ingredient - reply 3:number -] -+mem: storing 34 in location 2 -#? ? - -:(before "End Primitive Recipe Declarations") -CALL, -:(before "End Primitive Recipe Numbers") -Recipe_number["call"] = CALL; -:(before "End Primitive Recipe Implementations") -case CALL: { - recipe_number r = 0; - if (current_instruction().ingredients.at(0).initialized) { - assert(scalar(ingredients.at(0))); - // 'call' received an integer recipe_number - r = ingredients.at(0).at(0); - } - else { - // 'call' received a literal recipe name - r = Recipe_number[current_instruction().ingredients.at(0).name]; - } - Current_routine->calls.push_front(call(r)); - ingredients.erase(ingredients.begin()); // drop the callee - goto complete_call; -} diff --git a/037recipe.cc b/037recipe.cc new file mode 100644 index 00000000..a20994ea --- /dev/null +++ b/037recipe.cc @@ -0,0 +1,51 @@ +//: So far we've been calling a fixed recipe in each instruction, but we'd +//: also like to make the recipe a variable, pass recipes to "higher-order" +//: recipes, return recipes from recipes and so on. + +:(scenario call_literal_recipe) +recipe main [ + 1:number <- call f:recipe, 34:literal +] +recipe f [ + 2:number <- next-ingredient + reply 2:number +] ++mem: storing 34 in location 1 + +:(scenario call_variable) +recipe main [ + 1:recipe-code <- copy f:recipe + 2:number <- call 1:recipe-code, 34:literal +] +recipe f [ + 3:number <- next-ingredient + reply 3:number +] ++mem: storing 34 in location 2 +#? ? + +:(before "End Mu Types Initialization") +Type_number["recipe"] = 0; +type_number recipe_code = Type_number["recipe-code"] = Next_type_number++; +Type[recipe_code].name = "recipe-code"; + +:(before "End Reagent-parsing Exceptions") +if (r.properties.at(0).second.at(0) == "recipe") { + r.set_value(Recipe_number[r.name]); + return; +} + +:(before "End Primitive Recipe Declarations") +CALL, +:(before "End Primitive Recipe Numbers") +Recipe_number["call"] = CALL; +:(before "End Primitive Recipe Implementations") +case CALL: { + assert(scalar(ingredients.at(0))); + // 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; +} diff --git a/038scheduler.cc b/038scheduler.cc index 0857fe58..160753d4 100644 --- a/038scheduler.cc +++ b/038scheduler.cc @@ -127,10 +127,6 @@ Next_routine_id = 1; id = Next_routine_id; Next_routine_id++; -//: it needs a new type: 'recipe' -:(before "End Mu Types Initialization") -Type_number["recipe"] = 0; - //: routines save the routine that spawned them :(before "End routine Fields") // todo: really should be routine_id, but that's less efficient. @@ -144,9 +140,7 @@ START_RUNNING, Recipe_number["start-running"] = START_RUNNING; :(before "End Primitive Recipe Implementations") case START_RUNNING: { - assert(is_literal(current_instruction().ingredients.at(0))); - assert(!current_instruction().ingredients.at(0).initialized); - routine* new_routine = new routine(Recipe_number[current_instruction().ingredients.at(0).name]); + routine* new_routine = new routine(ingredients.at(0).at(0)); //? cerr << new_routine->id << " -> " << Current_routine->id << '\n'; //? 1 new_routine->parent_index = Current_routine_index; // populate ingredients |