1
2
3 :(scenario calling_recipe)
4 def main [
5 f
6 ]
7 def f [
8 3:num <- add 2, 2
9 ]
10 +mem: storing 4 in location 3
11
12 :(scenario return_on_fallthrough)
13 def main [
14 f
15 1:num <- copy 0
16 2:num <- copy 0
17 3:num <- copy 0
18 ]
19 def f [
20 4:num <- copy 0
21 5:num <- copy 0
22 ]
23 +run: f
24
25 +run: {4: "number"} <- copy {0: "literal"}
26 +run: {5: "number"} <- copy {0: "literal"}
27
28 +run: {1: "number"} <- copy {0: "literal"}
29 +run: {2: "number"} <- copy {0: "literal"}
30 +run: {3: "number"} <- copy {0: "literal"}
31
32 :(before "struct routine {")
33
34
35
36 struct call {
37 recipe_ordinal running_recipe;
38 int running_step_index;
39
40 call(recipe_ordinal r) { clear(r, 0); }
41 call(recipe_ordinal r, int index) { clear(r, index); }
42 void clear(recipe_ordinal r, int index) {
43 running_recipe = r;
44 running_step_index = index;
45
46 }
47 ~call() {
48
49 }
50 };
51 typedef list<call> call_stack;
52
53 :(replace{} "struct routine")
54 struct routine {
55 call_stack calls;
56
57 routine(recipe_ordinal r);
58 bool completed() const;
59 const vector<instruction>& steps() const;
60 };
61 :(code)
62 routine::routine(recipe_ordinal r) {
63 if (Trace_stream) {
64 ++Trace_stream->callstack_depth;
65 trace("trace") << "new routine; incrementing callstack depth to " << Trace_stream->callstack_depth << end();
66 assert(Trace_stream->callstack_depth < 9000);
67 }
68 calls.push_front(call(r));
69
70 }
71
72
73
74
75
76 :(delete{} "int& current_step_index()")
77 :(delete{} "recipe_ordinal currently_running_recipe()")
78 :(delete{} "const string& current_recipe_name()")
79 :(delete{} "const recipe& current_recipe()")
80 :(delete{} "const instruction& current_instruction()")
81
82 :(before "End Includes")
83 #define current_call() Current_routine->calls.front()
84 #define current_step_index() current_call().running_step_index
85 #define currently_running_recipe() current_call().running_recipe
86 #define current_recipe() get(Recipe, currently_running_recipe())
87 #define current_recipe_name() current_recipe().name
88 #define to_instruction(call) get(Recipe, (call).running_recipe).steps.at((call).running_step_index)
89 #define current_instruction() to_instruction(current_call())
90
91
92
93 :(code)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 :(after "Defined Recipe Checks")
137
138 if (!contains_key(Recipe, inst.operation)) {
139 raise << maybe(get(Recipe, r).name) << "undefined operation in '" << to_original_string(inst) << "'\n" << end();
140 break;
141 }
142 :(replace{} "default:" following "End Primitive Recipe Implementations")
143 default: {
144 if (contains_key(Recipe, current_instruction().operation)) {
145
146 if (Trace_stream) {
147 ++Trace_stream->callstack_depth;
148 trace("trace") << "incrementing callstack depth to " << Trace_stream->callstack_depth << end();
149 assert(Trace_stream->callstack_depth < 9000);
150 }
151 const call& caller_frame = current_call();
152 Current_routine->calls.push_front(call(to_instruction(caller_frame).operation));
153 finish_call_housekeeping(to_instruction(caller_frame), ingredients);
154
155 write_products = false;
156 fall_through_to_next_instruction = false;
157
158 }
159 }
160 :(code)
161 void finish_call_housekeeping(const instruction& call_instruction, const vector<vector<double> >& ingredients) {
162
163 }
164
165 :(scenario calling_undefined_recipe_fails)
166 % Hide_errors = true;
167 def main [
168 foo
169 ]
170 +error: main: undefined operation in 'foo'
171
172 :(scenario calling_undefined_recipe_handles_missing_result)
173 % Hide_errors = true;
174 def main [
175 x:num <- foo
176 ]
177 +error: main: undefined operation in 'x:num <- foo'
178
179
180
181 :(replace{} "bool routine::completed() const")
182 bool routine::completed() const {
183 return calls.empty();
184 }
185
186 :(replace{} "const vector<instruction>& routine::steps() const")
187 const vector<instruction>& routine::steps() const {
188 assert(!calls.empty());
189 return get(Recipe, calls.front().running_recipe).steps;
190 }
191
192 :(after "Running One Instruction")
193
194
195 while (current_step_index() >= SIZE(Current_routine->steps())) {
196
197 if (Trace_stream) {
198 trace("trace") << "fall-through: exiting " << current_recipe_name() << "; decrementing callstack depth from " << Trace_stream->callstack_depth << end();
199 --Trace_stream->callstack_depth;
200 assert(Trace_stream->callstack_depth >= 0);
201 }
202 Current_routine->calls.pop_front();
203 if (Current_routine->calls.empty()) goto stop_running_current_routine;
204
205
206 ++current_step_index();
207 }
208
209 :(before "End Primitive Recipe Declarations")
210 _DUMP_CALL_STACK,
211 :(before "End Primitive Recipe Numbers")
212 put(Recipe_ordinal, "$dump-call-stack", _DUMP_CALL_STACK);
213 :(before "End Primitive Recipe Checks")
214 case _DUMP_CALL_STACK: {
215 break;
216 }
217 :(before "End Primitive Recipe Implementations")
218 case _DUMP_CALL_STACK: {
219 dump(Current_routine->calls);
220 break;
221 }
222 :(code)
223 void dump(const call_stack& calls) {
224 for (call_stack::const_reverse_iterator p = calls.rbegin(); p != calls.rend(); ++p)
225 cerr << get(Recipe, p->running_recipe).name << ":" << p->running_step_index << " -- " << to_string(to_instruction(*p)) << '\n';
226 }