diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-07-17 12:51:32 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-07-17 12:58:37 -0700 |
commit | 32cd40ec3c9dad33738caf6f55fb742a316bd5be (patch) | |
tree | c6612fefc35741b43e1058826445d2913e94b3ba | |
parent | fe9e53ed19f84a1771d56bfa0cf7d1d017e07559 (diff) | |
download | mu-32cd40ec3c9dad33738caf6f55fb742a316bd5be.tar.gz |
1799 - continue to debug memory corruption of 1795
Things I figured out: - 'row' in render-screen doesn't perfectly track cursor-row in screen - proximal cause was forgetting to add left:number to stop-printing - trying to print to screen outside bounds was silently succeeding and corrupting simulated memory - if we silently ignore prints outside bounds things are fine But why are prints outside screen bounds working? We should be accessing screen data using 'index', and that's checking its bounds.
-rw-r--r-- | 029debug.cc | 29 | ||||
-rw-r--r-- | 036call_reply.cc | 1 | ||||
-rw-r--r-- | 043new.cc | 2 | ||||
-rw-r--r-- | 044space.cc | 1 | ||||
-rw-r--r-- | 071print.mu | 105 | ||||
-rw-r--r-- | 081run_interactive.cc | 76 | ||||
-rw-r--r-- | edit.mu | 355 |
7 files changed, 329 insertions, 240 deletions
diff --git a/029debug.cc b/029debug.cc index 301cd01a..90a1159e 100644 --- a/029debug.cc +++ b/029debug.cc @@ -103,3 +103,32 @@ case _DUMP_MEMORY: { dump_memory(); break; } + +:(before "End Primitive Recipe Declarations") +_DUMP, +:(before "End Primitive Recipe Numbers") +Recipe_ordinal["$dump"] = _DUMP; +:(before "End Primitive Recipe Implementations") +case _DUMP: { + reagent after_canonize = canonize(current_instruction().ingredients.at(0)); + cerr << current_recipe_name() << ": " << current_instruction().ingredients.at(0).name << ' ' << current_instruction().ingredients.at(0).value << " => " << after_canonize.value << " => " << Memory[after_canonize.value] << '\n'; + break; +} + +:(before "End Globals") +long long int foo = -1; +:(before "End Primitive Recipe Declarations") +_FOO, +:(before "End Primitive Recipe Numbers") +Recipe_ordinal["$foo"] = _FOO; +:(before "End Primitive Recipe Implementations") +case _FOO: { + if (current_instruction().ingredients.empty()) { + if (foo != -1) cerr << foo << ": " << Memory[foo] << '\n'; + else cerr << '\n'; + } + else { + foo = canonize(current_instruction().ingredients.at(0)).value; + } + break; +} diff --git a/036call_reply.cc b/036call_reply.cc index 22eeea79..618ad651 100644 --- a/036call_reply.cc +++ b/036call_reply.cc @@ -51,6 +51,7 @@ case REPLY: { raise << current_recipe_name() << ": 'same-as-ingredient' result " << caller_instruction.products.at(i).value << " from call to " << callee << " must be location " << caller_instruction.ingredients.at(ingredient_index).value << '\n'; } } + // End Reply break; // continue to process rest of *caller* instruction } diff --git a/043new.cc b/043new.cc index bd5dd7bf..18d93486 100644 --- a/043new.cc +++ b/043new.cc @@ -242,7 +242,7 @@ if (Free_list[size]) { Free_list[size] = Memory[result]; for (long long int curr = result+1; curr < result+size; ++curr) if (Memory[curr] != 0) - raise << "memory in free list was not zeroed out; somebody wrote to us after free!!!\n" << die(); + raise << current_recipe_name() << ": memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << die(); if (SIZE(current_instruction().ingredients) > 1) Memory[result] = array_length; else diff --git a/044space.cc b/044space.cc index 4469e47f..40f0f5ba 100644 --- a/044space.cc +++ b/044space.cc @@ -178,6 +178,7 @@ void try_reclaim_locals() { if (inst.name != "local-scope") return; //? cerr << inst.to_string() << '\n'; //? 1 +//? cerr << current_recipe_name() << ": abandon " << Current_routine->calls.front().default_space << '\n'; //? 1 abandon(Current_routine->calls.front().default_space, /*array length*/1+/*number-of-locals*/Name[r][""]); } diff --git a/071print.mu b/071print.mu index f0be8cfa..e8071b6e 100644 --- a/071print.mu +++ b/071print.mu @@ -69,6 +69,26 @@ recipe clear-screen [ reply x:address:screen/same-as-ingredient:0 ] +recipe fake-screen-is-clear? [ + local-scope + screen:address:screen <- next-ingredient + reply-unless screen:address:screen, 1:literal/true + buf:address:array:screen-cell <- get screen:address:screen/deref, data:offset + i:number <- copy 0:literal + len:number <- length buf:address:array:screen-cell/deref + { + done?:boolean <- greater-or-equal i:number, len:number + break-if done?:boolean + curr:screen-cell <- index buf:address:array:screen-cell/deref, i:number + curr-contents:character <- get curr:screen-cell, contents:offset + i:number <- add i:number, 1:literal + loop-unless curr-contents:character + # not 0 + reply 0:literal/false + } + reply 1:literal/true +] + recipe print-character [ local-scope x:address:screen <- next-ingredient @@ -85,15 +105,34 @@ recipe print-character [ break-if bg-color-found?:boolean bg-color:number <- copy 0:literal/black } + screen-width:number <- screen-width x:address:screen + screen-height:number <- screen-height x:address:screen +#? $print [eee ] #? 1 +#? $foo #? 1 #? trace [app], [print character] #? 1 { # if x exists # (handle special cases exactly like in the real screen) break-unless x:address:screen row:address:number <- get-address x:address:screen/deref, cursor-row:offset +#? $dump row:address:number/deref + legal?:boolean <- greater-or-equal row:address:number/deref, 0:literal + reply-unless legal?:boolean, x:address:screen + assert legal?:boolean, [row too small in print-character] + legal?:boolean <- lesser-than row:address:number/deref, screen-height:number + reply-unless legal?:boolean, x:address:screen + assert legal?:boolean, [row too large in print-character] column:address:number <- get-address x:address:screen/deref, cursor-column:offset + legal?:boolean <- greater-or-equal column:address:number/deref, 0:literal + reply-unless legal?:boolean, x:address:screen + assert legal?:boolean, [column too small in print-character] + legal?:boolean <- lesser-than column:address:number/deref, screen-width:number + reply-unless legal?:boolean, x:address:screen + assert legal?:boolean, [column too large in print-character] width:number <- get x:address:screen/deref, num-columns:offset height:number <- get x:address:screen/deref, num-rows:offset +#? $print [fff ] #? 1 +#? $foo #? 1 # special-case: newline { newline?:boolean <- equal c:character, 10:literal/newline @@ -112,11 +151,14 @@ recipe print-character [ reply x:address:screen/same-as-ingredient:0 } # save character in fake screen -#? $print row:address:number/deref, [, ], column:address:number/deref, [ -#? ] #? 1 +#? $print [ggg ] #? 1 +#? $foo #? 1 index:number <- multiply row:address:number/deref, width:number index:number <- add index:number, column:address:number/deref buf:address:array:screen-cell <- get x:address:screen/deref, data:offset + len:number <- length buf:address:array:screen-cell/deref +#? $print row:address:number/deref, [, ], column:address:number/deref, [ vs ], screen-height:number, [, ], screen-width:number, [ length ], len:number, [ +#? ] #? 1 # special-case: backspace { backspace?:boolean <- equal c:character, 8:literal @@ -136,20 +178,49 @@ recipe print-character [ } reply x:address:screen/same-as-ingredient:0 } +#? $print [hhh ] #? 1 +#? $foo #? 1 #? $print [saving character ], c:character, [ to fake screen ], cursor:address/screen, [ #? ] #? 1 cursor:address:screen-cell <- index-address buf:address:array:screen-cell/deref, index:number +#? $print [iii ] #? 1 +#? $foo #? 1 cursor-contents:address:character <- get-address cursor:address:screen-cell/deref, contents:offset +#? $print [jjj ] #? 1 +#? $foo #? 1 cursor-color:address:number <- get-address cursor:address:screen-cell/deref, color:offset +#? $print [kkk ] #? 1 +#? $foo #? 1 +#? $dump cursor-contents:address:character cursor-contents:address:character/deref <- copy c:character +#? $print [lll ] #? 1 +#? $foo #? 1 +#? $dump x:address:screen +#? $dump buf:address:array:screen-cell +#? $dump height:number +#? $dump width:number +#? $dump row:address:number/deref +#? $dump column:address:number/deref +#? $dump index:number +#? $dump len:number cursor-color:address:number/deref <- copy color:number +#? $print [mmm ] #? 1 +#? $foo #? 1 # increment column unless it's already all the way to the right { right:number <- subtract width:number, 1:literal +#? $print [nnn ] #? 1 +#? $foo #? 1 at-right?:boolean <- greater-or-equal column:address:number/deref, right:number +#? $print [ooo ] #? 1 +#? $foo #? 1 break-if at-right?:boolean +#? $print [ppp ] #? 1 +#? $foo #? 1 column:address:number/deref <- add column:address:number/deref, 1:literal } +#? $print [qqq ] #? 1 +#? $foo #? 1 reply x:address:screen/same-as-ingredient:0 } # otherwise, real screen @@ -361,12 +432,24 @@ recipe move-cursor [ x:address:screen <- next-ingredient new-row:number <- next-ingredient new-column:number <- next-ingredient +#? screen-width:number <- screen-width x:address:screen +#? screen-height:number <- screen-height x:address:screen # if x exists, move cursor in fake screen { break-unless x:address:screen row:address:number <- get-address x:address:screen/deref, cursor-row:offset +#? $print row:address:number/deref, [ vs ], screen-height:number, [ +#? ] #? 1 +#? legal?:boolean <- greater-or-equal row:address:number/deref, 0:literal +#? assert legal?:boolean, [row too small in move-cursor] +#? legal?:boolean <- lesser-than row:address:number/deref, screen-height:number +#? assert legal?:boolean, [row too large in move-cursor] row:address:number/deref <- copy new-row:number column:address:number <- get-address x:address:screen/deref, cursor-column:offset +#? legal?:boolean <- greater-or-equal column:address:number/deref, 0:literal +#? assert legal?:boolean, [column too small in move-cursor] +#? legal?:boolean <- lesser-than column:address:number/deref, screen-width:number +#? assert legal?:boolean, [column too large in move-cursor] column:address:number/deref <- copy new-column:number reply x:address:screen/same-as-ingredient:0 } @@ -413,10 +496,11 @@ recipe cursor-down [ { break-unless x:address:screen { - # if row < height + # if row < height-1 height:number <- get x:address:screen/deref, num-rows:offset row:address:number <- get-address x:address:screen/deref, cursor-row:offset - at-bottom?:boolean <- greater-or-equal row:address:number/deref, height:number + max:number <- subtract height:number, 1:literal + at-bottom?:boolean <- greater-or-equal row:address:number/deref, max:number break-if at-bottom?:boolean # row = row+1 #? $print [AAA: ], row:address:number, [ -> ], row:address:number/deref, [ @@ -440,9 +524,9 @@ recipe cursor-up [ { break-unless x:address:screen { - # if row >= 0 + # if row > 0 row:address:number <- get-address x:address:screen/deref, cursor-row:offset - at-top?:boolean <- lesser-than row:address:number/deref, 0:literal + at-top?:boolean <- lesser-or-equal row:address:number/deref, 0:literal break-if at-top?:boolean # row = row-1 row:address:number/deref <- subtract row:address:number/deref, 1:literal @@ -461,10 +545,11 @@ recipe cursor-right [ { break-unless x:address:screen { - # if column < width + # if column < width-1 width:number <- get x:address:screen/deref, num-columns:offset column:address:number <- get-address x:address:screen/deref, cursor-column:offset - at-bottom?:boolean <- greater-or-equal column:address:number/deref, width:number + max:number <- subtract width:number, 1:literal + at-bottom?:boolean <- greater-or-equal column:address:number/deref, max:number break-if at-bottom?:boolean # column = column+1 column:address:number/deref <- add column:address:number/deref, 1:literal @@ -483,9 +568,9 @@ recipe cursor-left [ { break-unless x:address:screen { - # if column >= 0 + # if column > 0 column:address:number <- get-address x:address:screen/deref, cursor-column:offset - at-top?:boolean <- lesser-than column:address:number/deref, 0:literal + at-top?:boolean <- lesser-or-equal column:address:number/deref, 0:literal break-if at-top?:boolean # column = column-1 column:address:number/deref <- subtract column:address:number/deref, 1:literal diff --git a/081run_interactive.cc b/081run_interactive.cc index 1d317d4b..f54a73e3 100644 --- a/081run_interactive.cc +++ b/081run_interactive.cc @@ -15,8 +15,10 @@ recipe main [ # result is null +mem: storing 0 in location 1 -//: run code in 'interactive mode', i.e. with warnings off, and recording -//: output in case we want to print it to screen +//: run code in 'interactive mode', i.e. with warnings off and return: +//: stringified output in case we want to print it to screen +//: any warnings encountered +//: simulated screen any prints went to :(before "End Primitive Recipe Declarations") RUN_INTERACTIVE, :(before "End Primitive Recipe Numbers") @@ -25,11 +27,12 @@ Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE; :(before "End Primitive Recipe Implementations") case RUN_INTERACTIVE: { assert(scalar(ingredients.at(0))); - products.resize(2); + products.resize(3); bool new_code_pushed_to_stack = run_interactive(ingredients.at(0).at(0)); if (!new_code_pushed_to_stack) { products.at(0).push_back(0); products.at(1).push_back(warnings_from_trace()); + products.at(2).push_back(0); clean_up_interactive(); break; // done with this instruction } @@ -40,8 +43,10 @@ case RUN_INTERACTIVE: { :(before "End Globals") bool Running_interactive = false; +long long int Old_screen = 0; // we can support one iteration of screen inside screen :(before "End Setup") Running_interactive = false; +Old_screen = 0; :(code) // reads a string, tries to call it as code (treating it as a test), saving // all warnings. @@ -49,6 +54,8 @@ Running_interactive = false; bool run_interactive(long long int address) { if (Recipe_ordinal.find("interactive") == Recipe_ordinal.end()) Recipe_ordinal["interactive"] = Next_recipe_ordinal++; + Old_screen = Memory[SCREEN]; + cerr << "save screen: " << Old_screen << '\n'; //? 1 // try to sandbox the run as best you can // todo: test this if (!Current_scenario) { @@ -57,6 +64,9 @@ bool run_interactive(long long int address) { Memory.erase(i); Name[Recipe_ordinal["interactive"]].clear(); } +//? cerr << "screen was at " << Name[Recipe_ordinal["interactive"]]["screen"] << '\n'; //? 1 + Name[Recipe_ordinal["interactive"]]["screen"] = SCREEN; +//? cerr << "screen now at " << Name[Recipe_ordinal["interactive"]]["screen"] << '\n'; //? 1 string command = trim(strip_comments(to_string(address))); if (command.empty()) return false; Recipe.erase(Recipe_ordinal["interactive"]); @@ -67,7 +77,12 @@ bool run_interactive(long long int address) { Trace_stream->collect_layer = "warn"; } // call run(string) but without the scheduling - load("recipe interactive [\n"+command+"\n]\n"); + // we won't create a local scope so that we can get to the new screen after + // we return from 'interactive'. + load(string("recipe interactive [\n") + + "screen:address <- new-fake-screen 5, 5\n" + + command + "\n" + + "]\n"); transform_all(); if (trace_count("warn") > 0) return false; Running_interactive = true; @@ -75,21 +90,6 @@ bool run_interactive(long long int address) { return true; } -:(after "Starting Reply") -if (current_recipe_name() == "interactive") clean_up_interactive(); -:(after "Falling Through End Of Recipe") -if (current_recipe_name() == "interactive") clean_up_interactive(); -:(code) -void clean_up_interactive() { - Hide_warnings = false; - Running_interactive = false; - // hack: assume collect_layer isn't set anywhere else - if (Trace_stream->collect_layer == "warn") { - delete Trace_stream; - Trace_stream = NULL; - } -} - :(scenario "run_interactive_returns_stringified_result") recipe main [ # try to interactively add 2 and 2 @@ -157,17 +157,51 @@ void record_products(const instruction& instruction, const vector<vector<double> } :(before "Complete Call Fallthrough") if (current_instruction().operation == RUN_INTERACTIVE && !current_instruction().products.empty()) { - assert(SIZE(current_instruction().products) <= 2); + assert(SIZE(current_instruction().products) <= 3); // Send the results of the most recently executed instruction, regardless of // call depth, to be converted to string and potentially printed to string. vector<double> result; result.push_back(new_string(Most_recent_results)); write_memory(current_instruction().products.at(0), result); - if (SIZE(current_instruction().products) == 2) { + if (SIZE(current_instruction().products) >= 2) { vector<double> warnings; warnings.push_back(warnings_from_trace()); write_memory(current_instruction().products.at(1), warnings); } + if (SIZE(current_instruction().products) >= 3) { + vector<double> screen; + cerr << "returning screen " << Memory[SCREEN] << " to " << current_instruction().products.at(2).to_string() << " value " << current_instruction().products.at(2).value << '\n'; + screen.push_back(Memory[SCREEN]); + write_memory(current_instruction().products.at(2), screen); + } +} + +//: clean up reply after we've popped it off the call-stack +//: however, we need what was on the stack to decide whether to clean up +:(after "Starting Reply") +bool must_clean_up_interactive = (current_recipe_name() == "interactive"); +//? cerr << "reply: " << Memory[SCREEN] << '\n'; //? 1 +//? cerr << "reply2: " << Name[Recipe_ordinal["render-sandboxes"]]["screen"] << '\n'; //? 1 +:(after "Falling Through End Of Recipe") +bool must_clean_up_interactive = (current_recipe_name() == "interactive"); +//? cerr << "pop: " << Memory[SCREEN] << '\n'; //? 1 +//? cerr << "pop2: " << Name[Recipe_ordinal["render-sandboxes"]]["screen"] << '\n'; //? 1 +:(before "End Reply") +if (must_clean_up_interactive) clean_up_interactive(); +:(before "Complete Call Fallthrough") +if (must_clean_up_interactive) clean_up_interactive(); +:(code) +void clean_up_interactive() { + Hide_warnings = false; + Running_interactive = false; + // hack: assume collect_layer isn't set anywhere else + if (Trace_stream->collect_layer == "warn") { + delete Trace_stream; + Trace_stream = NULL; + } + cerr << "restore screen: " << Memory[SCREEN] << " to " << Old_screen << '\n'; + Memory[SCREEN] = Old_screen; + Old_screen = 0; } :(code) diff --git a/edit.mu b/edit.mu index 5828ebdc..4bbf47b5 100644 --- a/edit.mu +++ b/edit.mu @@ -3,52 +3,13 @@ recipe main [ local-scope open-console - initial-recipe:address:array:character <- new [ -# return true if a list of numbers contains the pattern 1, 5, 3 -recipe check [ - default-space:address:array:location <- new location:type, 30:literal - state:number <- copy 0:literal - { - +next-number - curr:number, found?:boolean <- next-ingredient - break-unless found?:boolean - # if curr is 1, state = 1 - { - state1:boolean <- equal curr:number, 1:literal - break-unless state1:boolean - state:number <- copy 1:literal - loop +next-number:label - } - # if state is 1 and curr is 5, state = 2 - { - state-is-1?:boolean <- equal state:number, 1:literal - break-unless state-is-1?:boolean - state2:boolean <- equal curr:number, 5:literal - break-unless state2:boolean - state:number <- copy 2:literal - loop +next-number:label - } - # if state is 2 and curr is 3, return true - { - state-is-2?:boolean <- equal state:number, 2:literal - break-unless state-is-2?:boolean - state3:boolean <- equal curr:number, 3:literal - break-unless state3:boolean - reply 1:literal/found - } - # otherwise reset state - #state:number <- copy 0:literal - loop - } - reply 0:literal/not-found + initial-recipe:address:array:character <- new [recipe new-add [ + x:number <- next-ingredient + y:number <- next-ingredient + z:number <- add x:number, y:number + reply z:number ]] -#? initial-recipe:address:array:character <- new [recipe new-add [ -#? x:number <- next-ingredient -#? y:number <- next-ingredient -#? z:number <- add x:number, y:number -#? reply z:number -#? ]] - initial-sandbox:address:array:character <- new [] + initial-sandbox:address:array:character <- new [print-character screen:address, 97] env:address:programming-environment-data <- new-programming-environment 0:literal/screen, initial-recipe:address:array:character, initial-sandbox:address:array:character event-loop 0:literal/screen, 0:literal/console, env:address:programming-environment-data ] @@ -302,6 +263,7 @@ recipe render [ ] # row:number, screen:address <- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number +# move cursor at start of next line # print a string 's' to 'editor' in 'color' starting at 'row' # leave cursor at start of next line recipe render-string [ @@ -370,6 +332,76 @@ recipe render-string [ reply row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0 ] +# row:number, screen:address <- render-screen screen:address, sandbox-screen:address:screen, left:number, right:number, row:number +# print the fake sandbox screen to 'screen' with appropriate delimiters +# leave cursor at start of next line +recipe render-screen [ + local-scope + screen:address <- next-ingredient + s:address:screen <- next-ingredient + left:number <- next-ingredient + right:number <- next-ingredient + row:number <- next-ingredient + row:number <- add row:number, 1:literal + reply-unless s:address:screen, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 +#? $start-tracing #? 1 + # print 'screen:' + column:number <- copy left:number + move-cursor screen:address, row:number, column:number + screen-height:number <- screen-height screen:address + header:address:array:character <- new [screen:] + row:number <- subtract row:number, 1:literal # compensate for render-string below + row:number <- render-string screen:address, header:address:array:character, left:number, right:number, 245:literal/grey, row:number + # start printing s + column:number <- copy left:number + move-cursor screen:address, row:number, column:number + s-width:number <- screen-width s:address:screen + s-height:number <- screen-height s:address:screen + buf:address:array:screen-cell <- get s:address:screen/deref, data:offset + stop-printing:number <- add s-width:number, 3:literal +#? stop-printing:number <- add left:number, s-width:number, 3:literal + max-column:number <- min stop-printing:number, right:number + i:number <- copy 0:literal + len:number <- length buf:address:array:screen-cell/deref + { + done?:boolean <- greater-or-equal i:number, len:number + break-if done?:boolean + done?:boolean <- greater-or-equal row:number, screen-height:number + break-if done?:boolean + column:number <- copy left:number + move-cursor screen:address, row:number, column:number + # initial leader for each row: two spaces and a '.' + print-character screen:address, 32:literal/space, 245:literal/grey + print-character screen:address, 32:literal/space, 245:literal/grey + print-character screen:address, 46:literal/full-stop, 245:literal/grey + column:number <- add left:number, 3:literal + { + # print row + row-done?:boolean <- greater-than column:number, max-column:number + break-if row-done?:boolean + curr:screen-cell <- index buf:address:array:screen-cell/deref, i:number + print-character screen:address, 32:literal/space + column:number <- add column:number, 1:literal + i:number <- add i:number, 1:literal + loop + } + # print final '.' + print-character screen:address, 46:literal/full-stop, 245:literal/grey + column:number <- add column:number, 1:literal + { + # clear rest of current line + line-done?:boolean <- greater-than column:number, right:number + break-if line-done?:boolean + print-character screen:address, 32:literal/space + column:number <- add column:number, 1:literal + loop + } + row:number <- add row:number, 1:literal + loop + } + reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 +] + recipe clear-line-delimited [ local-scope screen:address <- next-ingredient @@ -522,19 +554,10 @@ recipe event-loop [ loop +next-event:label } } - # 'touch' event + # 'touch' event - send to both editors { t:address:touch-event <- maybe-convert e:event, touch:variant break-unless t:address:touch-event - # on a sandbox delete icon? process delete - { - was-delete?:boolean <- delete-sandbox t:address:touch-event/deref, env:address:programming-environment-data - break-unless was-delete?:boolean - screen:address <- render-sandbox-side screen:address, env:address:programming-environment-data, 1:literal/clear - update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref - loop +next-event:label - } - # if not, send to both editors _ <- move-cursor-in-editor screen:address, recipes:address:editor-data, t:address:touch-event/deref sandbox-in-focus?:address:boolean/deref <- move-cursor-in-editor screen:address, current-sandbox:address:editor-data, t:address:touch-event/deref jump +continue:label @@ -1063,7 +1086,6 @@ recipe render-sandbox-side [ local-scope screen:address <- next-ingredient env:address:programming-environment-data <- next-ingredient - clear:boolean <- next-ingredient current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset left:number <- get current-sandbox:address:editor-data/deref, left:offset right:number <- get current-sandbox:address:editor-data/deref, right:offset @@ -1076,62 +1098,61 @@ recipe render-sandbox-side [ row:number <- add row:number, 1:literal move-cursor screen:address, row:number, left:number clear-line-delimited screen:address, left:number, right:number - reply-unless clear:boolean, screen:address/same-as-ingredient:0 - screen-height:number <- screen-height screen:address - { - at-bottom-of-screen?:boolean <- greater-or-equal row:number, screen-height:number - break-if at-bottom-of-screen?:boolean - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - row:number <- add row:number, 1:literal - loop - } reply screen:address/same-as-ingredient:0 ] recipe render-sandboxes [ local-scope - screen:address <- next-ingredient + screen:address:screen <- next-ingredient sandbox:address:sandbox-data <- next-ingredient left:number <- next-ingredient right:number <- next-ingredient row:number <- next-ingredient - reply-unless sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 - screen-height:number <- screen-width screen:address + reply-unless sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0 + screen-height:number <- screen-height screen:address:screen at-bottom?:boolean <- greater-or-equal row:number screen-height:number - reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 -#? $print [rendering sandbox ], sandbox:address:sandbox-data, [ -#? ] #? 1 - # render sandbox menu - row:number <- add row:number, 1:literal - move-cursor screen:address, row:number, left:number - clear-line-delimited screen:address, left:number, right:number - print-character screen:address, 120:literal/x, 245:literal/grey - # save menu row so we can detect clicks to it later - starting-row:address:number <- get-address sandbox:address:sandbox-data/deref, starting-row-on-screen:offset - starting-row:address:number/deref <- copy row:number + reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0 # render sandbox contents sandbox-data:address:array:character <- get sandbox:address:sandbox-data/deref, data:offset - row:number, screen:address <- render-string screen:address, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number + row:number, screen:address:screen <- render-string screen:address:screen, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number # render sandbox warnings or response, in that order sandbox-response:address:array:character <- get sandbox:address:sandbox-data/deref, response:offset sandbox-warnings:address:array:character <- get sandbox:address:sandbox-data/deref, warnings:offset + sandbox-screen:address:screen <- get sandbox:address:sandbox-data/deref, screen:offset { break-unless sandbox-warnings:address:array:character - row:number, screen:address <- render-string screen:address, sandbox-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number + row:number, screen:address:screen <- render-string screen:address:screen, sandbox-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number } { break-if sandbox-warnings:address:array:character - row:number, screen:address <- render-string screen:address, sandbox-response:address:array:character, left:number, right:number, 245:literal/grey, row:number + row:number, screen:address:screen <- render-string screen:address:screen, sandbox-response:address:array:character, left:number, right:number, 245:literal/grey, row:number } + # render sandbox screen if necessary + at-bottom?:boolean <- greater-or-equal row:number screen-height:number + reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0 + { + empty-screen?:boolean <- fake-screen-is-clear? sandbox-screen:address:screen + break-if empty-screen?:boolean + row:number, screen:address:screen <- render-screen screen:address:screen, sandbox-screen:address:screen, left:number, right:number, row:number + } + at-bottom?:boolean <- greater-or-equal row:number screen-height:number + reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0 # draw solid line after sandbox - draw-horizontal screen:address, row:number, left:number, right:number, 9473:literal/horizontal-double +#? $print [aaa ] +#? $dump screen:address:screen +#? $dump right:number +#? $foo screen:address:screen +#? xxx:address:array:screen-cell <- get screen:address:screen/deref, data:offset +#? $dump xxx:address:array:screen-cell +#? yyy:number <- length xxx:address:array:screen-cell/deref +#? $dump yyy:number + draw-horizontal screen:address:screen, row:number, left:number, right:number, 9473:literal/horizontal-double +#? $print [zzz ] +#? $dump screen:address:screen # draw next sandbox next-sandbox:address:sandbox-data <- get sandbox:address:sandbox-data/deref, next-sandbox:offset -#? $print [next sandbox is ], next-sandbox:address:sandbox-data, [ -#? ] #? 1 - row:number, screen:address <- render-sandboxes screen:address, next-sandbox:address:sandbox-data, left:number, right:number, row:number - reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0 + row:number, screen:address:screen <- render-sandboxes screen:address:screen, next-sandbox:address:sandbox-data, left:number, right:number, row:number + reply row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0 ] recipe update-cursor [ @@ -2542,13 +2563,13 @@ container sandbox-data [ data:address:array:character response:address:array:character warnings:address:array:character - starting-row-on-screen:number # to track clicks on delete + screen:address:screen next-sandbox:address:sandbox-data ] scenario run-and-show-results [ $close-trace # trace too long for github - assume-screen 100:literal/width, 15:literal/height + assume-screen 100:literal/width, 12:literal/height # recipe editor is empty 1:address:array:character <- new [] # sandbox editor contains an instruction without storing outputs @@ -2566,7 +2587,6 @@ scenario run-and-show-results [ . run (F10) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊divide-with-remainder 11:literal, 3:literal . . ┊3 . . ┊2 . @@ -2577,7 +2597,6 @@ scenario run-and-show-results [ . . . . . . - . . . divide-with-remainder 11:literal, 3:literal . . . . . @@ -2588,7 +2607,6 @@ scenario run-and-show-results [ . . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊ . . ┊3 . . ┊2 . @@ -2609,11 +2627,9 @@ scenario run-and-show-results [ . run (F10) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊add 2:literal, 2:literal . . ┊4 . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊divide-with-remainder 11:literal, 3:literal . . ┊3 . . ┊2 . @@ -2648,14 +2664,15 @@ recipe run-sandboxes [ init:address:address:duplex-list <- get-address current-sandbox:address:editor-data/deref, data:offset init:address:address:duplex-list/deref <- push-duplex 167:literal/§, 0:literal/tail } - # rerun other sandboxes + # run all sandboxes curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset { break-unless curr:address:sandbox-data data:address:address:array:character <- get-address curr:address:sandbox-data/deref, data:offset response:address:address:array:character <- get-address curr:address:sandbox-data/deref, response:offset warnings:address:address:array:character <- get-address curr:address:sandbox-data/deref, warnings:offset - response:address:address:array:character/deref, warnings:address:address:array:character/deref <- run-interactive data:address:address:array:character/deref + fake-screen:address:address:screen <- get-address curr:address:sandbox-data/deref, screen:offset + response:address:address:array:character/deref, warnings:address:address:array:character/deref, fake-screen:address:address:screen/deref <- run-interactive data:address:address:array:character/deref #? $print warnings:address:address:array:character/deref, [ ], warnings:address:address:array:character/deref/deref, [ #? ] #? 1 curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset @@ -2663,55 +2680,6 @@ recipe run-sandboxes [ } ] -# was-deleted?:boolean <- delete-sandbox t:touch-event, env:address:programming-environment-data -recipe delete-sandbox [ - local-scope - t:touch-event <- next-ingredient - env:address:programming-environment-data <- next-ingredient - click-column:number <- get t:touch-event, column:offset - current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset - right:number <- get current-sandbox:address:editor-data/deref, right:offset -#? $print [comparing column ], click-column:number, [ vs ], right:number, [ -#? ] #? 1 - at-right?:boolean <- equal click-column:number, right:number - reply-unless at-right?:boolean, 0:literal/false -#? $print [trying to delete -#? ] #? 1 - click-row:number <- get t:touch-event, row:offset - prev:address:address:sandbox-data <- get-address env:address:programming-environment-data/deref, sandbox:offset -#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ -#? ] #? 1 - curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset - { -#? $print [next sandbox -#? ] #? 1 - break-unless curr:address:sandbox-data - # more sandboxes to check - { -#? $print [checking -#? ] #? 1 - target-row:number <- get curr:address:sandbox-data/deref, starting-row-on-screen:offset -#? $print [comparing row ], target-row:number, [ vs ], click-row:number, [ -#? ] #? 1 - delete-curr?:boolean <- equal target-row:number, click-row:number - break-unless delete-curr?:boolean -#? $print [found! -#? ] #? 1 - # delete this sandbox, rerender and stop - prev:address:address:sandbox-data/deref <- get curr:address:sandbox-data/deref, next-sandbox:offset -#? $print [setting prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ -#? ] #? 1 - reply 1:literal/true - } - prev:address:address:sandbox-data <- get-address curr:address:sandbox-data/deref, next-sandbox:offset -#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ -#? ] #? 1 - curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset - loop - } - reply 0:literal/false -] - scenario run-updates-results [ $close-trace # trace too long for github assume-screen 100:literal/width, 12:literal/height @@ -2735,10 +2703,9 @@ z:number <- add 2:literal, 2:literal . run (F10) . . ┊ . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - .z:number <- add 2:literal, 2:literal ┊ x. - .] ┊foo . - .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 . - . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .z:number <- add 2:literal, 2:literal ┊foo . + .] ┊4 . + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] # make a change (incrementing one of the args to 'add'), then rerun @@ -2757,10 +2724,9 @@ z:number <- add 2:literal, 2:literal . run (F10) . . ┊ . .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - .z:number <- add 2:literal, 3:literal ┊ x. - .] ┊foo . - .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 . - . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .z:number <- add 2:literal, 3:literal ┊foo . + .] ┊5 . + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . ] ] @@ -2785,7 +2751,6 @@ scenario run-instruction-and-print-warnings [ . run (F10) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊get 1234:number, foo:offset . . ┊unknown element foo in container number . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2795,7 +2760,6 @@ scenario run-instruction-and-print-warnings [ . . . . . . - . . . get 1234:number, foo:offset . . . . . @@ -2806,7 +2770,6 @@ scenario run-instruction-and-print-warnings [ . . . . . . - . . . unknown element foo in container number . . . ] @@ -2814,7 +2777,6 @@ scenario run-instruction-and-print-warnings [ . . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊ . . ┊ . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2843,7 +2805,6 @@ scenario run-instruction-and-print-warnings-only-once [ . run (F10) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. . ┊get 1234:number, foo:offset . . ┊unknown element foo in container number . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. @@ -2851,69 +2812,37 @@ scenario run-instruction-and-print-warnings-only-once [ ] ] -scenario deleting-sandboxes [ - $close-trace # trace too long for github - assume-screen 100:literal/width, 15:literal/height +scenario run-instruction-manages-screen-per-sandbox [ + $close-trace # trace too long for github #? 1 + assume-screen 100:literal/width, 20:literal/height + # left editor is empty 1:address:array:character <- new [] - 2:address:array:character <- new [] + # right editor contains an illegal instruction + 2:address:array:character <- new [print-integer screen:address, 4] 3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character - # run a few commands + # run the code in the editor assume-console [ - left-click 1, 80 - type [divide-with-remainder 11:literal, 3:literal] - press 65526 # F10 - type [add 2:literal, 2:literal] press 65526 # F10 ] run [ event-loop screen:address, console:address, 3:address:programming-environment-data ] + # check that it prints a little 5x5 toy screen + # hack: screen address is brittle screen-should-contain [ . run (F10) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. - . ┊add 2:literal, 2:literal . - . ┊4 . - . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. - . ┊divide-with-remainder 11:literal, 3:literal . - . ┊3 . - . ┊2 . - . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ . - ] - # delete second sandbox - assume-console [ - left-click 7, 99 - ] - run [ - event-loop screen:address, console:address, 3:address:programming-environment-data - ] - screen-should-contain [ - . run (F10) . - . ┊ . - .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ x. - . ┊add 2:literal, 2:literal . - . ┊4 . + . ┊print-integer screen:address, 4 . + . ┊5557 . + . ┊screen: . + . ┊ .4 . . + . ┊ . . . + . ┊ . . . + . ┊ . . . + . ┊ . . . . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. . ┊ . - . ┊ . - ] - # delete first sandbox - assume-console [ - left-click 3, 99 - ] - run [ - event-loop screen:address, console:address, 3:address:programming-environment-data - ] - screen-should-contain [ - . run (F10) . - . ┊ . - .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. - . ┊ . - . ┊ . ] ] @@ -3007,12 +2936,22 @@ recipe draw-horizontal [ break-if bg-color-found?:boolean bg-color:number <- copy 0:literal/black } +#? $print [bbb ], 5155:number/raw, [ #? 1 +#? ] #? 1 move-cursor screen:address, row:number, x:number { +#? $print [ccc ], 5155:number/raw, [ #? 1 +#? ] #? 1 continue?:boolean <- lesser-or-equal x:number, right:number # right is inclusive, to match editor-data semantics break-unless continue?:boolean +#? $print [ddd ], 5155:number/raw, [ #? 1 +#? ] #? 1 print-character screen:address, style:character, color:number, bg-color:number +#? $print [xxx ], 5155:number/raw, [ #? 1 +#? ] #? 1 x:number <- add x:number, 1:literal +#? $print [yyy ], 5155:number/raw, [ #? 1 +#? ] #? 1 loop } ] |