about summary refs log tree commit diff stats
path: root/baremetal/shell/value.mu
blob: 5b5ec1429b1ee0425db1c6ae31f974681f474ad2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# todo: turn this into a sum type
type value {
  type: int
  number-data: float  # if type = 0
  text-data: (handle array byte)  # if type = 1
  array-data: (handle array value)  # if type = 2
  boolean-data: boolean  # if type = 3
}

# top-level? is a hack just for numbers
# we'll eventually need to return a y coordinate as well to render 2D values
fn render-value screen: (addr screen), _val: (addr value), x: int, y: int, top-level?: boolean -> _/eax: int {
  var val/esi: (addr value) <- copy _val
  var val-type/ecx: (addr int) <- get val, type
  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
    var val-string/ecx: (addr array byte) <- copy _val-string
    var new-x/eax: int <- render-string screen, val-string, x, y
    return new-x
  }
  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
    var val-array/edx: (addr array value) <- copy _val-array
    var new-x/eax: int <- render-array screen, val-array, x, y
    return new-x
  }
  compare *val-type, 3/boolean
  {
    break-if-!=
    var val/eax: (addr boolean) <- get val, boolean-data
    var new-x/eax: int <- render-boolean screen, *val, x, y
    return new-x
  }
  # render ints by default for now
  var val-num/eax: (addr float) <- get val, number-data
  var new-x/eax: int <- render-number screen, *val-num, x, y, top-level?
  return new-x
}

fn initialize-value-with-integer _self: (addr value), n: int {
  var self/esi: (addr value) <- copy _self
  var type/eax: (addr int) <- get self, type
  copy-to *type, 0/number
  var val/xmm0: float <- convert n
  var dest/eax: (addr float) <- get self, number-data
  copy-to *dest, val
}

fn initialize-value-with-float _self: (addr value), n: float {
  var self/esi: (addr value) <- copy _self
  var type/eax: (addr int) <- get self, type
  copy-to *type, 0/number
  var val/xmm0: float <- copy n
  var dest/eax: (addr float) <- get self, number-data
  copy-to *dest, val
}

# synaesthesia
# TODO: right-justify
fn render-number screen: (addr screen), val: float, x: int, y: int, top-level?: boolean -> _/eax: int {
  # if we're inside an array, don't color
  compare top-level?, 0
  {
    break-if-!=
    var new-x/eax: int <- render-float-decimal screen, val, 3/precision, x, y, 3/fg, 0/bg
    return new-x
  }
  var val-int/eax: int <- convert val
  var _bg/eax: int <- hash-color val-int
  var bg/ecx: int <- copy _bg
  var fg/edx: 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
  }
  draw-code-point screen, 0x20/space, x, y, fg, bg
  increment x
  var new-x/eax: int <- render-float-decimal screen, val, 3/precision, x, y, fg, bg
  draw-code-point screen, 0x20/space, new-x, y, fg, bg
  new-x <- increment
  return new-x
}

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 test-render-number {
  # setup: screen
  var screen-on-stack: screen
  var screen/edi: (addr screen) <- address screen-on-stack
  initialize-screen screen, 0x20, 4
  # integers render with some padding spaces
  var new-x/eax: int <- render-number screen, 0/n, 0/x, 0/y, 1/at-top-level
  check-screen-row screen, 0/y, " 0 ", "F - test-render-number"
  check-ints-equal new-x, 3, "F - test-render-number: result"
  # we won't bother testing the background colors; lots of flexibility there
}

fn initialize-value-with-string _self: (addr value), s: (addr array byte) {
  var self/esi: (addr value) <- copy _self
  var type/eax: (addr int) <- get self, type
  copy-to *type, 1/string
  var dest/eax: (addr handle array byte) <- get self, text-data
  copy-array-object s, dest
}

fn render-string screen: (addr screen), _val: (addr array byte), x: int, y: int -> _/eax: int {
  var val/esi: (addr array byte) <- copy _val
  compare val, 0
  {
    break-if-!=
    return x
  }
  var orig-len/ecx: int <- length val
  # truncate to 12 graphemes
  # TODO: more sophisticated interactive rendering
  var truncated: (handle array byte)
  var truncated-ah/eax: (addr handle array byte) <- address truncated
  substring val, 0, 0xc, truncated-ah
  var _truncated-string/eax: (addr array byte) <- lookup *truncated-ah
  var truncated-string/edx: (addr array byte) <- copy _truncated-string
  var len/ebx: int <- length truncated-string
  draw-code-point screen, 0x22/double-quote, x, y, 7/fg, 0/bg
  increment x
  var new-x/eax: int <- draw-text-rightward-over-full-screen screen, truncated-string, x, y, 7/fg, 0/bg
  compare len, orig-len
  {
    break-if-=
    new-x <- draw-text-rightward-over-full-screen screen, "...", new-x, y, 7/fg, 0/bg
  }
  draw-code-point screen, 0x22/double-quote, new-x, y, 7/fg, 0/bg
  new-x <- increment
  return new-x
}

