1699 - first-class recipe types
It should now be easy to do dynamic dispatch, create higher-order functions, etc.
This commit is contained in:
parent
608d5c9aa1
commit
7f73795cf5
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
51
037recipe.cc
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user