https://github.com/akkartik/mu/blob/main/baremetal/shell/value-stack.mu
  1 # value stacks encode the result of a program at a single point in time
  2 # they are typically rendered vertically
  3 
  4 type value-stack {
  5   data: (handle array value)
  6   top: int
  7 }
  8 
  9 fn initialize-value-stack _self: (addr value-stack), n: int {
 10   var self/esi: (addr value-stack) <- copy _self
 11   var d/edi: (addr handle array value) <- get self, data
 12   populate d, n
 13   var top/eax: (addr int) <- get self, top
 14   copy-to *top, 0
 15 }
 16 
 17 fn clear-value-stack _self: (addr value-stack) {
 18   var self/esi: (addr value-stack) <- copy _self
 19   var top/eax: (addr int) <- get self, top
 20   copy-to *top, 0
 21 }
 22 
 23 fn push-number-to-value-stack _self: (addr value-stack), _val: float {
 24   var self/esi: (addr value-stack) <- copy _self
 25   var top-addr/ecx: (addr int) <- get self, top
 26   var data-ah/edx: (addr handle array value) <- get self, data
 27   var data/eax: (addr array value) <- lookup *data-ah
 28   var top/edx: int <- copy *top-addr
 29   var dest-offset/edx: (offset value) <- compute-offset data, top
 30   var dest-addr/edx: (addr value) <- index data, dest-offset
 31   var dest-addr2/eax: (addr float) <- get dest-addr, number-data
 32   var val/xmm0: float <- copy _val
 33   copy-to *dest-addr2, val
 34   increment *top-addr
 35   var type-addr/eax: (addr int) <- get dest-addr, type
 36   copy-to *type-addr, 0/number
 37 }
 38 
 39 fn push-int-to-value-stack _self: (addr value-stack), _val: int {
 40   var self/esi: (addr value-stack) <- copy _self
 41   var top-addr/ecx: (addr int) <- get self, top
 42   var data-ah/edx: (addr handle array value) <- get self, data
 43   var data/eax: (addr array value) <- lookup *data-ah
 44   var top/edx: int <- copy *top-addr
 45   var dest-offset/edx: (offset value) <- compute-offset data, top
 46   var dest-addr/edx: (addr value) <- index data, dest-offset
 47   var dest-addr2/eax: (addr float) <- get dest-addr, number-data
 48   var val/xmm0: float <- convert _val
 49   copy-to *dest-addr2, val
 50   increment *top-addr
 51   var type-addr/eax: (addr int) <- get dest-addr, type
 52   copy-to *type-addr, 0/number
 53 }
 54 
 55 fn push-string-to-value-stack _self: (addr value-stack), val: (handle array byte) {
 56   var self/esi: (addr value-stack) <- copy _self
 57   var top-addr/ecx: (addr int) <- get self, top
 58   var data-ah/edx: (addr handle array value) <- get self, data
 59   var data/eax: (addr array value) <- lookup *data-ah
 60   var top/edx: int <- copy *top-addr
 61   var dest-offset/edx: (offset value) <- compute-offset data, top
 62   var dest-addr/edx: (addr value) <- index data, dest-offset
 63   var dest-addr2/eax: (addr handle array byte) <- get dest-addr, text-data
 64   copy-handle val, dest-addr2
 65   var dest-addr3/eax: (addr int) <- get dest-addr, type
 66   copy-to *dest-addr3, 1/string
 67   increment *top-addr
 68 }
 69 
 70 fn push-array-to-value-stack _self: (addr value-stack), val: (handle array value) {
 71   var self/esi: (addr value-stack) <- copy _self
 72   var top-addr/ecx: (addr int) <- get self, top
 73   var data-ah/edx: (addr handle array value) <- get self, data
 74   var data/eax: (addr array value) <- lookup *data-ah
 75   var top/edx: int <- copy *top-addr
 76   var dest-offset/edx: (offset value) <- compute-offset data, top
 77   var dest-addr/edx: (addr value) <- index data, dest-offset
 78   var dest-addr2/eax: (addr handle array value) <- get dest-addr, array-data
 79   copy-handle val, dest-addr2
 80   # update type
 81   var dest-addr3/eax: (addr int) <- get dest-addr, type
 82   copy-to *dest-addr3, 2/array
 83   increment *top-addr
 84 }
 85 
 86 fn push-boolean-to-value-stack _self: (addr value-stack), _val: boolean {
 87   var self/esi: (addr value-stack) <- copy _self
 88   var top-addr/ecx: (addr int) <- get self, top
 89   var data-ah/edx: (addr handle array value) <- get self, data
 90   var data/eax: (addr array value) <- lookup *data-ah
 91   var top/edx: int <- copy *top-addr
 92   var dest-offset/edx: (offset value) <- compute-offset data, top
 93   var dest-addr/edx: (addr value) <- index data, dest-offset
 94   var dest-addr2/eax: (addr boolean) <- get dest-addr, boolean-data
 95   var val/esi: boolean <- copy _val
 96   copy-to *dest-addr2, val
 97   increment *top-addr
 98   var type-addr/eax: (addr int) <- get dest-addr, type
 99   copy-to *type-addr, 3/boolean
100 }
101 
102 fn push-value-stack _self: (addr value-stack), val: (addr value) {
103   var self/esi: (addr value-stack) <- copy _self
104   var top-addr/ecx: (addr int) <- get self, top
105   var data-ah/edx: (addr handle array value) <- get self, data
106   var data/eax: (addr array value) <- lookup *data-ah
107   var top/edx: int <- copy *top-addr
108   var dest-offset/edx: (offset value) <- compute-offset data, top
109   var dest-addr/edx: (addr value) <- index data, dest-offset
110   copy-object val, dest-addr
111   increment *top-addr
112 }
113 
114 fn pop-number-from-value-stack _self: (addr value-stack) -> _/xmm0: float {
115   var self/esi: (addr value-stack) <- copy _self
116   var top-addr/ecx: (addr int) <- get self, top
117   {
118     compare *top-addr, 0
119     break-if->
120     abort "pop number: empty stack"
121   }
122   decrement *top-addr
123   var data-ah/edx: (addr handle array value) <- get self, data
124   var data/eax: (addr array value) <- lookup *data-ah
125   var top/edx: int <- copy *top-addr
126   var dest-offset/edx: (offset value) <- compute-offset data, top
127   var result-addr/eax: (addr value) <- index data, dest-offset
128   var result-addr2/eax: (addr float) <- get result-addr, number-data
129   return *result-addr2
130 }
131 
132 fn pop-boolean-from-value-stack _self: (addr value-stack) -> _/eax: boolean {
133   var self/esi: (addr value-stack) <- copy _self
134   var top-addr/ecx: (addr int) <- get self, top
135   {
136     compare *top-addr, 0
137     break-if->
138     abort "pop boolean: empty stack"
139   }
140   decrement *top-addr
141   var data-ah/edx: (addr handle array value) <- get self, data
142   var data/eax: (addr array value) <- lookup *data-ah
143   var top/edx: int <- copy *top-addr
144   var dest-offset/edx: (offset value) <- compute-offset data, top
145   var result-addr/eax: (addr value) <- index data, dest-offset
146   var result-addr2/eax: (addr boolean) <- get result-addr, boolean-data
147   return *result-addr2
148 }
149 
150 fn value-stack-empty? _self: (addr value-stack) -> _/eax: boolean {
151   var self/esi: (addr value-stack) <- copy _self
152   var top/eax: (addr int) <- get self, top
153   compare *top, 0
154   {
155     break-if-!=
156     return 1/true
157   }
158   return 0/false
159 }
160 
161 fn value-stack-length _self: (addr value-stack) -> _/eax: int {
162   var self/esi: (addr value-stack) <- copy _self
163   var top-addr/eax: (addr int) <- get self, top
164   return *top-addr
165 }
166 
167 fn test-boolean {
168   var stack-storage: value-stack
169   var stack/esi: (addr value-stack) <- address stack-storage
170   push-boolean-to-value-stack stack, 0/false
171   var result/eax: boolean <- pop-boolean-from-value-stack stack
172   check-not result, "F - test-boolean/false"
173   push-boolean-to-value-stack stack, 1/true
174   var result/eax: boolean <- pop-boolean-from-value-stack stack
175   check result, "F - test-boolean/true"
176 }
177 
178 fn dump-stack _self: (addr value-stack) {
179   var self/esi: (addr value-stack) <- copy _self
180   var data-ah/eax: (addr handle array value) <- get self, data
181   var _data/eax: (addr array value) <- lookup *data-ah
182   var data/edi: (addr array value) <- copy _data
183   var top-addr/ecx: (addr int) <- get self, top
184   var top/ecx: int <- copy *top-addr
185   top <- decrement
186   var y/edx: int <- copy 0xa
187   var dummy/eax: int <- draw-text-rightward-over-full-screen 0/screen, "==", 0/x, 9/y, 0xc/red, 0/bg
188   {
189     compare top, 0
190     break-if-<
191     var dest-offset/eax: (offset value) <- compute-offset data, top
192     var curr/eax: (addr value) <- index data, dest-offset
193     var dummy/eax: int <- render-value 0/screen, curr, 0/x, y, 0/no-color
194     top <- decrement
195     y <- increment
196     loop
197   }
198 }
199 
200 fn render-value-stack screen: (addr screen), _self: (addr value-stack), x: int, y: int -> _/eax: int, _/ecx: int {
201   var self/ecx: (addr value-stack) <- copy _self
202   var data-ah/eax: (addr handle array value) <- get self, data
203   var _data/eax: (addr array value) <- lookup *data-ah
204   var data/edi: (addr array value) <- copy _data
205   var top-addr/eax: (addr int) <- get self, top
206   var curr-idx/ecx: int <- copy *top-addr
207   curr-idx <- decrement
208   var new-x/edx: int <- copy 0
209   {
210     compare curr-idx, 0
211     break-if-<
212     var dest-offset/eax: (offset value) <- compute-offset data, curr-idx
213     var curr/eax: (addr value) <- index data, dest-offset
214     var curr-x/eax: int <- render-value screen, curr, x, y, 1/top-level
215     {
216       compare curr-x, new-x
217       break-if-<=
218       new-x <- copy curr-x
219     }
220     curr-idx <- decrement
221     increment y
222     loop
223   }
224   return new-x, y
225 }
226 
227 fn test-render-value-stack {
228   var stack-storage: value-stack
229   var stack/esi: (addr value-stack) <- address stack-storage
230   push-int-to-value-stack stack, 3
231   # setup: screen
232   var screen-on-stack: screen
233   var screen/edi: (addr screen) <- address screen-on-stack
234   initialize-screen screen, 0x20, 4
235   #
236   var final-x/eax: int <- copy 0
237   var final-y/ecx: int <- copy 0
238   final-x, final-y <- render-value-stack screen, stack, 0/x, 0/y
239   check-ints-equal final-y, 1, "F - test-render-value-stack y"
240   check-ints-equal final-x, 3, "F - test-render-value-stack x"
241 }