https://github.com/akkartik/mu/blob/master/027call_ingredient.cc
1
2
3
4 :(scenario next_ingredient)
5 def main [
6 f 2
7 ]
8 def f [
9 12:num <- next-ingredient
10 13:num <- add 1, 12:num
11 ]
12 +mem: storing 3 in location 13
13
14 :(scenario next_ingredient_missing)
15 def main [
16 f
17 ]
18 def f [
19 _, 12:num <- next-ingredient
20 ]
21 +mem: storing 0 in location 12
22
23 :(before "End call Fields")
24 vector<vector<double> > ingredient_atoms;
25 vector<reagent> ingredients;
26 int next_ingredient_to_process;
27 :(before "End call Constructor")
28 next_ingredient_to_process = 0;
29
30 :(before "End Call Housekeeping")
31 for (int i = 0; i < SIZE(ingredients); ++i) {
32 current_call().ingredient_atoms.push_back(ingredients.at(i));
33 reagent ingredient = call_instruction.ingredients.at(i);
34
35 current_call().ingredients.push_back(ingredient);
36
37 }
38
39 :(before "End Primitive Recipe Declarations")
40 NEXT_INGREDIENT,
41 :(before "End Primitive Recipe Numbers")
42 put(Recipe_ordinal, "next-ingredient", NEXT_INGREDIENT);
43 put(Recipe_ordinal, "next-input", NEXT_INGREDIENT);
44 :(before "End Primitive Recipe Checks")
45 case NEXT_INGREDIENT: {
46 if (!inst.ingredients.empty()) {
47 raise << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << to_original_string(inst) << "'\n" << end();
48 break;
49 }
50 break;
51 }
52 :(before "End Primitive Recipe Implementations")
53 case NEXT_INGREDIENT: {
54 assert(!Current_routine->calls.empty());
55 if (current_call().next_ingredient_to_process < SIZE(current_call().ingredient_atoms)) {
56 reagent product = current_instruction().products.at(0);
57
58 if (current_recipe_name() == "main") {
59
60
61 if (!is_mu_text(product))
62 raise << "main: wrong type for ingredient '" << product.original_string << "'\n" << end();
63 }
64 else if (!types_coercible(product,
65 current_call().ingredients.at(current_call().next_ingredient_to_process))) {
66 raise << maybe(current_recipe_name()) << "wrong type for ingredient '" << product.original_string << "': " << current_call().ingredients.at(current_call().next_ingredient_to_process).original_string << '\n' << end();
67
68 }
69 products.push_back(
70 current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
71 assert(SIZE(products) == 1); products.resize(2);
72 products.at(1).push_back(1);
73 ++current_call().next_ingredient_to_process;
74 }
75 else {
76 if (SIZE(current_instruction().products) < 2)
77 raise << maybe(current_recipe_name()) << "no ingredient to save in '" << current_instruction().products.at(0).original_string << "'\n" << end();
78 if (current_instruction().products.empty()) break;
79 products.resize(2);
80
81 products.at(0).resize(size_of(current_instruction().products.at(0)));
82 products.at(1).push_back(0);
83 }
84 break;
85 }
86
87 :(scenario next_ingredient_fail_on_missing)
88 % Hide_errors = true;
89 def main [
90 f
91 ]
92 def f [
93 11:num <- next-ingredient
94 ]
95 +error: f: no ingredient to save in '11:num'
96
97 :(scenario rewind_ingredients)
98 def main [
99 f 2
100 ]
101 def f [
102 12:num <- next-ingredient
103 _, 1:bool <- next-ingredient
104 rewind-ingredients
105 13:num, 2:bool <- next-ingredient
106 ]
107 +mem: storing 2 in location 12
108 +mem: storing 0 in location 1
109 +mem: storing 2 in location 13
110 +mem: storing 1 in location 2
111
112 :(before "End Primitive Recipe Declarations")
113 REWIND_INGREDIENTS,
114 :(before "End Primitive Recipe Numbers")
115 put(Recipe_ordinal, "rewind-ingredients", REWIND_INGREDIENTS);
116 put(Recipe_ordinal, "rewind-inputs", REWIND_INGREDIENTS);
117 :(before "End Primitive Recipe Checks")
118 case REWIND_INGREDIENTS: {
119 break;
120 }
121 :(before "End Primitive Recipe Implementations")
122 case REWIND_INGREDIENTS: {
123 current_call().next_ingredient_to_process = 0;
124 break;
125 }
126
127
128
129 :(scenario ingredient)
130 def main [
131 f 1, 2
132 ]
133 def f [
134 12:num <- ingredient 1
135 13:num, 1:bool <- next-ingredient
136 ]
137 +mem: storing 2 in location 12
138 +mem: storing 0 in location 1
139
140 :(before "End Primitive Recipe Declarations")
141 INGREDIENT,
142 :(before "End Primitive Recipe Numbers")
143 put(Recipe_ordinal, "ingredient", INGREDIENT);
144 put(Recipe_ordinal, "input", INGREDIENT);
145 :(before "End Primitive Recipe Checks")
146 case INGREDIENT: {
147 if (SIZE(inst.ingredients) != 1) {
148 raise << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
149 break;
150 }
151 if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) {
152 raise << maybe(get(Recipe, r).name) << "'ingredient' expects a literal ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
153 break;
154 }
155 break;
156 }
157 :(before "End Primitive Recipe Implementations")
158 case INGREDIENT: {
159 if (static_cast<int>(ingredients.at(0).at(0)) < SIZE(current_call().ingredient_atoms)) {
160 current_call().next_ingredient_to_process = ingredients.at(0).at(0);
161 products.push_back(
162 current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
163 assert(SIZE(products) == 1); products.resize(2);
164 products.at(1).push_back(1);
165 ++current_call().next_ingredient_to_process;
166 }
167 else {
168 if (SIZE(current_instruction().products) > 1) {
169 products.resize(2);
170 products.at(0).push_back(0);
171 products.at(1).push_back(0);
172 }
173 }
174 break;
175 }
176
177
178 :(code)
179 bool is_mu_text(reagent x) {
180
181 return x.type
182 && !x.type->atom
183 && x.type->left->atom
184 && x.type->left->value == Address_type_ordinal
185 && x.type->right
186 && !x.type->right->atom
187 && x.type->right->left->atom
188 && x.type->right->left->value == Array_type_ordinal
189 && x.type->right->right
190 && !x.type->right->right->atom
191 && x.type->right->right->left->value == Character_type_ordinal
192 && x.type->right->right->right == NULL;
193 }