diff options
Diffstat (limited to 'linux/calls.subx')
-rw-r--r-- | linux/calls.subx | 1876 |
1 files changed, 1876 insertions, 0 deletions
diff --git a/linux/calls.subx b/linux/calls.subx new file mode 100644 index 00000000..903ae0f2 --- /dev/null +++ b/linux/calls.subx @@ -0,0 +1,1876 @@ +# Function calls in a single line. +# +# To run (on Linux): +# $ ./translate_subx init.linux [012]*.subx apps/subx-params.subx apps/calls.subx +# $ mv a.elf apps/calls +# +# Example 1: +# $ echo '(foo %eax)' | apps/calls +# # . (foo %eax) # output has comments +# ff 6/subop/push %eax # push +# e8/call foo/disp32 # call +# 81 0/subop/add %esp 4/imm32 # undo push +# +# Example 2: +# $ echo '(foo Var1 *(eax + 4) "blah")' | apps/calls +# # . (foo Var1 *(eax + 4) "blah") +# 68/push "blah"/imm32 +# ff 6/subop/push *(eax + 4) # push args in.. +# 68/push Var1/imm32 # ..reverse order +# e8/call foo/disp32 +# 81 0/subop/add %esp 0xc/imm32 # undo pushes +# +# Calls always begin with '(' as the first non-whitespace on a line. + +== code + +Entry: # run tests if necessary, convert stdin if not + # . prologue + 89/<- %ebp 4/r32/esp + + # initialize heap + # . Heap = new-segment(Heap-size) + # . . push args + 68/push Heap/imm32 + ff 6/subop/push *Heap-size + # . . call + e8/call new-segment/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + + # - if argc > 1 and argv[1] == "test", then return run_tests() + # if (argc <= 1) goto run-main + 81 7/subop/compare *ebp 1/imm32 + 7e/jump-if-<= $subx-calls-main:interactive/disp8 + # if (!kernel-string-equal?(argv[1], "test")) goto run-main + # . eax = kernel-string-equal?(argv[1], "test") + # . . push args + 68/push "test"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call kernel-string-equal?/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . if (eax == false) goto run-main + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $subx-calls-main:interactive/disp8 + # run-tests() + e8/call run-tests/disp32 + # syscall(exit, *Num-test-failures) + 8b/-> *Num-test-failures 3/r32/ebx + eb/jump $subx-calls-main:end/disp8 +$subx-calls-main:interactive: + # - otherwise convert stdin + # subx-calls(Stdin, Stdout) + # . . push args + 68/push Stdout/imm32 + 68/push Stdin/imm32 + # . . call + e8/call subx-calls/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # syscall(exit, 0) + bb/copy-to-ebx 0/imm32 +$subx-calls-main:end: + e8/call syscall_exit/disp32 + +subx-calls: # in: (addr buffered-file), out: (addr buffered-file) + # pseudocode: + # var line: (stream byte 512) + # var words: (stream slice 16) # at most function name and 15 args + # while true + # clear-stream(line) + # read-line-buffered(in, line) + # if (line->write == 0) break # end of file + # skip-chars-matching(line, ' ') + # if line->data[line->read] != '(' + # write-stream-data(out, line) + # continue + # # emit comment + # write-buffered(out, "# . ") + # write-stream-data(out, line) + # # emit code + # ++line->read to skip '(' + # clear-stream(words) + # words = parse-line(line) + # emit-call(out, words) + # flush(out) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + # var line/esi: (stream byte 512) + 81 5/subop/subtract %esp 0x200/imm32 + 68/push 0x200/imm32/length + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %esi 4/r32/esp + # var words/edx: (stream slice 128) # 16 rows * 8 bytes/row + 81 5/subop/subtract %esp 0x80/imm32 + 68/push 0x80/imm32/length + 68/push 0/imm32/read + 68/push 0/imm32/write + 89/<- %edx 4/r32/esp +$subx-calls:loop: + # clear-stream(line) + # . . push args + 56/push-esi + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # read-line-buffered(in, line) + # . . push args + 56/push-esi + ff 6/subop/push *(ebp+8) + # . . call + e8/call read-line-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$subx-calls:check0: + # if (line->write == 0) break + 81 7/subop/compare *esi 0/imm32 + 0f 84/jump-if-= $subx-calls:break/disp32 + # skip-chars-matching(line, ' ') + # . . push args + 68/push 0x20/imm32/space + 56/push-esi + # . . call + e8/call skip-chars-matching/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # if (line->data[line->read] == '(') goto convert-call + # . ecx = line->read + 8b/-> *(esi+4) 1/r32/ecx + # . eax = line->data[line->read] + 31/xor-with %eax 0/r32/eax + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax == '(') goto convert-call + 3d/compare-eax-and 0x28/imm32/open-paren + 74/jump-if-= $subx-calls:convert-call/disp8 +$subx-calls:pass-through: + # write-stream-data(out, line) + # . . push args + 56/push-esi + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # continue + eb/jump $subx-calls:loop/disp8 +$subx-calls:convert-call: + # - emit comment + # write-buffered(out, "# . ") + # . . push args + 68/push "# . "/imm32 + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-stream-data(out, line) + # . . push args + 56/push-esi + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # - emit code + # ++line->read to skip '(' + ff 0/subop/increment *(esi+4) + # clear-stream(words) + # . . push args + 52/push-edx + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # words = parse-line(line) + # . . push args + 52/push-edx + 56/push-esi + # . . call + e8/call parse-line/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # emit-call(out, words) + # . . push args + 52/push-edx + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call emit-call/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # loop + e9/jump $subx-calls:loop/disp32 +$subx-calls:break: + # flush(out) + # . . push args + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 +$subx-calls:end: + # . reclaim locals + 81 0/subop/add %esp 0x298/imm32 # 0x20c + 0x8c + # . restore registers + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +parse-line: # line: (addr stream byte), words: (addr stream slice) + # pseudocode: + # var word-slice: slice + # while true + # word-slice = next-word-string-or-expression-without-metadata(line) + # if slice-empty?(word-slice) + # break # end of line + # write-int(words, word-slice->start) + # write-int(words, word-slice->end) + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 51/push-ecx + # var word-slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp +$parse-line:loop: + # word-slice = next-word-string-or-expression-without-metadata(line) + # . . push args + 51/push-ecx + ff 6/subop/push *(ebp+8) + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$parse-line:check1: + # if (slice-empty?(word-slice)) break + # . eax = slice-empty?(word-slice) + # . . push args + 51/push-ecx + # . . call + e8/call slice-empty?/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . if (eax != false) break + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $parse-line:end/disp32 +#? # dump word-slice {{{ +#? # . write(2/stderr, "w: ") +#? # . . push args +#? 68/push "w: "/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add %esp 8/imm32 +#? # . clear-stream($Stderr->buffer) +#? # . . push args +#? 68/push $Stderr->buffer/imm32 +#? # . . call +#? e8/call clear-stream/disp32 +#? # . . discard args +#? 81 0/subop/add %esp 4/imm32 +#? # . write-slice-buffered(Stderr, word-slice) +#? # . . push args +#? 51/push-ecx +#? 68/push Stderr/imm32 +#? # . . call +#? e8/call write-slice-buffered/disp32 +#? # . . discard args +#? 81 0/subop/add %esp 8/imm32 +#? # . flush(Stderr) +#? # . . push args +#? 68/push Stderr/imm32 +#? # . . call +#? e8/call flush/disp32 +#? # . . discard args +#? 81 0/subop/add %esp 4/imm32 +#? # . 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 %esp 8/imm32 +#? # }}} +$parse-line:write-word: + # write-int(words, word-slice->start) + # . . push args + ff 6/subop/push *ecx + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call write-int/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-int(words, word-slice->end) + # . . push args + ff 6/subop/push *(ecx+4) + ff 6/subop/push *(ebp+0xc) + # . . call + e8/call write-int/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # loop + e9/jump $parse-line:loop/disp32 +$parse-line:end: + # . reclaim locals + 81 0/subop/add %esp 8/imm32 + # . restore registers + 59/pop-to-ecx + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +emit-call: # out: (addr buffered-file), words: (addr stream slice) + # pseudocode: + # if (words->write < 8) abort + # curr = &words->data[words->write-8] + # min = words->data + # # emit pushes + # while true + # if (curr <= min) break + # if slice-starts-with?(curr, "%x") # floating-point register + # write-buffered(out, "81 5/subop/subtract %esp 4/imm32\n") + # write-buffered(out, "f3 0f 11/<- *esp ") + # write-byte-buffered(out, *(curr->start+4)) + # write-buffered(out, "/x32\n") + # else if *curr->start in '%' '*' + # write-buffered(out, "ff 6/subop/push ") + # write-slice-buffered(out, curr) + # write-buffered(out, "\n") + # else + # write-buffered(out, "68/push ") + # write-slice-buffered(out, curr) + # write-buffered(out, "/imm32\n") + # curr -= 8 + # # emit call + # write-buffered(out, "e8/call ") + # write-slice-buffered(out, curr) + # write-buffered(out, "/disp32\n") + # # emit pops + # write-buffered(out, "81 0/subop/add %esp ") + # write-int32-hex-buffered(out, words->write >> 1 - 4) + # write-buffered(out, "/imm32\n") + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + # esi = words + 8b/-> *(ebp+0xc) 6/r32/esi + # if (words->write < 8) abort + # . ecx = words->write - 8 + 8b/-> *esi 1/r32/ecx + 81 5/subop/subtract %ecx 8/imm32 + 0f 8c/jump-if-< $emit-call:error1/disp32 + # var curr/ecx: (addr slice) = &words->data[words->write-8] + 8d/copy-address *(esi+ecx+0xc) 1/r32/ecx + # var min/edx: (addr byte) = words->data + 8d/copy-address *(esi+0xc) 2/r32/edx + # - emit pushes +$emit-call:push-loop: + # if (curr <= min) break + 39/compare %ecx 2/r32/edx + 0f 8e/jump-if-<= $emit-call:call-instruction/disp32 + # if !slice-starts-with?(curr, "%x") goto next check + # . eax = slice-starts-with?(curr, "%x") + # . . push args + 68/push "%x"/imm32 + 51/push-ecx + # . . call + e8/call slice-starts-with?/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . if (eax != 0) goto next check + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= $emit-call:push-int/disp8 + # emit floating-point push + # . write-buffered(out, "81 5/subop/subtract %esp 4/imm32\n") + # . . push args + 68/push "81 5/subop/subtract %esp 4/imm32\n"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(out, "f3 0f 11/<- *esp ") + # . . push args + 68/push "f3 0f 11/<- *esp "/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-byte-buffered(out, *(curr->start+4)) + # . . eax = *(curr->start+4) + 8b/-> *ecx 0/r32/eax + 8a/copy-byte *(eax+4) 0/r32/eax + 81 4/subop/and %eax 0xff/imm32 + # . . push args + 50/push-eax + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-byte-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(out, "/x32\n") + 68/push "/x32\n"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . continue + e9/jump $emit-call:next-push/disp32 +$emit-call:push-int: + # if (*curr->start in '%' '*') goto push-rm32 + # . var start/eax: (addr byte) = curr->start + 8b/-> *ecx 0/r32/eax + # . var c/eax: byte = *eax + 8b/-> *eax 0/r32/eax + 81 4/subop/and %eax 0xff/imm32 + # . if (c == '%') goto push-rm32 + 3d/compare-eax-and 0x25/imm32/percent + 74/jump-if-= $emit-call:push-rm32/disp8 + # . if (c == '*') goto push-rm32 + 3d/compare-eax-and 0x2a/imm32/asterisk + 74/jump-if-= $emit-call:push-rm32/disp8 +$emit-call:push-imm32: + # write-buffered(out, "68/push ") + # . . push args + 68/push "68/push "/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-slice-buffered(out, curr) + # . . push args + 51/push-ecx + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-slice-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-buffered(out, "/imm32\n") + 68/push "/imm32\n"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # continue + eb/jump $emit-call:next-push/disp8 +$emit-call:push-rm32: + # write-buffered(out, "ff 6/subop/push ") + # . . push args + 68/push "ff 6/subop/push "/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-slice-buffered(out, curr) + # . . push args + 51/push-ecx + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-slice-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-buffered(out, "\n") + 68/push Newline/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$emit-call:next-push: + # curr -= 8 + 81 5/subop/subtract %ecx 8/imm32 + # loop + e9/jump $emit-call:push-loop/disp32 +$emit-call:call-instruction: + # write-buffered(out, "e8/call ") + 68/push "e8/call "/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-slice-buffered(out, curr) + # . . push args + 51/push-ecx + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-slice-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-buffered(out, "/disp32\n") + 68/push "/disp32\n"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$emit-call:pop-instruction: + # write-buffered(out, "81 0/subop/add %esp ") + 68/push "81 0/subop/add %esp "/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-int32-hex-buffered(out, words->write >> 1 - 4) + # . . push args + 8b/-> *esi 0/r32/eax + c1/shift 7/subop/arith-right %eax 1/imm8 + 2d/subtract-from-eax 4/imm32 + 50/push-eax + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-int32-hex-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # write-buffered(out, "/imm32\n") + 68/push "/imm32\n"/imm32 + ff 6/subop/push *(ebp+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$emit-call:end: + # . restore registers + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$emit-call:error1: + # print(stderr, "error: calls.subx: '()' is not a valid call") + # . write-buffered(Stderr, "error: calls.subx: '()' is not a valid call") + # . . push args + 68/push "error: calls.subx: '()' is not a valid call"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +test-subx-calls-passes-most-lines-through: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream($_test-input-buffered-file->buffer) + # . . push args + 68/push $_test-input-buffered-file->buffer/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream(_test-output-stream) + # . . push args + 68/push _test-output-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream($_test-output-buffered-file->buffer) + # . . push args + 68/push $_test-output-buffered-file->buffer/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . write(_test-input-stream, "== abcd 0x1\n") + # . . push args + 68/push "== abcd 0x1\n"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # subx-calls(_test-input-buffered-file, _test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 + 68/push _test-input-buffered-file/imm32 + # . . call + e8/call subx-calls/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check that the line just passed through + # . flush(_test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . check-stream-equal(_test-output-stream, "== abcd 0x1\n", msg) + # . . push args + 68/push "F - test-subx-calls-passes-most-lines-through"/imm32 + 68/push "== abcd 0x1\n"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-stream-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-subx-calls-processes-calls: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream($_test-input-buffered-file->buffer) + # . . push args + 68/push $_test-input-buffered-file->buffer/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream(_test-output-stream) + # . . push args + 68/push _test-output-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . clear-stream($_test-output-buffered-file->buffer) + # . . push args + 68/push $_test-output-buffered-file->buffer/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . write(_test-input-stream, "(foo %eax)\n") + # . . push args + 68/push "(foo %eax)\n"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # subx-calls(_test-input-buffered-file, _test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 + 68/push _test-input-buffered-file/imm32 + # . . call + e8/call subx-calls/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check that the line just passed through + # . flush(_test-output-buffered-file) + # . . push args + 68/push _test-output-buffered-file/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 +#? # dump _test-output-stream {{{ +#? # . write(2/stderr, "^") +#? # . . push args +#? 68/push "^"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add %esp 8/imm32 +#? # . 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 %esp 8/imm32 +#? # . 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 %esp 8/imm32 +#? # . 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 %esp 4/imm32 +#? # }}} + # . check-next-stream-line-equal(_test-output-stream, "# . (foo %eax)", msg) + # . . push args + 68/push "F - test-subx-calls-processes-calls: comment"/imm32 + 68/push "# . (foo %eax)"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-next-stream-line-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . check-next-stream-line-equal(_test-output-stream, "ff 6/subop/push %eax", msg) + # . . push args + 68/push "F - test-subx-calls-processes-calls: arg 0"/imm32 + 68/push "ff 6/subop/push %eax"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-next-stream-line-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . check-next-stream-line-equal(_test-output-stream, "e8/call foo/disp32", msg) + # . . push args + 68/push "F - test-subx-calls-processes-calls: call"/imm32 + 68/push "e8/call foo/disp32"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-next-stream-line-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . check-next-stream-line-equal(_test-output-stream, "81 0/subop/add %esp 4/imm32", msg) + # . . push args + 68/push "F - test-subx-calls-processes-calls: pops"/imm32 + 68/push "81 0/subop/add %esp 0x00000004/imm32"/imm32 + 68/push _test-output-stream/imm32 + # . . call + e8/call check-next-stream-line-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +next-word-string-or-expression-without-metadata: # line: (addr stream byte), out: (addr slice) + # pseudocode: + # skip-chars-matching(line, ' ') + # if line->read >= line->write # end of line + # out = {0, 0} + # return + # out->start = &line->data[line->read] + # if line->data[line->read] == '#' # comment + # out->end = &line->data[line->write] # skip to end of line + # return + # if line->data[line->read] == '"' # string literal + # skip-string(line) + # out->end = &line->data[line->read] # no metadata + # return + # if line->data[line->read] == '*' # expression + # if line->data[line->read + 1] == ' ' + # abort + # if line->data[line->read + 1] == '(' + # skip-until-close-paren(line) + # if (line->data[line->read] != ')' + # abort + # ++line->read to skip ')' + # out->end = &line->data[line->read] + # return + # if line->data[line->read] == '(' + # abort + # if line->data[line->read] == ')' + # ++line->read to skip ')' + # # make sure there's nothing else of importance + # if line->read >= line->write + # out = {0, 0} + # return + # if line->data[line->read] != ' ' + # abort + # skip-chars-matching-whitespace(line) + # if line->read >= line->write + # out = {0, 0} + # return + # if line->data[line->read] == '#' # only thing permitted after ')' is a comment + # out = {0, 0} + # return + # abort + # # default case: read a word -- but no metadata + # while true + # if line->read >= line->write + # break + # if line->data[line->read] == ' ' + # break + # if line->data[line->read] == ')' + # break + # if line->data[line->read] == '/' + # abort + # ++line->read + # out->end = &line->data[line->read] + # + # registers: + # ecx: often line->read + # eax: often line->data[line->read] + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 56/push-esi + 57/push-edi + # esi = line + 8b/-> *(ebp+8) 6/r32/esi + # edi = out + 8b/-> *(ebp+0xc) 7/r32/edi + # skip-chars-matching(line, ' ') + # . . push args + 68/push 0x20/imm32/space + ff 6/subop/push *(ebp+8) + # . . call + e8/call skip-chars-matching/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 +$next-word-string-or-expression-without-metadata:check0: + # if (line->read >= line->write) abort because we didn't encounter a final ')' + # . ecx = line->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= line->write) abort + 3b/compare<- *esi 1/r32/ecx + 0f 8d/jump-if->= $next-word-string-or-expression-without-metadata:error0/disp32 +$next-word-string-or-expression-without-metadata:check-for-comment: + # out->start = &line->data[line->read] + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *edi 0/r32/eax + # if (line->data[line->read] != '#') goto next check + # . var eax: byte = line->data[line->read] + 31/xor-with %eax 0/r32/eax + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax != '#') goto next check + 3d/compare-eax-and 0x23/imm32/pound + 75/jump-if-!= $next-word-string-or-expression-without-metadata:check-for-string-literal/disp8 +$next-word-string-or-expression-without-metadata:comment: + # out->end = &line->data[line->write] + 8b/-> *esi 0/r32/eax + 8d/copy-address *(esi+eax+0xc) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + # line->read = line->write # skip rest of line + 8b/-> *esi 0/r32/eax + 89/<- *(esi+4) 0/r32/eax + # return + e9/jump $next-word-string-or-expression-without-metadata:end/disp32 +$next-word-string-or-expression-without-metadata:check-for-string-literal: + # if (line->data[line->read] != '"') goto next check + 3d/compare-eax-and 0x22/imm32/dquote + 75/jump-if-!= $next-word-string-or-expression-without-metadata:check-for-expression/disp8 +$next-word-string-or-expression-without-metadata:string-literal: + # skip-string(line) + # . . push args + 56/push-esi + # . . call + e8/call skip-string/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # out->end = &line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + # return + e9/jump $next-word-string-or-expression-without-metadata:end/disp32 +$next-word-string-or-expression-without-metadata:check-for-expression: + # if (line->data[line->read] != '*') goto next check + 3d/compare-eax-and 0x2a/imm32/asterisk + 75/jump-if-!= $next-word-string-or-expression-without-metadata:check-for-open-paren/disp8 + # if (line->data[line->read + 1] == ' ') goto error1 + 8a/copy-byte *(esi+ecx+0xd) 0/r32/AL + 3d/compare-eax-and 0x20/imm32/space + 0f 84/jump-if-= $next-word-string-or-expression-without-metadata:error1/disp32 + # if (line->data[line->read + 1] != '(') goto regular-word + 3d/compare-eax-and 0x28/imm32/open-paren + 0f 85/jump-if-!= $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32 +$next-word-string-or-expression-without-metadata:paren: + # skip-until-close-paren(line) + # . . push args + 56/push-esi + # . . call + e8/call skip-until-close-paren/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # if (line->data[line->read] != ')') goto error2 + # . eax = line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax != ')') goto error2 + 3d/compare-eax-and 0x29/imm32/close-paren + 0f 85/jump-if-!= $next-word-string-or-expression-without-metadata:error2/disp32 + # ++line->read to skip ')' + ff 0/subop/increment *(esi+4) + # out->end = &line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + # return + e9/jump $next-word-string-or-expression-without-metadata:end/disp32 +$next-word-string-or-expression-without-metadata:check-for-open-paren: + # if (line->data[line->read] == '(') abort + 3d/compare-eax-and 0x28/imm32/open-paren + 0f 84/jump-if-= $next-word-string-or-expression-without-metadata:error4a/disp32 +$next-word-string-or-expression-without-metadata:check-for-end-of-call: + # if (line->data[line->read] != ')') goto next check + 3d/compare-eax-and 0x29/imm32/close-paren + 75/jump-if-!= $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp8 + # ++line->read to skip ')' + ff 0/subop/increment *(esi+4) + # - error checking: make sure there's nothing else of importance on the line + # if (line->read >= line->write) return out = {0, 0} + # . ecx = line->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= line->write) return {0, 0} + 3b/compare<- *esi 1/r32/ecx + 0f 8d/jump-if->= $next-word-string-or-expression-without-metadata:return-eol/disp32 + # if (line->data[line->read] == '/') goto error3 + # . eax = line->data[line->read] + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax == '/') goto error3 + 3d/compare-eax-and 0x2f/imm32/slash + 0f 84/jump-if-= $next-word-string-or-expression-without-metadata:error3/disp32 + # skip-chars-matching-whitespace(line) + # . . push args + 56/push-esi + # . . call + e8/call skip-chars-matching-whitespace/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # if (line->read >= line->write) return out = {0, 0} + # . ecx = line->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= line->write) return {0, 0} + 3b/compare<- *esi 1/r32/ecx + 0f 8d/jump-if->= $next-word-string-or-expression-without-metadata:return-eol/disp32 + # if (line->data[line->read] == '#') return out = {0, 0} + # . eax = line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax == '#') return out = {0, 0} + 3d/compare-eax-and 0x23/imm32/pound + 74/jump-if-= $next-word-string-or-expression-without-metadata:return-eol/disp8 + # otherwise goto error4 + e9/jump $next-word-string-or-expression-without-metadata:error4/disp32 +$next-word-string-or-expression-without-metadata:regular-word-without-metadata: + # if (line->read >= line->write) break + # . ecx = line->read + 8b/-> *(esi+4) 1/r32/ecx + # . if (ecx >= line->write) break + 3b/compare<- *esi 1/r32/ecx + 7d/jump-if->= $next-word-string-or-expression-without-metadata:regular-word-break/disp8 + # if (line->data[line->read] == ' ') break + # . eax = line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL + # . if (eax == ' ') break + 3d/compare-eax-and 0x20/imm32/space + 74/jump-if-= $next-word-string-or-expression-without-metadata:regular-word-break/disp8 + # if (line->data[line->read] == ')') break + 3d/compare-eax-and 0x29/imm32/close-paren + 0f 84/jump-if-= $next-word-string-or-expression-without-metadata:regular-word-break/disp32 + # if (line->data[line->read] == '/') goto error5 + 3d/compare-eax-and 0x2f/imm32/slash + 0f 84/jump-if-= $next-word-string-or-expression-without-metadata:error5/disp32 + # ++line->read + ff 0/subop/increment *(esi+4) + # loop + e9/jump $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32 +$next-word-string-or-expression-without-metadata:regular-word-break: + # out->end = &line->data[line->read] + 8b/-> *(esi+4) 1/r32/ecx + 8d/copy-address *(esi+ecx+0xc) 0/r32/eax + 89/<- *(edi+4) 0/r32/eax + eb/jump $next-word-string-or-expression-without-metadata:end/disp8 +$next-word-string-or-expression-without-metadata:return-eol: + # return out = {0, 0} + c7 0/subop/copy *edi 0/imm32 + c7 0/subop/copy *(edi+4) 0/imm32 +$next-word-string-or-expression-without-metadata:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +$next-word-string-or-expression-without-metadata:error0: + # print(stderr, "error: missing final ')' in '" line "'") + # . write-buffered(Stderr, "error: missing final ')' in '") + # . . push args + 68/push "error: missing final ')' in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "'") + # . . push args + 68/push "'"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error1: + # print(stderr, "error: no space allowed after '*' in '" line "'") + # . write-buffered(Stderr, "error: no space allowed after '*' in '") + # . . push args + 68/push "error: no space allowed after '*' in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "'") + # . . push args + 68/push "'"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error2: + # print(stderr, "error: *(...) expression must be all on a single line in '" line "'") + # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '") + # . . push args + 68/push "error: *(...) expression must be all on a single line in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "'") + # . . push args + 68/push "'"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error3: + # print(stderr, "error: no metadata after calls; just use a comment (in '" line "')") + # . write-buffered(Stderr, "error: no metadata after calls; just use a comment (in '") + # . . push args + 68/push "error: no metadata after calls; just use a comment (in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "')") + # . . push args + 68/push "')"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error4a: + # print(stderr, "error: unexpected '(' within call in '" line "'") + # . write-buffered(Stderr, "error: unexpected '(' within call in '") + # . . push args + 68/push "error: unexpected '(' within call in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "'\n") + # . . push args + 68/push "'\n"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error4: + # print(stderr, "error: unexpected text after end of call in '" line "'") + # . write-buffered(Stderr, "error: unexpected text after end of call in '") + # . . push args + 68/push "error: unexpected text after end of call in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "'") + # . . push args + 68/push "'"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +$next-word-string-or-expression-without-metadata:error5: + # print(stderr, "error: no metadata anywhere in calls (in '" line "')") + # . write-buffered(Stderr, "error: no metadata anywhere in calls (in '") + # . . push args + 68/push "error: no metadata anywhere in calls (in '"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-stream-data(Stderr, line) + # . . push args + 56/push-esi + 68/push Stderr/imm32 + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . write-buffered(Stderr, "')") + # . . push args + 68/push "')"/imm32 + 68/push Stderr/imm32 + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # . flush(Stderr) + # . . push args + 68/push Stderr/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + # never gets here + +test-next-word-string-or-expression-without-metadata: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " ab") + # . . push args + 68/push " ab"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(_test-input-stream->read, 4, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata/updates-stream-read-correctly"/imm32 + 68/push 4/imm32 + b8/copy-to-eax _test-input-stream/imm32 + ff 6/subop/push *(eax+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) + # . check-ints-equal(slice->start - _test-input-stream, 14, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata: start"/imm32 + 68/push 0xe/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) + # . check-ints-equal(slice->end - _test-input-stream, 16, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata: end"/imm32 + 68/push 0x10/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-returns-whole-comment: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " # a") + # . . push args + 68/push " # a"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(_test-input-stream->read, 5, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment/updates-stream-read-correctly"/imm32 + 68/push 5/imm32 + b8/copy-to-eax _test-input-stream/imm32 + ff 6/subop/push *(eax+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) + # . check-ints-equal(slice->start - _test-input-stream, 14, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: start"/imm32 + 68/push 0xe/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) + # . check-ints-equal(slice->end - _test-input-stream, 17, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: end"/imm32 + 68/push 0x11/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-returns-string-literal: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " \"a b\" ") + # . . push args + 68/push " \"a b\" "/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) + # . check-ints-equal(slice->start - _test-input-stream, 13, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: start"/imm32 + 68/push 0xd/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 6, msg) + # . check-ints-equal(slice->end - _test-input-stream, 18, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: end"/imm32 + 68/push 0x12/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " \"a\\\"b\"") + # . . push args + 68/push " \"a\\\"b\""/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) + # . check-ints-equal(slice->start - _test-input-stream, 13, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: start"/imm32 + 68/push 0xd/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 7, msg) + # . check-ints-equal(slice->end - _test-input-stream, 19, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: end"/imm32 + 68/push 0x13/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-returns-whole-expression: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " *(a b) ") + # . . push args + 68/push " *(a b) "/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) + # . check-ints-equal(slice->start - _test-input-stream, 13, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: start"/imm32 + 68/push 0xd/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 7, msg) + # . check-ints-equal(slice->end - _test-input-stream, 19, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: end"/imm32 + 68/push 0x13/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " ) ") + # . . push args + 68/push " ) "/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: start"/imm32 + 68/push 0/imm32 + ff 6/subop/push *ecx + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: end"/imm32 + 68/push 0/imm32 + ff 6/subop/push *(ecx+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " ) # abc ") + # . . push args + 68/push " ) # abc "/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: start"/imm32 + 68/push 0/imm32 + ff 6/subop/push *ecx + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: end"/imm32 + 68/push 0/imm32 + ff 6/subop/push *(ecx+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " )\n") + # . . push args + 68/push " )\n"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: start"/imm32 + 68/push 0/imm32 + ff 6/subop/push *ecx + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end, 0, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: end"/imm32 + 68/push 0/imm32 + ff 6/subop/push *(ecx+4) + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +test-next-word-string-or-expression-without-metadata-stops-at-close-paren: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # setup + # . clear-stream(_test-input-stream) + # . . push args + 68/push _test-input-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add %esp 4/imm32 + # var slice/ecx: slice + 68/push 0/imm32/end + 68/push 0/imm32/start + 89/<- %ecx 4/r32/esp + # write(_test-input-stream, " abc) # def") + # . . push args + 68/push " abc) # def"/imm32 + 68/push _test-input-stream/imm32 + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # next-word-string-or-expression-without-metadata(_test-input-stream, slice) + # . . push args + 51/push-ecx + 68/push _test-input-stream/imm32 + # . . call + e8/call next-word-string-or-expression-without-metadata/disp32 + # . . discard args + 81 0/subop/add %esp 8/imm32 + # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) + # . check-ints-equal(slice->start - _test-input-stream, 13, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: start"/imm32 + 68/push 0xd/imm32 + # . . push slice->start - _test-input-stream + 8b/-> *ecx 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) + # . check-ints-equal(slice->end - _test-input-stream, 16, msg) + # . . push args + 68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: end"/imm32 + 68/push 0x10/imm32 + # . . push slice->end - _test-input-stream + 8b/-> *(ecx+4) 0/r32/eax + 81 5/subop/subtract %eax _test-input-stream/imm32 + 50/push-eax + # . . call + e8/call check-ints-equal/disp32 + # . . discard args + 81 0/subop/add %esp 0xc/imm32 + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return |