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