complete the skeleton of dquotes.subx

Still some failing tests:
  - emit-string-literal-data doesn't ignore metadata when computing the
    length of literal strings
  - emit-string-literal-data doesn't handle escape sequences

One issue doesn't have a failing test:
  - emit-metadata doesn't handle string literals containing '/'

All these open issues involve a common design question: how to parse a
'word' that includes a string literal that may include spaces.

For everything else I know words can't contain spaces and datums can't
contain slashes. But for string literals things are tougher.
This commit is contained in:
Kartik Agaram 2019-05-15 23:47:12 -07:00
parent 50581f2a0e
commit 438e5a0db0
12 changed files with 210 additions and 49 deletions

View File

@ -151,8 +151,9 @@ _test-stream:
# current read index
0/imm32
# length
8/imm32
# data
00 00 00 00 00 00 00 00 # 8 bytes
0x10/imm32
# data (2 lines x 8 bytes/line)
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
# . . vim:nowrap:textwidth=0

View File

@ -6,7 +6,7 @@
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
#? Entry: # run a single test, while debugging
#? e8/call test-print-int32-buffered/disp32
#? e8/call test-print-int32/disp32
#? # syscall(exit, Num-test-failures)
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
#? b8/copy-to-EAX 1/imm32/exit
@ -171,8 +171,97 @@ test-print-byte-buffered:
# . end
c3/return
print-int32: # f : (address stream), n : int -> <void>
# pseudocode:
# write(f, "0x")
# ECX = 28
# while true
# if (ECX < 0) break
# EAX = n >> ECX
# EAX = EAX & 0xf
# append-byte(f, AL)
# ECX -= 4
#
# . prolog
55/push-EBP
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
# . save registers
50/push-EAX
51/push-ECX
# ECX = 28
b9/copy-to-ECX 0x1c/imm32
$print-int32:print-hex-prefix:
# write(f, "0x")
# . . push args
68/push "0x"/imm32
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
$print-int32:loop:
# if (ECX < 0) break
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX
7c/jump-if-lesser $print-int32:end/disp8
# EAX = n >> ECX
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX
d3/>>ECX 5/subop/pad-zeroes 3/mod/direct 0/rm32/EAX . . . . . . # shift EAX right by ECX bits, padding zeroes
# EAX = to-hex-char(AL)
25/and-EAX 0xf/imm32
e8/call to-hex-char/disp32
# append-byte(f, AL)
# . . push args
50/push-EAX
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call append-byte/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# ECX -= 4
81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # subtract from ECX
eb/jump $print-int32:loop/disp8
$print-int32:end:
# . restore registers
59/pop-to-ECX
58/pop-to-EAX
# . epilog
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
5d/pop-to-EBP
c3/return
test-print-int32:
# - check that print-int32 prints the hex textual representation
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# print-int32(_test-stream, 0x8899aa)
# . . push args
68/push 0x8899aa/imm32
68/push _test-stream/imm32
# . . call
e8/call print-int32/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# check-stream-equal(_test-stream, "0x008899aa", msg)
# . . push args
68/push "F - test-print-int32"/imm32
68/push "0x008899aa"/imm32
68/push _test-stream/imm32
# . . call
e8/call check-stream-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . end
c3/return
print-int32-buffered: # f : (address buffered-file), n : int -> <void>
# pseudocode:
# write-buffered(f, "0x")
# ECX = 28
# while true
# if (ECX < 0) break
@ -189,6 +278,15 @@ print-int32-buffered: # f : (address buffered-file), n : int -> <void>
51/push-ECX
# ECX = 28
b9/copy-to-ECX 0x1c/imm32
$print-int32-buffered:print-hex-prefix:
# write-buffered(f, "0x")
# . . push args
68/push "0x"/imm32
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call write-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
$print-int32-buffered:loop:
# if (ECX < 0) break
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX
@ -271,10 +369,10 @@ test-print-int32-buffered:
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# check-stream-equal(_test-stream, "008899aa", msg)
# check-stream-equal(_test-stream, "0x008899aa", msg)
# . . push args
68/push "F - test-print-int32-buffered"/imm32
68/push "008899aa"/imm32
68/push "0x008899aa"/imm32
68/push _test-stream/imm32
# . . call
e8/call check-stream-equal/disp32

View File

