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 :(scenario ingredient)
128 def main [
129 f 1, 2
130 ]
131 def f [
132 12:num <- ingredient 1
133 13:num, 1:bool <- next-ingredient
134 ]
135 +mem: storing 2 in location 12
136 +mem: storing 0 in location 1
137
138 :(before "End Primitive Recipe Declarations")
139 INGREDIENT,
140 :(before "End Primitive Recipe Numbers")
141 put(Recipe_ordinal, "ingredient", INGREDIENT);
142 put(Recipe_ordinal, "input", INGREDIENT);
143 :(before "End Primitive Recipe Checks")
144 case INGREDIENT: {
145 if (SIZE(inst.ingredients) != 1) {
146 raise << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << to_original_string(inst) << "'\n" << end();
147 break;
148 }
149 if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) {
150 raise << maybe(get(Recipe, r).name) << "'ingredient' expects a literal ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
151 break;
152 }
153 break;
154 }
155 :(before "End Primitive Recipe Implementations")
156 case INGREDIENT: {
157 if (static_cast<int>(ingredients.at(0).at(0)) < SIZE(current_call().ingredient_atoms)) {
158 current_call().next_ingredient_to_process = ingredients.at(0).at(0);
159 products.push_back(
160 current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
161 assert(SIZE(products) == 1); products.resize(2);
162 products.at(1).push_back(1);
163 ++current_call().next_ingredient_to_process;
164 }
165 else {
166 if (SIZE(current_instruction().products) > 1) {
167 products.resize(2);
168 products.at(0).push_back(0);
169 products.at(1).push_back(0);
170 }
171 }
172 break;
173 }
174
175
176 :(code)
177 bool is_mu_text(reagent x) {
178
179 return x.type
180 && !x.type->atom
181 && x.type->left->atom
182 && x.type->left->value == Address_type_ordinal
183 && x.type->right
184 && !x.type->right->atom
185 && x.type->right->left->atom
186 && x.type->right->left->value == Array_type_ordinal
187 && x.type->right->right
188 && !x.type->right->right->atom
189 && x.type->right->right->left->value == Character_type_ordinal
190 && x.type->right->right->right == NULL;
191 }