1 ## handling malformed programs
  2 
  3 container environment [
  4   recipe-errors:text
  5 ]
  6 
  7 # copy code from recipe editor, persist to disk, load, save any errors
  8 def! update-recipes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
  9   local-scope
 10   load-ingredients
 11   recipes:&:editor <- get *env, recipes:offset
 12   in:text <- editor-contents recipes
 13   resources <- dump resources, [lesson/recipes.mu], in
 14   recipe-errors:text <- reload in
 15   *env <- put *env, recipe-errors:offset, recipe-errors
 16   # if recipe editor has errors, stop
 17   {
 18     break-unless recipe-errors
 19     update-status screen, [errors found     ], 1/red
 20     errors-found? <- copy 1/true
 21     return
 22   }
 23   errors-found? <- copy 0/false
 24 ]
 25 
 26 before <render-components-end> [
 27   trace 11, [app], [render status]
 28   recipe-errors:text <- get *env, recipe-errors:offset
 29   {
 30     break-unless recipe-errors
 31     update-status screen, [errors found     ], 1/red
 32   }
 33 ]
 34 
 35 before <render-recipe-components-end> [
 36   {
 37     recipe-errors:text <- get *env, recipe-errors:offset
 38     break-unless recipe-errors
 39     row, screen <- render-text screen, recipe-errors, left, right, 1/red, row
 40   }
 41 ]
 42 
 43 container environment [
 44   error-index:num  # index of first sandbox with an error (or -1 if none)
 45 ]
 46 
 47 after <programming-environment-initialization> [
 48   *result <- put *result, error-index:offset, -1
 49 ]
 50 
 51 after <run-sandboxes-begin> [
 52   *env <- put *env, error-index:offset, -1
 53 ]
 54 
 55 before <run-sandboxes-end> [
 56   {
 57     error-index:num <- get *env, error-index:offset
 58     sandboxes-completed-successfully?:bool <- equal error-index, -1
 59     break-if sandboxes-completed-successfully?
 60     errors-found? <- copy 1/true
 61   }
 62 ]
 63 
 64 before <render-components-end> [
 65   {
 66     break-if recipe-errors
 67     error-index:num <- get *env, error-index:offset
 68     sandboxes-completed-successfully?:bool <- equal error-index, -1
 69     break-if sandboxes-completed-successfully?
 70     error-index-text:text <- to-text error-index
 71     status:text <- interpolate [errors found (_)    ], error-index-text
 72     update-status screen, status, 1/red
 73   }
 74 ]
 75 
 76 container sandbox [
 77   errors:text
 78 ]
 79 
 80 def! update-sandbox sandbox:&:sandbox, env:&:environment, idx:num -> sandbox:&:sandbox, env:&:environment [
 81   local-scope
 82   load-ingredients
 83   data:text <- get *sandbox, data:offset
 84   response:text, errors:text, fake-screen:&:screen, trace:text, completed?:bool <- run-sandboxed data
 85   *sandbox <- put *sandbox, response:offset, response
 86   *sandbox <- put *sandbox, errors:offset, errors
 87   *sandbox <- put *sandbox, screen:offset, fake-screen
 88   *sandbox <- put *sandbox, trace:offset, trace
 89   {
 90     break-if errors
 91     break-if completed?:bool
 92     errors <- new [took too long!
 93 ]
 94     *sandbox <- put *sandbox, errors:offset, errors
 95   }
 96   {
 97     break-unless errors
 98     error-index:num <- get *env, error-index:offset
 99     error-not-set?:bool <- equal error-index, -1
100     break-unless error-not-set?
101     *env <- put *env, error-index:offset, idx
102   }
103 ]
104 
105 # make sure we render any trace
106 after <render-sandbox-trace-done> [
107   {
108     sandbox-errors:text <- get *sandbox, errors:offset
109     break-unless sandbox-errors
110     *sandbox <- put *sandbox, response-starting-row-on-screen:offset, 0  # no response
111     row, screen <- render-text screen, sandbox-errors, left, right, 1/red, row
112     # don't try to print anything more for this sandbox
113     jump +render-sandbox-end
114   }
115 ]
116 
117 scenario run-shows-errors-in-get [
118   local-scope
119   trace-until 100/app  # trace too long
120   assume-screen 100/width, 15/height
121   assume-resources [
122     [lesson/recipes.mu] <- [
123       |recipe foo [|
124       |  get 123:num, foo:offset|
125       |]|
126     ]
127   ]
128   env:&:environment <- new-programming-environment resources, screen, [foo]
129   render-all screen, env, render
130   screen-should-contain [
131     .                                                                                 run (F4)           .
132     .recipe foo [                                      ╎foo                                              .
133     .  get 123:num, foo:offset                         ╎─────────────────────────────────────────────────.
134     .]                                                 ╎                                                 .
135     .                                                  ╎                                                 .
136     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
137     .                                                  ╎                                                 .
138   ]
139   assume-console [
140     press F4
141   ]
142   run [
143     event-loop screen, console, env, resources
144   ]
145   screen-should-contain [
146     .  errors found                                                                   run (F4)           .
147     .recipe foo [                                      ╎foo                                              .
148     .  get 123:num, foo:offset                         ╎─────────────────────────────────────────────────.
149     .]                                                 ╎                                                 .
150     .                                                  ╎                                                 .
151     .foo: unknown element 'foo' in container 'number'  ╎                                                 .
152     .foo: first ingredient of 'get' should be a contai↩╎                                                 .
153     .ner, but got '123:num'                            ╎                                                 .
154     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
155     .                                                  ╎                                                 .
156   ]
157   screen-should-contain-in-color 1/red, [
158     .  errors found                                                                                      .
159     .                                                                                                    .
160     .                                                                                                    .
161     .                                                                                                    .
162     .                                                                                                    .
163     .foo: unknown element 'foo' in container 'number'                                                    .
164     .foo: first ingredient of 'get' should be a contai                                                   .
165     .ner, but got '123:num'                                                                              .
166     .                                                                                                    .
167   ]
168 ]
169 
170 scenario run-updates-status-with-first-erroneous-sandbox [
171   local-scope
172   trace-until 100/app  # trace too long
173   assume-screen 100/width, 15/height
174   assume-resources [
175   ]
176   env:&:environment <- new-programming-environment resources, screen, []
177   assume-console [
178     left-click 3, 80
179     # create invalid sandbox 1
180     type [get foo, x:offset]
181     press F4
182     # create invalid sandbox 0
183     type [get foo, x:offset]
184     press F4
185   ]
186   run [
187     event-loop screen, console, env, resources
188   ]
189   # status line shows that error is in first sandbox
190   screen-should-contain [
191     .  errors found (0)                                                               run (F4)           .
192   ]
193 ]
194 
195 scenario run-updates-status-with-first-erroneous-sandbox-2 [
196   local-scope
197   trace-until 100/app  # trace too long
198   assume-screen 100/width, 15/height
199   assume-resources [
200   ]
201   env:&:environment <- new-programming-environment resources, screen, []
202   assume-console [
203     left-click 3, 80
204     # create invalid sandbox 2
205     type [get foo, x:offset]
206     press F4
207     # create invalid sandbox 1
208     type [get foo, x:offset]
209     press F4
210     # create valid sandbox 0
211     type [add 2, 2]
212     press F4
213   ]
214   run [
215     event-loop screen, console, env, resources
216   ]
217   # status line shows that error is in second sandbox
218   screen-should-contain [
219     .  errors found (1)                                                               run (F4)           .
220   ]
221 ]
222 
223 scenario run-hides-errors-from-past-sandboxes [
224   local-scope
225   trace-until 100/app  # trace too long
226   assume-screen 100/width, 15/height
227   assume-resources [
228   ]
229   env:&:environment <- new-programming-environment resources, screen, [get foo, x:offset]  # invalid
230   assume-console [
231     press F4  # generate error
232   ]
233   event-loop screen, console, env, resources
234   assume-console [
235     left-click 3, 58
236     press ctrl-k
237     type [add 2, 2]  # valid code
238     press F4  # update sandbox
239   ]
240   run [
241     event-loop screen, console, env, resources
242   ]
243   # error should disappear
244   screen-should-contain [
245     .                                                                                 run (F4)           .
246     .                                                  ╎                                                 .
247     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
248     .                                                  ╎0   edit          copy            delete         .
249     .                                                  ╎add 2, 2                                         .
250     .                                                  ╎4                                                .
251     .                                                  ╎─────────────────────────────────────────────────.
252     .                                                  ╎                                                 .
253   ]
254 ]
255 
256 scenario run-updates-errors-for-shape-shifting-recipes [
257   local-scope
258   trace-until 100/app  # trace too long
259   assume-screen 100/width, 15/height
260   # define a shape-shifting recipe with an error
261   assume-resources [
262     [lesson/recipes.mu] <- [
263       |recipe foo x:_elem -> z:_elem [|
264       |  local-scope|
265       |  load-ingredients|
266       |  y:&:num <- copy 0|
267       |  z <- add x, y|
268       |]|
269     ]
270   ]
271   env:&:environment <- new-programming-environment resources, screen, [foo 2]
272   assume-console [
273     press F4
274   ]
275   event-loop screen, console, env, resources
276   screen-should-contain [
277     .  errors found (0)                                                               run (F4)           .
278     .recipe foo x:_elem -> z:_elem [                   ╎                                                 .
279     .  local-scope                                     ╎─────────────────────────────────────────────────.
280     .  load-ingredients                                ╎0   edit          copy            delete         .
281     .  y:&:num <- copy 0                               ╎foo 2                                            .
282     .  z <- add x, y                                   ╎foo_2: 'add' requires number ingredients, but go↩.
283     .]                                                 ╎t 'y'                                            .
284     .                                                  ╎─────────────────────────────────────────────────.
285     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
286     .                                                  ╎                                                 .
287   ]
288   # now rerun everything
289   assume-console [
290     press F4
291   ]
292   run [
293     event-loop screen, console, env, resources
294   ]
295   # error should remain unchanged
296   screen-should-contain [
297     .  errors found (0)                                                               run (F4)           .
298     .recipe foo x:_elem -> z:_elem [                   ╎                                                 .
299     .  local-scope                                     ╎─────────────────────────────────────────────────.
300     .  load-ingredients                                ╎0   edit          copy            delete         .
301     .  y:&:num <- copy 0                               ╎foo 2                                            .
302     .  z <- add x, y                                   ╎foo_3: 'add' requires number ingredients, but go↩.
303     .]                                                 ╎t 'y'                                            .
304     .                                                  ╎─────────────────────────────────────────────────.
305     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
306     .                                                  ╎                                                 .
307   ]
308 ]
309 
310 scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [
311   local-scope
312   trace-until 100/app  # trace too long
313   assume-screen 100/width, 15/height
314   # overload a well-known shape-shifting recipe
315   assume-resources [
316     [lesson/recipes.mu] <- [
317       |recipe length l:&:list:_elem -> n:num [|
318       |]|
319     ]
320   ]
321   # call code that uses other variants of it, but not it itself
322   test-sandbox:text <- new [x:&:list:num <- copy 0
323 to-text x]
324   env:&:environment <- new-programming-environment resources, screen, test-sandbox
325   # run it once
326   assume-console [
327     press F4
328   ]
329   event-loop screen, console, env, resources
330   # no errors anywhere on screen (can't check anything else, since to-text will return an address)
331   screen-should-contain-in-color 1/red, [
332     .                                                                                                    .
333     .                                                                                                    .
334     .                                                                                                    .
335     .                                                                                                    .
336     .                                                                <-                                  .
337     .                                                                                                    .
338     .                                                                                                    .
339     .                                                                                                    .
340     .                                                                                                    .
341     .                                                                                                    .
342     .                                                                                                    .
343     .                                                                                                    .
344     .                                                                                                    .
345     .                                                                                                    .
346     .                                                                                                    .
347   ]
348   # rerun everything
349   assume-console [
350     press F4
351   ]
352   run [
353     event-loop screen, console, env, resources
354   ]
355   # still no errors
356   screen-should-contain-in-color 1/red, [
357     .                                                                                                    .
358     .                                                                                                    .
359     .                                                                                                    .
360     .                                                                                                    .
361     .                                                                <-                                  .
362     .                                                                                                    .
363     .                                                                                                    .
364     .                                                                                                    .
365     .                                                                                                    .
366     .                                                                                                    .
367     .                                                                                                    .
368     .                                                                                                    .
369     .                                                                                                    .
370     .                                                                                                    .
371     .                                                                                                    .
372   ]
373 ]
374 
375 scenario run-shows-missing-type-errors [
376   local-scope
377   trace-until 100/app  # trace too long
378   assume-screen 100/width, 15/height
379   assume-resources [
380     [lesson/recipes.mu] <- [
381       |recipe foo [|
382       |  x <- copy 0|
383       |]|
384     ]
385   ]
386   env:&:environment <- new-programming-environment resources, screen, [foo]
387   assume-console [
388     press F4
389   ]
390   run [
391     event-loop screen, console, env, resources
392   ]
393   screen-should-contain [
394     .  errors found                                                                   run (F4)           .
395     .recipe foo [                                      ╎foo                                              .
396     .  x <- copy 0                                     ╎─────────────────────────────────────────────────.
397     .]                                                 ╎                                                 .
398     .                                                  ╎                                                 .
399     .foo: missing type for 'x' in 'x <- copy 0'        ╎                                                 .
400     .foo: can't copy '0' to 'x'; types don't match     ╎                                                 .
401     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
402     .                                                  ╎                                                 .
403   ]
404 ]
405 
406 scenario run-shows-unbalanced-bracket-errors [
407   local-scope
408   trace-until 100/app  # trace too long
409   assume-screen 100/width, 15/height
410   # recipe is incomplete (unbalanced '[')
411   assume-resources [
412     [lesson/recipes.mu] <- [
413       |recipe foo \\\[|
414       |  x <- copy 0|
415     ]
416   ]
417   env:&:environment <- new-programming-environment resources, screen, [foo]
418   assume-console [
419     press F4
420   ]
421   run [
422     event-loop screen, console, env, resources
423   ]
424   screen-should-contain [
425     .  errors found                                                                   run (F4)           .
426     .recipe foo \\[                                      ╎foo                                              .
427     .  x <- copy 0                                     ╎─────────────────────────────────────────────────.
428     .                                                  ╎                                                 .
429     .9: unbalanced '\\[' for recipe                      ╎                                                 .
430     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
431     .                                                  ╎                                                 .
432   ]
433 ]
434 
435 scenario run-shows-get-on-non-container-errors [
436   local-scope
437   trace-until 100/app  # trace too long
438   assume-screen 100/width, 15/height
439   assume-resources [
440     [lesson/recipes.mu] <- [
441       |recipe foo [|
442       |  local-scope|
443       |  x:&:point <- new point:type|
444       |  get x:&:point, 1:offset|
445       |]|
446     ]
447   ]
448   env:&:environment <- new-programming-environment resources, screen, [foo]
449   assume-console [
450     press F4
451   ]
452   run [
453     event-loop screen, console, env, resources
454   ]
455   screen-should-contain [
456     .  errors found                                                                   run (F4)           .
457     .recipe foo [                                      ╎foo                                              .
458     .  local-scope                                     ╎─────────────────────────────────────────────────.
459     .  x:&:point <- new point:type                     ╎                                                 .
460     .  get x:&:point, 1:offset                         ╎                                                 .
461     .]                                                 ╎                                                 .
462     .                                                  ╎                                                 .
463     .foo: first ingredient of 'get' should be a contai↩╎                                                 .
464     .ner, but got 'x:&:point'                          ╎                                                 .
465     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
466     .                                                  ╎                                                 .
467   ]
468 ]
469 
470 scenario run-shows-non-literal-get-argument-errors [
471   local-scope
472   trace-until 100/app  # trace too long
473   assume-screen 100/width, 15/height
474   assume-resources [
475     [lesson/recipes.mu] <- [
476       |recipe foo [|
477       |  local-scope|
478       |  x:num <- copy 0|
479       |  y:&:point <- new point:type|
480       |  get *y:&:point, x:num|
481       |]|
482     ]
483   ]
484   env:&:environment <- new-programming-environment resources, screen, [foo]
485   assume-console [
486     press F4
487   ]
488   run [
489     event-loop screen, console, env, resources
490   ]
491   screen-should-contain [
492     .  errors found                                                                   run (F4)           .
493     .recipe foo [                                      ╎foo                                              .
494     .  local-scope                                     ╎─────────────────────────────────────────────────.
495     .  x:num <- copy 0                                 ╎                                                 .
496     .  y:&:point <- new point:type                     ╎                                                 .
497     .  get *y:&:point, x:num                           ╎                                                 .
498     .]                                                 ╎                                                 .
499     .                                                  ╎                                                 .
500     .foo: second ingredient of 'get' should have type ↩╎                                                 .
501     .'offset', but got 'x:num'                         ╎                                                 .
502     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
503     .                                                  ╎                                                 .
504   ]
505 ]
506 
507 scenario run-shows-errors-everytime [
508   local-scope
509   trace-until 100/app  # trace too long
510   assume-screen 100/width, 15/height
511   # try to run a file with an error
512   assume-resources [
513     [lesson/recipes.mu] <- [
514       |recipe foo [|
515       |  local-scope|
516       |  x:num <- copy y:num|
517       |]|
518     ]
519   ]
520   env:&:environment <- new-programming-environment resources, screen, [foo]
521   assume-console [
522     press F4
523   ]
524   event-loop screen, console, env, resources
525   screen-should-contain [
526     .  errors found                                                                   run (F4)           .
527     .recipe foo [                                      ╎foo                                              .
528     .  local-scope                                     ╎─────────────────────────────────────────────────.
529     .  x:num <- copy y:num                             ╎                                                 .
530     .]                                                 ╎                                                 .
531     .                                                  ╎                                                 .
532     .foo: tried to read ingredient 'y' in 'x:num <- co↩╎                                                 .
533     .py y:num' but it hasn't been written to yet       ╎                                                 .
534     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
535     .                                                  ╎                                                 .
536   ]
537   # rerun the file, check for the same error
538   assume-console [
539     press F4
540   ]
541   run [
542     event-loop screen, console, env, resources
543   ]
544   screen-should-contain [
545     .  errors found                                                                   run (F4)           .
546     .recipe foo [                                      ╎foo                                              .
547     .  local-scope                                     ╎─────────────────────────────────────────────────.
548     .  x:num <- copy y:num                             ╎                                                 .
549     .]                                                 ╎                                                 .
550     .                                                  ╎                                                 .
551     .foo: tried to read ingredient 'y' in 'x:num <- co↩╎                                                 .
552     .py y:num' but it hasn't been written to yet       ╎                                                 .
553     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
554     .                                                  ╎                                                 .
555   ]
556 ]
557 
558 scenario run-instruction-and-print-errors [
559   local-scope
560   trace-until 100/app  # trace too long
561   assume-screen 100/width, 10/height
562   assume-resources [
563   ]
564   # sandbox editor contains an illegal instruction
565   env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset]
566   assume-console [
567     press F4
568   ]
569   run [
570     event-loop screen, console, env, resources
571   ]
572   # check that screen prints error message in red
573   screen-should-contain [
574     .  errors found (0)                                                               run (F4)           .
575     .                                                  ╎                                                 .
576     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
577     .                                                  ╎0   edit          copy            delete         .
578     .                                                  ╎get 1234:num, foo:offset                         .
579     .                                                  ╎unknown element 'foo' in container 'number'      .
580     .                                                  ╎first ingredient of 'get' should be a container,↩.
581     .                                                  ╎ but got '1234:num'                              .
582     .                                                  ╎─────────────────────────────────────────────────.
583     .                                                  ╎                                                 .
584   ]
585   screen-should-contain-in-color 7/white, [
586     .                                                                                                    .
587     .                                                                                                    .
588     .                                                                                                    .
589     .                                                                                                    .
590     .                                                   get 1234:num, foo:offset                         .
591     .                                                                                                    .
592     .                                                                                                    .
593     .                                                                                                    .
594   ]
595   screen-should-contain-in-color 1/red, [
596     .  errors found (0)                                                                                  .
597     .                                                                                                    .
598     .                                                                                                    .
599     .                                                                                                    .
600     .                                                                                                    .
601     .                                                   unknown element 'foo' in container 'number'      .
602     .                                                   first ingredient of 'get' should be a container, .
603     .                                                    but got '1234:num'                              .
604     .                                                                                                    .
605   ]
606   screen-should-contain-in-color 245/grey, [
607     .                                                                                                    .
608     .                                                  ╎                                                 .
609     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
610     .                                                  ╎                                                 .
611     .                                                  ╎                                                 .
612     .                                                  ╎                                                 .
613     .                                                  ╎                                                ↩.
614     .                                                  ╎                                                 .
615     .                                                  ╎─────────────────────────────────────────────────.
616     .                                                  ╎                                                 .
617   ]
618 ]
619 
620 scenario run-instruction-and-print-errors-only-once [
621   local-scope
622   trace-until 100/app  # trace too long
623   assume-screen 100/width, 10/height
624   assume-resources [
625   ]
626   # sandbox editor contains an illegal instruction
627   env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset]
628   # run the code in the editors multiple times
629   assume-console [
630     press F4
631     press F4
632   ]
633   run [
634     event-loop screen, console, env, resources
635   ]
636   # check that screen prints error message just once
637   screen-should-contain [
638     .  errors found (0)                                                               run (F4)           .
639     .                                                  ╎                                                 .
640     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
641     .                                                  ╎0   edit          copy            delete         .
642     .                                                  ╎get 1234:num, foo:offset                         .
643     .                                                  ╎unknown element 'foo' in container 'number'      .
644     .                                                  ╎first ingredient of 'get' should be a container,↩.
645     .                                                  ╎ but got '1234:num'                              .
646     .                                                  ╎─────────────────────────────────────────────────.
647     .                                                  ╎                                                 .
648   ]
649 ]
650 
651 scenario sandbox-can-handle-infinite-loop [
652   local-scope
653   trace-until 100/app  # trace too long
654   assume-screen 100/width, 20/height
655   # sandbox editor will trigger an infinite loop
656   assume-resources [
657     [lesson/recipes.mu] <- [
658       |recipe foo [|
659       |  {|
660       |    loop|
661       |  }|
662       |]|
663     ]
664   ]
665   env:&:environment <- new-programming-environment resources, screen, [foo]
666   # run the sandbox
667   assume-console [
668     press F4
669   ]
670   run [
671     event-loop screen, console, env, resources
672   ]
673   screen-should-contain [
674     .  errors found (0)                                                               run (F4)           .
675     .recipe foo [                                      ╎                                                 .
676     .  {                                               ╎─────────────────────────────────────────────────.
677     .    loop                                          ╎0   edit          copy            delete         .
678     .  }                                               ╎foo                                              .
679     .]                                                 ╎took too long!                                   .
680     .                                                  ╎─────────────────────────────────────────────────.
681     .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎                                                 .
682     .                                                  ╎                                                 .
683   ]
684 ]
685 
686 scenario sandbox-with-errors-shows-trace [
687   local-scope
688   trace-until 100/app  # trace too long
689   assume-screen 100/width, 10/height
690   # generate a stash and a error
691   assume-resources [
692     [lesson/recipes.mu] <- [
693       |recipe foo [|
694       |  local-scope|
695       |  a:num <- next-ingredient|
696       |  b:num <- next-ingredient|
697       |  stash [dividing by], b|
698       |  _, c:num <- divide-with-remainder a, b|
699       |  reply b|
700       |]|
701     ]
702   ]
703   env:&:environment <- new-programming-environment resources, screen, [foo 4, 0]
704   # run
705   assume-console [
706     press F4
707   ]
708   event-loop screen, console, env, resources
709   # screen prints error message
710   screen-should-contain [
711     .  errors found (0)                                                               run (F4)           .
712     .recipe foo [                                      ╎                                                 .
713     .  local-scope                                     ╎─────────────────────────────────────────────────.
714     .  a:num <- next-ingredient                        ╎0   edit          copy            delete         .
715     .  b:num <- next-ingredient                        ╎foo 4, 0                                         .
716     .  stash [dividing by], b                          ╎foo: divide by zero in '_, c:num <- divide-with-↩.
717     .  _, c:num <- divide-with-remainder a, b          ╎remainder a, b'                                  .
718     .  reply b                                         ╎─────────────────────────────────────────────────.
719     .]                                                 ╎                                                 .
720     .                                                  ╎                                                 .
721   ]
722   # click on the call in the sandbox
723   assume-console [
724     left-click 4, 55
725   ]
726   run [
727     event-loop screen, console, env, resources
728   ]
729   # screen should expand trace
730   screen-should-contain [
731     .  errors found (0)                                                               run (F4)           .
732     .recipe foo [                                      ╎                                                 .
733     .  local-scope                                     ╎─────────────────────────────────────────────────.
734     .  a:num <- next-ingredient                        ╎0   edit          copy            delete         .
735     .  b:num <- next-ingredient                        ╎foo 4, 0                                         .
736     .  stash [dividing by], b                          ╎dividing by 0                                    .
737     .  _, c:num <- divide-with-remainder a, b          ╎14 instructions run                              .
738     .  reply b                                         ╎foo: divide by zero in '_, c:num <- divide-with-↩.
739     .]                                                 ╎remainder a, b'                                  .
740     .                                                  ╎─────────────────────────────────────────────────.
741   ]
742 ]