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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
|
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-num/eax: (addr float) <- get val, number-data
render-number screen, *val-num, max-width
}
# synaesthesia
# TODO: right-justify
fn render-number screen: (addr screen), val: float, max-width: int {
# if max-width is 0, we're inside an array. No coloring.
compare max-width, 0
{
break-if-!=
print-float-decimal-approximate screen, val, 3
return
}
var val-int/eax: int <- convert val
var bg/eax: int <- hash-color val-int
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-float-decimal-approximate screen, val, 3
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-num/edx: (addr float) <- get v, number-data
var result/eax: int <- float-size *v-num, 3
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 src-n/eax: (addr float) <- get src, number-data
var dest-n/ecx: (addr float) <- get dest, number-data
copy-object src-n, dest-n
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
}
}
|