49424b1933
There's a dependency cycle here: - draw-grapheme (Mu) uses read-grapheme (Mu) to be unicode-aware. - read-grapheme uses read-byte (SubX). Streams are a fundamental data structure in Mu. For the Mu compiler to be able to reason about the safety of stream operations, they need to be an opaque type. All stream primitives are written in SubX. To manipulate a stream's internals we force people to reach for SubX. That way if there's no SubX code there's confidence that things are safe. - read-byte and other stream operations have unit tests, like they should. The unit tests need to print data to screen when say a test fails. To do this they use various check- functions (SubX) that take a string argument. - Printing a string to screen uses draw-grapheme (Mu). Perhaps I should maintain variants of drawing primitives that operate only on ASCII.
599 lines
29 KiB
Plaintext
599 lines
29 KiB
Plaintext
# some primitives for checking stream contents
|
|
#
|
|
# We need to do this in machine code because streams need to be opaque types,
|
|
# and we don't yet support opaque types in Mu.
|
|
|
|
== code
|
|
# instruction effective address register displacement immediate
|
|
# . op subop mod rm32 base index scale r32
|
|
# . 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
|
|
|
|
# compare all the data in a stream (ignoring the read pointer)
|
|
stream-data-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
56/push-esi
|
|
57/push-edi
|
|
# esi = f
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
|
|
# eax = f->write
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
|
|
# var maxf/edx: (addr byte) = &f->data[f->write]
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 2/r32/edx 0xc/disp8 . # copy esi+eax+12 to edx
|
|
# var currf/esi: (addr byte) = f->data
|
|
81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0xc/imm32 # add to esi
|
|
# edi = s
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
|
|
$stream-data-equal?:compare-sizes:
|
|
# if (f->write != s->size) return false
|
|
39/compare 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # compare *edi and eax
|
|
75/jump-if-!= $stream-data-equal?:false/disp8
|
|
# var currs/edi: (addr byte) = s->data
|
|
81 0/subop/add 3/mod/direct 7/rm32/edi . . . . . 4/imm32 # add to edi
|
|
# var eax: byte = 0
|
|
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
|
# var ecx: byte = 0
|
|
31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx
|
|
$stream-data-equal?:loop:
|
|
# if (currf >= maxf) return true
|
|
39/compare 3/mod/direct 6/rm32/esi . . . 2/r32/edx . . # compare esi with edx
|
|
73/jump-if-addr>= $stream-data-equal?:true/disp8
|
|
# AL = *currs
|
|
8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL
|
|
# CL = *curr
|
|
8a/copy-byte 0/mod/indirect 7/rm32/edi . . . 1/r32/CL . . # copy byte at *edi to CL
|
|
# if (eax != ecx) return false
|
|
39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax and ecx
|
|
75/jump-if-!= $stream-data-equal?:false/disp8
|
|
# ++f
|
|
46/increment-esi
|
|
# ++curr
|
|
47/increment-edi
|
|
eb/jump $stream-data-equal?:loop/disp8
|
|
$stream-data-equal?:false:
|
|
b8/copy-to-eax 0/imm32
|
|
eb/jump $stream-data-equal?:end/disp8
|
|
$stream-data-equal?:true:
|
|
b8/copy-to-eax 1/imm32
|
|
$stream-data-equal?:end:
|
|
# . restore registers
|
|
5f/pop-to-edi
|
|
5e/pop-to-esi
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-stream-data-equal:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = stream-data-equal?(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call stream-data-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
68/push "F - test-stream-data-equal"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-stream-data-equal-2:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = stream-data-equal?(_test-stream, "Abd")
|
|
# . . push args
|
|
68/push "Abd"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call stream-data-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-stream-data-equal-2"/imm32
|
|
68/push 0/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-stream-data-equal-size-check:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = stream-data-equal?(_test-stream, "Abcd")
|
|
# . . push args
|
|
68/push "Abcd"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call stream-data-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-stream-data-equal-size-check"/imm32
|
|
68/push 0/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# helper for later tests
|
|
check-stream-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
# eax = stream-data-equal?(f, s)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call stream-data-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
$check-stream-equal:end:
|
|
# . restore registers
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# scan the next line until newline starting from f->read and compare it with
|
|
# 's' (ignoring the trailing newline)
|
|
# on success, set f->read to after the next newline
|
|
# on failure, leave f->read unmodified
|
|
# this function is usually used only in tests, so we repeatedly write f->read
|
|
next-stream-line-equal?: # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
|
|
# pseudocode:
|
|
# currf = f->read # bound: f->write
|
|
# currs = 0 # bound: s->size
|
|
# while true
|
|
# if currf >= f->write
|
|
# return currs >= s->size
|
|
# if f[currf] == '\n'
|
|
# ++currf
|
|
# return currs >= s->size
|
|
# if (currs >= s->size) return false # the current line of f still has data to match
|
|
# if (f[currf] != s[currs]) return false
|
|
# ++currf
|
|
# ++currs
|
|
#
|
|
# collapsing the two branches that can return true:
|
|
# currf = f->read # bound: f->write
|
|
# currs = 0 # bound: s->size
|
|
# while true
|
|
# if (currf >= f->write) break
|
|
# if (f[currf] == '\n') break
|
|
# if (currs >= s->size) return false # the current line of f still has data to match
|
|
# if (f[currf] != s[currs]) return false
|
|
# ++currf
|
|
# ++currs
|
|
# ++currf # skip '\n'
|
|
# return currs >= s->size
|
|
# Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
|
|
#
|
|
# registers:
|
|
# f: esi
|
|
# s: edi
|
|
# currf: ecx
|
|
# currs: edx
|
|
# f[currf]: eax
|
|
# s[currs]: ebx
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
56/push-esi
|
|
57/push-edi
|
|
# esi = f
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
|
|
# var currf/ecx: int = f->read
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
|
|
# edi = s
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
|
|
# var currs/edx: int = 0
|
|
31/xor 3/mod/direct 2/rm32/edx . . . 2/r32/edx . . # clear edx
|
|
# var c1/eax: byte = 0
|
|
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
|
# var c2/ebx: byte = 0
|
|
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
|
|
$next-stream-line-equal?:loop:
|
|
# if (currf >= f->write) break
|
|
3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi
|
|
7d/jump-if->= $next-stream-line-equal?:break/disp8
|
|
# c1 = f->data[f->read]
|
|
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL
|
|
# if (c1 == '\n') break
|
|
3d/compare-eax-and 0xa/imm32/newline
|
|
74/jump-if-= $next-stream-line-equal?:break/disp8
|
|
# if (currs >= s->size) return false
|
|
3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi
|
|
7d/jump-if->= $next-stream-line-equal?:false/disp8
|
|
# c2 = s->data[currs]
|
|
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 3/r32/BL 4/disp8 . # copy byte at *(edi+edx+4) to BL
|
|
# if (c1 != c2) return false
|
|
39/compare 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # compare eax and ebx
|
|
75/jump-if-!= $next-stream-line-equal?:false/disp8
|
|
# ++currf
|
|
41/increment-ecx
|
|
# ++currs
|
|
42/increment-edx
|
|
eb/jump $next-stream-line-equal?:loop/disp8
|
|
$next-stream-line-equal?:break:
|
|
# ++currf
|
|
41/increment-ecx
|
|
# if (currs >= s->size) return true
|
|
3b/compare 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # compare edx with *edi
|
|
7c/jump-if-< $next-stream-line-equal?:false/disp8
|
|
$next-stream-line-equal?:true:
|
|
b8/copy-to-eax 1/imm32
|
|
# persist f->read on success
|
|
89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
|
|
eb/jump $next-stream-line-equal?:end/disp8
|
|
$next-stream-line-equal?:false:
|
|
b8/copy-to-eax 0/imm32
|
|
$next-stream-line-equal?:end:
|
|
# . restore registers
|
|
5f/pop-to-edi
|
|
5e/pop-to-esi
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-next-stream-line-equal-stops-at-newline:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc\ndef")
|
|
# . . push args
|
|
68/push "Abc\ndef"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = next-stream-line-equal?(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-stops-at-newline"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-next-stream-line-equal-stops-at-newline-2:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc\ndef")
|
|
# . . push args
|
|
68/push "Abc\ndef"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = next-stream-line-equal?(_test-stream, "def")
|
|
# . . push args
|
|
68/push "def"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-stops-at-newline-2"/imm32
|
|
68/push 0/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-next-stream-line-equal-skips-newline:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc\ndef\n")
|
|
# . . push args
|
|
68/push "Abc\ndef\n"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# next-stream-line-equal?(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = next-stream-line-equal?(_test-stream, "def")
|
|
# . . push args
|
|
68/push "def"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-skips-newline"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-next-stream-line-equal-handles-final-line:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write(_test-stream, "Abc\ndef")
|
|
# . . push args
|
|
68/push "Abc\ndef"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# next-stream-line-equal?(_test-stream, "Abc")
|
|
# . . push args
|
|
68/push "Abc"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# eax = next-stream-line-equal?(_test-stream, "def")
|
|
# . . push args
|
|
68/push "def"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-skips-newline"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-next-stream-line-equal-always-fails-after-Eof:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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
|
|
# write nothing
|
|
# eax = next-stream-line-equal?(_test-stream, "")
|
|
# . . push args
|
|
68/push ""/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-always-fails-after-Eof"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# eax = next-stream-line-equal?(_test-stream, "")
|
|
# . . push args
|
|
68/push ""/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-next-stream-line-equal-always-fails-after-Eof/2"/imm32
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# helper for later tests
|
|
check-next-stream-line-equal: # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
# eax = next-stream-line-equal?(f, s)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call next-stream-line-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 1, msg)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
68/push 1/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . restore registers
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# . . vim:nowrap:textwidth=0
|