fn render-value-at screen: (addr screen), row: int, col: int, _val: (addr value), max-width: int { move-cursor screen, row, col var val/esi: (addr value) <- copy _val var val-type/ecx: (addr int) <- get val, type # per-type rendering logic goes here compare *val-type, 1 # string { break-if-!= var val-ah/eax: (addr handle array byte) <- get val, text-data var val-string/eax: (addr array byte) <- lookup *val-ah compare val-string, 0 break-if-= var orig-len/ecx: int <- length val-string var truncated: (handle array byte) var truncated-ah/esi: (addr handle array byte) <- address truncated substring val-string, 0, 0xc, truncated-ah var truncated-string/eax: (addr array byte) <- lookup *truncated-ah var len/edx: int <- length truncated-string start-color screen, 0xf2, 7 print-code-point screen, 0x275d # open-quote print-string screen, truncated-string compare len, orig-len { break-if-= print-code-point screen, 0x2026 # ellipses } print-code-point screen, 0x275e # close-quote reset-formatting screen return } compare *val-type, 2 # array { break-if-!= var val-ah/eax: (addr handle array value) <- get val, array-data var val-array/eax: (addr array value) <- lookup *val-ah render-array-at screen, row, col, val-array return } compare *val-type, 3 # file { break-if-!= var val-ah/eax: (addr handle buffered-file) <- get val, file-data var val-file/eax: (addr buffered-file) <- lookup *val-ah start-color screen, 0, 7 # TODO print-string screen, " FILE " return } compare *val-type, 4 # screen { break-if-!= #? print-string 0, "render-screen" var val-ah/eax: (addr handle screen) <- get val, screen-data var val-screen/eax: (addr screen) <- lookup *val-ah render-screen screen, row, col, val-screen #? print-string 0, "}\n" return } # render ints by default for now var val-int/eax: (addr int) <- get val, int-data render-integer screen, *val-int, max-width } # synaesthesia fn render-integer screen: (addr screen), val: int, max-width: int { # if max-width is 0, we're inside an array. No coloring. compare max-width, 0 { break-if-!= print-int32-decimal screen, val return } var bg/eax: int <- hash-color val var fg/ecx: int <- copy 7 { compare bg, 2 break-if-!= fg <- copy 0 } { compare bg, 3 break-if-!= fg <- copy 0 } { compare bg, 6 break-if-!= fg <- copy 0 } start-color screen, fg, bg print-grapheme screen, 0x20 # space print-int32-decimal-right-justified screen, val, max-width print-grapheme screen, 0x20 # space } fn render-array-at screen: (addr screen), row: int, col: int, _a: (addr array value) { start-color screen, 0xf2, 7 # don't surround in spaces print-grapheme screen, 0x5b # '[' increment col var a/esi: (addr array value) <- copy _a var max/ecx: int <- length a var i/eax: int <- copy 0 { compare i, max break-if->= { compare i, 0 break-if-= print-string screen, " " } var off/ecx: (offset value) <- compute-offset a, i var x/ecx: (addr value) <- index a, off render-value-at screen, row, col, x, 0 { var w/eax: int <- value-width x, 0 add-to col, w increment col } i <- increment loop } print-grapheme screen, 0x5d # ']' } fn render-screen screen: (addr screen), row: int, col: int, _target-screen: (addr screen) { reset-formatting screen move-cursor screen, row, col var target-screen/esi: (addr screen) <- copy _target-screen var ncols-a/ecx: (addr int) <- get target-screen, num-cols print-upper-border screen, *ncols-a var r/edx: int <- copy 1 var nrows-a/ebx: (addr int) <- get target-screen, num-rows { compare r, *nrows-a break-if-> increment row # mutate arg move-cursor screen, row, col print-string screen, " " var c/edi: int <- copy 1 { compare c, *ncols-a break-if-> print-screen-cell-of-fake-screen screen, target-screen, r, c c <- increment loop } print-string screen, " " r <- increment loop } increment row # mutate arg move-cursor screen, row, col print-lower-border screen, *ncols-a } fn hash-color val: int -> _/eax: int { var quotient/eax: int <- copy 0 var remainder/edx: int <- copy 0 quotient, remainder <- integer-divide val, 7 # assumes that 7 is always the background color return remainder } fn print-screen-cell-of-fake-screen screen: (addr screen), _target: (addr screen), _row: int, _col: int { start-color screen, 0, 0xf6 var target/esi: (addr screen) <- copy _target var row/ecx: int <- copy _row var col/edx: int <- copy _col # if cursor is at screen-cell, add some fancy { var cursor-row/eax: (addr int) <- get target, cursor-row compare *cursor-row, row break-if-!= var cursor-col/eax: (addr int) <- get target, cursor-col compare *cursor-col, col break-if-!= start-blinking screen start-color screen, 0, 1 } var g/eax: grapheme <- screen-grapheme-at target, row, col { compare g, 0 break-if-!= g <- copy 0x20 # space } print-grapheme screen, g reset-formatting screen } fn print-upper-border screen: (addr screen), width: int { print-code-point screen, 0x250c # top-left corner var i/eax: int <- copy 0 { compare i, width break-if->= print-code-point screen, 0x2500 # horizontal line i <- increment loop } print-code-point screen, 0x2510 # top-right corner } fn print-lower-border screen: (addr screen), width: int { print-code-point screen, 0x2514 # bottom-left corner var i/eax: int <- copy 0 { compare i, width break-if->= print-code-point screen, 0x2500 # horizontal line i <- increment loop } print-code-point screen, 0x2518 # bottom-right corner } fn value-width _v: (addr value), top-level: boolean -> _/eax: int { var v/esi: (addr value) <- copy _v var type/eax: (addr int) <- get v, type { compare *type, 0 # int break-if-!= var v-int/edx: (addr int) <- get v, int-data var result/eax: int <- decimal-size *v-int return result } { compare *type, 1 # string break-if-!= var s-ah/eax: (addr handle array byte) <- get v, text-data var s/eax: (addr array byte) <- lookup *s-ah compare s, 0 break-if-= var result/eax: int <- length s compare result, 0xd # max string size { break-if-<= result <- copy 0xd } # if it's a nested string, include space for quotes # we don't do this for the top-level, where the quotes will overflow # into surrounding padding. compare top-level, 0 # false { break-if-!= result <- add 2 } return result } { compare *type, 2 # array break-if-!= var a-ah/eax: (addr handle array value) <- get v, array-data var a/eax: (addr array value) <- lookup *a-ah compare a, 0 break-if-= var result/eax: int <- array-width a return result } { compare *type, 3 # file handle break-if-!= var f-ah/eax: (addr handle buffered-file) <- get v, file-data var f/eax: (addr buffered-file) <- lookup *f-ah compare f, 0 break-if-= # TODO: visualizing file handles return 4 } { compare *type, 4 # screen break-if-!= var screen-ah/eax: (addr handle screen) <- get v, screen-data var screen/eax: (addr screen) <- lookup *screen-ah compare screen, 0 break-if-= var ncols/ecx: (addr int) <- get screen, num-cols var result/eax: int <- copy *ncols result <- add 2 # left/right margins return *ncols } return 0 } # keep sync'd with render-array-at fn array-width _a: (addr array value) -> _/eax: int { var a/esi: (addr array value) <- copy _a var max/ecx: int <- length a var i/eax: int <- copy 0 var result/edi: int <- copy 0 { compare i, max break-if->= { compare i, 0 break-if-= result <- increment # for space } var off/ecx: (offset value) <- compute-offset a, i var x/ecx: (addr value) <- index a, off { var w/eax: int <- value-width x, 0 result <- add w } i <- increment loop } # we won't add 2 for surrounding brackets since we don't surround arrays in # spaces like other value types return result } fn value-height _v: (addr value) -> _/eax: int { var v/esi: (addr value) <- copy _v var type/eax: (addr int) <- get v, type { compare *type, 3 # file handle break-if-!= # TODO: visualizing file handles return 1 } { compare *type, 4 # screen break-if-!= var screen-ah/eax: (addr handle screen) <- get v, screen-data var screen/eax: (addr screen) <- lookup *screen-ah compare screen, 0 break-if-= var nrows/ecx: (addr int) <- get screen, num-rows var result/eax: int <- copy *nrows result <- add 2 # top and bottom border return result } return 1 } fn deep-copy-value _src: (addr value), _dest: (addr value) { #? print-string 0, "deep-copy-value\n" var src/esi: (addr value) <- copy _src var dest/edi: (addr value) <- copy _dest var type/ebx: (addr int) <- get src, type var y/ecx: (addr int) <- get dest, type copy-object type, y compare *type, 0 # int { break-if-!= #? print-string 0, "int value\n" var x/eax: (addr int) <- get src, int-data y <- get dest, int-data copy-object x, y return } compare *type, 1 # string { break-if-!= #? print-string 0, "string value\n" var src-ah/eax: (addr handle array byte) <- get src, text-data var src/eax: (addr array byte) <- lookup *src-ah var dest-ah/edx: (addr handle array byte) <- get dest, text-data copy-array-object src, dest-ah return } compare *type, 2 # array { break-if-!= #? print-string 0, "array value\n" var src-ah/eax: (addr handle array value) <- get src, array-data var _src/eax: (addr array value) <- lookup *src-ah var src/esi: (addr array value) <- copy _src var n/ecx: int <- length src var dest-ah/edx: (addr handle array value) <- get dest, array-data populate dest-ah, n var _dest/eax: (addr array value) <- lookup *dest-ah var dest/edi: (addr array value) <- copy _dest var i/eax: int <- copy 0 { compare i, n break-if->= { var offset/edx: (offset value) <- compute-offset src, i var src-element/eax: (addr value) <- index src, offset var dest-element/ecx: (addr value) <- index dest, offset deep-copy-value src-element, dest-element } i <- increment loop } copy-array-object src, dest-ah return } compare *type, 3 # file { break-if-!= #? print-string 0, "file value\n" var src-filename-ah/eax: (addr handle array byte) <- get src, filename var _src-filename/eax: (addr array byte) <- lookup *src-filename-ah var src-filename/ecx: (addr array byte) <- copy _src-filename var dest-filename-ah/ebx: (addr handle array byte) <- get dest, filename copy-array-object src-filename, dest-filename-ah var src-file-ah/eax: (addr handle buffered-file) <- get src, file-data var src-file/eax: (addr buffered-file) <- lookup *src-file-ah var dest-file-ah/edx: (addr handle buffered-file) <- get dest, file-data copy-file src-file, dest-file-ah, src-filename return } compare *type, 4 # screen { break-if-!= #? print-string 0, "screen value\n" var src-screen-ah/eax: (addr handle screen) <- get src, screen-data var _src-screen/eax: (addr screen) <- lookup *src-screen-ah var src-screen/ecx: (addr screen) <- copy _src-screen var dest-screen-ah/eax: (addr handle screen) <- get dest, screen-data allocate dest-screen-ah var dest-screen/eax: (addr screen) <- lookup *dest-screen-ah copy-object src-screen, dest-screen var dest-screen-data-ah/ebx: (addr handle array screen-cell) <- get dest-screen, data var src-screen-data-ah/eax: (addr handle array screen-cell) <- get src-screen, data var src-screen-data/eax: (addr array screen-cell) <- lookup *src-screen-data-ah copy-array-object src-screen-data, dest-screen-data-ah return } }