From 8cff1c04e38787a99b3382055542d967dca420df Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 14 Feb 2021 16:12:47 -0800 Subject: 7745 --- html/baremetal/shell/word.mu.html | 784 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 784 insertions(+) create mode 100644 html/baremetal/shell/word.mu.html (limited to 'html/baremetal/shell/word.mu.html') diff --git a/html/baremetal/shell/word.mu.html b/html/baremetal/shell/word.mu.html new file mode 100644 index 00000000..40412697 --- /dev/null +++ b/html/baremetal/shell/word.mu.html @@ -0,0 +1,784 @@ + + + + +Mu - baremetal/shell/word.mu + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/baremetal/shell/word.mu +
+  1 type word {
+  2   scalar-data: (handle gap-buffer)
+  3   next: (handle word)
+  4   prev: (handle word)
+  5 }
+  6 
+  7 fn initialize-word _self: (addr word) {
+  8   var self/esi: (addr word) <- copy _self
+  9   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+ 10   allocate data-ah
+ 11   var data/eax: (addr gap-buffer) <- lookup *data-ah
+ 12   initialize-gap-buffer data
+ 13 }
+ 14 
+ 15 ## some helpers for creating words. mostly for tests
+ 16 
+ 17 fn initialize-word-with _self: (addr word), s: (addr array byte) {
+ 18   var self/esi: (addr word) <- copy _self
+ 19   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+ 20   allocate data-ah
+ 21   var data/eax: (addr gap-buffer) <- lookup *data-ah
+ 22   initialize-gap-buffer-with data, s
+ 23 }
+ 24 
+ 25 fn allocate-word-with _out: (addr handle word), s: (addr array byte) {
+ 26   var out/eax: (addr handle word) <- copy _out
+ 27   allocate out
+ 28   var out-addr/eax: (addr word) <- lookup *out
+ 29   initialize-word-with out-addr, s
+ 30 }
+ 31 
+ 32 # just for tests for now
+ 33 # TODO: handle existing next
+ 34 # one implication of handles: append must take a handle
+ 35 fn append-word-with self-h: (handle word), s: (addr array byte) {
+ 36   var self/eax: (addr word) <- lookup self-h
+ 37   var next-ah/eax: (addr handle word) <- get self, next
+ 38   allocate-word-with next-ah, s
+ 39   var next/eax: (addr word) <- lookup *next-ah
+ 40   var prev-ah/eax: (addr handle word) <- get next, prev
+ 41   copy-handle self-h, prev-ah
+ 42 }
+ 43 
+ 44 # just for tests for now
+ 45 # TODO: handle existing prev
+ 46 fn prepend-word-with self-h: (handle word), s: (addr array byte) {
+ 47   var self/eax: (addr word) <- lookup self-h
+ 48   var prev-ah/eax: (addr handle word) <- get self, prev
+ 49   allocate-word-with prev-ah, s
+ 50   var prev/eax: (addr word) <- lookup *prev-ah
+ 51   var next-ah/eax: (addr handle word) <- get prev, next
+ 52   copy-handle self-h, next-ah
+ 53 }
+ 54 
+ 55 ## real primitives
+ 56 
+ 57 fn move-word-contents _src-ah: (addr handle word), _dest-ah: (addr handle word) {
+ 58   var dest-ah/eax: (addr handle word) <- copy _dest-ah
+ 59   var _dest/eax: (addr word) <- lookup *dest-ah
+ 60   var dest/edi: (addr word) <- copy _dest
+ 61   var src-ah/eax: (addr handle word) <- copy _src-ah
+ 62   var _src/eax: (addr word) <- lookup *src-ah
+ 63   var src/esi: (addr word) <- copy _src
+ 64   cursor-to-start src
+ 65   var src-data-ah/eax: (addr handle gap-buffer) <- get src, scalar-data
+ 66   var src-data/eax: (addr gap-buffer) <- lookup *src-data-ah
+ 67   var src-stack/ecx: (addr grapheme-stack) <- get src-data, right
+ 68   {
+ 69     var done?/eax: boolean <- grapheme-stack-empty? src-stack
+ 70     compare done?, 0/false
+ 71     break-if-!=
+ 72     var g/eax: grapheme <- pop-grapheme-stack src-stack
+ 73     add-grapheme-to-word dest, g
+ 74     loop
+ 75   }
+ 76 }
+ 77 
+ 78 fn copy-word-contents-before-cursor _src-ah: (addr handle word), _dest-ah: (addr handle word) {
+ 79   var dest-ah/eax: (addr handle word) <- copy _dest-ah
+ 80   var _dest/eax: (addr word) <- lookup *dest-ah
+ 81   var dest/edi: (addr word) <- copy _dest
+ 82   var src-ah/eax: (addr handle word) <- copy _src-ah
+ 83   var src/eax: (addr word) <- lookup *src-ah
+ 84   var src-data-ah/eax: (addr handle gap-buffer) <- get src, scalar-data
+ 85   var src-data/eax: (addr gap-buffer) <- lookup *src-data-ah
+ 86   var src-stack/ecx: (addr grapheme-stack) <- get src-data, left
+ 87   var src-stack-data-ah/eax: (addr handle array grapheme) <- get src-stack, data
+ 88   var _src-stack-data/eax: (addr array grapheme) <- lookup *src-stack-data-ah
+ 89   var src-stack-data/edx: (addr array grapheme) <- copy _src-stack-data
+ 90   var top-addr/ecx: (addr int) <- get src-stack, top
+ 91   var i/eax: int <- copy 0
+ 92   {
+ 93     compare i, *top-addr
+ 94     break-if->=
+ 95     var g/edx: (addr grapheme) <- index src-stack-data, i
+ 96     add-grapheme-to-word dest, *g
+ 97     i <- increment
+ 98     loop
+ 99   }
+100 }
+101 
+102 fn word-equal? _self: (addr word), s: (addr array byte) -> _/eax: boolean {
+103   var self/esi: (addr word) <- copy _self
+104   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+105   var data/eax: (addr gap-buffer) <- lookup *data-ah
+106   var result/eax: boolean <- gap-buffer-equal? data, s
+107   return result
+108 }
+109 
+110 fn words-equal? _self: (addr word), _w: (addr word) -> _/eax: boolean {
+111   var self/eax: (addr word) <- copy _self
+112   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+113   var _data/eax: (addr gap-buffer) <- lookup *data-ah
+114   var data/ecx: (addr gap-buffer) <- copy _data
+115   var w/eax: (addr word) <- copy _w
+116   var w-data-ah/eax: (addr handle gap-buffer) <- get w, scalar-data
+117   var w-data/eax: (addr gap-buffer) <- lookup *w-data-ah
+118   var result/eax: boolean <- gap-buffers-equal? data, w-data
+119   return result
+120 }
+121 
+122 fn word-length _self: (addr word) -> _/eax: int {
+123   var self/esi: (addr word) <- copy _self
+124   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+125   var data/eax: (addr gap-buffer) <- lookup *data-ah
+126   var result/eax: int <- gap-buffer-length data
+127   return result
+128 }
+129 
+130 fn first-word _in: (addr handle word), out: (addr handle word) {
+131   var curr-ah/esi: (addr handle word) <- copy _in
+132   var curr/eax: (addr word) <- lookup *curr-ah
+133   var prev/edi: (addr handle word) <- copy 0
+134   {
+135     prev <- get curr, prev
+136     var curr/eax: (addr word) <- lookup *prev
+137     compare curr, 0
+138     break-if-=
+139     copy-object prev, curr-ah
+140     loop
+141   }
+142   copy-object curr-ah, out
+143 }
+144 
+145 fn final-word _in: (addr handle word), out: (addr handle word) {
+146   var curr-h: (handle word)
+147   var curr-ah/esi: (addr handle word) <- address curr-h
+148   copy-object _in, curr-ah
+149   var curr/eax: (addr word) <- copy 0
+150   var next/edi: (addr handle word) <- copy 0
+151   {
+152     curr <- lookup *curr-ah
+153     next <- get curr, next
+154     curr <- lookup *next
+155     compare curr, 0
+156     break-if-=
+157     copy-object next, curr-ah
+158     loop
+159   }
+160   copy-object curr-ah, out  # modify 'out' right at the end, just in case it's same as 'in'
+161 }
+162 
+163 fn first-grapheme _self: (addr word) -> _/eax: grapheme {
+164   var self/esi: (addr word) <- copy _self
+165   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+166   var data/eax: (addr gap-buffer) <- lookup *data-ah
+167   var result/eax: grapheme <- first-grapheme-in-gap-buffer data
+168   return result
+169 }
+170 
+171 fn grapheme-before-cursor _self: (addr word) -> _/eax: grapheme {
+172   var self/esi: (addr word) <- copy _self
+173   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+174   var data/eax: (addr gap-buffer) <- lookup *data-ah
+175   var result/eax: grapheme <- grapheme-before-cursor-in-gap-buffer data
+176   return result
+177 }
+178 
+179 fn add-grapheme-to-word _self: (addr word), c: grapheme {
+180   var self/esi: (addr word) <- copy _self
+181   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+182   var data/eax: (addr gap-buffer) <- lookup *data-ah
+183   add-grapheme-at-gap data, c
+184 }
+185 
+186 fn cursor-at-start? _self: (addr word) -> _/eax: boolean {
+187   var self/esi: (addr word) <- copy _self
+188   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+189   var data/eax: (addr gap-buffer) <- lookup *data-ah
+190   var result/eax: boolean <- gap-at-start? data
+191   return result
+192 }
+193 
+194 fn cursor-at-end? _self: (addr word) -> _/eax: boolean {
+195   var self/esi: (addr word) <- copy _self
+196   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+197   var data/eax: (addr gap-buffer) <- lookup *data-ah
+198   var result/eax: boolean <- gap-at-end? data
+199   return result
+200 }
+201 
+202 fn cursor-left _self: (addr word) {
+203   var self/esi: (addr word) <- copy _self
+204   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+205   var data/eax: (addr gap-buffer) <- lookup *data-ah
+206   var dummy/eax: grapheme <- gap-left data
+207 }
+208 
+209 fn cursor-right _self: (addr word) {
+210   var self/esi: (addr word) <- copy _self
+211   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+212   var data/eax: (addr gap-buffer) <- lookup *data-ah
+213   var dummy/eax: grapheme <- gap-right data
+214 }
+215 
+216 fn cursor-to-start _self: (addr word) {
+217   var self/esi: (addr word) <- copy _self
+218   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+219   var data/eax: (addr gap-buffer) <- lookup *data-ah
+220   gap-to-start data
+221 }
+222 
+223 fn cursor-to-end _self: (addr word) {
+224   var self/esi: (addr word) <- copy _self
+225   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+226   var data/eax: (addr gap-buffer) <- lookup *data-ah
+227   gap-to-end data
+228 }
+229 
+230 fn cursor-index _self: (addr word) -> _/eax: int {
+231   var self/esi: (addr word) <- copy _self
+232   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+233   var data/eax: (addr gap-buffer) <- lookup *data-ah
+234   var result/eax: int <- index-of-gap data
+235   return result
+236 }
+237 
+238 fn delete-before-cursor _self: (addr word) {
+239   var self/esi: (addr word) <- copy _self
+240   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+241   var data/eax: (addr gap-buffer) <- lookup *data-ah
+242   delete-before-gap data
+243 }
+244 
+245 fn pop-after-cursor _self: (addr word) -> _/eax: grapheme {
+246   var self/esi: (addr word) <- copy _self
+247   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+248   var data/eax: (addr gap-buffer) <- lookup *data-ah
+249   var result/eax: grapheme <- pop-after-gap data
+250   return result
+251 }
+252 
+253 fn delete-next _self: (addr word) {
+254   var self/esi: (addr word) <- copy _self
+255   var next-ah/edi: (addr handle word) <- get self, next
+256   var next/eax: (addr word) <- lookup *next-ah
+257   compare next, 0
+258   break-if-=
+259   var next-next-ah/ecx: (addr handle word) <- get next, next
+260   var self-ah/esi: (addr handle word) <- get next, prev
+261   copy-object next-next-ah, next-ah
+262   var new-next/eax: (addr word) <- lookup *next-next-ah
+263   compare new-next, 0
+264   break-if-=
+265   var dest/eax: (addr handle word) <- get new-next, prev
+266   copy-object self-ah, dest
+267 }
+268 
+269 fn render-word screen: (addr screen), _self: (addr word), x: int, y: int, render-cursor?: boolean -> _/eax: int {
+270   var self/esi: (addr word) <- copy _self
+271   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+272   var data/eax: (addr gap-buffer) <- lookup *data-ah
+273   var result/eax: int <- render-gap-buffer screen, data, x, y, render-cursor?
+274   return result
+275 }
+276 
+277 fn render-words screen: (addr screen), _words-ah: (addr handle word), x: int, y: int, cursor-word-addr: int -> _/eax: int {
+278   var words-ah/eax: (addr handle word) <- copy _words-ah
+279   var _words-a/eax: (addr word) <- lookup *words-ah
+280   var words-a/ecx: (addr word) <- copy _words-a
+281   compare words-a, 0
+282   {
+283     break-if-!=
+284     return x
+285   }
+286   # print
+287   var render-cursor?/edx: boolean <- copy 0/false
+288   {
+289     compare cursor-word-addr, words-a
+290     break-if-!=
+291     render-cursor? <- copy 1/true
+292   }
+293   var next-x/eax: int <- render-word screen, words-a, x, y, render-cursor?
+294   var space/edx: grapheme <- copy 0x20/space
+295   draw-grapheme screen, space, next-x, y, 3/fg=cyan, 0/bg
+296   next-x <- increment
+297   # recurse
+298   var next-ah/ecx: (addr handle word) <- get words-a, next
+299   next-x <- render-words screen, next-ah, next-x, y, cursor-word-addr
+300   return next-x
+301 }
+302 
+303 fn test-render-words {
+304   # words = [aaa, bbb, ccc, ddd]
+305   var w-storage: (handle word)
+306   var w-ah/esi: (addr handle word) <- address w-storage
+307   allocate-word-with w-ah, "aaa"
+308   append-word-at-end-with w-ah, "bbb"
+309   append-word-at-end-with w-ah, "ccc"
+310   append-word-at-end-with w-ah, "ddd"
+311   # setup: screen
+312   var screen-on-stack: screen
+313   var screen/edi: (addr screen) <- address screen-on-stack
+314   initialize-screen screen, 0x20, 4
+315   #
+316   var _w/eax: (addr word) <- lookup *w-ah
+317   var w/ecx: (addr word) <- copy _w
+318   var cursor-word/eax: int <- copy w
+319   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+320   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+321   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "   |                ", "F - test-render-words/0 cursor"
+322   # - start moving cursor left through final word
+323   cursor-left w
+324   var cursor-word/eax: int <- copy w
+325   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+326   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+327   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "  |                 ", "F - test-render-words/1 cursor"
+328   #
+329   cursor-left w
+330   var cursor-word/eax: int <- copy w
+331   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+332   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+333   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  " |                  ", "F - test-render-words/2 cursor"
+334   #
+335   cursor-left w
+336   var cursor-word/eax: int <- copy w
+337   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+338   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+339   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "|                   ", "F - test-render-words/3 cursor"
+340   # further moves left within the word change nothing
+341   cursor-left w
+342   var cursor-word/eax: int <- copy w
+343   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+344   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+345   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "|                   ", "F - test-render-words/4 cursor"
+346   # - switch to next word
+347   var w2-ah/eax: (addr handle word) <- get w, next
+348   var _w/eax: (addr word) <- lookup *w2-ah
+349   var w/ecx: (addr word) <- copy _w
+350   var cursor-word/eax: int <- copy w
+351   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+352   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+353   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "        |           ", "F - test-render-words/5 cursor"
+354   # now speed up a little
+355   cursor-left w
+356   cursor-left w
+357   var cursor-word/eax: int <- copy w
+358   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+359   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+360   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "      |             ", "F - test-render-words/6 cursor"
+361   #
+362   var w2-ah/eax: (addr handle word) <- get w, next
+363   var _w/eax: (addr word) <- lookup *w2-ah
+364   var w/ecx: (addr word) <- copy _w
+365   cursor-left w
+366   var cursor-word/eax: int <- copy w
+367   var new-x/eax: int <- render-words screen, w-ah, 0/x, 0/y, cursor-word
+368   check-screen-row screen, 0/y,                                   "aaa  bbb  ccc  ddd  ", "F - test-render-words/0"
+369   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "            |       ", "F - test-render-words/7 cursor"
+370 }
+371 
+372 fn render-words-in-reverse screen: (addr screen), _words-ah: (addr handle word), x: int, y: int, cursor-word-addr: int -> _/eax: int {
+373   var words-ah/eax: (addr handle word) <- copy _words-ah
+374   var _words-a/eax: (addr word) <- lookup *words-ah
+375   var words-a/ecx: (addr word) <- copy _words-a
+376   compare words-a, 0
+377   {
+378     break-if-!=
+379     return x
+380   }
+381   # recurse
+382   var next-ah/eax: (addr handle word) <- get words-a, next
+383   var next-x/eax: int <- render-words-in-reverse screen, next-ah, x, y, cursor-word-addr
+384   # print
+385   var render-cursor?/edx: boolean <- copy 0/false
+386   {
+387     compare cursor-word-addr, words-a
+388     break-if-!=
+389     render-cursor? <- copy 1/true
+390   }
+391   next-x <- render-word screen, words-a, next-x, y, render-cursor?
+392   var space/ecx: grapheme <- copy 0x20/space
+393   draw-grapheme screen, space, next-x, y, 3/fg=cyan, 0/bg
+394   next-x <- increment
+395   return next-x
+396 }
+397 
+398 fn test-render-words-in-reverse {
+399   # words = [aaa, bbb, ccc, ddd]
+400   var w-storage: (handle word)
+401   var w-ah/esi: (addr handle word) <- address w-storage
+402   allocate-word-with w-ah, "aaa"
+403   append-word-at-end-with w-ah, "bbb"
+404   append-word-at-end-with w-ah, "ccc"
+405   append-word-at-end-with w-ah, "ddd"
+406   # setup: screen
+407   var screen-on-stack: screen
+408   var screen/edi: (addr screen) <- address screen-on-stack
+409   initialize-screen screen, 0x20, 4
+410   #
+411   var _w/eax: (addr word) <- lookup *w-ah
+412   var w/ecx: (addr word) <- copy _w
+413   var cursor-word/eax: int <- copy w
+414   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+415   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/0"
+416   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "                  | ", "F - test-render-words-in-reverse/0 cursor"
+417   # - start moving cursor left through final word
+418   cursor-left w
+419   var cursor-word/eax: int <- copy w
+420   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+421   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/1"
+422   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "                 |  ", "F - test-render-words-in-reverse/1 cursor"
+423   #
+424   cursor-left w
+425   var cursor-word/eax: int <- copy w
+426   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+427   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/2"
+428   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "                |   ", "F - test-render-words-in-reverse/2 cursor"
+429   #
+430   cursor-left w
+431   var cursor-word/eax: int <- copy w
+432   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+433   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/3"
+434   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "               |    ", "F - test-render-words-in-reverse/3 cursor"
+435   # further moves left within the word change nothing
+436   cursor-left w
+437   var cursor-word/eax: int <- copy w
+438   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+439   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/4"
+440   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "               |    ", "F - test-render-words-in-reverse/4 cursor"
+441   # - switch to next word
+442   var w2-ah/eax: (addr handle word) <- get w, next
+443   var _w/eax: (addr word) <- lookup *w2-ah
+444   var w/ecx: (addr word) <- copy _w
+445   var cursor-word/eax: int <- copy w
+446   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+447   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/5"
+448   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "             |      ", "F - test-render-words-in-reverse/5 cursor"
+449   # now speed up a little
+450   cursor-left w
+451   cursor-left w
+452   var cursor-word/eax: int <- copy w
+453   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+454   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/6"
+455   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "           |        ", "F - test-render-words-in-reverse/6 cursor"
+456   #
+457   var w2-ah/eax: (addr handle word) <- get w, next
+458   var _w/eax: (addr word) <- lookup *w2-ah
+459   var w/ecx: (addr word) <- copy _w
+460   cursor-left w
+461   var cursor-word/eax: int <- copy w
+462   var new-x/eax: int <- render-words-in-reverse screen, w-ah, 0/x, 0/y, cursor-word
+463   check-screen-row screen, 0/y,                                   "ddd  ccc  bbb  aaa  ", "F - test-render-words-in-reverse/7"
+464   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y,  "       |            ", "F - test-render-words-in-reverse/7 cursor"
+465 }
+466 
+467 # Gotcha with some word operations: ensure dest-ah isn't in the middle of some
+468 # existing chain of words. There are two pointers to patch, and you'll forget
+469 # to do the other one.
+470 fn copy-words _src-ah: (addr handle word), _dest-ah: (addr handle word) {
+471   var src-ah/eax: (addr handle word) <- copy _src-ah
+472   var src-a/eax: (addr word) <- lookup *src-ah
+473   compare src-a, 0
+474   break-if-=
+475   # copy
+476   var dest-ah/edi: (addr handle word) <- copy _dest-ah
+477   copy-word src-a, dest-ah
+478   # recurse
+479   var rest: (handle word)
+480   var rest-ah/ecx: (addr handle word) <- address rest
+481   var next-src-ah/esi: (addr handle word) <- get src-a, next
+482   copy-words next-src-ah, rest-ah
+483   chain-words dest-ah, rest-ah
+484 }
+485 
+486 fn copy-words-in-reverse _src-ah: (addr handle word), _dest-ah: (addr handle word) {
+487   var src-ah/eax: (addr handle word) <- copy _src-ah
+488   var _src-a/eax: (addr word) <- lookup *src-ah
+489   var src-a/esi: (addr word) <- copy _src-a
+490   compare src-a, 0
+491   break-if-=
+492   # recurse
+493   var next-src-ah/ecx: (addr handle word) <- get src-a, next
+494   var dest-ah/edi: (addr handle word) <- copy _dest-ah
+495   copy-words-in-reverse next-src-ah, dest-ah
+496   #
+497   copy-word-at-end src-a, dest-ah
+498 }
+499 
+500 fn copy-word-at-end src: (addr word), _dest-ah: (addr handle word) {
+501   var dest-ah/edi: (addr handle word) <- copy _dest-ah
+502   # if dest is null, copy and return
+503   var dest-a/eax: (addr word) <- lookup *dest-ah
+504   compare dest-a, 0
+505   {
+506     break-if-!=
+507     copy-word src, dest-ah
+508     return
+509   }
+510   # copy current word
+511   var new: (handle word)
+512   var new-ah/ecx: (addr handle word) <- address new
+513   copy-word src, new-ah
+514   # append it at the end
+515   var curr-ah/edi: (addr handle word) <- copy dest-ah
+516   {
+517     var curr-a/eax: (addr word) <- lookup *curr-ah  # curr-a guaranteed not to be null
+518     var next-ah/ecx: (addr handle word) <- get curr-a, next
+519     var next-a/eax: (addr word) <- lookup *next-ah
+520     compare next-a, 0
+521     break-if-=
+522     curr-ah <- copy next-ah
+523     loop
+524   }
+525   chain-words curr-ah, new-ah
+526 }
+527 
+528 fn append-word-at-end-with _dest-ah: (addr handle word), s: (addr array byte) {
+529   var dest-ah/edi: (addr handle word) <- copy _dest-ah
+530   # if dest is null, copy and return
+531   var dest-a/eax: (addr word) <- lookup *dest-ah
+532   compare dest-a, 0
+533   {
+534     break-if-!=
+535     allocate-word-with dest-ah, s
+536     return
+537   }
+538   # otherwise append at end
+539   var curr-ah/edi: (addr handle word) <- copy dest-ah
+540   {
+541     var curr-a/eax: (addr word) <- lookup *curr-ah  # curr-a guaranteed not to be null
+542     var next-ah/ecx: (addr handle word) <- get curr-a, next
+543     var next-a/eax: (addr word) <- lookup *next-ah
+544     compare next-a, 0
+545     break-if-=
+546     curr-ah <- copy next-ah
+547     loop
+548   }
+549   append-word-with *curr-ah, s
+550 }
+551 
+552 fn copy-word _src-a: (addr word), _dest-ah: (addr handle word) {
+553   var dest-ah/eax: (addr handle word) <- copy _dest-ah
+554   allocate dest-ah
+555   var _dest-a/eax: (addr word) <- lookup *dest-ah
+556   var dest-a/eax: (addr word) <- copy _dest-a
+557   initialize-word dest-a
+558   var dest/edi: (addr handle gap-buffer) <- get dest-a, scalar-data
+559   var src-a/eax: (addr word) <- copy _src-a
+560   var src/eax: (addr handle gap-buffer) <- get src-a, scalar-data
+561   copy-gap-buffer src, dest
+562 }
+563 
+564 # one implication of handles: append must take a handle
+565 fn append-word _self-ah: (addr handle word) {
+566   var saved-self-storage: (handle word)
+567   var saved-self/eax: (addr handle word) <- address saved-self-storage
+568   copy-object _self-ah, saved-self
+569   var self-ah/esi: (addr handle word) <- copy _self-ah
+570   var _self/eax: (addr word) <- lookup *self-ah
+571   var self/ebx: (addr word) <- copy _self
+572   # allocate new handle
+573   var new: (handle word)
+574   var new-ah/ecx: (addr handle word) <- address new
+575   allocate new-ah
+576   var new-addr/eax: (addr word) <- lookup new
+577   initialize-word new-addr
+578   # new->next = self->next
+579   var src/esi: (addr handle word) <- get self, next
+580   var dest/edi: (addr handle word) <- get new-addr, next
+581   copy-object src, dest
+582   # new->next->prev = new
+583   {
+584     var next-addr/eax: (addr word) <- lookup *src
+585     compare next-addr, 0
+586     break-if-=
+587     dest <- get next-addr, prev
+588     copy-object new-ah, dest
+589   }
+590   # new->prev = saved-self
+591   dest <- get new-addr, prev
+592   var saved-self-ah/eax: (addr handle word) <- address saved-self-storage
+593   copy-object saved-self-ah, dest
+594   # self->next = new
+595   dest <- get self, next
+596   copy-object new-ah, dest
+597 }
+598 
+599 fn chain-words _self-ah: (addr handle word), _next: (addr handle word) {
+600   var self-ah/esi: (addr handle word) <- copy _self-ah
+601   var _self/eax: (addr word) <- lookup *self-ah
+602   var self/ecx: (addr word) <- copy _self
+603   var dest/edx: (addr handle word) <- get self, next
+604   var next-ah/edi: (addr handle word) <- copy _next
+605   copy-object next-ah, dest
+606   var next/eax: (addr word) <- lookup *next-ah
+607   compare next, 0
+608   break-if-=
+609   dest <- get next, prev
+610   copy-object self-ah, dest
+611 }
+612 
+613 fn emit-word _self: (addr word), out: (addr stream byte) {
+614   var self/esi: (addr word) <- copy _self
+615   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+616   var data/eax: (addr gap-buffer) <- lookup *data-ah
+617   emit-gap-buffer data, out
+618 }
+619 
+620 fn word-is-decimal-integer? _self: (addr word) -> _/eax: boolean {
+621   var self/eax: (addr word) <- copy _self
+622   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
+623   var data/eax: (addr gap-buffer) <- lookup *data-ah
+624   var result/eax: boolean <- gap-buffer-is-decimal-integer? data
+625   return result
+626 }
+627 
+628 fn word-exists? haystack: (addr word), needle: (addr word) -> _/eax: boolean {
+629   # base case
+630   compare haystack, 0
+631   {
+632     break-if-!=
+633     return 0/false
+634   }
+635   # check current word
+636   var found?/eax: boolean <- words-equal? haystack, needle
+637   compare found?, 0/false
+638   {
+639     break-if-=
+640     return 1/true
+641   }
+642   # recurse
+643   var curr/eax: (addr word) <- copy haystack
+644   var next-ah/eax: (addr handle word) <- get curr, next
+645   var next/eax: (addr word) <- lookup *next-ah
+646   var result/eax: boolean <- word-exists? next, needle
+647   return result
+648 }
+649 
+650 fn test-word-exists? {
+651   var needle-storage: word
+652   var needle/esi: (addr word) <- address needle-storage
+653   initialize-word-with needle, "abc"
+654   var w-storage: (handle word)
+655   var w-ah/edi: (addr handle word) <- address w-storage
+656   allocate w-ah
+657   var _w/eax: (addr word) <- lookup *w-ah
+658   var w/ecx: (addr word) <- copy _w
+659   initialize-word-with w, "aaa"
+660   #
+661   var result/eax: boolean <- word-exists? w, w
+662   check result, "F - test-word-exists? reflexive"
+663   result <- word-exists? w, needle
+664   check-not result, "F - test-word-exists? 1"
+665   append-word-at-end-with w-ah, "bbb"
+666   result <- word-exists? w, needle
+667   check-not result, "F - test-word-exists? 2"
+668   append-word-at-end-with w-ah, "abc"
+669   result <- word-exists? w, needle
+670   check result, "F - test-word-exists? 3"
+671   append-word-at-end-with w-ah, "ddd"
+672   result <- word-exists? w, needle
+673   check result, "F - test-word-exists? 4"
+674 }
+675 
+676 fn word-list-length words: (addr handle word) -> _/eax: int {
+677   var curr-ah/esi: (addr handle word) <- copy words
+678   var result/edi: int <- copy 0
+679   {
+680     var curr/eax: (addr word) <- lookup *curr-ah
+681     compare curr, 0
+682     break-if-=
+683     {
+684       var word-len/eax: int <- word-length curr
+685       result <- add word-len
+686       result <- add 1/inter-word-margin
+687     }
+688     curr-ah <- get curr, next
+689     loop
+690   }
+691   return result
+692 }
+693 
+694 # out-ah already has a word allocated and initialized
+695 fn parse-words in: (addr array byte), out-ah: (addr handle word) {
+696   var in-stream: (stream byte 0x100)
+697   var in-stream-a/esi: (addr stream byte) <- address in-stream
+698   write in-stream-a, in
+699   var cursor-word-ah/ebx: (addr handle word) <- copy out-ah
+700   $parse-words:loop: {
+701     var done?/eax: boolean <- stream-empty? in-stream-a
+702     compare done?, 0/false
+703     break-if-!=
+704     var _g/eax: grapheme <- read-grapheme in-stream-a
+705     var g/ecx: grapheme <- copy _g
+706     # if not space, insert
+707     compare g, 0x20/space
+708     {
+709       break-if-=
+710       var cursor-word/eax: (addr word) <- lookup *cursor-word-ah
+711       add-grapheme-to-word cursor-word, g
+712       loop $parse-words:loop
+713     }
+714     # otherwise insert word after and move cursor to it
+715     append-word cursor-word-ah
+716     var cursor-word/eax: (addr word) <- lookup *cursor-word-ah
+717     cursor-to-start cursor-word  # reset cursor in each function
+718     cursor-word-ah <- get cursor-word, next
+719     loop
+720   }
+721 }
+
+ + + -- cgit 1.4.1-2-gfad0