1699 - first-class recipe types

It should now be easy to do dynamic dispatch, create higher-order
functions, etc.
This commit is contained in:
Kartik K. Agaram 2015-07-03 19:38:21 -07:00
parent 608d5c9aa1
commit 7f73795cf5
5 changed files with 54 additions and 51 deletions

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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;
}

51
037recipe.cc Normal file
View File

@ -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;
}

View File

@ -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