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 :(before "End Primitive Recipe Checks")
44 case NEXT_INGREDIENT: {
45 if (!inst.ingredients.empty()) {
46 ¦ raise << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << inst.original_string << "'\n" << end();
47 ¦ break;
48 }
49 break;
50 }
51 :(before "End Primitive Recipe Implementations")
52 case NEXT_INGREDIENT: {
53 assert(!Current_routine->calls.empty());
54 if (current_call().next_ingredient_to_process < SIZE(current_call().ingredient_atoms)) {
55 ¦ reagent product = current_instruction().products.at(0);
56 ¦
57 ¦ if (current_recipe_name() == "main") {
58 ¦ ¦
59 ¦ ¦
60 ¦ ¦ if (!is_mu_text(product))
61 ¦ ¦ ¦ raise << "main: wrong type for ingredient '" << product.original_string << "'\n" << end();
62 ¦ }
63 ¦ else if (!types_coercible(product,
64 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ current_call().ingredients.at(current_call().next_ingredient_to_process))) {
65 ¦ ¦ raise << maybe(current_recipe_name()) << "wrong type for ingredient '" << product.original_string << "'\n" << end();
66 ¦ ¦
67 ¦ }
68 ¦ products.push_back(
69 ¦ ¦ ¦ current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
70 ¦ assert(SIZE(products) == 1); products.resize(2);
71 ¦ products.at(1).push_back(1);
72 ¦ ++current_call().next_ingredient_to_process;
73 }
74 else {
75 ¦ if (SIZE(current_instruction().products) < 2)
76 ¦ ¦ raise << maybe(current_recipe_name()) << "no ingredient to save in '" << current_instruction().products.at(0).original_string << "'\n" << end();
77 ¦ if (current_instruction().products.empty()) break;
78 ¦ products.resize(2);
79 ¦
80 ¦ products.at(0).resize(size_of(current_instruction().products.at(0)));
81 ¦ products.at(1).push_back(0);
82 }
83 break;
84 }
85
86 :(scenario next_ingredient_fail_on_missing)
87 % Hide_errors = true;
88 def main [
89 f
90 ]
91 def f [
92 11:num <- next-ingredient
93 ]
94 +error: f: no ingredient to save in '11:num'
95
96 :(scenario rewind_ingredients)
97 def main [
98 f 2
99 ]
100 def f [
101 12:num <- next-ingredient
102 _, 1:bool <- next-ingredient
103 rewind-ingredients
104 13:num, 2:bool <- next-ingredient
105 ]
106 +mem: storing 2 in location 12
107 +mem: storing 0 in location 1
108 +mem: storing 2 in location 13
109 +mem: storing 1 in location 2
110
111 :(before "End Primitive Recipe Declarations")
112 REWIND_INGREDIENTS,
113 :(before "End Primitive Recipe Numbers")
114 put(Recipe_ordinal, "rewind-ingredients", REWIND_INGREDIENTS);
115 :(before "End Primitive Recipe Checks")
116 case REWIND_INGREDIENTS: {
117 break;
118 }
119 :(before "End Primitive Recipe Implementations")
120 case REWIND_INGREDIENTS: {
121 current_call().next_ingredient_to_process = 0;
122 break;
123 }
124
125 :(scenario ingredient)
126 def main [
127 f 1, 2
128 ]
129 def f [
130 12:num <- ingredient 1
131 13:num, 1:bool <- next-ingredient
132 ]
133 +mem: storing 2 in location 12
134 +mem: storing 0 in location 1
135
136 :(before "End Primitive Recipe Declarations")
137 INGREDIENT,
138 :(before "End Primitive Recipe Numbers")
139 put(Recipe_ordinal, "ingredient", INGREDIENT);
140 :(before "End Primitive Recipe Checks")
141 case INGREDIENT: {
142 if (SIZE(inst.ingredients) != 1) {
143 ¦ raise << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << inst.original_string << "'\n" << end();
144 ¦ break;
145 }
146 if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) {
147 ¦ raise << maybe(get(Recipe, r).name) << "'ingredient' expects a literal ingredient, but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
148 ¦ break;
149 }
150 break;
151 }
152 :(before "End Primitive Recipe Implementations")
153 case INGREDIENT: {
154 if (static_cast<int>(ingredients.at(0).at(0)) < SIZE(current_call().ingredient_atoms)) {
155 ¦ current_call().next_ingredient_to_process = ingredients.at(0).at(0);
156 ¦ products.push_back(
157 ¦ ¦ ¦ current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
158 ¦ assert(SIZE(products) == 1); products.resize(2);
159 ¦ products.at(1).push_back(1);
160 ¦ ++current_call().next_ingredient_to_process;
161 }
162 else {
163 ¦ if (SIZE(current_instruction().products) > 1) {
164 ¦ ¦ products.resize(2);
165 ¦ ¦ products.at(0).push_back(0);
166 ¦ ¦ products.at(1).push_back(0);
167 ¦ }
168 }
169 break;
170 }
171
172
173 :(code)
174 bool is_mu_text(reagent x) {
175
176 return x.type
177 ¦ ¦ && !x.type->atom
178 ¦ ¦ && x.type->left->atom
179 ¦ ¦ && x.type->left->value == get(Type_ordinal, "address")
180 ¦ ¦ && x.type->right
181 ¦ ¦ && !x.type->right->atom
182 ¦ ¦ && x.type->right->left->atom
183 ¦ ¦ && x.type->right->left->value == get(Type_ordinal, "array")
184 ¦ ¦ && x.type->right->right
185 ¦ ¦ && !x.type->right->right->atom
186 ¦ ¦ && x.type->right->right->left->value == get(Type_ordinal, "character")
187 ¦ ¦ && x.type->right->right->right == NULL;
188 }