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) {
41 ¦ running_recipe = r;
42 ¦ running_step_index = 0;
43 ¦
44 }
45 ~call() {
46 ¦
47 }
48 };
49 typedef list<call> call_stack;
50
51 :(replace{} "struct routine")
52 struct routine {
53 call_stack calls;
54
55 routine(recipe_ordinal r);
56 bool completed() const;
57 const vector<instruction>& steps() const;
58 };
59 :(code)
60 routine::routine(recipe_ordinal r) {
61 if (Trace_stream) {
62 ¦ ++Trace_stream->callstack_depth;
63 ¦ trace(9999, "trace") << "new routine; incrementing callstack depth to " << Trace_stream->callstack_depth << end();
64 ¦ assert(Trace_stream->callstack_depth < 9000);
65 }
66 calls.push_front(call(r));
67
68 }
69
70 :(code)
71 call& current_call() {
72 return Current_routine->calls.front();
73 }
74
75
76
77 :(replace{} "int& current_step_index()")
78 int& current_step_index() {
79 assert(!Current_routine->calls.empty());
80 return current_call().running_step_index;
81 }
82 :(replace{} "recipe_ordinal currently_running_recipe()")
83 recipe_ordinal currently_running_recipe() {
84 assert(!Current_routine->calls.empty());
85 return current_call().running_recipe;
86 }
87 :(replace{} "const string& current_recipe_name()")
88 const string& current_recipe_name() {
89 assert(!Current_routine->calls.empty());
90 return get(Recipe, current_call().running_recipe).name;
91 }
92 :(replace{} "const recipe& current_recipe()")
93 const recipe& current_recipe() {
94 assert(!Current_routine->calls.empty());
95 return get(Recipe, current_call().running_recipe);
96 }
97 :(replace{} "const instruction& current_instruction()")
98 const instruction& current_instruction() {
99 assert(!Current_routine->calls.empty());
100 return to_instruction(current_call());
101 }
102 :(code)
103 const instruction& to_instruction(const call& call) {
104 return get(Recipe, call.running_recipe).steps.at(call.running_step_index);
105 }
106
107 :(after "Defined Recipe Checks")
108
109 if (!contains_key(Recipe, inst.operation)) {
110 raise << maybe(get(Recipe, r).name) << "undefined operation in '" << to_original_string(inst) << "'\n" << end();
111 break;
112 }
113 :(replace{} "default:" following "End Primitive Recipe Implementations")
114 default: {
115 if (contains_key(Recipe, current_instruction().operation)) {
116 ¦
117 ¦ if (Trace_stream) {
118 ¦ ¦ ++Trace_stream->callstack_depth;
119 ¦ ¦ trace(9999, "trace") << "incrementing callstack depth to " << Trace_stream->callstack_depth << end();
120 ¦ ¦ assert(Trace_stream->callstack_depth < 9000);
121 ¦ }
122 ¦ const call& caller_frame = current_call();
123 ¦ Current_routine->calls.push_front(call(to_instruction(caller_frame).operation));
124 ¦ finish_call_housekeeping(to_instruction(caller_frame), ingredients);
125 ¦
126 ¦ write_products = false;
127 ¦ fall_through_to_next_instruction = false;
128 ¦
129 }
130 }
131 :(code)
132 void finish_call_housekeeping(const instruction& call_instruction, const vector<vector<double> >& ingredients) {
133
134 }
135
136 :(scenario calling_undefined_recipe_fails)
137 % Hide_errors = true;
138 def main [
139 foo
140 ]
141 +error: main: undefined operation in 'foo'
142
143 :(scenario calling_undefined_recipe_handles_missing_result)
144 % Hide_errors = true;
145 def main [
146 x:num <- foo
147 ]
148 +error: main: undefined operation in 'x:num <- foo'
149
150
151
152 :(replace{} "bool routine::completed() const")
153 bool routine::completed() const {
154 return calls.empty();
155 }
156
157 :(replace{} "const vector<instruction>& routine::steps() const")
158 const vector<instruction>& routine::steps() const {
159 assert(!calls.empty());
160 return get(Recipe, calls.front().running_recipe).steps;
161 }
162
163 :(after "Running One Instruction")
164
165
166 while (current_step_index() >= SIZE(Current_routine->steps())) {
167
168 if (Trace_stream) {
169 ¦ trace(9999, "trace") << "fall-through: exiting " << current_recipe_name() << "; decrementing callstack depth from " << Trace_stream->callstack_depth << end();
170 ¦ --Trace_stream->callstack_depth;
171 ¦ assert(Trace_stream->callstack_depth >= 0);
172 }
173 Current_routine->calls.pop_front();
174 if (Current_routine->calls.empty()) goto stop_running_current_routine;
175
176
177 ++current_step_index();
178 }