https://github.com/akkartik/mu/blob/master/026call.cc
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
84
85
86
87
88
89
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 :(code)
137 void dump_callstack() {
138 if (!Current_routine) return;
139 if (Current_routine->calls.size() <= 1) return;
140 for (call_stack::const_iterator p = ++Current_routine->calls.begin(); p != Current_routine->calls.end(); ++p)
141 raise << " called from " << get(Recipe, p->running_recipe).name << ": " << to_original_string(to_instruction(*p)) << '\n' << end();
142 }
143
144 :(after "Defined Recipe Checks")
145
146 if (!contains_key(Recipe, inst.operation)) {
147 raise << maybe(get(Recipe, r).name) << "undefined operation in '" << to_original_string(inst) << "'\n" << end();
148 break;
149 }
150 :(replace{} "default:" following "End Primitive Recipe Implementations")
151 default: {
152 if (contains_key(Recipe, current_instruction().operation)) {
153
154 if (Trace_stream) {
155 ++Trace_stream->callstack_depth;
156 trace("trace") << "incrementing callstack depth to " << Trace_stream->callstack_depth << end();
157 assert(Trace_stream->callstack_depth < 9000);
158 }
159 const call& caller_frame = current_call();
160 Current_routine->calls.push_front(call(to_instruction(caller_frame).operation));
161 finish_call_housekeeping(to_instruction(caller_frame), ingredients);
162
163 write_products = false;
164 fall_through_to_next_instruction = false;
165
166 }
167 }
168 :(code)
169 void finish_call_housekeeping(const instruction& call_instruction, const vector<vector<double> >& ingredients) {
170
171 }
172
173 :(scenario calling_undefined_recipe_fails)
174 % Hide_errors = true;
175 def main [
176 foo
177 ]
178 +error: main: undefined operation in 'foo'
179
180 :(scenario calling_undefined_recipe_handles_missing_result)
181 % Hide_errors = true;
182 def main [
183 x:num <- foo
184 ]
185 +error: main: undefined operation in 'x:num <- foo'
186
187
188
189 :(replace{} "bool routine::completed() const")
190 bool routine::completed() const {
191 return calls.empty();
192 }
193
194 :(replace{} "const vector<instruction>& routine::steps() const")
195 const vector<instruction>& routine::steps() const {
196 assert(!calls.empty());
197 return get(Recipe, calls.front().running_recipe).steps;
198 }
199
200 :(after "Running One Instruction")
201
202
203 while (current_step_index() >= SIZE(Current_routine->steps())) {
204
205 if (Trace_stream) {
206 trace("trace") << "fall-through: exiting " << current_recipe_name() << "; decrementing callstack depth from " << Trace_stream->callstack_depth << end();
207 --Trace_stream->callstack_depth;
208 assert(Trace_stream->callstack_depth >= 0);
209 }
210 Current_routine->calls.pop_front();
211 if (Current_routine->calls.empty()) goto stop_running_current_routine;
212
213
214 ++current_step_index();
215 }
216
217 :(before "End Primitive Recipe Declarations")
218 _DUMP_CALL_STACK,
219 :(before "End Primitive Recipe Numbers")
220 put(Recipe_ordinal, "$dump-call-stack", _DUMP_CALL_STACK);
221 :(before "End Primitive Recipe Checks")
222 case _DUMP_CALL_STACK: {
223 break;
224 }
225 :(before "End Primitive Recipe Implementations")
226 case _DUMP_CALL_STACK: {
227 dump(Current_routine->calls);
228 break;
229 }
230 :(code)
231 void dump(const call_stack& calls) {
232 for (call_stack::const_reverse_iterator p = calls.rbegin(); p != calls.rend(); ++p)
233 cerr << get(Recipe, p->running_recipe).name << ":" << p->running_step_index << " -- " << to_string(to_instruction(*p)) << '\n';
234 }