https://github.com/akkartik/mu/blob/master/101run_sandboxed.cc
1
2
3
4 :(scenario run_interactive_code)
5 def main [
6 1:num <- copy 0
7 10:text <- new [1:num/raw <- copy 34]
8
9 run-sandboxed 10:text
10 20:num <- copy 1:num
11 ]
12 +mem: storing 34 in location 20
13
14 :(scenario run_interactive_empty)
15 def main [
16 10:text <- copy null
17 20:text <- run-sandboxed 10:text
18 ]
19
20 +mem: storing 0 in location 20
21 +mem: storing 0 in location 21
22
23
24
25 :(before "End Globals")
26 bool Sandbox_mode = false;
27
28 :(before "End Load Recipe Name")
29 if (Sandbox_mode && result.name == "main") {
30 slurp_balanced_bracket(in);
31 return -1;
32 }
33
34
35
36
37
38
39 :(before "End Primitive Recipe Declarations")
40 RUN_SANDBOXED,
41 :(before "End Primitive Recipe Numbers")
42 put(Recipe_ordinal, "run-sandboxed", RUN_SANDBOXED);
43 :(before "End Primitive Recipe Checks")
44 case RUN_SANDBOXED: {
45 if (SIZE(inst.ingredients) != 1) {
46 raise << maybe(get(Recipe, r).name) << "'run-sandboxed' requires exactly one ingredient, but got '" << inst.original_string << "'\n" << end();
47 break;
48 }
49 if (!is_mu_text(inst.ingredients.at(0))) {
50 raise << maybe(get(Recipe, r).name) << "first ingredient of 'run-sandboxed' should be a string, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end();
51 break;
52 }
53 break;
54 }
55 :(before "End Primitive Recipe Implementations")
56 case RUN_SANDBOXED: {
57 bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(1));
58 if (!new_code_pushed_to_stack) {
59 products.resize(5);
60 products.at(0).push_back(0);
61 products.at(0).push_back(0);
62 products.at(1).push_back(0);
63 products.at(1).push_back(trace_error_contents());
64 products.at(2).push_back(0);
65 products.at(2).push_back(0);
66 products.at(3).push_back(0);
67 products.at(3).push_back(trace_app_contents());
68 products.at(4).push_back(1);
69 run_code_end();
70 break;
71 }
72 else {
73 continue;
74 }
75 }
76
77
78
79
80
81
82 :(before "End Globals")
83 bool Track_most_recent_products = false;
84 int Call_depth_to_track_most_recent_products_at = 0;
85 string Most_recent_products;
86 :(before "End Reset")
87 Track_most_recent_products = false;
88 Call_depth_to_track_most_recent_products_at = 0;
89 Most_recent_products = "";
90
91 :(before "End Globals")
92 trace_stream* Save_trace_stream = NULL;
93 string Save_trace_file;
94 :(code)
95
96
97
98 bool run_interactive(int address) {
99
100 assert(contains_key(Recipe_ordinal, "interactive") && get(Recipe_ordinal, "interactive") != 0);
101
102
103 if (!Current_scenario) {
104 for (int i = 1; i < Reserved_for_tests; ++i)
105 Memory.erase(i);
106 }
107 string command = trim(strip_comments(read_mu_text(address)));
108
109 Name[get(Recipe_ordinal, "interactive")].clear();
110 run_code_begin(true);
111 if (command.empty()) return false;
112
113 routine* save_current_routine = Current_routine;
114 Current_routine = NULL;
115
116 load(string("recipe! interactive [\n") +
117 "local-scope\n" +
118 "screen:&:screen <- next-ingredient\n" +
119 "$start-tracking-products\n" +
120 command + "\n" +
121 "$stop-tracking-products\n" +
122 "return screen\n" +
123 "]\n");
124 transform_all();
125 Current_routine = save_current_routine;
126 if (trace_count("error") > 0) return false;
127
128
129 if (Save_trace_stream) {
130 ++Save_trace_stream->callstack_depth;
131 trace(9999, "trace") << "run-sandboxed: incrementing callstack depth to " << Save_trace_stream->callstack_depth << end();
132 assert(Save_trace_stream->callstack_depth < 9000);
133 }
134 Current_routine->calls.push_front(call(get(Recipe_ordinal, "sandbox")));
135 return true;
136 }
137
138
139
140 :(before "End Globals")
141 bool Run_profiler_stash = false;
142 map<string, recipe_ordinal> Recipe_ordinal_snapshot_stash;
143 map<recipe_ordinal, recipe> Recipe_snapshot_stash;
144 map<string, type_ordinal> Type_ordinal_snapshot_stash;
145 map<type_ordinal, type_info> Type_snapshot_stash;
146 map<recipe_ordinal, map<string, int> > Name_snapshot_stash;
147 map<string, vector<recipe_ordinal> > Recipe_variants_snapshot_stash;
148 map<string, type_tree*> Type_abbreviations_snapshot_stash;
149 vector<scenario> Scenarios_snapshot_stash;
150 set<string> Scenario_names_snapshot_stash;
151
152 :(code)
153 void run_code_begin(bool should_stash_snapshots) {
154
155 Hide_errors = true;
156 Disable_redefine_checks = true;
157 Run_profiler_stash = Run_profiler;
158 Run_profiler = false;
159 if (should_stash_snapshots)
160 stash_snapshots();
161 Save_trace_stream = Trace_stream;
162 Trace_stream = new trace_stream;
163 Trace_stream->collect_depth = App_depth;
164 }
165
166 void run_code_end() {
167 Hide_errors = false;
168 Disable_redefine_checks = false;
169 Run_profiler = Run_profiler_stash;
170 Run_profiler_stash = false;
171
172
173
174 delete Trace_stream;
175 Trace_stream = Save_trace_stream;
176 Save_trace_stream = NULL;
177 Save_trace_file.clear();
178 Recipe.erase(get(Recipe_ordinal, "interactive"));
179 if (!Recipe_snapshot_stash.empty())
180 unstash_snapshots();
181 }
182
183
184 void stash_snapshots() {
185 assert(Recipe_ordinal_snapshot_stash.empty());
186 Recipe_ordinal_snapshot_stash = Recipe_ordinal_snapshot;
187 assert(Recipe_snapshot_stash.empty());
188 Recipe_snapshot_stash = Recipe_snapshot;
189 assert(Type_ordinal_snapshot_stash.empty());
190 Type_ordinal_snapshot_stash = Type_ordinal_snapshot;
191 assert(Type_snapshot_stash.empty());
192 Type_snapshot_stash = Type_snapshot;
193 assert(Name_snapshot_stash.empty());
194 Name_snapshot_stash = Name_snapshot;
195 assert(Recipe_variants_snapshot_stash.empty());
196 Recipe_variants_snapshot_stash = Recipe_variants_snapshot;
197 assert(Type_abbreviations_snapshot_stash.empty());
198 Type_abbreviations_snapshot_stash = Type_abbreviations_snapshot;
199 assert(Scenarios_snapshot_stash.empty());
200 Scenarios_snapshot_stash = Scenarios_snapshot;
201 assert(Scenario_names_snapshot_stash.empty());
202 Scenario_names_snapshot_stash = Scenario_names_snapshot;
203 save_snapshots();
204 }
205 void unstash_snapshots() {
206 restore_snapshots();
207 Recipe_ordinal_snapshot = Recipe_ordinal_snapshot_stash; Recipe_ordinal_snapshot_stash.clear();
208 Recipe_snapshot = Recipe_snapshot_stash; Recipe_snapshot_stash.clear();
209 Type_ordinal_snapshot = Type_ordinal_snapshot_stash; Type_ordinal_snapshot_stash.clear();
210 Type_snapshot = Type_snapshot_stash; Type_snapshot_stash.clear();
211 Name_snapshot = Name_snapshot_stash; Name_snapshot_stash.clear();
212 Recipe_variants_snapshot = Recipe_variants_snapshot_stash; Recipe_variants_snapshot_stash.clear();
213 Type_abbreviations_snapshot = Type_abbreviations_snapshot_stash; Type_abbreviations_snapshot_stash.clear();
214 Scenarios_snapshot = Scenarios_snapshot_stash; Scenarios_snapshot_stash.clear();
215 Scenario_names_snapshot = Scenario_names_snapshot_stash; Scenario_names_snapshot_stash.clear();
216 }
217
218 :(before "End Mu Prelude")
219 load(string(
220 "recipe interactive [\n") +
221 "]\n" +
222 "recipe sandbox [\n" +
223 "local-scope\n" +
224
225 "screen:&:screen <- new-fake-screen 30, 5\n" +
226 "routine-id:num <- start-running interactive, screen\n" +
227 "limit-time routine-id, 100000/instructions\n" +
228 "wait-for-routine routine-id\n" +
229
230 "instructions-run:num <- number-of-instructions routine-id\n" +
231 "stash instructions-run [instructions run]\n" +
232 "sandbox-state:num <- routine-state routine-id\n" +
233 "completed?:bool <- equal sandbox-state, 1/completed\n" +
234
235 "output:text <- $most-recent-products\n" +
236
237
238 "errors:text <- save-errors\n" +
239 "stashes:text <- save-app-trace\n" +
240 "$cleanup-run-sandboxed\n" +
241 "return output, errors, screen, stashes, completed?\n" +
242 "]\n");
243
244
245 :(before "End maybe(recipe_name) Special-cases")
246 if (recipe_name == "interactive") return "";
247
248 :(scenario run_interactive_comments)
249 def main [
250 1:text <- new [
251 add 2, 2]
252 2:text <- run-sandboxed 1:text
253 3:@:char <- copy *2:text
254 ]
255 +mem: storing 52 in location 4
256
257 :(before "End Primitive Recipe Declarations")
258 _START_TRACKING_PRODUCTS,
259 :(before "End Primitive Recipe Numbers")
260 put(Recipe_ordinal, "$start-tracking-products", _START_TRACKING_PRODUCTS);
261 :(before "End Primitive Recipe Checks")
262 case _START_TRACKING_PRODUCTS: {
263 break;
264 }
265 :(before "End Primitive Recipe Implementations")
266 case _START_TRACKING_PRODUCTS: {
267 Track_most_recent_products = true;
268 Call_depth_to_track_most_recent_products_at = SIZE(Current_routine->calls);
269 break;
270 }
271
272 :(before "End Primitive Recipe Declarations")
273 _STOP_TRACKING_PRODUCTS,
274 :(before "End Primitive Recipe Numbers")
275 put(Recipe_ordinal, "$stop-tracking-products", _STOP_TRACKING_PRODUCTS);
276 :(before "End Primitive Recipe Checks")
277 case _STOP_TRACKING_PRODUCTS: {
278 break;
279 }
280 :(before "End Primitive Recipe Implementations")
281 case _STOP_TRACKING_PRODUCTS: {
282 Track_most_recent_products = false;
283 break;
284 }
285
286 :(before "End Primitive Recipe Declarations")
287 _MOST_RECENT_PRODUCTS,
288 :(before "End Primitive Recipe Numbers")
289 put(Recipe_ordinal, "$most-recent-products", _MOST_RECENT_PRODUCTS);
290 :(before "End Primitive Recipe Checks")
291 case _MOST_RECENT_PRODUCTS: {
292 break;
293 }
294 :(before "End Primitive Recipe Implementations")
295 case _MOST_RECENT_PRODUCTS: {
296 products.resize(1);
297 products.at(0).push_back(0);
298 products.at(0).push_back(new_mu_text(Most_recent_products));
299 break;
300 }
301
302 :(before "End Primitive Recipe Declarations")
303 SAVE_ERRORS,
304 :(before "End Primitive Recipe Numbers")
305 put(Recipe_ordinal, "save-errors", SAVE_ERRORS);
306 :(before "End Primitive Recipe Checks")
307 case SAVE_ERRORS: {
308 break;
309 }
310 :(before "End Primitive Recipe Implementations")
311 case SAVE_ERRORS: {
312 products.resize(1);
313 products.at(0).push_back(0