# value stacks encode the result of a program at a single point in time # they are typically rendered vertically type value-stack { data: (handle array value) top: int } fn initialize-value-stack _self: (addr value-stack), n: int { var self/esi: (addr value-stack) <- copy _self var d/edi: (addr handle array value) <- get self, data populate d, n var top/eax: (addr int) <- get self, top copy-to *top, 0 } fn clear-value-stack _self: (addr value-stack) { var self/esi: (addr value-stack) <- copy _self var top/eax: (addr int) <- get self, top copy-to *top, 0 } fn push-number-to-value-stack _self: (addr value-stack), _val: float { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset var dest-addr2/eax: (addr float) <- get dest-addr, number-data var val/xmm0: float <- copy _val copy-to *dest-addr2, val increment *top-addr var type-addr/eax: (addr int) <- get dest-addr, type copy-to *type-addr, 0/number } fn push-int-to-value-stack _self: (addr value-stack), _val: int { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset var dest-addr2/eax: (addr float) <- get dest-addr, number-data var val/xmm0: float <- convert _val copy-to *dest-addr2, val increment *top-addr var type-addr/eax: (addr int) <- get dest-addr, type copy-to *type-addr, 0/number } fn push-string-to-value-stack _self: (addr value-stack), val: (handle array byte) { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset var dest-addr2/eax: (addr handle array byte) <- get dest-addr, text-data copy-handle val, dest-addr2 var dest-addr3/eax: (addr int) <- get dest-addr, type copy-to *dest-addr3, 1/string increment *top-addr } fn push-array-to-value-stack _self: (addr value-stack), val: (handle array value) { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset var dest-addr2/eax: (addr handle array value) <- get dest-addr, array-data copy-handle val, dest-addr2 # update type var dest-addr3/eax: (addr int) <- get dest-addr, type copy-to *dest-addr3, 2/array increment *top-addr } fn push-boolean-to-value-stack _self: (addr value-stack), _val: boolean { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset var dest-addr2/eax: (addr boolean) <- get dest-addr, boolean-data var val/esi: boolean <- copy _val copy-to *dest-addr2, val increment *top-addr var type-addr/eax: (addr int) <- get dest-addr, type copy-to *type-addr, 3/boolean } fn push-value-stack _self: (addr value-stack), val: (addr value) { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var dest-addr/edx: (addr value) <- index data, dest-offset copy-object val, dest-addr increment *top-addr } fn pop-number-from-value-stack _self: (addr value-stack) -> _/xmm0: float { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top { compare *top-addr, 0 break-if-> abort "pop number: empty stack" } decrement *top-addr var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var result-addr/eax: (addr value) <- index data, dest-offset var result-addr2/eax: (addr float) <- get result-addr, number-data return *result-addr2 } fn pop-boolean-from-value-stack _self: (addr value-stack) -> _/eax: boolean { var self/esi: (addr value-stack) <- copy _self var top-addr/ecx: (addr int) <- get self, top { compare *top-addr, 0 break-if-> abort "pop boolean: empty stack" } decrement *top-addr var data-ah/edx: (addr handle array value) <- get self, data var data/eax: (addr array value) <- lookup *data-ah var top/edx: int <- copy *top-addr var dest-offset/edx: (offset value) <- compute-offset data, top var result-addr/eax: (addr value) <- index data, dest-offset var result-addr2/eax: (addr boolean) <- get result-addr, boolean-data return *result-addr2 } fn value-stack-empty? _self: (addr value-stack) -> _/eax: boolean { var self/esi: (addr value-stack) <- copy _self var top/eax: (addr int) <- get self, top compare *top, 0 { break-if-!= return 1/true } return 0/false } fn value-stack-length _self: (addr value-stack) -> _/eax: int { var self/esi: (addr value-stack) <- copy _self var top-addr/eax: (addr int) <- get self, top return *top-addr } fn test-boolean { var stack-storage: value-stack var stack/esi: (addr value-stack) <- address stack-storage push-boolean-to-value-stack stack, 0/false var result/eax: boolean <- pop-boolean-from-value-stack stack check-not result, "F - test-boolean/false" push-boolean-to-value-stack stack, 1/true var result/eax: boolean <- pop-boolean-from-value-stack stack check result, "F - test-boolean/true" } fn dump-stack _self: (addr value-stack) { var self/esi: (addr value-stack) <- copy _self var data-ah/eax: (addr handle array value) <- get self, data var _data/eax: (addr array value) <- lookup *data-ah var data/edi: (addr array value) <- copy _data var top-addr/ecx: (addr int) <- get self, top var top/ecx: int <- copy *top-addr top <- decrement var y/edx: int <- copy 0xa var dummy/eax: int <- draw-text-rightward-over-full-screen 0/screen, "==", 0/x, 9/y, 0xc/red, 0/bg { compare top, 0 break-if-< var dest-offset/eax: (offset value) <- compute-offset data, top var curr/eax: (addr value) <- index data, dest-offset var dummy/eax: int <- render-value 0/screen, curr, 0/x, y, 0/no-color top <- decrement y <- increment loop } } fn render-value-stack screen: (addr screen), _self: (addr value-stack), x: int, y: int -> _/eax: int, _/ecx: int { var self/ecx: (addr value-stack) <- copy _self var data-ah/eax: (addr handle array value) <- get self, data var _data/eax: (addr array value) <- lookup *data-ah var data/edi: (addr array value) <- copy _data var top-addr/eax: (addr int) <- get self, top var curr-idx/ecx: int <- copy *top-addr curr-idx <- decrement var new-x/edx: int <- copy 0 { compare curr-idx, 0 break-if-< var dest-offset/eax: (offset value) <- compute-offset data, curr-idx var curr/eax: (addr value) <- index data, dest-offset var curr-x/eax: int <- render-value screen, curr, x, y, 1/top-level { compare curr-x, new-x break-if-<= new-x <- copy curr-x } curr-idx <- decrement increment y loop } return new-x, y } fn test-render-value-stack { var stack-storage: value-stack var stack/esi: (addr value-stack) <- address stack-storage push-int-to-value-stack stack, 3 # setup: screen var screen-on-stack: screen var screen/edi: (addr screen) <- address screen-on-stack initialize-screen screen, 0x20, 4 # var final-x/eax: int <- copy 0 var final-y/ecx: int <- copy 0 final-x, final-y <- render-value-stack screen, stack, 0/x, 0/y check-ints-equal final-y, 1, "F - test-render-value-stack y" check-ints-equal final-x, 3, "F - test-render-value-stack x" }