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