fn test-render-string {
  # setup: screen
  var screen-on-stack: screen
  var screen/edi: (addr screen) <- address screen-on-stack
  initialize-screen screen, 0x20, 4
  # strings render with quotes
  var new-x/eax: int <- render-string screen, "abc", 0/x, 0/y
  check-screen-row screen, 0/y, "\"abc\"", "F - test-render-string"
  check-ints-equal new-x, 5, "F - test-render-string: result"
}

fn initialize-value-with-array-of-integers _self: (addr value), s: (addr array byte) {
  # parse s into a temporary array of ints
  var tmp-storage: (handle array int)
  var tmp-ah/eax: (addr handle array int) <- address tmp-storage
  parse-array-of-decimal-ints s, tmp-ah  # leak
  var _tmp/eax: (addr array int ) <- lookup *tmp-ah
  var tmp/esi: (addr array int ) <- copy _tmp
  # load the array into values
  var self/edi: (addr value) <- copy _self
  var type/eax: (addr int) <- get self, type
  copy-to *type, 2/string
  var dest-array-ah/eax: (addr handle array value) <- get self, array-data
  var len/ebx: int <- length tmp
  populate dest-array-ah, len
  var _dest-array/eax: (addr array value) <- lookup *dest-array-ah
  var dest-array/edi: (addr array value) <- copy _dest-array
  var i/eax: int <- copy 0
  {
    compare i, len
    break-if->=
    var src-addr/ecx: (addr int) <- index tmp, i
    var src/ecx: int <- copy *src-addr
    var src-f/xmm0: float <- convert src
    var dest-offset/edx: (offset value) <- compute-offset dest-array, i
    var dest-val/edx: (addr value) <- index dest-array, dest-offset
    var dest/edx: (addr float) <- get dest-val, number-data
    copy-to *dest, src-f
    i <- increment
    loop
  }
}

fn render-array screen: (addr screen), _arr: (addr array value), x: int, y: int -> _/eax: int {
  # don't surround in spaces
  draw-code-point screen, 0x5b/open-bracket, x, y, 7/fg, 0/bg
  increment x
  var arr/esi: (addr array value) <- copy _arr
  var max/ecx: int <- length arr
  var i/edx: int <- copy 0
  var new-x/eax: int <- copy x
  {
    compare i, max
    break-if->=
    {
      compare i, 0
      break-if-=
      draw-code-point screen, 0x20/space, new-x, y, 7/fg, 0/bg
      new-x <- increment
    }
    var off/ecx: (offset value) <- compute-offset arr, i
    var x/ecx: (addr value) <- index arr, off
    new-x <- render-value screen, x, new-x, y, 0/nested
    i <- increment
    loop
  }
  draw-code-point screen, 0x5d/close-bracket, new-x, y, 7/fg, 0/bg
  new-x <- increment
  return new-x
}

fn test-render-array {
  # setup: screen
  var screen-on-stack: screen
  var screen/edi: (addr screen) <- address screen-on-stack
  initialize-screen screen, 0x20, 4
  #
  var val-storage: value
  var val/eax: (addr value) <- address val-storage
  initialize-value-with-array-of-integers val, "0 1 2"
  var val-array-ah/eax: (addr handle array value) <- get val, array-data
  var val-array/eax: (addr array value) <- lookup *val-array-ah
  var new-x/eax: int <- render-array screen, val-array, 0/x, 0/y
  check-screen-row screen, 0/y, "[0 1 2]", "F - test-render-array"
  check-ints-equal new-x, 7, "F - test-render-array: result"
}

fn initialize-value-with-boolean _self: (addr value), _b: boolean {
  var self/esi: (addr value) <- copy _self
  var type/eax: (addr int) <- get self, type
  copy-to *type, 3/boolean
  var dest/edi: (addr boolean) <- get self, boolean-data
  var b/esi: boolean <- copy _b
  copy-to *dest, b
}

fn render-boolean screen: (addr screen), val: boolean, x: int, y: int -> _/eax: int {
  var new-x/eax: int <- copy 0
  compare val, 0/false
  {
    break-if-=
    new-x <- draw-text-rightward-over-full-screen screen, "true", new-x, y, 7/fg, 0/bg
    return new-x
  }
  new-x <- draw-text-rightward-over-full-screen screen, "false", new-x, y, 7/fg, 0/bg
  return new-x
}