@ -629,13 +629,19 @@ allocated memory for it.)_
* `append-byte`: int -> stream
- Will abort the entire program if there isn't enough room.
* `append-byte-hex`: int -> stream
- textual representation in hex, no '0x' prefix
- Will abort the entire program if there isn't enough room.
* `print-int32`: int -> stream
- textual representation in hex, including '0x' prefix
- Will abort the entire program if there isn't enough room.
* `write-buffered`: string -> buffered-file
* `write-slice-buffered`: slice -> buffered-file
* `flush`: buffered-file
* `write-byte-buffered`: int -> buffered-file
* `print-byte-buffered`: int -> buffered-file
- textual representation in hex
- textual representation in hex, no '0x' prefix
* `print-int32-buffered`: int -> buffered-file
- textual representation in hex, including '0x' prefix
#### reading from disk
* `read`: file -> stream

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -31,7 +31,7 @@ Entry: # run tests if necessary, convert stdin if not
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . test()
#? e8/call test-convert-is-idempotent-by-default/disp32
#? e8/call test-convert-processes-string-literals/disp32
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
#? eb/jump $main:end/disp8
@ -256,6 +256,21 @@ $convert:next-line:
# loop
e9/jump $convert:line-loop/disp32
$convert:break:
# write-stream-data(out, new-data-segment)
# . . push args
57/push-EDI
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
# . . call
e8/call write-stream-data/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# flush(out)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12)
# . . call
e8/call flush/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
$convert:end:
# . reclaim locals
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP
@ -318,6 +333,13 @@ process-string-literal: # string-literal : (address slice), out : (address buff
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# emit-string-literal-data(out-segment, string-literal)
# . . push args
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x8/disp8 . # push *(EBP+8)
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16)
# . . call
e8/call emit-string-literal-data/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# write(out-segment, "\n")
# . . push args
68/push Newline/imm32
@ -722,32 +744,39 @@ test-convert-processes-string-literals:
# called. We just want to make sure instructions using string literals
# switch to a string variable with the right value.
# (Modifying string literals completely off the radar for now.)
#? # dump output {{{
#? # . write(2/stderr, "result: ^")
#? # . . push args
#? 68/push "result: ^"/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . write-stream(2/stderr, _test-output-stream)
#? # . . push args
#? 68/push _test-output-stream/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write-stream/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # . write(2/stderr, "$\n")
#? # . . push args
#? 68/push "$\n"/imm32
#? 68/push 2/imm32/stderr
#? # . . call
#? e8/call write/disp32
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# dump output {{{
# . write(2/stderr, "result: ^")
# . . push args
68/push "result: ^"/imm32
68/push 2/imm32/stderr
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . write-stream(2/stderr, _test-output-stream)
# . . push args
68/push _test-output-stream/imm32
68/push 2/imm32/stderr
# . . call
e8/call write-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . write(2/stderr, "$\n")
# . . push args
68/push "$\n"/imm32
68/push 2/imm32/stderr
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . rewind-stream(_test-output-stream)
# . . push args
68/push _test-output-stream/imm32
# . . call
e8/call rewind-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
# }}}
# . check-next-stream-line-equal(_test-output-stream, "== code ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/0"/imm32
@ -769,16 +798,16 @@ test-convert-processes-string-literals:
# . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/2"/imm32
68/push "2 3 "/imm32
68/push "2 _string2/y "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP
# . check-next-stream-line-equal(_test-output-stream, "== data ", msg)
# . check-next-stream-line-equal(_test-output-stream, "== data", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/3"/imm32
68/push "== data "/imm32
68/push "== data"/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
@ -787,7 +816,7 @@ test-convert-processes-string-literals:
# . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/4"/imm32
68/push "_string1: "/imm32
68/push "_string1:"/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
@ -796,7 +825,7 @@ test-convert-processes-string-literals:
# . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/5"/imm32
68/push "1/imm32 61/a "/imm32
68/push "0x00000001/imm32 61/a "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
@ -805,7 +834,7 @@ test-convert-processes-string-literals:
# . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/6"/imm32
68/push "_string2: "/imm32
68/push "_string2:"/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
@ -814,7 +843,7 @@ test-convert-processes-string-literals:
# . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg)
# . . push args
68/push "F - test-convert-processes-string-literals/7"/imm32
68/push "2/imm32 62/b 63/c "/imm32
68/push "0x00000002/imm32 62/b 63/c "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
@ -828,6 +857,9 @@ test-convert-processes-string-literals:
# generate the data segment contents byte by byte for a given slice
emit-string-literal-data: # out : (address stream), word : (address slice)
# pseudocode
# var len = word->end - word->start - 2 # ignore the double-quotes
# append-int32-hex(out, len)
# write(out, "/imm32")
# curr = word->start
# ++curr # skip '"'
# while true
@ -853,6 +885,30 @@ emit-string-literal-data: # out : (address stream), word : (address slice)
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
# curr/EDX = word->start
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
$emit-string-literal-data:emit-length:
# TODO: handle metadata here
# print(out, "#{len}/imm32 ")
# . len/ECX = word->end - word->start - 2
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
29/subtract 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # subtract EDX from ECX
81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 2/imm32 # subtract from ECX
# . print-int32(out, len)
# . . push args
51/push-ECX
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call print-int32/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# . write(out, "/imm32 ")
# . . push args
68/push "/imm32 "/imm32
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
$emit-string-literal-data:loop-init:
# ++curr # skip initial '"'
42/increment-EDX
# max/ESI = word->end
@ -1012,10 +1068,10 @@ test-emit-string-literal-data:
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# . check-stream-equal(_test-output-stream, "61/a 62/b 63/c ", msg)
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg)
# . . push args
68/push "F - test-emit-string-literal-data"/imm32
68/push "61/a 62/b 63/c "/imm32
68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-stream-equal/disp32
@ -1076,10 +1132,10 @@ test-emit-string-literal-data-empty:
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# . check-stream-equal(_test-output-stream, "", msg)
# . check-stream-equal(_test-output-stream, "0/imm32 ", msg)
# . . push args
68/push "F - test-emit-string-literal-data-empty"/imm32
68/push ""/imm32
68/push "0x00000000/imm32 "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-stream-equal/disp32
@ -1141,10 +1197,10 @@ test-emit-string-literal-data-no-metadata-for-non-alphanumerics:
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# . check-stream-equal(_test-output-stream, "61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints
# . . push args
68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32
68/push "61/a 20 62/b "/imm32
68/push "0x00000003/imm32 61/a 20 62/b "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-stream-equal/disp32
@ -1205,10 +1261,10 @@ test-emit-string-literal-data-handles-escape-sequences:
#? # . . discard args
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
#? # }}}
# . check-stream-equal(_test-output-stream, "61/a 22 62/b ", msg)
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg)
# . . push args
68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32
68/push "61/a 22 62/b "/imm32
68/push "3/imm32 61/a 22 62/b "/imm32
68/push _test-output-stream/imm32
# . . call
e8/call check-stream-equal/disp32

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.