From 3dda906d2457a6ff577d6fa34274f43529a87dbe Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 4 Dec 2020 23:57:35 -0800 Subject: 7335 --- html/apps/tile/environment.mu.html | 3310 ++++++++++++++++++------------------ 1 file changed, 1660 insertions(+), 1650 deletions(-) (limited to 'html/apps/tile/environment.mu.html') diff --git a/html/apps/tile/environment.mu.html b/html/apps/tile/environment.mu.html index 31b3fe43..bb4cec67 100644 --- a/html/apps/tile/environment.mu.html +++ b/html/apps/tile/environment.mu.html @@ -62,1672 +62,1682 @@ if ('onhashchange' in window) { 2 screen: (handle screen) 3 functions: (handle function) 4 sandboxes: (handle sandbox) - 5 nrows: int - 6 ncols: int - 7 code-separator-col: int - 8 } - 9 - 10 fn initialize-environment _env: (addr environment) { - 11 var env/esi: (addr environment) <- copy _env - 12 # initialize some predefined function definitions - 13 var functions/eax: (addr handle function) <- get env, functions - 14 create-primitive-functions functions - 15 # initialize first sandbox - 16 var sandbox-ah/eax: (addr handle sandbox) <- get env, sandboxes - 17 allocate sandbox-ah - 18 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah - 19 initialize-sandbox sandbox - 20 # initialize screen - 21 var screen-ah/eax: (addr handle screen) <- get env, screen - 22 var _screen/eax: (addr screen) <- lookup *screen-ah - 23 var screen/edi: (addr screen) <- copy _screen - 24 var nrows/eax: int <- copy 0 - 25 var ncols/ecx: int <- copy 0 - 26 nrows, ncols <- screen-size screen - 27 var dest/edx: (addr int) <- get env, nrows - 28 copy-to *dest, nrows - 29 dest <- get env, ncols - 30 copy-to *dest, ncols - 31 var repl-col/ecx: int <- copy ncols - 32 repl-col <- shift-right 1 - 33 dest <- get env, code-separator-col - 34 copy-to *dest, repl-col - 35 } - 36 - 37 fn draw-screen _env: (addr environment) { - 38 var env/esi: (addr environment) <- copy _env - 39 var screen-ah/eax: (addr handle screen) <- get env, screen - 40 var _screen/eax: (addr screen) <- lookup *screen-ah - 41 var screen/edi: (addr screen) <- copy _screen - 42 var dest/edx: (addr int) <- get env, code-separator-col - 43 var tmp/eax: int <- copy *dest - 44 clear-canvas env - 45 tmp <- add 2 # repl-margin-left - 46 move-cursor screen, 3, tmp # input-row - 47 } - 48 - 49 fn initialize-environment-with-fake-screen _self: (addr environment), nrows: int, ncols: int { - 50 var self/esi: (addr environment) <- copy _self - 51 var screen-ah/eax: (addr handle screen) <- get self, screen - 52 allocate screen-ah - 53 var screen-addr/eax: (addr screen) <- lookup *screen-ah - 54 initialize-screen screen-addr, nrows, ncols - 55 initialize-environment self - 56 } - 57 - 58 ############# - 59 # Iterate - 60 ############# + 5 cursor-sandbox: (handle sandbox) + 6 nrows: int + 7 ncols: int + 8 code-separator-col: int + 9 } + 10 + 11 fn initialize-environment _env: (addr environment) { + 12 var env/esi: (addr environment) <- copy _env + 13 # initialize some predefined function definitions + 14 var functions/eax: (addr handle function) <- get env, functions + 15 create-primitive-functions functions + 16 # initialize first sandbox + 17 var sandbox-ah/ecx: (addr handle sandbox) <- get env, sandboxes + 18 allocate sandbox-ah + 19 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah + 20 initialize-sandbox sandbox + 21 # initialize cursor sandbox + 22 var cursor-sandbox-ah/eax: (addr handle sandbox) <- get env, cursor-sandbox + 23 copy-object sandbox-ah, cursor-sandbox-ah + 24 # initialize screen + 25 var screen-ah/eax: (addr handle screen) <- get env, screen + 26 var _screen/eax: (addr screen) <- lookup *screen-ah + 27 var screen/edi: (addr screen) <- copy _screen + 28 var nrows/eax: int <- copy 0 + 29 var ncols/ecx: int <- copy 0 + 30 nrows, ncols <- screen-size screen + 31 var dest/edx: (addr int) <- get env, nrows + 32 copy-to *dest, nrows + 33 dest <- get env, ncols + 34 copy-to *dest, ncols + 35 var repl-col/ecx: int <- copy ncols + 36 repl-col <- shift-right 1 + 37 dest <- get env, code-separator-col + 38 copy-to *dest, repl-col + 39 } + 40 + 41 fn draw-screen _env: (addr environment) { + 42 var env/esi: (addr environment) <- copy _env + 43 var screen-ah/eax: (addr handle screen) <- get env, screen + 44 var _screen/eax: (addr screen) <- lookup *screen-ah + 45 var screen/edi: (addr screen) <- copy _screen + 46 var dest/edx: (addr int) <- get env, code-separator-col + 47 var tmp/eax: int <- copy *dest + 48 clear-canvas env + 49 tmp <- add 2 # repl-margin-left + 50 move-cursor screen, 3, tmp # input-row + 51 } + 52 + 53 fn initialize-environment-with-fake-screen _self: (addr environment), nrows: int, ncols: int { + 54 var self/esi: (addr environment) <- copy _self + 55 var screen-ah/eax: (addr handle screen) <- get self, screen + 56 allocate screen-ah + 57 var screen-addr/eax: (addr screen) <- lookup *screen-ah + 58 initialize-screen screen-addr, nrows, ncols + 59 initialize-environment self + 60 } 61 - 62 fn process _self: (addr environment), key: grapheme { - 63 var self/esi: (addr environment) <- copy _self - 64 var sandbox-ah/eax: (addr handle sandbox) <- get self, sandboxes - 65 var _sandbox/eax: (addr sandbox) <- lookup *sandbox-ah - 66 var sandbox/edi: (addr sandbox) <- copy _sandbox - 67 var rename-word-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-cursor-word - 68 var rename-word-mode?/eax: (addr word) <- lookup *rename-word-mode-ah? - 69 compare rename-word-mode?, 0 - 70 { - 71 break-if-= - 72 #? print-string 0, "processing sandbox rename\n" - 73 process-sandbox-rename sandbox, key - 74 return - 75 } - 76 var define-function-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-function - 77 var define-function-mode?/eax: (addr word) <- lookup *define-function-mode-ah? - 78 compare define-function-mode?, 0 - 79 { - 80 break-if-= - 81 #? print-string 0, "processing function definition\n" - 82 var functions/ecx: (addr handle function) <- get self, functions - 83 process-sandbox-define sandbox, functions, key + 62 ############# + 63 # Iterate + 64 ############# + 65 + 66 fn process _self: (addr environment), key: grapheme { + 67 var self/esi: (addr environment) <- copy _self + 68 var sandbox-ah/eax: (addr handle sandbox) <- get self, cursor-sandbox + 69 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah + 70 #? print-string 0, "processing sandbox\n" + 71 process-sandbox self, sandbox, key + 72 } + 73 + 74 fn process-sandbox _self: (addr environment), _sandbox: (addr sandbox), key: grapheme { + 75 var self/esi: (addr environment) <- copy _self + 76 var sandbox/edi: (addr sandbox) <- copy _sandbox + 77 var rename-word-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-cursor-word + 78 var rename-word-mode?/eax: (addr word) <- lookup *rename-word-mode-ah? + 79 compare rename-word-mode?, 0 + 80 { + 81 break-if-= + 82 #? print-string 0, "processing sandbox rename\n" + 83 process-sandbox-rename sandbox, key 84 return 85 } - 86 #? print-string 0, "processing sandbox\n" - 87 process-sandbox self, sandbox, key - 88 } - 89 - 90 fn process-sandbox _self: (addr environment), _sandbox: (addr sandbox), key: grapheme { - 91 var self/esi: (addr environment) <- copy _self - 92 var sandbox/edi: (addr sandbox) <- copy _sandbox - 93 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 94 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 95 var cursor-word-ah/ebx: (addr handle word) <- get cursor-call-path, word - 96 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 97 var cursor-word/ecx: (addr word) <- copy _cursor-word - 98 compare key, 0x445b1b # left-arrow - 99 $process-sandbox:key-left-arrow: { - 100 break-if-!= - 101 #? print-string 0, "left-arrow\n" - 102 # if not at start, move left within current word - 103 var at-start?/eax: boolean <- cursor-at-start? cursor-word - 104 compare at-start?, 0 # false - 105 { - 106 break-if-!= - 107 #? print-string 0, "cursor left within word\n" - 108 cursor-left cursor-word - 109 return - 110 } - 111 # if current word is expanded, move to the rightmost word in its body - 112 { - 113 var cursor-call-path/esi: (addr handle call-path-element) <- get sandbox, cursor-call-path - 114 var expanded-words/edx: (addr handle call-path) <- get sandbox, expanded-words - 115 var curr-word-is-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path - 116 compare curr-word-is-expanded?, 0 # false - 117 break-if-= - 118 # update cursor-call-path - 119 #? print-string 0, "curr word is expanded\n" - 120 var self/ecx: (addr environment) <- copy _self - 121 var functions/ecx: (addr handle function) <- get self, functions - 122 var body: (handle line) - 123 var body-ah/eax: (addr handle line) <- address body - 124 function-body functions, cursor-word-ah, body-ah - 125 var body-addr/eax: (addr line) <- lookup *body-ah - 126 var first-word-ah/edx: (addr handle word) <- get body-addr, data - 127 var final-word-h: (handle word) - 128 var final-word-ah/eax: (addr handle word) <- address final-word-h - 129 final-word first-word-ah, final-word-ah - 130 push-to-call-path-element cursor-call-path, final-word-ah - 131 # move cursor to end of word - 132 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 133 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 134 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 135 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 136 cursor-to-end cursor-word - 137 return - 138 } - 139 # if at first word, look for a caller to jump to - 140 $process-sandbox:key-left-arrow-first-word: { - 141 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev - 142 var prev-word/eax: (addr word) <- lookup *prev-word-ah - 143 compare prev-word, 0 - 144 break-if-!= - 145 $process-sandbox:key-left-arrow-first-word-and-caller: { - 146 #? print-string 0, "return\n" - 147 { - 148 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path - 149 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 150 var next-cursor-element-ah/edx: (addr handle call-path-element) <- get cursor-call-path, next - 151 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah - 152 compare next-cursor-element, 0 - 153 break-if-= $process-sandbox:key-left-arrow-first-word-and-caller - 154 copy-object next-cursor-element-ah, cursor-call-path-ah - 155 } - 156 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 157 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 158 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 159 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 160 cursor-word <- copy _cursor-word - 161 } - 162 } - 163 # then move to end of previous word - 164 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev - 165 var prev-word/eax: (addr word) <- lookup *prev-word-ah - 166 { - 167 compare prev-word, 0 - 168 break-if-= - 169 #? print-string 0, "move to previous word\n" - 170 cursor-to-end prev-word - 171 #? { - 172 #? var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 173 #? var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 174 #? var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 175 #? var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 176 #? var cursor-word/ebx: (addr word) <- copy _cursor-word - 177 #? print-string 0, "word at cursor before: " - 178 #? print-word 0, cursor-word - 179 #? print-string 0, "\n" - 180 #? } - 181 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 182 decrement-final-element cursor-call-path - 183 #? { - 184 #? var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 185 #? var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 186 #? var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 187 #? var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 188 #? var cursor-word/ebx: (addr word) <- copy _cursor-word - 189 #? print-string 0, "word at cursor after: " - 190 #? print-word 0, cursor-word - 191 #? print-string 0, "\n" - 192 #? } - 193 } - 194 return - 195 } - 196 compare key, 0x435b1b # right-arrow - 197 $process-sandbox:key-right-arrow: { - 198 break-if-!= - 199 # if not at end, move right within current word - 200 var at-end?/eax: boolean <- cursor-at-end? cursor-word - 201 compare at-end?, 0 # false - 202 { - 203 break-if-!= - 204 #? print-string 0, "a\n" - 205 cursor-right cursor-word - 206 return - 207 } - 208 # if at final word, look for a caller to jump to - 209 { - 210 var next-word-ah/edx: (addr handle word) <- get cursor-word, next - 211 var next-word/eax: (addr word) <- lookup *next-word-ah - 212 compare next-word, 0 + 86 var define-function-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-function + 87 var define-function-mode?/eax: (addr word) <- lookup *define-function-mode-ah? + 88 compare define-function-mode?, 0 + 89 { + 90 break-if-= + 91 #? print-string 0, "processing function definition\n" + 92 var functions/ecx: (addr handle function) <- get self, functions + 93 process-sandbox-define sandbox, functions, key + 94 return + 95 } + 96 #? print-string 0, "processing sandbox edit\n" + 97 process-sandbox-edit self, sandbox, key + 98 } + 99 + 100 fn process-sandbox-edit _self: (addr environment), _sandbox: (addr sandbox), key: grapheme { + 101 var self/esi: (addr environment) <- copy _self + 102 var sandbox/edi: (addr sandbox) <- copy _sandbox + 103 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 104 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 105 var cursor-word-ah/ebx: (addr handle word) <- get cursor-call-path, word + 106 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 107 var cursor-word/ecx: (addr word) <- copy _cursor-word + 108 compare key, 0x445b1b # left-arrow + 109 $process-sandbox-edit:key-left-arrow: { + 110 break-if-!= + 111 #? print-string 0, "left-arrow\n" + 112 # if not at start, move left within current word + 113 var at-start?/eax: boolean <- cursor-at-start? cursor-word + 114 compare at-start?, 0 # false + 115 { + 116 break-if-!= + 117 #? print-string 0, "cursor left within word\n" + 118 cursor-left cursor-word + 119 return + 120 } + 121 # if current word is expanded, move to the rightmost word in its body + 122 { + 123 var cursor-call-path/esi: (addr handle call-path-element) <- get sandbox, cursor-call-path + 124 var expanded-words/edx: (addr handle call-path) <- get sandbox, expanded-words + 125 var curr-word-is-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path + 126 compare curr-word-is-expanded?, 0 # false + 127 break-if-= + 128 # update cursor-call-path + 129 #? print-string 0, "curr word is expanded\n" + 130 var self/ecx: (addr environment) <- copy _self + 131 var functions/ecx: (addr handle function) <- get self, functions + 132 var body: (handle line) + 133 var body-ah/eax: (addr handle line) <- address body + 134 function-body functions, cursor-word-ah, body-ah + 135 var body-addr/eax: (addr line) <- lookup *body-ah + 136 var first-word-ah/edx: (addr handle word) <- get body-addr, data + 137 var final-word-h: (handle word) + 138 var final-word-ah/eax: (addr handle word) <- address final-word-h + 139 final-word first-word-ah, final-word-ah + 140 push-to-call-path-element cursor-call-path, final-word-ah + 141 # move cursor to end of word + 142 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 143 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 144 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 145 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 146 cursor-to-end cursor-word + 147 return + 148 } + 149 # if at first word, look for a caller to jump to + 150 $process-sandbox-edit:key-left-arrow-first-word: { + 151 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev + 152 var prev-word/eax: (addr word) <- lookup *prev-word-ah + 153 compare prev-word, 0 + 154 break-if-!= + 155 $process-sandbox-edit:key-left-arrow-first-word-and-caller: { + 156 #? print-string 0, "return\n" + 157 { + 158 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path + 159 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 160 var next-cursor-element-ah/edx: (addr handle call-path-element) <- get cursor-call-path, next + 161 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah + 162 compare next-cursor-element, 0 + 163 break-if-= $process-sandbox-edit:key-left-arrow-first-word-and-caller + 164 copy-object next-cursor-element-ah, cursor-call-path-ah + 165 } + 166 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 167 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 168 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 169 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 170 cursor-word <- copy _cursor-word + 171 } + 172 } + 173 # then move to end of previous word + 174 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev + 175 var prev-word/eax: (addr word) <- lookup *prev-word-ah + 176 { + 177 compare prev-word, 0 + 178 break-if-= + 179 #? print-string 0, "move to previous word\n" + 180 cursor-to-end prev-word + 181 #? { + 182 #? var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 183 #? var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 184 #? var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 185 #? var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 186 #? var cursor-word/ebx: (addr word) <- copy _cursor-word + 187 #? print-string 0, "word at cursor before: " + 188 #? print-word 0, cursor-word + 189 #? print-string 0, "\n" + 190 #? } + 191 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 192 decrement-final-element cursor-call-path + 193 #? { + 194 #? var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 195 #? var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 196 #? var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 197 #? var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 198 #? var cursor-word/ebx: (addr word) <- copy _cursor-word + 199 #? print-string 0, "word at cursor after: " + 200 #? print-word 0, cursor-word + 201 #? print-string 0, "\n" + 202 #? } + 203 } + 204 return + 205 } + 206 compare key, 0x435b1b # right-arrow + 207 $process-sandbox-edit:key-right-arrow: { + 208 break-if-!= + 209 # if not at end, move right within current word + 210 var at-end?/eax: boolean <- cursor-at-end? cursor-word + 211 compare at-end?, 0 # false + 212 { 213 break-if-!= - 214 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path - 215 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 216 var next-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next - 217 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah - 218 compare next-cursor-element, 0 - 219 break-if-= - 220 copy-object next-cursor-element-ah, cursor-call-path-ah - 221 return - 222 } - 223 # otherwise, move to the next word - 224 var next-word-ah/edx: (addr handle word) <- get cursor-word, next - 225 var next-word/eax: (addr word) <- lookup *next-word-ah - 226 { - 227 compare next-word, 0 - 228 break-if-= - 229 #? print-string 0, "b\n" - 230 cursor-to-start next-word - 231 # . . cursor-word now out of date - 232 var cursor-call-path/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path - 233 increment-final-element cursor-call-path - 234 # Is the new cursor word expanded? If so, it's a function call. Add a - 235 # new level to the cursor-call-path for the call's body. - 236 $process-sandbox:key-right-arrow-next-word-is-call-expanded: { - 237 #? print-string 0, "c\n" - 238 { - 239 var expanded-words/eax: (addr handle call-path) <- get sandbox, expanded-words - 240 var curr-word-is-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path - 241 compare curr-word-is-expanded?, 0 # false - 242 break-if-= $process-sandbox:key-right-arrow-next-word-is-call-expanded - 243 } - 244 var callee-h: (handle function) - 245 var callee-ah/edx: (addr handle function) <- address callee-h - 246 var functions/ebx: (addr handle function) <- get self, functions - 247 callee functions, next-word, callee-ah - 248 var callee/eax: (addr function) <- lookup *callee-ah - 249 var callee-body-ah/eax: (addr handle line) <- get callee, body - 250 var callee-body/eax: (addr line) <- lookup *callee-body-ah - 251 var callee-body-first-word/edx: (addr handle word) <- get callee-body, data - 252 push-to-call-path-element cursor-call-path, callee-body-first-word - 253 # position cursor at left - 254 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 255 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 256 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 257 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 258 cursor-to-start cursor-word - 259 #? print-string 0, "d\n" - 260 return - 261 } - 262 } - 263 return - 264 } - 265 compare key, 0xa # enter - 266 { - 267 break-if-!= - 268 # toggle display of subsidiary stack - 269 toggle-cursor-word sandbox - 270 return - 271 } - 272 compare key, 0xc # ctrl-l - 273 $process-sandbox:new-line: { - 274 break-if-!= - 275 # new line in sandbox - 276 append-line sandbox - 277 return - 278 } - 279 # word-based motions - 280 compare key, 2 # ctrl-b - 281 $process-sandbox:prev-word: { - 282 break-if-!= - 283 # jump to previous word at same level - 284 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev - 285 var prev-word/eax: (addr word) <- lookup *prev-word-ah - 286 { - 287 compare prev-word, 0 - 288 break-if-= - 289 cursor-to-end prev-word - 290 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 291 decrement-final-element cursor-call-path - 292 return - 293 } - 294 # if previous word doesn't exist, try to bump up one level - 295 { - 296 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path - 297 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 298 var caller-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next - 299 var caller-cursor-element/eax: (addr call-path-element) <- lookup *caller-cursor-element-ah - 300 compare caller-cursor-element, 0 - 301 break-if-= - 302 # check if previous word exists in caller - 303 var caller-word-ah/eax: (addr handle word) <- get caller-cursor-element, word - 304 var caller-word/eax: (addr word) <- lookup *caller-word-ah - 305 var word-before-caller-ah/eax: (addr handle word) <- get caller-word, prev - 306 var word-before-caller/eax: (addr word) <- lookup *word-before-caller-ah - 307 compare word-before-caller, 0 - 308 break-if-= - 309 # if so jump to it - 310 drop-from-call-path-element cursor-call-path-ah - 311 decrement-final-element cursor-call-path-ah - 312 return - 313 } - 314 } - 315 compare key, 6 # ctrl-f - 316 $process-sandbox:next-word: { - 317 break-if-!= - 318 #? print-string 0, "AA\n" - 319 # jump to previous word at same level - 320 var next-word-ah/edx: (addr handle word) <- get cursor-word, next - 321 var next-word/eax: (addr word) <- lookup *next-word-ah - 322 { - 323 compare next-word, 0 - 324 break-if-= - 325 #? print-string 0, "BB\n" - 326 cursor-to-end next-word - 327 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 328 increment-final-element cursor-call-path - 329 return - 330 } - 331 # if next word doesn't exist, try to bump up one level - 332 #? print-string 0, "CC\n" - 333 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path - 334 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 335 var caller-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next - 336 var caller-cursor-element/eax: (addr call-path-element) <- lookup *caller-cursor-element-ah - 337 compare caller-cursor-element, 0 - 338 break-if-= - 339 #? print-string 0, "DD\n" - 340 copy-object caller-cursor-element-ah, cursor-call-path-ah - 341 return - 342 } - 343 # line-based motions - 344 compare key, 1 # ctrl-a - 345 $process-sandbox:start-of-line: { - 346 break-if-!= - 347 # move cursor up past all calls and to start of line - 348 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 349 drop-nested-calls cursor-call-path-ah - 350 move-final-element-to-start-of-line cursor-call-path-ah - 351 # move cursor to start of word - 352 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 353 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 354 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 355 cursor-to-start cursor-word - 356 # this works as long as the first word isn't expanded - 357 # but we don't expect to see zero-arg functions first-up - 358 return - 359 } - 360 compare key, 5 # ctrl-e - 361 $process-sandbox:end-of-line: { - 362 break-if-!= - 363 # move cursor up past all calls and to start of line - 364 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 365 drop-nested-calls cursor-call-path-ah - 366 move-final-element-to-end-of-line cursor-call-path-ah - 367 # move cursor to end of word - 368 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 369 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word - 370 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah - 371 cursor-to-end cursor-word - 372 # this works because expanded words lie to the right of their bodies - 373 # so the final word is always guaranteed to be at the top-level - 374 return - 375 } - 376 compare key, 0x15 # ctrl-u - 377 $process-sandbox:clear-line: { - 378 break-if-!= - 379 # clear line in sandbox - 380 initialize-sandbox sandbox - 381 return - 382 } - 383 # if cursor is within a call, disable editing hotkeys below - 384 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 385 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 386 var next-cursor-element-ah/eax: (addr handle call-path-element) <- get cursor-call-path, next - 387 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah - 388 compare next-cursor-element, 0 - 389 { - 390 break-if-= + 214 #? print-string 0, "a\n" + 215 cursor-right cursor-word + 216 return + 217 } + 218 # if at final word, look for a caller to jump to + 219 { + 220 var next-word-ah/edx: (addr handle word) <- get cursor-word, next + 221 var next-word/eax: (addr word) <- lookup *next-word-ah + 222 compare next-word, 0 + 223 break-if-!= + 224 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path + 225 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 226 var next-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next + 227 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah + 228 compare next-cursor-element, 0 + 229 break-if-= + 230 copy-object next-cursor-element-ah, cursor-call-path-ah + 231 return + 232 } + 233 # otherwise, move to the next word + 234 var next-word-ah/edx: (addr handle word) <- get cursor-word, next + 235 var next-word/eax: (addr word) <- lookup *next-word-ah + 236 { + 237 compare next-word, 0 + 238 break-if-= + 239 #? print-string 0, "b\n" + 240 cursor-to-start next-word + 241 # . . cursor-word now out of date + 242 var cursor-call-path/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path + 243 increment-final-element cursor-call-path + 244 # Is the new cursor word expanded? If so, it's a function call. Add a + 245 # new level to the cursor-call-path for the call's body. + 246 $process-sandbox-edit:key-right-arrow-next-word-is-call-expanded: { + 247 #? print-string 0, "c\n" + 248 { + 249 var expanded-words/eax: (addr handle call-path) <- get sandbox, expanded-words + 250 var curr-word-is-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path + 251 compare curr-word-is-expanded?, 0 # false + 252 break-if-= $process-sandbox-edit:key-right-arrow-next-word-is-call-expanded + 253 } + 254 var callee-h: (handle function) + 255 var callee-ah/edx: (addr handle function) <- address callee-h + 256 var functions/ebx: (addr handle function) <- get self, functions + 257 callee functions, next-word, callee-ah + 258 var callee/eax: (addr function) <- lookup *callee-ah + 259 var callee-body-ah/eax: (addr handle line) <- get callee, body + 260 var callee-body/eax: (addr line) <- lookup *callee-body-ah + 261 var callee-body-first-word/edx: (addr handle word) <- get callee-body, data + 262 push-to-call-path-element cursor-call-path, callee-body-first-word + 263 # position cursor at left + 264 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 265 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 266 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 267 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 268 cursor-to-start cursor-word + 269 #? print-string 0, "d\n" + 270 return + 271 } + 272 } + 273 return + 274 } + 275 compare key, 0xa # enter + 276 { + 277 break-if-!= + 278 # toggle display of subsidiary stack + 279 toggle-cursor-word sandbox + 280 return + 281 } + 282 compare key, 0xc # ctrl-l + 283 $process-sandbox-edit:new-line: { + 284 break-if-!= + 285 # new line in sandbox + 286 append-line sandbox + 287 return + 288 } + 289 # word-based motions + 290 compare key, 2 # ctrl-b + 291 $process-sandbox-edit:prev-word: { + 292 break-if-!= + 293 # jump to previous word at same level + 294 var prev-word-ah/edx: (addr handle word) <- get cursor-word, prev + 295 var prev-word/eax: (addr word) <- lookup *prev-word-ah + 296 { + 297 compare prev-word, 0 + 298 break-if-= + 299 cursor-to-end prev-word + 300 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 301 decrement-final-element cursor-call-path + 302 return + 303 } + 304 # if previous word doesn't exist, try to bump up one level + 305 { + 306 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path + 307 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 308 var caller-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next + 309 var caller-cursor-element/eax: (addr call-path-element) <- lookup *caller-cursor-element-ah + 310 compare caller-cursor-element, 0 + 311 break-if-= + 312 # check if previous word exists in caller + 313 var caller-word-ah/eax: (addr handle word) <- get caller-cursor-element, word + 314 var caller-word/eax: (addr word) <- lookup *caller-word-ah + 315 var word-before-caller-ah/eax: (addr handle word) <- get caller-word, prev + 316 var word-before-caller/eax: (addr word) <- lookup *word-before-caller-ah + 317 compare word-before-caller, 0 + 318 break-if-= + 319 # if so jump to it + 320 drop-from-call-path-element cursor-call-path-ah + 321 decrement-final-element cursor-call-path-ah + 322 return + 323 } + 324 } + 325 compare key, 6 # ctrl-f + 326 $process-sandbox-edit:next-word: { + 327 break-if-!= + 328 #? print-string 0, "AA\n" + 329 # jump to previous word at same level + 330 var next-word-ah/edx: (addr handle word) <- get cursor-word, next + 331 var next-word/eax: (addr word) <- lookup *next-word-ah + 332 { + 333 compare next-word, 0 + 334 break-if-= + 335 #? print-string 0, "BB\n" + 336 cursor-to-end next-word + 337 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 338 increment-final-element cursor-call-path + 339 return + 340 } + 341 # if next word doesn't exist, try to bump up one level + 342 #? print-string 0, "CC\n" + 343 var cursor-call-path-ah/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path + 344 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 345 var caller-cursor-element-ah/ecx: (addr handle call-path-element) <- get cursor-call-path, next + 346 var caller-cursor-element/eax: (addr call-path-element) <- lookup *caller-cursor-element-ah + 347 compare caller-cursor-element, 0 + 348 break-if-= + 349 #? print-string 0, "DD\n" + 350 copy-object caller-cursor-element-ah, cursor-call-path-ah + 351 return + 352 } + 353 # line-based motions + 354 compare key, 1 # ctrl-a + 355 $process-sandbox-edit:start-of-line: { + 356 break-if-!= + 357 # move cursor up past all calls and to start of line + 358 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 359 drop-nested-calls cursor-call-path-ah + 360 move-final-element-to-start-of-line cursor-call-path-ah + 361 # move cursor to start of word + 362 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 363 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 364 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 365 cursor-to-start cursor-word + 366 # this works as long as the first word isn't expanded + 367 # but we don't expect to see zero-arg functions first-up + 368 return + 369 } + 370 compare key, 5 # ctrl-e + 371 $process-sandbox-edit:end-of-line: { + 372 break-if-!= + 373 # move cursor up past all calls and to start of line + 374 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 375 drop-nested-calls cursor-call-path-ah + 376 move-final-element-to-end-of-line cursor-call-path-ah + 377 # move cursor to end of word + 378 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 379 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word + 380 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah + 381 cursor-to-end cursor-word + 382 # this works because expanded words lie to the right of their bodies + 383 # so the final word is always guaranteed to be at the top-level + 384 return + 385 } + 386 compare key, 0x15 # ctrl-u + 387 $process-sandbox-edit:clear-line: { + 388 break-if-!= + 389 # clear line in sandbox + 390 initialize-sandbox sandbox 391 return 392 } - 393 # - remaining keys only work at the top row outside any function calls - 394 compare key, 0x7f # del (backspace on Macs) - 395 $process-sandbox:backspace: { - 396 break-if-!= - 397 # if not at start of some word, delete grapheme before cursor within current word - 398 var at-start?/eax: boolean <- cursor-at-start? cursor-word - 399 compare at-start?, 0 # false - 400 { - 401 break-if-!= - 402 delete-before-cursor cursor-word - 403 return - 404 } - 405 # otherwise delete current word and move to end of prev word - 406 var prev-word-ah/eax: (addr handle word) <- get cursor-word, prev - 407 var prev-word/eax: (addr word) <- lookup *prev-word-ah - 408 { - 409 compare prev-word, 0 - 410 break-if-= - 411 cursor-to-end prev-word - 412 delete-next prev-word - 413 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 414 decrement-final-element cursor-call-path - 415 } - 416 return - 417 } - 418 compare key, 0x20 # space - 419 $process-sandbox:space: { - 420 break-if-!= - 421 #? print-string 0, "space\n" - 422 # if cursor is at start of word, insert word before - 423 { - 424 var at-start?/eax: boolean <- cursor-at-start? cursor-word - 425 compare at-start?, 0 # false - 426 break-if-= - 427 var prev-word-ah/eax: (addr handle word) <- get cursor-word, prev - 428 append-word prev-word-ah - 429 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 430 decrement-final-element cursor-call-path - 431 return - 432 } - 433 # if start of word is quote and grapheme before cursor is not, just insert it as usual - 434 # TODO: support string escaping - 435 { - 436 var first-grapheme/eax: grapheme <- first-grapheme cursor-word - 437 compare first-grapheme, 0x22 # double quote - 438 break-if-!= - 439 var final-grapheme/eax: grapheme <- grapheme-before-cursor cursor-word - 440 compare final-grapheme, 0x22 # double quote - 441 break-if-= - 442 break $process-sandbox:space - 443 } - 444 # if start of word is '[' and grapheme before cursor is not ']', just insert it as usual - 445 # TODO: support nested arrays - 446 { - 447 var first-grapheme/eax: grapheme <- first-grapheme cursor-word - 448 compare first-grapheme, 0x5b # '[' - 449 break-if-!= - 450 var final-grapheme/eax: grapheme <- grapheme-before-cursor cursor-word - 451 compare final-grapheme, 0x5d # ']' - 452 break-if-= - 453 break $process-sandbox:space - 454 } - 455 # otherwise insert word after and move cursor to it for the next key - 456 # (but we'll continue to track the current cursor-word for the rest of this function) - 457 append-word cursor-word-ah - 458 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 459 increment-final-element cursor-call-path - 460 # if cursor is at end of word, that's all - 461 var at-end?/eax: boolean <- cursor-at-end? cursor-word - 462 compare at-end?, 0 # false - 463 { - 464 break-if-= - 465 return - 466 } - 467 # otherwise we're in the middle of a word - 468 # move everything after cursor to the (just created) next word - 469 var next-word-ah/eax: (addr handle word) <- get cursor-word, next - 470 var _next-word/eax: (addr word) <- lookup *next-word-ah - 471 var next-word/ebx: (addr word) <- copy _next-word - 472 { - 473 var at-end?/eax: boolean <- cursor-at-end? cursor-word - 474 compare at-end?, 0 # false - 475 break-if-!= - 476 var g/eax: grapheme <- pop-after-cursor cursor-word - 477 add-grapheme-to-word next-word, g - 478 loop - 479 } - 480 cursor-to-start next-word - 481 return - 482 } - 483 compare key, 0xe # ctrl-n - 484 $process:rename-word: { - 485 break-if-!= - 486 # TODO: ensure current word is not a function - 487 # rename word at cursor - 488 var new-name-ah/eax: (addr handle word) <- get sandbox, partial-name-for-cursor-word - 489 allocate new-name-ah - 490 var new-name/eax: (addr word) <- lookup *new-name-ah - 491 initialize-word new-name - 492 return - 493 } - 494 compare key, 4 # ctrl-d - 495 $process:define-function: { - 496 break-if-!= - 497 # define function out of line at cursor - 498 var new-name-ah/eax: (addr handle word) <- get sandbox, partial-name-for-function + 393 # if cursor is within a call, disable editing hotkeys below + 394 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 395 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 396 var next-cursor-element-ah/eax: (addr handle call-path-element) <- get cursor-call-path, next + 397 var next-cursor-element/eax: (addr call-path-element) <- lookup *next-cursor-element-ah + 398 compare next-cursor-element, 0 + 399 { + 400 break-if-= + 401 return + 402 } + 403 # - remaining keys only work at the top row outside any function calls + 404 compare key, 0x7f # del (backspace on Macs) + 405 $process-sandbox-edit:backspace: { + 406 break-if-!= + 407 # if not at start of some word, delete grapheme before cursor within current word + 408 var at-start?/eax: boolean <- cursor-at-start? cursor-word + 409 compare at-start?, 0 # false + 410 { + 411 break-if-!= + 412 delete-before-cursor cursor-word + 413 return + 414 } + 415 # otherwise delete current word and move to end of prev word + 416 var prev-word-ah/eax: (addr handle word) <- get cursor-word, prev + 417 var prev-word/eax: (addr word) <- lookup *prev-word-ah + 418 { + 419 compare prev-word, 0 + 420 break-if-= + 421 cursor-to-end prev-word + 422 delete-next prev-word + 423 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 424 decrement-final-element cursor-call-path + 425 } + 426 return + 427 } + 428 compare key, 0x20 # space + 429 $process-sandbox-edit:space: { + 430 break-if-!= + 431 #? print-string 0, "space\n" + 432 # if cursor is at start of word, insert word before + 433 { + 434 var at-start?/eax: boolean <- cursor-at-start? cursor-word + 435 compare at-start?, 0 # false + 436 break-if-= + 437 var prev-word-ah/eax: (addr handle word) <- get cursor-word, prev + 438 append-word prev-word-ah + 439 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 440 decrement-final-element cursor-call-path + 441 return + 442 } + 443 # if start of word is quote and grapheme before cursor is not, just insert it as usual + 444 # TODO: support string escaping + 445 { + 446 var first-grapheme/eax: grapheme <- first-grapheme cursor-word + 447 compare first-grapheme, 0x22 # double quote + 448 break-if-!= + 449 var final-grapheme/eax: grapheme <- grapheme-before-cursor cursor-word + 450 compare final-grapheme, 0x22 # double quote + 451 break-if-= + 452 break $process-sandbox-edit:space + 453 } + 454 # if start of word is '[' and grapheme before cursor is not ']', just insert it as usual + 455 # TODO: support nested arrays + 456 { + 457 var first-grapheme/eax: grapheme <- first-grapheme cursor-word + 458 compare first-grapheme, 0x5b # '[' + 459 break-if-!= + 460 var final-grapheme/eax: grapheme <- grapheme-before-cursor cursor-word + 461 compare final-grapheme, 0x5d # ']' + 462 break-if-= + 463 break $process-sandbox-edit:space + 464 } + 465 # otherwise insert word after and move cursor to it for the next key + 466 # (but we'll continue to track the current cursor-word for the rest of this function) + 467 append-word cursor-word-ah + 468 var cursor-call-path/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 469 increment-final-element cursor-call-path + 470 # if cursor is at end of word, that's all + 471 var at-end?/eax: boolean <- cursor-at-end? cursor-word + 472 compare at-end?, 0 # false + 473 { + 474 break-if-= + 475 return + 476 } + 477 # otherwise we're in the middle of a word + 478 # move everything after cursor to the (just created) next word + 479 var next-word-ah/eax: (addr handle word) <- get cursor-word, next + 480 var _next-word/eax: (addr word) <- lookup *next-word-ah + 481 var next-word/ebx: (addr word) <- copy _next-word + 482 { + 483 var at-end?/eax: boolean <- cursor-at-end? cursor-word + 484 compare at-end?, 0 # false + 485 break-if-!= + 486 var g/eax: grapheme <- pop-after-cursor cursor-word + 487 add-grapheme-to-word next-word, g + 488 loop + 489 } + 490 cursor-to-start next-word + 491 return + 492 } + 493 compare key, 0xe # ctrl-n + 494 $process:rename-word: { + 495 break-if-!= + 496 # TODO: ensure current word is not a function + 497 # rename word at cursor + 498 var new-name-ah/eax: (addr handle word) <- get sandbox, partial-name-for-cursor-word 499 allocate new-name-ah 500 var new-name/eax: (addr word) <- lookup *new-name-ah 501 initialize-word new-name 502 return 503 } - 504 # otherwise insert key within current word - 505 var g/edx: grapheme <- copy key - 506 var print?/eax: boolean <- real-grapheme? key - 507 $process-sandbox:real-grapheme: { - 508 compare print?, 0 # false - 509 break-if-= - 510 add-grapheme-to-word cursor-word, g - 511 return - 512 } - 513 # silently ignore other hotkeys - 514 } - 515 - 516 # collect new name in partial-name-for-cursor-word, and then rename the word - 517 # at cursor to it - 518 # Precondition: cursor-call-path is a singleton (not within a call) - 519 fn process-sandbox-rename _sandbox: (addr sandbox), key: grapheme { - 520 var sandbox/esi: (addr sandbox) <- copy _sandbox - 521 var new-name-ah/edi: (addr handle word) <- get sandbox, partial-name-for-cursor-word - 522 # if 'esc' pressed, cancel rename - 523 compare key, 0x1b # esc - 524 $process-sandbox-rename:cancel: { - 525 break-if-!= - 526 clear-object new-name-ah - 527 return - 528 } - 529 # if 'enter' pressed, perform rename - 530 compare key, 0xa # enter - 531 $process-sandbox-rename:commit: { - 532 break-if-!= - 533 #? print-string 0, "rename\n" - 534 # new line - 535 var new-line-h: (handle line) - 536 var new-line-ah/eax: (addr handle line) <- address new-line-h - 537 allocate new-line-ah - 538 var new-line/eax: (addr line) <- lookup *new-line-ah - 539 initialize-line new-line - 540 var new-line-word-ah/ecx: (addr handle word) <- get new-line, data - 541 { - 542 # move word at cursor to new line - 543 var cursor-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 544 var cursor/eax: (addr call-path-element) <- lookup *cursor-ah - 545 var word-at-cursor-ah/eax: (addr handle word) <- get cursor, word - 546 #? print-string 0, "cursor before at word " - 547 #? { - 548 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah - 549 #? print-word 0, cursor-word - 550 #? print-string 0, "\n" - 551 #? } - 552 move-word-contents word-at-cursor-ah, new-line-word-ah - 553 # copy name to word at cursor - 554 copy-word-contents-before-cursor new-name-ah, word-at-cursor-ah - 555 #? print-string 0, "cursor after at word " - 556 #? { - 557 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah - 558 #? print-word 0, cursor-word - 559 #? print-string 0, "\n" - 560 #? var foo/eax: int <- copy cursor-word - 561 #? print-int32-hex 0, foo - 562 #? print-string 0, "\n" - 563 #? } - 564 #? print-string 0, "new name word " - 565 #? { - 566 #? var new-name/eax: (addr word) <- lookup *new-name-ah - 567 #? print-word 0, new-name - 568 #? print-string 0, "\n" - 569 #? var foo/eax: int <- copy new-name - 570 #? print-int32-hex 0, foo - 571 #? print-string 0, "\n" - 572 #? } - 573 } - 574 # prepend '=' to name - 575 { - 576 var new-name/eax: (addr word) <- lookup *new-name-ah - 577 cursor-to-start new-name - 578 add-grapheme-to-word new-name, 0x3d # '=' - 579 } - 580 # append name to new line - 581 chain-words new-line-word-ah, new-name-ah - 582 # new-line->next = sandbox->data - 583 var new-line-next/ecx: (addr handle line) <- get new-line, next - 584 var sandbox-slot/edx: (addr handle line) <- get sandbox, data - 585 copy-object sandbox-slot, new-line-next - 586 # sandbox->data = new-line - 587 copy-handle new-line-h, sandbox-slot - 588 # clear partial-name-for-cursor-word - 589 clear-object new-name-ah - 590 #? var cursor-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 591 #? var cursor/eax: (addr call-path-element) <- lookup *cursor-ah - 592 #? var word-at-cursor-ah/eax: (addr handle word) <- get cursor, word - 593 #? print-string 0, "cursor after rename: " - 594 #? { - 595 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah - 596 #? print-word 0, cursor-word - 597 #? print-string 0, " -- " - 598 #? var foo/eax: int <- copy cursor-word - 599 #? print-int32-hex 0, foo - 600 #? print-string 0, "\n" - 601 #? } - 602 return - 603 } - 604 # - 605 compare key, 0x7f # del (backspace on Macs) - 606 $process-sandbox-rename:backspace: { - 607 break-if-!= - 608 # if not at start, delete grapheme before cursor - 609 var new-name/eax: (addr word) <- lookup *new-name-ah - 610 var at-start?/eax: boolean <- cursor-at-start? new-name - 611 compare at-start?, 0 # false - 612 { - 613 break-if-!= - 614 var new-name/eax: (addr word) <- lookup *new-name-ah - 615 delete-before-cursor new-name - 616 } - 617 return - 618 } - 619 # otherwise insert key within current word - 620 var print?/eax: boolean <- real-grapheme? key - 621 $process-sandbox-rename:real-grapheme: { - 622 compare print?, 0 # false - 623 break-if-= - 624 var new-name/eax: (addr word) <- lookup *new-name-ah - 625 add-grapheme-to-word new-name, key - 626 return - 627 } - 628 # silently ignore other hotkeys - 629 } - 630 - 631 # collect new name in partial-name-for-function, and then define the last line - 632 # of the sandbox to be a new function with that name. Replace the last line - 633 # with a call to the appropriate function. - 634 # Precondition: cursor-call-path is a singleton (not within a call) - 635 fn process-sandbox-define _sandbox: (addr sandbox), functions: (addr handle function), key: grapheme { - 636 var sandbox/esi: (addr sandbox) <- copy _sandbox - 637 var new-name-ah/edi: (addr handle word) <- get sandbox, partial-name-for-function - 638 # if 'esc' pressed, cancel define - 639 compare key, 0x1b # esc - 640 $process-sandbox-define:cancel: { - 641 break-if-!= - 642 clear-object new-name-ah - 643 return - 644 } - 645 # if 'enter' pressed, perform define - 646 compare key, 0xa # enter - 647 $process-sandbox-define:commit: { - 648 break-if-!= - 649 #? print-string 0, "define\n" - 650 # create new function - 651 var new-function: (handle function) - 652 var new-function-ah/ecx: (addr handle function) <- address new-function - 653 allocate new-function-ah - 654 var _new-function/eax: (addr function) <- lookup *new-function-ah - 655 var new-function/ebx: (addr function) <- copy _new-function - 656 var dest/edx: (addr handle function) <- get new-function, next - 657 copy-object functions, dest - 658 copy-object new-function-ah, functions - 659 # set function name to new-name - 660 var new-name/eax: (addr word) <- lookup *new-name-ah - 661 var dest/edx: (addr handle array byte) <- get new-function, name - 662 word-to-string new-name, dest - 663 # move final line to body - 664 var body-ah/eax: (addr handle line) <- get new-function, body - 665 allocate body-ah - 666 var body/eax: (addr line) <- lookup *body-ah - 667 var body-contents/ecx: (addr handle word) <- get body, data - 668 var final-line-storage: (handle line) - 669 var final-line-ah/eax: (addr handle line) <- address final-line-storage - 670 final-line sandbox, final-line-ah - 671 var final-line/eax: (addr line) <- lookup *final-line-ah - 672 var final-line-contents/eax: (addr handle word) <- get final-line, data - 673 copy-object final-line-contents, body-contents - 674 # - 675 copy-unbound-words-to-args functions - 676 # - 677 var empty-word: (handle word) - 678 copy-handle empty-word, final-line-contents - 679 construct-call functions, final-line-contents - 680 # clear partial-name-for-function - 681 var empty-word: (handle word) - 682 copy-handle empty-word, new-name-ah - 683 # update cursor - 684 var final-line/eax: (addr line) <- lookup final-line-storage - 685 var cursor-call-path-ah/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path - 686 allocate cursor-call-path-ah # leak - 687 initialize-path-from-line final-line, cursor-call-path-ah - 688 return - 689 } - 690 # - 691 compare key, 0x7f # del (backspace on Macs) - 692 $process-sandbox-define:backspace: { - 693 break-if-!= - 694 # if not at start, delete grapheme before cursor - 695 var new-name/eax: (addr word) <- lookup *new-name-ah - 696 var at-start?/eax: boolean <- cursor-at-start? new-name - 697 compare at-start?, 0 # false - 698 { - 699 break-if-!= - 700 var new-name/eax: (addr word) <- lookup *new-name-ah - 701 delete-before-cursor new-name - 702 } - 703 return - 704 } - 705 # otherwise insert key within current word - 706 var print?/eax: boolean <- real-grapheme? key - 707 $process-sandbox-define:real-grapheme: { - 708 compare print?, 0 # false - 709 break-if-= - 710 var new-name/eax: (addr word) <- lookup *new-name-ah - 711 add-grapheme-to-word new-name, key - 712 return - 713 } - 714 # silently ignore other hotkeys - 715 } - 716 - 717 # extract from the body of the first function in 'functions' all words that - 718 # aren't defined in the rest of 'functions'. Prepend them in reverse order. - 719 # Assumes function body is a single line for now. - 720 fn copy-unbound-words-to-args _functions: (addr handle function) { - 721 # target - 722 var target-ah/eax: (addr handle function) <- copy _functions - 723 var _target/eax: (addr function) <- lookup *target-ah - 724 var target/esi: (addr function) <- copy _target - 725 var dest-ah/edi: (addr handle word) <- get target, args - 726 # next - 727 var functions-ah/edx: (addr handle function) <- get target, next - 728 # src - 729 var line-ah/eax: (addr handle line) <- get target, body - 730 var line/eax: (addr line) <- lookup *line-ah - 731 var curr-ah/eax: (addr handle word) <- get line, data - 732 var curr/eax: (addr word) <- lookup *curr-ah - 733 { - 734 compare curr, 0 - 735 break-if-= - 736 $copy-unbound-words-to-args:loop-iter: { - 737 # is it a number? - 738 { - 739 var is-int?/eax: boolean <- word-is-decimal-integer? curr - 740 compare is-int?, 0 # false - 741 break-if-!= $copy-unbound-words-to-args:loop-iter - 742 } - 743 # is it a pre-existing function? - 744 var bound?/ebx: boolean <- bound-function? curr, functions-ah - 745 compare bound?, 0 # false - 746 break-if-!= - 747 # is it already bound as an arg? - 748 var dup?/ebx: boolean <- arg-exists? _functions, curr # _functions = target-ah - 749 compare dup?, 0 # false - 750 break-if-!= $copy-unbound-words-to-args:loop-iter - 751 # push copy of curr before dest-ah - 752 var rest-h: (handle word) - 753 var rest-ah/ecx: (addr handle word) <- address rest-h - 754 copy-object dest-ah, rest-ah - 755 copy-word curr, dest-ah - 756 chain-words dest-ah, rest-ah - 757 } - 758 var next-ah/ecx: (addr handle word) <- get curr, next - 759 curr <- lookup *next-ah - 760 loop - 761 } - 762 } - 763 - 764 fn bound-function? w: (addr word), functions-ah: (addr handle function) -> _/ebx: boolean { - 765 var result/ebx: boolean <- copy 1 # true - 766 { - 767 ## numbers - 768 # if w == "+" return true - 769 var subresult/eax: boolean <- word-equal? w, "+" - 770 compare subresult, 0 # false - 771 break-if-!= - 772 # if w == "-" return true - 773 subresult <- word-equal? w, "-" - 774 compare subresult, 0 # false - 775 break-if-!= - 776 # if w == "*" return true - 777 subresult <- word-equal? w, "*" - 778 compare subresult, 0 # false - 779 break-if-!= - 780 # if w == "/" return true - 781 subresult <- word-equal? w, "/" - 782 compare subresult, 0 # false - 783 break-if-!= - 784 # if w == "sqrt" return true - 785 subresult <- word-equal? w, "sqrt" - 786 compare subresult, 0 # false - 787 break-if-!= - 788 ## strings/arrays - 789 # if w == "len" return true - 790 subresult <- word-equal? w, "len" - 791 compare subresult, 0 # false - 792 break-if-!= - 793 ## files - 794 # if w == "open" return true - 795 subresult <- word-equal? w, "open" + 504 compare key, 4 # ctrl-d + 505 $process:define-function: { + 506 break-if-!= + 507 # define function out of line at cursor + 508 var new-name-ah/eax: (addr handle word) <- get sandbox, partial-name-for-function + 509 allocate new-name-ah + 510 var new-name/eax: (addr word) <- lookup *new-name-ah + 511 initialize-word new-name + 512 return + 513 } + 514 # otherwise insert key within current word + 515 var g/edx: grapheme <- copy key + 516 var print?/eax: boolean <- real-grapheme? key + 517 $process-sandbox-edit:real-grapheme: { + 518 compare print?, 0 # false + 519 break-if-= + 520 add-grapheme-to-word cursor-word, g + 521 return + 522 } + 523 # silently ignore other hotkeys + 524 } + 525 + 526 # collect new name in partial-name-for-cursor-word, and then rename the word + 527 # at cursor to it + 528 # Precondition: cursor-call-path is a singleton (not within a call) + 529 fn process-sandbox-rename _sandbox: (addr sandbox), key: grapheme { + 530 var sandbox/esi: (addr sandbox) <- copy _sandbox + 531 var new-name-ah/edi: (addr handle word) <- get sandbox, partial-name-for-cursor-word + 532 # if 'esc' pressed, cancel rename + 533 compare key, 0x1b # esc + 534 $process-sandbox-rename:cancel: { + 535 break-if-!= + 536 clear-object new-name-ah + 537 return + 538 } + 539 # if 'enter' pressed, perform rename + 540 compare key, 0xa # enter + 541 $process-sandbox-rename:commit: { + 542 break-if-!= + 543 #? print-string 0, "rename\n" + 544 # new line + 545 var new-line-h: (handle line) + 546 var new-line-ah/eax: (addr handle line) <- address new-line-h + 547 allocate new-line-ah + 548 var new-line/eax: (addr line) <- lookup *new-line-ah + 549 initialize-line new-line + 550 var new-line-word-ah/ecx: (addr handle word) <- get new-line, data + 551 { + 552 # move word at cursor to new line + 553 var cursor-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 554 var cursor/eax: (addr call-path-element) <- lookup *cursor-ah + 555 var word-at-cursor-ah/eax: (addr handle word) <- get cursor, word + 556 #? print-string 0, "cursor before at word " + 557 #? { + 558 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah + 559 #? print-word 0, cursor-word + 560 #? print-string 0, "\n" + 561 #? } + 562 move-word-contents word-at-cursor-ah, new-line-word-ah + 563 # copy name to word at cursor + 564 copy-word-contents-before-cursor new-name-ah, word-at-cursor-ah + 565 #? print-string 0, "cursor after at word " + 566 #? { + 567 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah + 568 #? print-word 0, cursor-word + 569 #? print-string 0, "\n" + 570 #? var foo/eax: int <- copy cursor-word + 571 #? print-int32-hex 0, foo + 572 #? print-string 0, "\n" + 573 #? } + 574 #? print-string 0, "new name word " + 575 #? { + 576 #? var new-name/eax: (addr word) <- lookup *new-name-ah + 577 #? print-word 0, new-name + 578 #? print-string 0, "\n" + 579 #? var foo/eax: int <- copy new-name + 580 #? print-int32-hex 0, foo + 581 #? print-string 0, "\n" + 582 #? } + 583 } + 584 # prepend '=' to name + 585 { + 586 var new-name/eax: (addr word) <- lookup *new-name-ah + 587 cursor-to-start new-name + 588 add-grapheme-to-word new-name, 0x3d # '=' + 589 } + 590 # append name to new line + 591 chain-words new-line-word-ah, new-name-ah + 592 # new-line->next = sandbox->data + 593 var new-line-next/ecx: (addr handle line) <- get new-line, next + 594 var sandbox-slot/edx: (addr handle line) <- get sandbox, data + 595 copy-object sandbox-slot, new-line-next + 596 # sandbox->data = new-line + 597 copy-handle new-line-h, sandbox-slot + 598 # clear partial-name-for-cursor-word + 599 clear-object new-name-ah + 600 #? var cursor-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 601 #? var cursor/eax: (addr call-path-element) <- lookup *cursor-ah + 602 #? var word-at-cursor-ah/eax: (addr handle word) <- get cursor, word + 603 #? print-string 0, "cursor after rename: " + 604 #? { + 605 #? var cursor-word/eax: (addr word) <- lookup *word-at-cursor-ah + 606 #? print-word 0, cursor-word + 607 #? print-string 0, " -- " + 608 #? var foo/eax: int <- copy cursor-word + 609 #? print-int32-hex 0, foo + 610 #? print-string 0, "\n" + 611 #? } + 612 return + 613 } + 614 # + 615 compare key, 0x7f # del (backspace on Macs) + 616 $process-sandbox-rename:backspace: { + 617 break-if-!= + 618 # if not at start, delete grapheme before cursor + 619 var new-name/eax: (addr word) <- lookup *new-name-ah + 620 var at-start?/eax: boolean <- cursor-at-start? new-name + 621 compare at-start?, 0 # false + 622 { + 623 break-if-!= + 624 var new-name/eax: (addr word) <- lookup *new-name-ah + 625 delete-before-cursor new-name + 626 } + 627 return + 628 } + 629 # otherwise insert key within current word + 630 var print?/eax: boolean <- real-grapheme? key + 631 $process-sandbox-rename:real-grapheme: { + 632 compare print?, 0 # false + 633 break-if-= + 634 var new-name/eax: (addr word) <- lookup *new-name-ah + 635 add-grapheme-to-word new-name, key + 636 return + 637 } + 638 # silently ignore other hotkeys + 639 } + 640 + 641 # collect new name in partial-name-for-function, and then define the last line + 642 # of the sandbox to be a new function with that name. Replace the last line + 643 # with a call to the appropriate function. + 644 # Precondition: cursor-call-path is a singleton (not within a call) + 645 fn process-sandbox-define _sandbox: (addr sandbox), functions: (addr handle function), key: grapheme { + 646 var sandbox/esi: (addr sandbox) <- copy _sandbox + 647 var new-name-ah/edi: (addr handle word) <- get sandbox, partial-name-for-function + 648 # if 'esc' pressed, cancel define + 649 compare key, 0x1b # esc + 650 $process-sandbox-define:cancel: { + 651 break-if-!= + 652 clear-object new-name-ah + 653 return + 654 } + 655 # if 'enter' pressed, perform define + 656 compare key, 0xa # enter + 657 $process-sandbox-define:commit: { + 658 break-if-!= + 659 #? print-string 0, "define\n" + 660 # create new function + 661 var new-function: (handle function) + 662 var new-function-ah/ecx: (addr handle function) <- address new-function + 663 allocate new-function-ah + 664 var _new-function/eax: (addr function) <- lookup *new-function-ah + 665 var new-function/ebx: (addr function) <- copy _new-function + 666 var dest/edx: (addr handle function) <- get new-function, next + 667 copy-object functions, dest + 668 copy-object new-function-ah, functions + 669 # set function name to new-name + 670 var new-name/eax: (addr word) <- lookup *new-name-ah + 671 var dest/edx: (addr handle array byte) <- get new-function, name + 672 word-to-string new-name, dest + 673 # move final line to body + 674 var body-ah/eax: (addr handle line) <- get new-function, body + 675 allocate body-ah + 676 var body/eax: (addr line) <- lookup *body-ah + 677 var body-contents/ecx: (addr handle word) <- get body, data + 678 var final-line-storage: (handle line) + 679 var final-line-ah/eax: (addr handle line) <- address final-line-storage + 680 final-line sandbox, final-line-ah + 681 var final-line/eax: (addr line) <- lookup *final-line-ah + 682 var final-line-contents/eax: (addr handle word) <- get final-line, data + 683 copy-object final-line-contents, body-contents + 684 # + 685 copy-unbound-words-to-args functions + 686 # + 687 var empty-word: (handle word) + 688 copy-handle empty-word, final-line-contents + 689 construct-call functions, final-line-contents + 690 # clear partial-name-for-function + 691 var empty-word: (handle word) + 692 copy-handle empty-word, new-name-ah + 693 # update cursor + 694 var final-line/eax: (addr line) <- lookup final-line-storage + 695 var cursor-call-path-ah/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path + 696 allocate cursor-call-path-ah # leak + 697 initialize-path-from-line final-line, cursor-call-path-ah + 698 return + 699 } + 700 # + 701 compare key, 0x7f # del (backspace on Macs) + 702 $process-sandbox-define:backspace: { + 703 break-if-!= + 704 # if not at start, delete grapheme before cursor + 705 var new-name/eax: (addr word) <- lookup *new-name-ah + 706 var at-start?/eax: boolean <- cursor-at-start? new-name + 707 compare at-start?, 0 # false + 708 { + 709 break-if-!= + 710 var new-name/eax: (addr word) <- lookup *new-name-ah + 711 delete-before-cursor new-name + 712 } + 713 return + 714 } + 715 # otherwise insert key within current word + 716 var print?/eax: boolean <- real-grapheme? key + 717 $process-sandbox-define:real-grapheme: { + 718 compare print?, 0 # false + 719 break-if-= + 720 var new-name/eax: (addr word) <- lookup *new-name-ah + 721 add-grapheme-to-word new-name, key + 722 return + 723 } + 724 # silently ignore other hotkeys + 725 } + 726 + 727 # extract from the body of the first function in 'functions' all words that + 728 # aren't defined in the rest of 'functions'. Prepend them in reverse order. + 729 # Assumes function body is a single line for now. + 730 fn copy-unbound-words-to-args _functions: (addr handle function) { + 731 # target + 732 var target-ah/eax: (addr handle function) <- copy _functions + 733 var _target/eax: (addr function) <- lookup *target-ah + 734 var target/esi: (addr function) <- copy _target + 735 var dest-ah/edi: (addr handle word) <- get target, args + 736 # next + 737 var functions-ah/edx: (addr handle function) <- get target, next + 738 # src + 739 var line-ah/eax: (addr handle line) <- get target, body + 740 var line/eax: (addr line) <- lookup *line-ah + 741 var curr-ah/eax: (addr handle word) <- get line, data + 742 var curr/eax: (addr word) <- lookup *curr-ah + 743 { + 744 compare curr, 0 + 745 break-if-= + 746 $copy-unbound-words-to-args:loop-iter: { + 747 # is it a number? + 748 { + 749 var is-int?/eax: boolean <- word-is-decimal-integer? curr + 750 compare is-int?, 0 # false + 751 break-if-!= $copy-unbound-words-to-args:loop-iter + 752 } + 753 # is it a pre-existing function? + 754 var bound?/ebx: boolean <- bound-function? curr, functions-ah + 755 compare bound?, 0 # false + 756 break-if-!= + 757 # is it already bound as an arg? + 758 var dup?/ebx: boolean <- arg-exists? _functions, curr # _functions = target-ah + 759 compare dup?, 0 # false + 760 break-if-!= $copy-unbound-words-to-args:loop-iter + 761 # push copy of curr before dest-ah + 762 var rest-h: (handle word) + 763 var rest-ah/ecx: (addr handle word) <- address rest-h + 764 copy-object dest-ah, rest-ah + 765 copy-word curr, dest-ah + 766 chain-words dest-ah, rest-ah + 767 } + 768 var next-ah/ecx: (addr handle word) <- get curr, next + 769 curr <- lookup *next-ah + 770 loop + 771 } + 772 } + 773 + 774 fn bound-function? w: (addr word), functions-ah: (addr handle function) -> _/ebx: boolean { + 775 var result/ebx: boolean <- copy 1 # true + 776 { + 777 ## numbers + 778 # if w == "+" return true + 779 var subresult/eax: boolean <- word-equal? w, "+" + 780 compare subresult, 0 # false + 781 break-if-!= + 782 # if w == "-" return true + 783 subresult <- word-equal? w, "-" + 784 compare subresult, 0 # false + 785 break-if-!= + 786 # if w == "*" return true + 787 subresult <- word-equal? w, "*" + 788 compare subresult, 0 # false + 789 break-if-!= + 790 # if w == "/" return true + 791 subresult <- word-equal? w, "/" + 792 compare subresult, 0 # false + 793 break-if-!= + 794 # if w == "sqrt" return true + 795 subresult <- word-equal? w, "sqrt" 796 compare subresult, 0 # false 797 break-if-!= - 798 # if w == "read" return true - 799 subresult <- word-equal? w, "read" - 800 compare subresult, 0 # false - 801 break-if-!= - 802 # if w == "slurp" return true - 803 subresult <- word-equal? w, "slurp" - 804 compare subresult, 0 # false - 805 break-if-!= - 806 # if w == "lines" return true - 807 subresult <- word-equal? w, "lines" - 808 compare subresult, 0 # false - 809 break-if-!= - 810 ## screens - 811 # if w == "fake-screen" return true - 812 subresult <- word-equal? w, "fake-screen" - 813 compare subresult, 0 # false - 814 break-if-!= - 815 # if w == "print" return true - 816 subresult <- word-equal? w, "print" - 817 compare subresult, 0 # false - 818 break-if-!= - 819 # if w == "move" return true - 820 subresult <- word-equal? w, "move" - 821 compare subresult, 0 # false - 822 break-if-!= - 823 # if w == "up" return true - 824 subresult <- word-equal? w, "up" - 825 compare subresult, 0 # false - 826 break-if-!= - 827 # if w == "down" return true - 828 subresult <- word-equal? w, "down" - 829 compare subresult, 0 # false - 830 break-if-!= - 831 # if w == "left" return true - 832 subresult <- word-equal? w, "left" - 833 compare subresult, 0 # false - 834 break-if-!= - 835 # if w == "right" return true - 836 subresult <- word-equal? w, "right" - 837 compare subresult, 0 # false - 838 break-if-!= - 839 ## hacks - 840 # if w == "dup" return true - 841 subresult <- word-equal? w, "dup" - 842 compare subresult, 0 # false - 843 break-if-!= - 844 # if w == "swap" return true - 845 subresult <- word-equal? w, "swap" - 846 compare subresult, 0 # false - 847 break-if-!= - 848 # return w in functions - 849 var out-h: (handle function) - 850 var out/eax: (addr handle function) <- address out-h - 851 callee functions-ah, w, out - 852 var found?/eax: (addr function) <- lookup *out - 853 result <- copy found? - 854 } - 855 return result - 856 } - 857 - 858 fn arg-exists? _f-ah: (addr handle function), arg: (addr word) -> _/ebx: boolean { - 859 var f-ah/eax: (addr handle function) <- copy _f-ah - 860 var f/eax: (addr function) <- lookup *f-ah - 861 var args-ah/eax: (addr handle word) <- get f, args - 862 var result/ebx: boolean <- word-exists? args-ah, arg - 863 return result - 864 } - 865 - 866 # construct a call to `f` with copies of exactly its args - 867 fn construct-call _f-ah: (addr handle function), _dest-ah: (addr handle word) { - 868 var f-ah/eax: (addr handle function) <- copy _f-ah - 869 var _f/eax: (addr function) <- lookup *f-ah - 870 var f/esi: (addr function) <- copy _f - 871 # append args in reverse - 872 var args-ah/eax: (addr handle word) <- get f, args - 873 var dest-ah/edi: (addr handle word) <- copy _dest-ah - 874 copy-words-in-reverse args-ah, dest-ah - 875 # append name - 876 var name-ah/eax: (addr handle array byte) <- get f, name - 877 var name/eax: (addr array byte) <- lookup *name-ah - 878 append-word-at-end-with dest-ah, name - 879 } - 880 - 881 fn word-index _words: (addr handle word), _n: int, out: (addr handle word) { - 882 var n/ecx: int <- copy _n - 883 { - 884 compare n, 0 - 885 break-if-!= - 886 copy-object _words, out - 887 return - 888 } - 889 var words-ah/eax: (addr handle word) <- copy _words - 890 var words/eax: (addr word) <- lookup *words-ah - 891 var next/eax: (addr handle word) <- get words, next - 892 n <- decrement - 893 word-index next, n, out - 894 } - 895 - 896 fn toggle-cursor-word _sandbox: (addr sandbox) { - 897 var sandbox/esi: (addr sandbox) <- copy _sandbox - 898 var expanded-words/edi: (addr handle call-path) <- get sandbox, expanded-words - 899 var cursor-call-path/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path - 900 #? print-string 0, "cursor call path: " - 901 #? dump-call-path-element 0, cursor-call-path - 902 #? print-string 0, "expanded words:\n" - 903 #? dump-call-paths 0, expanded-words - 904 var already-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path - 905 compare already-expanded?, 0 # false - 906 { - 907 break-if-!= - 908 #? print-string 0, "expand\n" - 909 # if not already-expanded, insert - 910 insert-in-call-path expanded-words cursor-call-path - 911 #? print-string 0, "expanded words now:\n" - 912 #? dump-call-paths 0, expanded-words - 913 return - 914 } - 915 { - 916 break-if-= - 917 # otherwise delete - 918 delete-in-call-path expanded-words cursor-call-path - 919 } - 920 } - 921 - 922 fn append-line _sandbox: (addr sandbox) { - 923 var sandbox/esi: (addr sandbox) <- copy _sandbox - 924 var line-ah/ecx: (addr handle line) <- get sandbox, data + 798 ## strings/arrays + 799 # if w == "len" return true + 800 subresult <- word-equal? w, "len" + 801 compare subresult, 0 # false + 802 break-if-!= + 803 ## files + 804 # if w == "open" return true + 805 subresult <- word-equal? w, "open" + 806 compare subresult, 0 # false + 807 break-if-!= + 808 # if w == "read" return true + 809 subresult <- word-equal? w, "read" + 810 compare subresult, 0 # false + 811 break-if-!= + 812 # if w == "slurp" return true + 813 subresult <- word-equal? w, "slurp" + 814 compare subresult, 0 # false + 815 break-if-!= + 816 # if w == "lines" return true + 817 subresult <- word-equal? w, "lines" + 818 compare subresult, 0 # false + 819 break-if-!= + 820 ## screens + 821 # if w == "fake-screen" return true + 822 subresult <- word-equal? w, "fake-screen" + 823 compare subresult, 0 # false + 824 break-if-!= + 825 # if w == "print" return true + 826 subresult <- word-equal? w, "print" + 827 compare subresult, 0 # false + 828 break-if-!= + 829 # if w == "move" return true + 830 subresult <- word-equal? w, "move" + 831 compare subresult, 0 # false + 832 break-if-!= + 833 # if w == "up" return true + 834 subresult <- word-equal? w, "up" + 835 compare subresult, 0 # false + 836 break-if-!= + 837 # if w == "down" return true + 838 subresult <- word-equal? w, "down" + 839 compare subresult, 0 # false + 840 break-if-!= + 841 # if w == "left" return true + 842 subresult <- word-equal? w, "left" + 843 compare subresult, 0 # false + 844 break-if-!= + 845 # if w == "right" return true + 846 subresult <- word-equal? w, "right" + 847 compare subresult, 0 # false + 848 break-if-!= + 849 ## hacks + 850 # if w == "dup" return true + 851 subresult <- word-equal? w, "dup" + 852 compare subresult, 0 # false + 853 break-if-!= + 854 # if w == "swap" return true + 855 subresult <- word-equal? w, "swap" + 856 compare subresult, 0 # false + 857 break-if-!= + 858 # return w in functions + 859 var out-h: (handle function) + 860 var out/eax: (addr handle function) <- address out-h + 861 callee functions-ah, w, out + 862 var found?/eax: (addr function) <- lookup *out + 863 result <- copy found? + 864 } + 865 return result + 866 } + 867 + 868 fn arg-exists? _f-ah: (addr handle function), arg: (addr word) -> _/ebx: boolean { + 869 var f-ah/eax: (addr handle function) <- copy _f-ah + 870 var f/eax: (addr function) <- lookup *f-ah + 871 var args-ah/eax: (addr handle word) <- get f, args + 872 var result/ebx: boolean <- word-exists? args-ah, arg + 873 return result + 874 } + 875 + 876 # construct a call to `f` with copies of exactly its args + 877 fn construct-call _f-ah: (addr handle function), _dest-ah: (addr handle word) { + 878 var f-ah/eax: (addr handle function) <- copy _f-ah + 879 var _f/eax: (addr function) <- lookup *f-ah + 880 var f/esi: (addr function) <- copy _f + 881 # append args in reverse + 882 var args-ah/eax: (addr handle word) <- get f, args + 883 var dest-ah/edi: (addr handle word) <- copy _dest-ah + 884 copy-words-in-reverse args-ah, dest-ah + 885 # append name + 886 var name-ah/eax: (addr handle array byte) <- get f, name + 887 var name/eax: (addr array byte) <- lookup *name-ah + 888 append-word-at-end-with dest-ah, name + 889 } + 890 + 891 fn word-index _words: (addr handle word), _n: int, out: (addr handle word) { + 892 var n/ecx: int <- copy _n + 893 { + 894 compare n, 0 + 895 break-if-!= + 896 copy-object _words, out + 897 return + 898 } + 899 var words-ah/eax: (addr handle word) <- copy _words + 900 var words/eax: (addr word) <- lookup *words-ah + 901 var next/eax: (addr handle word) <- get words, next + 902 n <- decrement + 903 word-index next, n, out + 904 } + 905 + 906 fn toggle-cursor-word _sandbox: (addr sandbox) { + 907 var sandbox/esi: (addr sandbox) <- copy _sandbox + 908 var expanded-words/edi: (addr handle call-path) <- get sandbox, expanded-words + 909 var cursor-call-path/ecx: (addr handle call-path-element) <- get sandbox, cursor-call-path + 910 #? print-string 0, "cursor call path: " + 911 #? dump-call-path-element 0, cursor-call-path + 912 #? print-string 0, "expanded words:\n" + 913 #? dump-call-paths 0, expanded-words + 914 var already-expanded?/eax: boolean <- find-in-call-paths expanded-words, cursor-call-path + 915 compare already-expanded?, 0 # false + 916 { + 917 break-if-!= + 918 #? print-string 0, "expand\n" + 919 # if not already-expanded, insert + 920 insert-in-call-path expanded-words cursor-call-path + 921 #? print-string 0, "expanded words now:\n" + 922 #? dump-call-paths 0, expanded-words + 923 return + 924 } 925 { - 926 var line/eax: (addr line) <- lookup *line-ah - 927 var next-line-ah/edx: (addr handle line) <- get line, next - 928 var next-line/eax: (addr line) <- lookup *next-line-ah - 929 compare next-line, 0 - 930 break-if-= - 931 line-ah <- copy next-line-ah - 932 loop - 933 } - 934 var line/eax: (addr line) <- lookup *line-ah - 935 var final-line-ah/edx: (addr handle line) <- get line, next - 936 allocate final-line-ah - 937 var final-line/eax: (addr line) <- lookup *final-line-ah - 938 initialize-line final-line - 939 var final-prev/eax: (addr handle line) <- get final-line, prev - 940 copy-object line-ah, final-prev - 941 # clear cursor - 942 var final-line/eax: (addr line) <- lookup *final-line-ah - 943 var word-ah/ecx: (addr handle word) <- get final-line, data - 944 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path - 945 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah - 946 var dest/eax: (addr handle word) <- get cursor-call-path, word - 947 copy-object word-ah, dest - 948 } - 949 - 950 ############# - 951 # Visualize - 952 ############# - 953 - 954 fn evaluate-environment _env: (addr environment), stack: (addr value-stack) { - 955 var env/esi: (addr environment) <- copy _env - 956 # functions - 957 var functions/edx: (addr handle function) <- get env, functions - 958 # line - 959 var sandbox-ah/esi: (addr handle sandbox) <- get env, sandboxes - 960 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah - 961 var line-ah/eax: (addr handle line) <- get sandbox, data - 962 var _line/eax: (addr line) <- lookup *line-ah - 963 var line/esi: (addr line) <- copy _line - 964 evaluate functions, 0, line, 0, stack - 965 } - 966 - 967 fn render _env: (addr environment) { - 968 #? print-string 0, "== render\n" - 969 var env/esi: (addr environment) <- copy _env - 970 clear-canvas env - 971 # screen - 972 var screen-ah/eax: (addr handle screen) <- get env, screen - 973 var _screen/eax: (addr screen) <- lookup *screen-ah - 974 var screen/edi: (addr screen) <- copy _screen - 975 # repl-col - 976 var _repl-col/eax: (addr int) <- get env, code-separator-col - 977 var repl-col/ecx: int <- copy *_repl-col - 978 repl-col <- add 2 # repl-margin-left - 979 # functions - 980 var functions/edx: (addr handle function) <- get env, functions - 981 # sandbox - 982 var sandbox-ah/eax: (addr handle sandbox) <- get env, sandboxes - 983 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah - 984 # bindings - 985 var bindings-storage: table - 986 var bindings/ebx: (addr table) <- address bindings-storage - 987 initialize-table bindings, 0x10 - 988 #? print-string 0, "render-sandbox {\n" - 989 render-sandbox screen, functions, bindings, sandbox, 3, repl-col - 990 #? print-string 0, "render-sandbox }\n" - 991 } - 992 - 993 fn render-sandbox screen: (addr screen), functions: (addr handle function), bindings: (addr table), _sandbox: (addr sandbox), top-row: int, left-col: int { - 994 var sandbox/esi: (addr sandbox) <- copy _sandbox - 995 # line - 996 var curr-line-ah/eax: (addr handle line) <- get sandbox, data - 997 var _curr-line/eax: (addr line) <- lookup *curr-line-ah - 998 var curr-line/ecx: (addr line) <- copy _curr-line - 999 # -1000 var curr-row/edx: int <- copy top-row -1001 # cursor row, col -1002 var cursor-row: int -1003 var cursor-row-addr: (addr int) -1004 var tmp/eax: (addr int) <- address cursor-row -1005 copy-to cursor-row-addr, tmp -1006 var cursor-col: int -1007 var cursor-col-addr: (addr int) -1008 tmp <- address cursor-col -1009 copy-to cursor-col-addr, tmp -1010 # render all but final line without stack -1011 #? print-string 0, "render all but final line\n" -1012 { -1013 var next-line-ah/eax: (addr handle line) <- get curr-line, next -1014 var next-line/eax: (addr line) <- lookup *next-line-ah -1015 compare next-line, 0 -1016 break-if-= -1017 { -1018 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path -1019 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah -1020 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word -1021 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah -1022 # it's enough to pass in the first word of the path, because if the path isn't a singleton the word is guaranteed to be unique -1023 render-line-without-stack screen, curr-line, curr-row, left-col, cursor-word, cursor-row-addr, cursor-col-addr -1024 } -1025 curr-line <- copy next-line -1026 curr-row <- add 2 -1027 loop -1028 } -1029 # -1030 render-final-line-with-stack screen, functions, bindings, sandbox, curr-row, left-col, cursor-row-addr, cursor-col-addr -1031 # at most one of the following dialogs will be rendered -1032 render-rename-dialog screen, sandbox, cursor-row, cursor-col -1033 render-define-dialog screen, sandbox, cursor-row, cursor-col -1034 move-cursor screen, cursor-row, cursor-col -1035 } -1036 -1037 fn render-final-line-with-stack screen: (addr screen), functions: (addr handle function), bindings: (addr table), _sandbox: (addr sandbox), top-row: int, left-col: int, cursor-row-addr: (addr int), cursor-col-addr: (addr int) { -1038 var sandbox/esi: (addr sandbox) <- copy _sandbox -1039 # expanded-words -1040 var expanded-words/edi: (addr handle call-path) <- get sandbox, expanded-words -1041 # cursor-word -1042 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path -1043 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah -1044 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word -1045 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah -1046 var cursor-word/ebx: (addr word) <- copy _cursor-word -1047 #? print-string 0, "word at cursor: " -1048 #? print-word 0, cursor-word -1049 #? print-string 0, "\n" -1050 # cursor-call-path -1051 var cursor-call-path: (addr handle call-path-element) -1052 { -1053 var src/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path -1054 copy-to cursor-call-path, src -1055 } -1056 # first line -1057 var first-line-ah/eax: (addr handle line) <- get sandbox, data -1058 var _first-line/eax: (addr line) <- lookup *first-line-ah -1059 var first-line/edx: (addr line) <- copy _first-line -1060 # final line -1061 var final-line-storage: (handle line) -1062 var final-line-ah/eax: (addr handle line) <- address final-line-storage -1063 final-line sandbox, final-line-ah -1064 var final-line/eax: (addr line) <- lookup *final-line-ah -1065 # curr-path -1066 var curr-path-storage: (handle call-path-element) -1067 var curr-path/ecx: (addr handle call-path-element) <- address curr-path-storage -1068 allocate curr-path # leak -1069 initialize-path-from-line final-line, curr-path -1070 # -1071 var dummy/ecx: int <- render-line screen, functions, bindings, first-line, final-line, expanded-words, top-row, left-col, curr-path, cursor-word, cursor-call-path, cursor-row-addr, cursor-col-addr -1072 } -1073 -1074 fn final-line _sandbox: (addr sandbox), out: (addr handle line) { -1075 var sandbox/esi: (addr sandbox) <- copy _sandbox -1076 var curr-line-ah/ecx: (addr handle line) <- get sandbox, data -1077 { -1078 var curr-line/eax: (addr line) <- lookup *curr-line-ah -1079 var next-line-ah/edx: (addr handle line) <- get curr-line, next -1080 var next-line/eax: (addr line) <- lookup *next-line-ah -1081 compare next-line, 0 -1082 break-if-= -1083 curr-line-ah <- copy next-line-ah -1084 loop -1085 } -1086 copy-object curr-line-ah, out -1087 } -1088 -1089 fn render-rename-dialog screen: (addr screen), _sandbox: (addr sandbox), cursor-row: int, cursor-col: int { -1090 var sandbox/edi: (addr sandbox) <- copy _sandbox -1091 var rename-word-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-cursor-word -1092 var rename-word-mode?/eax: (addr word) <- lookup *rename-word-mode-ah? -1093 compare rename-word-mode?, 0 -1094 break-if-= -1095 # clear a space for the dialog -1096 var top-row/eax: int <- copy cursor-row -1097 top-row <- subtract 3 -1098 var bottom-row/ecx: int <- copy cursor-row -1099 bottom-row <- add 3 -1100 var left-col/edx: int <- copy cursor-col -1101 left-col <- subtract 0x10 -1102 var right-col/ebx: int <- copy cursor-col -1103 right-col <- add 0x10 -1104 clear-rect screen, top-row, left-col, bottom-row, right-col -1105 draw-box screen, top-row, left-col, bottom-row, right-col -1106 # render a little menu for the dialog -1107 var menu-row/ecx: int <- copy bottom-row -1108 menu-row <- decrement -1109 var menu-col/edx: int <- copy left-col -1110 menu-col <- add 2 -1111 move-cursor screen, menu-row, menu-col -1112 start-reverse-video screen -1113 print-string screen, " esc " -1114 reset-formatting screen -1115 print-string screen, " cancel " -1116 start-reverse-video screen -1117 print-string screen, " enter " -1118 reset-formatting screen -1119 print-string screen, " rename " -1120 # draw the word, positioned appropriately around the cursor -1121 var start-col/ecx: int <- copy cursor-col -1122 var word-ah?/edx: (addr handle word) <- get sandbox, partial-name-for-cursor-word -1123 var word/eax: (addr word) <- lookup *word-ah? -1124 var cursor-index/eax: int <- cursor-index word -1125 start-col <- subtract cursor-index -1126 move-cursor screen, cursor-row, start-col -1127 var word/eax: (addr word) <- lookup *word-ah? -1128 print-word screen, word -1129 } -1130 -1131 fn render-define-dialog screen: (addr screen), _sandbox: (addr sandbox), cursor-row: int, cursor-col: int { -1132 var sandbox/edi: (addr sandbox) <- copy _sandbox -1133 var define-function-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-function -1134 var define-function-mode?/eax: (addr word) <- lookup *define-function-mode-ah? -1135 compare define-function-mode?, 0 -1136 break-if-= -1137 # clear a space for the dialog -1138 var top-row/eax: int <- copy cursor-row -1139 top-row <- subtract 3 -1140 var bottom-row/ecx: int <- copy cursor-row -1141 bottom-row <- add 3 -1142 var left-col/edx: int <- copy cursor-col -1143 left-col <- subtract 0x10 -1144 var right-col/ebx: int <- copy cursor-col -1145 right-col <- add 0x10 -1146 clear-rect screen, top-row, left-col, bottom-row, right-col -1147 draw-box screen, top-row, left-col, bottom-row, right-col -1148 # render a little menu for the dialog -1149 var menu-row/ecx: int <- copy bottom-row -1150 menu-row <- decrement -1151 var menu-col/edx: int <- copy left-col -1152 menu-col <- add 2 -1153 move-cursor screen, menu-row, menu-col -1154 start-reverse-video screen -1155 print-string screen, " esc " -1156 reset-formatting screen -1157 print-string screen, " cancel " -1158 start-reverse-video screen -1159 print-string screen, " enter " -1160 reset-formatting screen -1161 print-string screen, " define " -1162 # draw the word, positioned appropriately around the cursor -1163 var start-col/ecx: int <- copy cursor-col -1164 var word-ah?/edx: (addr handle word) <- get sandbox, partial-name-for-function -1165 var word/eax: (addr word) <- lookup *word-ah? -1166 var cursor-index/eax: int <- cursor-index word -1167 start-col <- subtract cursor-index -1168 move-cursor screen, cursor-row, start-col -1169 var word/eax: (addr word) <- lookup *word-ah? -1170 print-word screen, word -1171 } -1172 -1173 # Render just the words in 'line'. -1174 fn render-line-without-stack screen: (addr screen), _line: (addr line), curr-row: int, left-col: int, cursor-word: (addr word), cursor-row-addr: (addr int), cursor-col-addr: (addr int) { -1175 # curr-word -1176 var line/eax: (addr line) <- copy _line -1177 var first-word-ah/eax: (addr handle word) <- get line, data -1178 var _curr-word/eax: (addr word) <- lookup *first-word-ah -1179 var curr-word/esi: (addr word) <- copy _curr-word -1180 # -1181 # loop-carried dependency -1182 var curr-col/ecx: int <- copy left-col -1183 # -1184 { -1185 compare curr-word, 0 -1186 break-if-= -1187 #? print-string 0, "-- word in penultimate lines: " -1188 #? { -1189 #? var foo/eax: int <- copy curr-word -1190 #? print-int32-hex 0, foo -1191 #? } -1192 #? print-string 0, "\n" -1193 var old-col/edx: int <- copy curr-col -1194 reset-formatting screen -1195 move-cursor screen, curr-row, curr-col -1196 print-word screen, curr-word -1197 { -1198 var max-width/eax: int <- word-length curr-word -1199 curr-col <- add max-width -1200 curr-col <- add 1 # margin-right -1201 } -1202 # cache cursor column if necessary -1203 { -1204 compare curr-word, cursor-word -1205 break-if-!= -1206 #? print-string 0, "Cursor at " -1207 #? print-int32-decimal 0, curr-row -1208 #? print-string 0, ", " -1209 #? print-int32-decimal 0, old-col -1210 #? print-string 0, "\n" -1211 #? print-string 0, "contents: " -1212 #? print-word 0, cursor-word -1213 #? print-string 0, "\n" -1214 #? { -1215 #? var foo/eax: int <- copy cursor-word -1216 #? print-int32-hex 0, foo -1217 #? print-string 0, "\n" -1218 #? } -1219 var dest/ecx: (addr int) <- copy cursor-row-addr -1220 var src/eax: int <- copy curr-row -1221 copy-to *dest, src -1222 dest <- copy cursor-col-addr -1223 copy-to *dest, old-col -1224 var cursor-index-in-word/eax: int <- cursor-index curr-word -1225 add-to *dest, cursor-index-in-word -1226 } -1227 # loop update -1228 var next-word-ah/edx: (addr handle word) <- get curr-word, next -1229 var _curr-word/eax: (addr word) <- lookup *next-word-ah -1230 curr-word <- copy _curr-word -1231 loop -1232 } -1233 } -1234 -1235 fn call-depth-at-cursor _sandbox: (addr sandbox) -> _/eax: int { -1236 var sandbox/esi: (addr sandbox) <- copy _sandbox -1237 var cursor-call-path/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path -1238 var result/eax: int <- call-path-element-length cursor-call-path -1239 result <- add 2 # input-row - 1 -1240 return result -1241 } -1242 -1243 fn call-path-element-length _x: (addr handle call-path-element) -> _/eax: int { -1244 var curr-ah/ecx: (addr handle call-path-element) <- copy _x -1245 var result/edi: int <- copy 0 -1246 { -1247 var curr/eax: (addr call-path-element) <- lookup *curr-ah -1248 compare curr, 0 -1249 break-if-= -1250 curr-ah <- get curr, next -1251 result <- increment -1252 loop -1253 } -1254 return result -1255 } -1256 -1257 # Render the line of words in line, along with the state of the stack under each word. -1258 # Also render any expanded function calls using recursive calls. -1259 # -1260 # Along the way, compute the column the cursor should be positioned at (cursor-col-addr). -1261 fn render-line screen: (addr screen), functions: (addr handle function), bindings: (addr table), first-line: (addr line), _line: (addr line), expanded-words: (addr handle call-path), top-row: int, left-col: int, curr-path: (addr handle call-path-element), cursor-word: (addr word), cursor-call-path: (addr handle call-path-element), cursor-row-addr: (addr int), cursor-col-addr: (addr int) -> _/ecx: int { -1262 #? print-string 0, "render-line\n" -1263 #? dump-table bindings -1264 # curr-word -1265 var line/esi: (addr line) <- copy _line -1266 var first-word-ah/eax: (addr handle word) <- get line, data -1267 var curr-word/eax: (addr word) <- lookup *first-word-ah -1268 # -1269 # loop-carried dependency -1270 var curr-col/ecx: int <- copy left-col -1271 # -1272 { -1273 compare curr-word, 0 -1274 break-if-= -1275 #? print-string 0, "-- word " -1276 #? print-word 0, curr-word -1277 #? print-string 0, "\n" -1278 # if necessary, first render columns for subsidiary stack -1279 $render-line:subsidiary: { -1280 { -1281 #? print-string 0, "check sub\n" -1282 var display-subsidiary-stack?/eax: boolean <- find-in-call-paths expanded-words, curr-path -1283 compare display-subsidiary-stack?, 0 # false -1284 break-if-= $render-line:subsidiary -1285 } -1286 #? print-string 0, "render subsidiary stack\n" -1287 # does function exist? -1288 var callee/edi: (addr function) <- copy 0 -1289 { -1290 var callee-h: (handle function) -1291 var callee-ah/ecx: (addr handle function) <- address callee-h -1292 callee functions, curr-word, callee-ah -1293 var _callee/eax: (addr function) <- lookup *callee-ah -1294 callee <- copy _callee -1295 compare callee, 0 -1296 break-if-= $render-line:subsidiary -1297 } -1298 move-cursor screen, top-row, curr-col -1299 start-color screen, 8, 7 -1300 print-word screen, curr-word -1301 { -1302 var word-len/eax: int <- word-length curr-word -1303 curr-col <- add word-len -1304 curr-col <- add 2 -1305 increment top-row -1306 } -1307 # obtain stack at call site -1308 var stack-storage: value-stack -1309 var stack/edx: (addr value-stack) <- address stack-storage -1310 initialize-value-stack stack, 0x10 + 926 break-if-= + 927 # otherwise delete + 928 delete-in-call-path expanded-words cursor-call-path + 929 } + 930 } + 931 + 932 fn append-line _sandbox: (addr sandbox) { + 933 var sandbox/esi: (addr sandbox) <- copy _sandbox + 934 var line-ah/ecx: (addr handle line) <- get sandbox, data + 935 { + 936 var line/eax: (addr line) <- lookup *line-ah + 937 var next-line-ah/edx: (addr handle line) <- get line, next + 938 var next-line/eax: (addr line) <- lookup *next-line-ah + 939 compare next-line, 0 + 940 break-if-= + 941 line-ah <- copy next-line-ah + 942 loop + 943 } + 944 var line/eax: (addr line) <- lookup *line-ah + 945 var final-line-ah/edx: (addr handle line) <- get line, next + 946 allocate final-line-ah + 947 var final-line/eax: (addr line) <- lookup *final-line-ah + 948 initialize-line final-line + 949 var final-prev/eax: (addr handle line) <- get final-line, prev + 950 copy-object line-ah, final-prev + 951 # clear cursor + 952 var final-line/eax: (addr line) <- lookup *final-line-ah + 953 var word-ah/ecx: (addr handle word) <- get final-line, data + 954 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path + 955 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah + 956 var dest/eax: (addr handle word) <- get cursor-call-path, word + 957 copy-object word-ah, dest + 958 } + 959 + 960 ############# + 961 # Visualize + 962 ############# + 963 + 964 fn evaluate-environment _env: (addr environment), stack: (addr value-stack) { + 965 var env/esi: (addr environment) <- copy _env + 966 # functions + 967 var functions/edx: (addr handle function) <- get env, functions + 968 # line + 969 var sandbox-ah/esi: (addr handle sandbox) <- get env, sandboxes + 970 var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah + 971 var line-ah/eax: (addr handle line) <- get sandbox, data + 972 var _line/eax: (addr line) <- lookup *line-ah + 973 var line/esi: (addr line) <- copy _line + 974 evaluate functions, 0, line, 0, stack + 975 } + 976 + 977 fn render _env: (addr environment) { + 978 #? print-string 0, "== render\n" + 979 var env/esi: (addr environment) <- copy _env + 980 clear-canvas env + 981 # screen + 982 var screen-ah/eax: (addr handle screen) <- get env, screen + 983 var _screen/eax: (addr screen) <- lookup *screen-ah + 984 var screen/edi: (addr screen) <- copy _screen + 985 # repl-col + 986 var _repl-col/eax: (addr int) <- get env, code-separator-col + 987 var repl-col/ecx: int <- copy *_repl-col + 988 repl-col <- add 2 # repl-margin-left + 989 # functions + 990 var functions/edx: (addr handle function) <- get env, functions + 991 # sandbox + 992 var cursor-sandbox-ah/eax: (addr handle sandbox) <- get env, cursor-sandbox + 993 var cursor-sandbox/eax: (addr sandbox) <- lookup *cursor-sandbox-ah + 994 # bindings + 995 var bindings-storage: table + 996 var bindings/ebx: (addr table) <- address bindings-storage + 997 initialize-table bindings, 0x10 + 998 #? print-string 0, "render-sandbox {\n" + 999 render-sandbox screen, functions, bindings, cursor-sandbox, 3, repl-col +1000 #? print-string 0, "render-sandbox }\n" +1001 } +1002 +1003 fn render-sandbox screen: (addr screen), functions: (addr handle function), bindings: (addr table), _sandbox: (addr sandbox), top-row: int, left-col: int { +1004 var sandbox/esi: (addr sandbox) <- copy _sandbox +1005 # line +1006 var curr-line-ah/eax: (addr handle line) <- get sandbox, data +1007 var _curr-line/eax: (addr line) <- lookup *curr-line-ah +1008 var curr-line/ecx: (addr line) <- copy _curr-line +1009 # +1010 var curr-row/edx: int <- copy top-row +1011 # cursor row, col +1012 var cursor-row: int +1013 var cursor-row-addr: (addr int) +1014 var tmp/eax: (addr int) <- address cursor-row +1015 copy-to cursor-row-addr, tmp +1016 var cursor-col: int +1017 var cursor-col-addr: (addr int) +1018 tmp <- address cursor-col +1019 copy-to cursor-col-addr, tmp +1020 # render all but final line without stack +1021 #? print-string 0, "render all but final line\n" +1022 { +1023 var next-line-ah/eax: (addr handle line) <- get curr-line, next +1024 var next-line/eax: (addr line) <- lookup *next-line-ah +1025 compare next-line, 0 +1026 break-if-= +1027 { +1028 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path +1029 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah +1030 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word +1031 var cursor-word/eax: (addr word) <- lookup *cursor-word-ah +1032 # it's enough to pass in the first word of the path, because if the path isn't a singleton the word is guaranteed to be unique +1033 render-line-without-stack screen, curr-line, curr-row, left-col, cursor-word, cursor-row-addr, cursor-col-addr +1034 } +1035 curr-line <- copy next-line +1036 curr-row <- add 2 +1037 loop +1038 } +1039 # +1040 render-final-line-with-stack screen, functions, bindings, sandbox, curr-row, left-col, cursor-row-addr, cursor-col-addr +1041 # at most one of the following dialogs will be rendered +1042 render-rename-dialog screen, sandbox, cursor-row, cursor-col +1043 render-define-dialog screen, sandbox, cursor-row, cursor-col +1044 move-cursor screen, cursor-row, cursor-col +1045 } +1046 +1047 fn render-final-line-with-stack screen: (addr screen), functions: (addr handle function), bindings: (addr table), _sandbox: (addr sandbox), top-row: int, left-col: int, cursor-row-addr: (addr int), cursor-col-addr: (addr int) { +1048 var sandbox/esi: (addr sandbox) <- copy _sandbox +1049 # expanded-words +1050 var expanded-words/edi: (addr handle call-path) <- get sandbox, expanded-words +1051 # cursor-word +1052 var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path +1053 var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah +1054 var cursor-word-ah/eax: (addr handle word) <- get cursor-call-path, word +1055 var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah +1056 var cursor-word/ebx: (addr word) <- copy _cursor-word +1057 #? print-string 0, "word at cursor: " +1058 #? print-word 0, cursor-word +1059 #? print-string 0, "\n" +1060 # cursor-call-path +1061 var cursor-call-path: (addr handle call-path-element) +1062 { +1063 var src/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path +1064 copy-to cursor-call-path, src +1065 } +1066 # first line +1067 var first-line-ah/eax: (addr handle line) <- get sandbox, data +1068 var _first-line/eax: (addr line) <- lookup *first-line-ah +1069 var first-line/edx: (addr line) <- copy _first-line +1070 # final line +1071 var final-line-storage: (handle line) +1072 var final-line-ah/eax: (addr handle line) <- address final-line-storage +1073 final-line sandbox, final-line-ah +1074 var final-line/eax: (addr line) <- lookup *final-line-ah +1075 # curr-path +1076 var curr-path-storage: (handle call-path-element) +1077 var curr-path/ecx: (addr handle call-path-element) <- address curr-path-storage +1078 allocate curr-path # leak +1079 initialize-path-from-line final-line, curr-path +1080 # +1081 var dummy/ecx: int <- render-line screen, functions, bindings, first-line, final-line, expanded-words, top-row, left-col, curr-path, cursor-word, cursor-call-path, cursor-row-addr, cursor-col-addr +1082 } +1083 +1084 fn final-line _sandbox: (addr sandbox), out: (addr handle line) { +1085 var sandbox/esi: (addr sandbox) <- copy _sandbox +1086 var curr-line-ah/ecx: (addr handle line) <- get sandbox, data +1087 { +1088 var curr-line/eax: (addr line) <- lookup *curr-line-ah +1089 var next-line-ah/edx: (addr handle line) <- get curr-line, next +1090 var next-line/eax: (addr line) <- lookup *next-line-ah +1091 compare next-line, 0 +1092 break-if-= +1093 curr-line-ah <- copy next-line-ah +1094 loop +1095 } +1096 copy-object curr-line-ah, out +1097 } +1098 +1099 fn render-rename-dialog screen: (addr screen), _sandbox: (addr sandbox), cursor-row: int, cursor-col: int { +1100 var sandbox/edi: (addr sandbox) <- copy _sandbox +1101 var rename-word-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-cursor-word +1102 var rename-word-mode?/eax: (addr word) <- lookup *rename-word-mode-ah? +1103 compare rename-word-mode?, 0 +1104 break-if-= +1105 # clear a space for the dialog +1106 var top-row/eax: int <- copy cursor-row +1107 top-row <- subtract 3 +1108 var bottom-row/ecx: int <- copy cursor-row +1109 bottom-row <- add 3 +1110 var left-col/edx: int <- copy cursor-col +1111 left-col <- subtract 0x10 +1112 var right-col/ebx: int <- copy cursor-col +1113 right-col <- add 0x10 +1114 clear-rect screen, top-row, left-col, bottom-row, right-col +1115 draw-box screen, top-row, left-col, bottom-row, right-col +1116 # render a little menu for the dialog +1117 var menu-row/ecx: int <- copy bottom-row +1118 menu-row <- decrement +1119 var menu-col/edx: int <- copy left-col +1120 menu-col <- add 2 +1121 move-cursor screen, menu-row, menu-col +1122 start-reverse-video screen +1123 print-string screen, " esc " +1124 reset-formatting screen +1125 print-string screen, " cancel " +1126 start-reverse-video screen +1127 print-string screen, " enter " +1128 reset-formatting screen +1129 print-string screen, " rename " +1130 # draw the word, positioned appropriately around the cursor +1131 var start-col/ecx: int <- copy cursor-col +1132 var word-ah?/edx: (addr handle word) <- get sandbox, partial-name-for-cursor-word +1133 var word/eax: (addr word) <- lookup *word-ah? +1134 var cursor-index/eax: int <- cursor-index word +1135 start-col <- subtract cursor-index +1136 move-cursor screen, cursor-row, start-col +1137 var word/eax: (addr word) <- lookup *word-ah? +1138 print-word screen, word +1139 } +1140 +1141 fn render-define-dialog screen: (addr screen), _sandbox: (addr sandbox), cursor-row: int, cursor-col: int { +1142 var sandbox/edi: (addr sandbox) <- copy _sandbox +1143 var define-function-mode-ah?/ecx: (addr handle word) <- get sandbox, partial-name-for-function +1144 var define-function-mode?/eax: (addr word) <- lookup *define-function-mode-ah? +1145 compare define-function-mode?, 0 +1146 break-if-= +1147 # clear a space for the dialog +1148 var top-row/eax: int <- copy cursor-row +1149 top-row <- subtract 3 +1150 var bottom-row/ecx: int <- copy cursor-row +1151 bottom-row <- add 3 +1152 var left-col/edx: int <- copy cursor-col +1153 left-col <- subtract 0x10 +1154 var right-col/ebx: int <- copy cursor-col +1155 right-col <- add 0x10 +1156 clear-rect screen, top-row, left-col, bottom-row, right-col +1157 draw-box screen, top-row, left-col, bottom-row, right-col +1158 # render a little menu for the dialog +1159 var menu-row/ecx: int <- copy bottom-row +1160 menu-row <- decrement +1161 var menu-col/edx: int <- copy left-col +1162 menu-col <- add 2 +1163 move-cursor screen, menu-row, menu-col +1164 start-reverse-video screen +1165 print-string screen, " esc " +1166 reset-formatting screen +1167 print-string screen, " cancel " +1168 start-reverse-video screen +1169 print-string screen, " enter " +1170 reset-formatting screen +1171 print-string screen, " define " +1172 # draw the word, positioned appropriately around the cursor +1173 var start-col/ecx: int <- copy cursor-col +1174 var word-ah?/edx: (addr handle word) <- get sandbox, partial-name-for-function +1175 var word/eax: (addr word) <- lookup *word-ah? +1176 var cursor-index/eax: int <- cursor-index word +1177 start-col <- subtract cursor-index +1178 move-cursor screen, cursor-row, start-col +1179 var word/eax: (addr word) <- lookup *word-ah? +1180 print-word screen, word +1181 } +1182 +1183 # Render just the words in 'line'. +1184 fn render-line-without-stack screen: (addr screen), _line: (addr line), curr-row: int, left-col: int, cursor-word: (addr word), cursor-row-addr: (addr int), cursor-col-addr: (addr int) { +1185 # curr-word +1186 var line/eax: (addr line) <- copy _line +1187 var first-word-ah/eax: (addr handle word) <- get line, data +1188 var _curr-word/eax: (addr word) <- lookup *first-word-ah +1189 var curr-word/esi: (addr word) <- copy _curr-word +1190 # +1191 # loop-carried dependency +1192 var curr-col/ecx: int <- copy left-col +1193 # +1194 { +1195 compare curr-word, 0 +1196 break-if-= +1197 #? print-string 0, "-- word in penultimate lines: " +1198 #? { +1199 #? var foo/eax: int <- copy curr-word +1200 #? print-int32-hex 0, foo +1201 #? } +1202 #? print-string 0, "\n" +1203 var old-col/edx: int <- copy curr-col +1204 reset-formatting screen +1205 move-cursor screen, curr-row, curr-col +1206 print-word screen, curr-word +1207 { +1208 var max-width/eax: int <- word-length curr-word +1209 curr-col <- add max-width +1210 curr-col <- add 1 # margin-right +1211 } +1212 # cache cursor column if necessary +1213 { +1214 compare curr-word, cursor-word +1215 break-if-!= +1216 #? print-string 0, "Cursor at " +1217 #? print-int32-decimal 0, curr-row +1218 #? print-string 0, ", " +1219 #? print-int32-decimal 0, old-col +1220 #? print-string 0, "\n" +1221 #? print-string 0, "contents: " +1222 #? print-word 0, cursor-word +1223 #? print-string 0, "\n" +1224 #? { +1225 #? var foo/eax: int <- copy cursor-word +1226 #? print-int32-hex 0, foo +1227 #? print-string 0, "\n" +1228 #? } +1229 var dest/ecx: (addr int) <- copy cursor-row-addr +1230 var src/eax: int <- copy curr-row +1231 copy-to *dest, src +1232 dest <- copy cursor-col-addr +1233 copy-to *dest, old-col +1234 var cursor-index-in-word/eax: int <- cursor-index curr-word +1235 add-to *dest, cursor-index-in-word +1236 } +1237 # loop update +1238 var next-word-ah/edx: (addr handle word) <- get curr-word, next +1239 var _curr-word/eax: (addr word) <- lookup *next-word-ah +1240 curr-word <- copy _curr-word +1241 loop +1242 } +1243 } +1244 +1245 fn call-depth-at-cursor _sandbox: (addr sandbox) -> _/eax: int { +1246 var sandbox/esi: (addr sandbox) <- copy _sandbox +1247 var cursor-call-path/edi: (addr handle call-path-element) <- get sandbox, cursor-call-path +1248 var result/eax: int <- call-path-element-length cursor-call-path +1249 result <- add 2 # input-row - 1 +1250 return result +1251 } +1252 +1253 fn call-path-element-length _x: (addr handle call-path-element) -> _/eax: int { +1254 var curr-ah/ecx: (addr handle call-path-element) <- copy _x +1255 var result/edi: int <- copy 0 +1256 { +1257 var curr/eax: (addr call-path-element) <- lookup *curr-ah +1258 compare curr, 0 +1259 break-if-= +1260 curr-ah <- get curr, next +1261 result <- increment +1262 loop +1263 } +1264 return result +1265 } +1266 +1267 # Render the line of words in line, along with the state of the stack under each word. +1268 # Also render any expanded function calls using recursive calls. +1269 # +1270 # Along the way, compute the column the cursor should be positioned at (cursor-col-addr). +1271 fn render-line screen: (addr screen), functions: (addr handle function), bindings: (addr table), first-line: (addr line), _line: (addr line), expanded-words: (addr handle call-path), top-row: int, left-col: int, curr-path: (addr handle call-path-element), cursor-word: (addr word), cursor-call-path: (addr handle call-path-element), cursor-row-addr: (addr int), cursor-col-addr: (addr int) -> _/ecx: int { +1272 #? print-string 0, "render-line\n" +1273 #? dump-table bindings +1274 # curr-word +1275 var line/esi: (addr line) <- copy _line +1276 var first-word-ah/eax: (addr handle word) <- get line, data +1277 var curr-word/eax: (addr word) <- lookup *first-word-ah +1278 # +1279 # loop-carried dependency +1280 var curr-col/ecx: int <- copy left-col +1281 # +1282 { +1283 compare curr-word, 0 +1284 break-if-= +1285 #? print-string 0, "-- word " +1286 #? print-word 0, curr-word +1287 #? print-string 0, "\n" +1288 # if necessary, first render columns for subsidiary stack +1289 $render-line:subsidiary: { +1290 { +1291 #? print-string 0, "check sub\n" +1292 var display-subsidiary-stack?/eax: boolean <- find-in-call-paths expanded-words, curr-path +1293 compare display-subsidiary-stack?, 0 # false +1294 break-if-= $render-line:subsidiary +1295 } +1296 #? print-string 0, "render subsidiary stack\n" +1297 # does function exist? +1298 var callee/edi: (addr function) <- copy 0 +1299 { +1300 var callee-h: (handle function) +1301 var callee-ah/ecx: (addr handle function) <- address callee-h +1302 callee functions, curr-word, callee-ah +1303 var _callee/eax: (addr function) <- lookup *callee-ah +1304 callee <- copy _callee +1305 compare callee, 0 +1306 break-if-= $render-line:subsidiary +1307 } +1308 move-cursor screen, top-row, curr-col +1309 start-color screen, 8, 7 +1310 print-word screen, curr-word 1311 { -1312 var prev-word-ah/eax: (addr handle word) <- get curr-word, prev -1313 var prev-word/eax: (addr word) <- lookup *prev-word-ah -1314 compare prev-word, 0 -1315 break-if-= -1316 var bindings2-storage: table -1317 var bindings2/ebx: (addr table) <- address bindings2-storage -1318 deep-copy-table bindings, bindings2 -1319 evaluate functions, bindings2, first-line, prev-word, stack -1320 } -1321 # construct new bindings -1322 var callee-bindings-storage: table -1323 var callee-bindings/esi: (addr table) <- address callee-bindings-storage -1324 initialize-table callee-bindings, 0x10 -1325 bind-args callee, stack, callee-bindings -1326 # obtain body -1327 var callee-body-ah/eax: (addr handle line) <- get callee, body -1328 var callee-body/eax: (addr line) <- lookup *callee-body-ah -1329 var callee-body-first-word/edx: (addr handle word) <- get callee-body, data -1330 # - render subsidiary stack -1331 push-to-call-path-element curr-path, callee-body-first-word # leak -1332 #? print-string 0, "subsidiary {\n" -1333 #? dump-table callee-bindings -1334 #? syscall_exit -1335 curr-col <- render-line screen, functions, callee-bindings, callee-body, callee-body, expanded-words, top-row, curr-col, curr-path, cursor-word, cursor-call-path, cursor-row-addr, cursor-col-addr -1336 #? print-string 0, "}\n" -1337 drop-from-call-path-element curr-path -1338 # -1339 move-cursor screen, top-row, curr-col -1340 print-code-point screen, 0x21d7 # ⇗ -1341 # -1342 curr-col <- add 2 -1343 decrement top-row -1344 } -1345 # render main column -1346 var old-col/edx: int <- copy curr-col -1347 var bindings2-storage: table -1348 var bindings2/ebx: (addr table) <- address bindings2-storage -1349 #? print-string 0, "deep-copy {\n" -1350 deep-copy-table bindings, bindings2 -1351 #? print-string 0, "}\n" -1352 #? print-string 0, "render column {\n" -1353 curr-col <- render-column screen, functions, bindings2, first-line, line, curr-word, top-row, curr-col -1354 #? print-string 0, "}\n" -1355 # cache cursor column if necessary -1356 $render-line:cache-cursor-column: { -1357 { -1358 var found?/eax: boolean <- call-path-element-match? curr-path, cursor-call-path -1359 compare found?, 0 # false -1360 break-if-= $render-line:cache-cursor-column -1361 } -1362 var dest/edi: (addr int) <- copy cursor-row-addr -1363 { -1364 var src/eax: int <- copy top-row -1365 copy-to *dest, src -1366 } -1367 dest <- copy cursor-col-addr -1368 copy-to *dest, old-col -1369 var cursor-index-in-word/eax: int <- cursor-index curr-word -1370 add-to *dest, cursor-index-in-word -1371 } -1372 # loop update -1373 #? print-string 0, "next word\n" -1374 var next-word-ah/edx: (addr handle word) <- get curr-word, next -1375 curr-word <- lookup *next-word-ah -1376 #? { -1377 #? var foo/eax: int <- copy curr-word -1378 #? print-int32-hex 0, foo -1379 #? print-string 0, "\n" -1380 #? } -1381 increment-final-element curr-path -1382 loop -1383 } -1384 return curr-col -1385 } -1386 -1387 fn callee functions: (addr handle function), word: (addr word), out: (addr handle function) { -1388 var stream-storage: (stream byte 0x10) -1389 var stream/esi: (addr stream byte) <- address stream-storage -1390 emit-word word, stream -1391 find-function functions, stream, out -1392 } -1393 -1394 # Render: -1395 # - starting at top-row, left-col: final-word -1396 # - starting somewhere below at left-col: the stack result from interpreting first-world to final-word (inclusive) -1397 # -1398 # Return the farthest column written. -1399 fn render-column screen: (addr screen), functions: (addr handle function), bindings: (addr table), first-line: (addr line), line: (addr line), final-word: (addr word), top-row: int, left-col: int -> _/ecx: int { -1400 #? print-string 0, "render-column\n" -1401 #? dump-table bindings -1402 var max-width/esi: int <- copy 0 -1403 { -1404 # compute stack -1405 var stack: value-stack -1406 var stack-addr/edi: (addr value-stack) <- address stack -1407 initialize-value-stack stack-addr, 0x10 # max-words -1408 # copy bindings -1409 var bindings2-storage: table -1410 var bindings2/ebx: (addr table) <- address bindings2-storage -1411 #? print-string 0, "deep copy table {\n" -1412 deep-copy-table bindings, bindings2 -1413 #? print-string 0, "}\n" -1414 evaluate functions, bindings2, first-line, final-word, stack-addr -1415 # indent stack -1416 var indented-col/ebx: int <- copy left-col -1417 indented-col <- add 1 # margin-right -1418 # render stack -1419 var curr-row/edx: int <- copy top-row -1420 curr-row <- add 2 # stack-margin-top -1421 var _max-width/eax: int <- value-stack-max-width stack-addr -1422 max-width <- copy _max-width -1423 { -1424 var top-addr/ecx: (addr int) <- get stack-addr, top -1425 compare *top-addr, 0 -1426 break-if-<= -1427 decrement *top-addr -1428 var data-ah/eax: (addr handle array value) <- get stack-addr, data -1429 var data/eax: (addr array value) <- lookup *data-ah -1430 var top/ecx: int <- copy *top-addr -1431 var dest-offset/ecx: (offset value) <- compute-offset data, top -1432 var val/eax: (addr value) <- index data, dest-offset -1433 render-value-at screen, curr-row, indented-col, val, max-width -1434 var height/eax: int <- value-height val -1435 curr-row <- add height -1436 loop -1437 } -1438 } -1439 -1440 max-width <- add 2 # spaces on either side of items on the stack -1441 -1442 # render word, initialize result -1443 reset-formatting screen -1444 move-cursor screen, top-row, left-col -1445 print-word screen, final-word -1446 { -1447 var size/eax: int <- word-length final-word -1448 compare size, max-width -1449 break-if-<= -1450 max-width <- copy size -1451 } -1452 -1453 # post-process right-col -1454 var right-col/ecx: int <- copy left-col -1455 right-col <- add max-width -1456 right-col <- add 1 # margin-right -1457 #? print-int32-decimal 0, left-col -1458 #? print-string 0, " => " -1459 #? print-int32-decimal 0, right-col -1460 #? print-string 0, "\n" -1461 return right-col -1462 } -1463 -1464 fn clear-canvas _env: (addr environment) { -1465 var env/esi: (addr environment) <- copy _env -1466 var screen-ah/edi: (addr handle screen) <- get env, screen -1467 var _screen/eax: (addr screen) <- lookup *screen-ah -1468 var screen/edi: (addr screen) <- copy _screen -1469 clear-screen screen -1470 var nrows/eax: (addr int) <- get env, nrows -1471 var _repl-col/ecx: (addr int) <- get env, code-separator-col -1472 var repl-col/ecx: int <- copy *_repl-col -1473 draw-vertical-line screen, 1, *nrows, repl-col -1474 # wordstar-style cheatsheet of shortcuts -1475 move-cursor screen, *nrows, 0 -1476 start-reverse-video screen -1477 print-string screen, " ctrl-q " -1478 reset-formatting screen -1479 print-string screen, " quit " -1480 var menu-start/ebx: int <- copy repl-col -1481 menu-start <- subtract 0x48 # 72 = half the size of the menu -1482 move-cursor screen, *nrows, menu-start -1483 start-reverse-video screen -1484 print-string screen, " ctrl-a " -1485 reset-formatting screen -1486 print-string screen, " ⏮ " -1487 start-reverse-video screen -1488 print-string screen, " ctrl-b " -1489 reset-formatting screen -1490 print-string screen, " ◀ word " -1491 start-reverse-video screen -1492 print-string screen, " ctrl-f " -1493 reset-formatting screen -1494 print-string screen, " word ▶ " -1495 start-reverse-video screen -1496 print-string screen, " ctrl-e " -1497 reset-formatting screen -1498 print-string screen, " ⏭ " -1499 start-reverse-video screen -1500 print-string screen, " ctrl-l " -1501 reset-formatting screen -1502 print-string screen, " new line " -1503 start-reverse-video screen -1504 print-string screen, " ctrl-u " -1505 reset-formatting screen -1506 print-string screen, " clear " -1507 start-reverse-video screen -1508 print-string screen, " ctrl-n " -1509 reset-formatting screen -1510 print-string screen, " name value " -1511 start-reverse-video screen -1512 print-string screen, " ctrl-d " -1513 reset-formatting screen -1514 print-string screen, " define function " -1515 # primitives -1516 var dummy/eax: int <- render-primitives screen, *nrows, repl-col -1517 # currently defined functions -1518 render-functions screen, repl-col, env -1519 } -1520 -1521 # return value: top-most row written to -1522 fn render-primitives screen: (addr screen), bottom-margin-row: int, right-col: int -> _/eax: int { -1523 # render primitives from the bottom of the screen upward -1524 var row/ecx: int <- copy bottom-margin-row -1525 row <- subtract 1 -1526 var col/edx: int <- copy 1 -1527 move-cursor screen, row, col -1528 row, col <- render-primitive-group screen, row, col, right-col, "numbers: ", "+ - * / sqrt " -1529 row, col <- render-primitive-group screen, row, col, right-col, "arrays: ", "len " -1530 row, col <- render-primitive-group screen, row, col, right-col, "files: ", "open read slurp lines " -1531 row, col <- render-primitive-group screen, row, col, right-col, "misc: ", "dup swap " # hack: keep these at the right of the bottom row -1532 row, col <- render-primitive-group screen, row, col, right-col, "screens: ", "fake-screen print move up down left right " -1533 # finally print heading up top -1534 row <- decrement -1535 move-cursor screen, row, 1 -1536 start-bold screen -1537 print-string screen, "primitives:" -1538 reset-formatting screen -1539 return row -1540 } -1541 -1542 # start at row, col and print the given strings -1543 # move up one row if there isn't enough room before right-col -1544 # return row, col printed until -1545 fn render-primitive-group screen: (addr screen), _row: int, _col: int, right-col: int, _heading: (addr array byte), _contents: (addr array byte) -> _/ecx: int, _/edx: int { -1546 var row/ecx: int <- copy _row -1547 var col/edx: int <- copy _col -1548 # decrement row if necessary -1549 var new-col/ebx: int <- copy col -1550 var heading/esi: (addr array byte) <- copy _heading -1551 var len1/eax: int <- length heading -1552 new-col <- add len1 -1553 var contents/edi: (addr array byte) <- copy _contents -1554 var len2/eax: int <- length contents -1555 new-col <- add len2 -1556 var bound/eax: int <- copy right-col -1557 bound <- decrement -1558 { -1559 compare new-col, bound -1560 break-if-<= -1561 row <- decrement -1562 col <- copy 1 -1563 } -1564 move-cursor screen, row, col -1565 start-color screen, 0xf6, 7 -1566 print-string screen, heading -1567 reset-formatting screen -1568 print-string screen, contents -1569 return row, new-col -1570 } -1571 -1572 fn render-functions screen: (addr screen), right-col: int, _env: (addr environment) { -1573 var row/ecx: int <- copy 1 -1574 var dummy-col/edx: int <- copy right-col -1575 var env/esi: (addr environment) <- copy _env -1576 var functions/esi: (addr handle function) <- get env, functions -1577 { -1578 var curr/eax: (addr function) <- lookup *functions -1579 compare curr, 0 -1580 break-if-= -1581 row, dummy-col <- render-function-right-aligned screen, row, right-col, curr -1582 functions <- get curr, next -1583 row <- add 1 # inter-function-margin -1584 loop -1585 } -1586 } -1587 -1588 # print function starting at row, right-aligned before right-col -1589 # return row, col printed until -1590 fn render-function-right-aligned screen: (addr screen), row: int, right-col: int, f: (addr function) -> _/ecx: int, _/edx: int { -1591 var col/edx: int <- copy right-col -1592 col <- subtract 1 # function-right-margin -1593 var col2/ebx: int <- copy col -1594 var width/eax: int <- function-width f -1595 col <- subtract width -1596 var new-row/ecx: int <- copy row -1597 var height/eax: int <- function-height f -1598 new-row <- add height -1599 new-row <- decrement -1600 col <- subtract 1 # function-left-padding -1601 start-color screen, 0, 0xf7 -1602 clear-rect screen, row, col, new-row, col2 -1603 col <- add 1 -1604 #? var dummy/eax: grapheme <- read-key-from-real-keyboard -1605 render-function screen, row, col, f -1606 new-row <- add 1 # function-bottom-margin -1607 col <- subtract 1 # function-left-padding -1608 col <- subtract 1 # function-left-margin -1609 reset-formatting screen -1610 return new-row, col -1611 } -1612 -1613 # render function starting at row, col -1614 # only single-line functions supported for now -1615 fn render-function screen: (addr screen), row: int, col: int, _f: (addr function) { -1616 var f/esi: (addr function) <- copy _f -1617 var args/ecx: (addr handle word) <- get f, args -1618 move-cursor screen, row, col -1619 print-words-in-reverse screen, args -1620 var name-ah/eax: (addr handle array byte) <- get f, name -1621 var name/eax: (addr array byte) <- lookup *name-ah -1622 start-bold screen -1623 print-string screen, name -1624 reset-formatting screen -1625 start-color screen, 0, 0xf7 -1626 increment row -1627 add-to col, 2 +1312 var word-len/eax: int <- word-length curr-word +1313 curr-col <- add word-len +1314 curr-col <- add 2 +1315 increment top-row +1316 } +1317 # obtain stack at call site +1318 var stack-storage: value-stack +1319 var stack/edx: (addr value-stack) <- address stack-storage +1320 initialize-value-stack stack, 0x10 +1321 { +1322 var prev-word-ah/eax: (addr handle word) <- get curr-word, prev +1323 var prev-word/eax: (addr word) <- lookup *prev-word-ah +1324 compare prev-word, 0 +1325 break-if-= +1326 var bindings2-storage: table +1327 var bindings2/ebx: (addr table) <- address bindings2-storage +1328 deep-copy-table bindings, bindings2 +1329 evaluate functions, bindings2, first-line, prev-word, stack +1330 } +1331 # construct new bindings +1332 var callee-bindings-storage: table +1333 var callee-bindings/esi: (addr table) <- address callee-bindings-storage +1334 initialize-table callee-bindings, 0x10 +1335 bind-args callee, stack, callee-bindings +1336 # obtain body +1337 var callee-body-ah/eax: (addr handle line) <- get callee, body +1338 var callee-body/eax: (addr line) <- lookup *callee-body-ah +1339 var callee-body-first-word/edx: (addr handle word) <- get callee-body, data +1340 # - render subsidiary stack +1341 push-to-call-path-element curr-path, callee-body-first-word # leak +1342 #? print-string 0, "subsidiary {\n" +1343 #? dump-table callee-bindings +1344 #? syscall_exit +1345 curr-col <- render-line screen, functions, callee-bindings, callee-body, callee-body, expanded-words, top-row, curr-col, curr-path, cursor-word, cursor-call-path, cursor-row-addr, cursor-col-addr +1346 #? print-string 0, "}\n" +1347 drop-from-call-path-element curr-path +1348 # +1349 move-cursor screen, top-row, curr-col +1350 print-code-point screen, 0x21d7 # ⇗ +1351 # +1352 curr-col <- add 2 +1353 decrement top-row +1354 } +1355 # render main column +1356 var old-col/edx: int <- copy curr-col +1357 var bindings2-storage: table +1358 var bindings2/ebx: (addr table) <- address bindings2-storage +1359 #? print-string 0, "deep-copy {\n" +1360 deep-copy-table bindings, bindings2 +1361 #? print-string 0, "}\n" +1362 #? print-string 0, "render column {\n" +1363 curr-col <- render-column screen, functions, bindings2, first-line, line, curr-word, top-row, curr-col +1364 #? print-string 0, "}\n" +1365 # cache cursor column if necessary +1366 $render-line:cache-cursor-column: { +1367 { +1368 var found?/eax: boolean <- call-path-element-match? curr-path, cursor-call-path +1369 compare found?, 0 # false +1370 break-if-= $render-line:cache-cursor-column +1371 } +1372 var dest/edi: (addr int) <- copy cursor-row-addr +1373 { +1374 var src/eax: int <- copy top-row +1375 copy-to *dest, src +1376 } +1377 dest <- copy cursor-col-addr +1378 copy-to *dest, old-col +1379 var cursor-index-in-word/eax: int <- cursor-index curr-word +1380 add-to *dest, cursor-index-in-word +1381 } +1382 # loop update +1383 #? print-string 0, "next word\n" +1384 var next-word-ah/edx: (addr handle word) <- get curr-word, next +1385 curr-word <- lookup *next-word-ah +1386 #? { +1387 #? var foo/eax: int <- copy curr-word +1388 #? print-int32-hex 0, foo +1389 #? print-string 0, "\n" +1390 #? } +1391 increment-final-element curr-path +1392 loop +1393 } +1394 return curr-col +1395 } +1396 +1397 fn callee functions: (addr handle function), word: (addr word), out: (addr handle function) { +1398 var stream-storage: (stream byte 0x10) +1399 var stream/esi: (addr stream byte) <- address stream-storage +1400 emit-word word, stream +1401 find-function functions, stream, out +1402 } +1403 +1404 # Render: +1405 # - starting at top-row, left-col: final-word +1406 # - starting somewhere below at left-col: the stack result from interpreting first-world to final-word (inclusive) +1407 # +1408 # Return the farthest column written. +1409 fn render-column screen: (addr screen), functions: (addr handle function), bindings: (addr table), first-line: (addr line), line: (addr line), final-word: (addr word), top-row: int, left-col: int -> _/ecx: int { +1410 #? print-string 0, "render-column\n" +1411 #? dump-table bindings +1412 var max-width/esi: int <- copy 0 +1413 { +1414 # compute stack +1415 var stack: value-stack +1416 var stack-addr/edi: (addr value-stack) <- address stack +1417 initialize-value-stack stack-addr, 0x10 # max-words +1418 # copy bindings +1419 var bindings2-storage: table +1420 var bindings2/ebx: (addr table) <- address bindings2-storage +1421 #? print-string 0, "deep copy table {\n" +1422 deep-copy-table bindings, bindings2 +1423 #? print-string 0, "}\n" +1424 evaluate functions, bindings2, first-line, final-word, stack-addr +1425 # indent stack +1426 var indented-col/ebx: int <- copy left-col +1427 indented-col <- add 1 # margin-right +1428 # render stack +1429 var curr-row/edx: int <- copy top-row +1430 curr-row <- add 2 # stack-margin-top +1431 var _max-width/eax: int <- value-stack-max-width stack-addr +1432 max-width <- copy _max-width +1433 { +1434 var top-addr/ecx: (addr int) <- get stack-addr, top +1435 compare *top-addr, 0 +1436 break-if-<= +1437 decrement *top-addr +1438 var data-ah/eax: (addr handle array value) <- get stack-addr, data +1439 var data/eax: (addr array value) <- lookup *data-ah +1440 var top/ecx: int <- copy *top-addr +1441 var dest-offset/ecx: (offset value) <- compute-offset data, top +1442 var val/eax: (addr value) <- index data, dest-offset +1443 render-value-at screen, curr-row, indented-col, val, max-width +1444 var height/eax: int <- value-height val +1445 curr-row <- add height +1446 loop +1447 } +1448 } +1449 +1450 max-width <- add 2 # spaces on either side of items on the stack +1451 +1452 # render word, initialize result +1453 reset-formatting screen +1454 move-cursor screen, top-row, left-col +1455 print-word screen, final-word +1456 { +1457 var size/eax: int <- word-length final-word +1458 compare size, max-width +1459 break-if-<= +1460 max-width <- copy size +1461 } +1462 +1463 # post-process right-col +1464 var right-col/ecx: int <- copy left-col +1465 right-col <- add max-width +1466 right-col <- add 1 # margin-right +1467 #? print-int32-decimal 0, left-col +1468 #? print-string 0, " => " +1469 #? print-int32-decimal 0, right-col +1470 #? print-string 0, "\n" +1471 return right-col +1472 } +1473 +1474 fn clear-canvas _env: (addr environment) { +1475 var env/esi: (addr environment) <- copy _env +1476 var screen-ah/edi: (addr handle screen) <- get env, screen +1477 var _screen/eax: (addr screen) <- lookup *screen-ah +1478 var screen/edi: (addr screen) <- copy _screen +1479 clear-screen screen +1480 var nrows/eax: (addr int) <- get env, nrows +1481 var _sep-col/ecx: (addr int) <- get env, code-separator-col +1482 var sep-col/ecx: int <- copy *_sep-col +1483 draw-vertical-line screen, 1, *nrows, sep-col +1484 # wordstar-style cheatsheet of shortcuts +1485 move-cursor screen, *nrows, 0 +1486 start-reverse-video screen +1487 print-string screen, " ctrl-q " +1488 reset-formatting screen +1489 print-string screen, " quit " +1490 var menu-start/ebx: int <- copy sep-col +1491 menu-start <- subtract 0x48 # 72 = half the size of the menu +1492 move-cursor screen, *nrows, menu-start +1493 start-reverse-video screen +1494 print-string screen, " ctrl-a " +1495 reset-formatting screen +1496 print-string screen, " ⏮ " +1497 start-reverse-video screen +1498 print-string screen, " ctrl-b " +1499 reset-formatting screen +1500 print-string screen, " ◀ word " +1501 start-reverse-video screen +1502 print-string screen, " ctrl-f " +1503 reset-formatting screen +1504 print-string screen, " word ▶ " +1505 start-reverse-video screen +1506 print-string screen, " ctrl-e " +1507 reset-formatting screen +1508 print-string screen, " ⏭ " +1509 start-reverse-video screen +1510 print-string screen, " ctrl-l " +1511 reset-formatting screen +1512 print-string screen, " new line " +1513 start-reverse-video screen +1514 print-string screen, " ctrl-u " +1515 reset-formatting screen +1516 print-string screen, " clear " +1517 start-reverse-video screen +1518 print-string screen, " ctrl-n " +1519 reset-formatting screen +1520 print-string screen, " name value " +1521 start-reverse-video screen +1522 print-string screen, " ctrl-d " +1523 reset-formatting screen +1524 print-string screen, " define function " +1525 # primitives +1526 var dummy/eax: int <- render-primitives screen, *nrows, sep-col +1527 # currently defined functions +1528 render-functions screen, sep-col, env +1529 } +1530 +1531 # return value: top-most row written to +1532 fn render-primitives screen: (addr screen), bottom-margin-row: int, right-col: int -> _/eax: int { +1533 # render primitives from the bottom of the screen upward +1534 var row/ecx: int <- copy bottom-margin-row +1535 row <- subtract 1 +1536 var col/edx: int <- copy 1 +1537 move-cursor screen, row, col +1538 row, col <- render-primitive-group screen, row, col, right-col, "numbers: ", "+ - * / sqrt " +1539 row, col <- render-primitive-group screen, row, col, right-col, "arrays: ", "len " +1540 row, col <- render-primitive-group screen, row, col, right-col, "files: ", "open read slurp lines " +1541 row, col <- render-primitive-group screen, row, col, right-col, "misc: ", "dup swap " # hack: keep these at the right of the bottom row +1542 row, col <- render-primitive-group screen, row, col, right-col, "screens: ", "fake-screen print move up down left right " +1543 # finally print heading up top +1544 row <- decrement +1545 move-cursor screen, row, 1 +1546 start-bold screen +1547 print-string screen, "primitives:" +1548 reset-formatting screen +1549 return row +1550 } +1551 +1552 # start at row, col and print the given strings +1553 # move up one row if there isn't enough room before right-col +1554 # return row, col printed until +1555 fn render-primitive-group screen: (addr screen), _row: int, _col: int, right-col: int, _heading: (addr array byte), _contents: (addr array byte) -> _/ecx: int, _/edx: int { +1556 var row/ecx: int <- copy _row +1557 var col/edx: int <- copy _col +1558 # decrement row if necessary +1559 var new-col/ebx: int <- copy col +1560 var heading/esi: (addr array byte) <- copy _heading +1561 var len1/eax: int <- length heading +1562 new-col <- add len1 +1563 var contents/edi: (addr array byte) <- copy _contents +1564 var len2/eax: int <- length contents +1565 new-col <- add len2 +1566 var bound/eax: int <- copy right-col +1567 bound <- decrement +1568 { +1569 compare new-col, bound +1570 break-if-<= +1571 row <- decrement +1572 col <- copy 1 +1573 } +1574 move-cursor screen, row, col +1575 start-color screen, 0xf6, 7 +1576 print-string screen, heading +1577 reset-formatting screen +1578 print-string screen, contents +1579 return row, new-col +1580 } +1581 +1582 fn render-functions screen: (addr screen), right-col: int, _env: (addr environment) { +1583 var row/ecx: int <- copy 1 +1584 var dummy-col/edx: int <- copy right-col +1585 var env/esi: (addr environment) <- copy _env +1586 var functions/esi: (addr handle function) <- get env, functions +1587 { +1588 var curr/eax: (addr function) <- lookup *functions +1589 compare curr, 0 +1590 break-if-= +1591 row, dummy-col <- render-function-right-aligned screen, row, right-col, curr +1592 functions <- get curr, next +1593 row <- add 1 # inter-function-margin +1594 loop +1595 } +1596 } +1597 +1598 # print function starting at row, right-aligned before right-col +1599 # return row, col printed until +1600 fn render-function-right-aligned screen: (addr screen), row: int, right-col: int, f: (addr function) -> _/ecx: int, _/edx: int { +1601 var col/edx: int <- copy right-col +1602 col <- subtract 1 # function-right-margin +1603 var col2/ebx: int <- copy col +1604 var width/eax: int <- function-width f +1605 col <- subtract width +1606 var new-row/ecx: int <- copy row +1607 var height/eax: int <- function-height f +1608 new-row <- add height +1609 new-row <- decrement +1610 col <- subtract 1 # function-left-padding +1611 start-color screen, 0, 0xf7 +1612 clear-rect screen, row, col, new-row, col2 +1613 col <- add 1 +1614 #? var dummy/eax: grapheme <- read-key-from-real-keyboard +1615 render-function screen, row, col, f +1616 new-row <- add 1 # function-bottom-margin +1617 col <- subtract 1 # function-left-padding +1618 col <- subtract 1 # function-left-margin +1619 reset-formatting screen +1620 return new-row, col +1621 } +1622 +1623 # render function starting at row, col +1624 # only single-line functions supported for now +1625 fn render-function screen: (addr screen), row: int, col: int, _f: (addr function) { +1626 var f/esi: (addr function) <- copy _f +1627 var args/ecx: (addr handle word) <- get f, args 1628 move-cursor screen, row, col -1629 print-string screen, "≡ " -1630 var body-ah/eax: (addr handle line) <- get f, body -1631 var body/eax: (addr line) <- lookup *body-ah -1632 var body-words-ah/eax: (addr handle word) <- get body, data -1633 print-words screen, body-words-ah -1634 } -1635 -1636 fn real-grapheme? g: grapheme -> _/eax: boolean { -1637 # if g == newline return true -1638 compare g, 0xa -1639 { -1640 break-if-!= -1641 return 1 # true -1642 } -1643 # if g == tab return true -1644 compare g, 9 -1645 { -1646 break-if-!= -1647 return 1 # true -1648 } -1649 # if g < 32 return false -1650 compare g, 0x20 -1651 { -1652 break-if->= -1653 return 0 # false -1654 } -1655 # if g <= 255 return true -1656 compare g, 0xff -1657 { -1658 break-if-> -1659 return 1 # true -1660 } -1661 # if (g&0xff == Esc) it's an escape sequence -1662 and-with g, 0xff -1663 compare g, 0x1b # Esc -1664 { -1665 break-if-!= -1666 return 0 # false -1667 } -1668 # otherwise return true -1669 return 1 # true -1670 } +1629 print-words-in-reverse screen, args +1630 var name-ah/eax: (addr handle array byte) <- get f, name +1631 var name/eax: (addr array byte) <- lookup *name-ah +1632 start-bold screen +1633 print-string screen, name +1634 reset-formatting screen +1635 start-color screen, 0, 0xf7 +1636 increment row +1637 add-to col, 2 +1638 move-cursor screen, row, col +1639 print-string screen, "≡ " +1640 var body-ah/eax: (addr handle line) <- get f, body +1641 var body/eax: (addr line) <- lookup *body-ah +1642 var body-words-ah/eax: (addr handle word) <- get body, data +1643 print-words screen, body-words-ah +1644 } +1645 +1646 fn real-grapheme? g: grapheme -> _/eax: boolean { +1647 # if g == newline return true +1648 compare g, 0xa +1649 { +1650 break-if-!= +1651 return 1 # true +1652 } +1653 # if g == tab return true +1654 compare g, 9 +1655 { +1656 break-if-!= +1657 return 1 # true +1658 } +1659 # if g < 32 return false +1660 compare g, 0x20 +1661 { +1662 break-if->= +1663 return 0 # false +1664 } +1665 # if g <= 255 return true +1666 compare g, 0xff +1667 { +1668 break-if-> +1669 return 1 # true +1670 } +1671 # if (g&0xff == Esc) it's an escape sequence +1672 and-with g, 0xff +1673 compare g, 0x1b # Esc +1674 { +1675 break-if-!= +1676 return 0 # false +1677 } +1678 # otherwise return true +1679 return 1 # true +1680 } -- cgit 1.4.1-2-gfad0