6630 - define type signatures for SubX functions

This was easier than I'd feared.
This commit is contained in:
Kartik Agaram 2020-07-10 23:41:34 -07:00
parent 229d63aad2
commit c5a3f65502
5 changed files with 500 additions and 12 deletions

159
400.mu Normal file
View File

@ -0,0 +1,159 @@
# The 4xx series is for primitives implemented in Mu.
# Signatures for major SubX functions defined so far.
# autogenerated
sig run-tests
# init.linux
# TODO: make this OS-specific
# TODO: include result type at least, even if register args are too much
sig syscall_exit # status/ebx: int
sig syscall_read # fd/ebx: int, buf/ecx: addr, size/edx: int -> nbytes-or-error/eax: int
sig syscall_write # fd/ebx: int, buf/ecx: addr, size/edx: int -> nbytes-or-error/eax: int
sig syscall_open # filename/ebx: (addr kernel-string), flags/ecx: int, dummy=0x180/edx -> fd-or-error/eax: int
sig syscall_close # fd/ebx: int -> status/eax
sig syscall_creat # filename/ebx: (addr kernel-string) -> fd-or-error/eax: int
sig syscall_unlink # filename/ebx: (addr kernel-string) -> status/eax: int
sig syscall_rename # source/ebx: (addr kernel-string), dest/ecx: (addr kernel-string) -> status/eax: int
sig syscall_mmap # arg/ebx: (addr mmap_arg_struct) -> status/eax: int
sig syscall_ioctl # fd/ebx: int, cmd/ecx: int, arg/edx: (addr _)
sig syscall_nanosleep # req/ebx: (addr timespec)
sig syscall_clock_gettime # clock/ebx: int, out/ecx: (addr timespec)
# Generated using:
# grep -h '^[a-z]' [0-9]*.subx |grep -v '^test-'
# Functions we don't want to make accessible from Mu are commented out.
# Many functions here may not be usable yet because of missing features
# (global variable support, type definitions for stuff like `stream`)
sig check-ints-equal a: int, b: int, msg: (addr array byte)
sig kernel-string-equal? s: (addr kernel-string), benchmark: (addr array byte) -> result/eax: boolean
sig new-segment len: int, ad: (addr allocation-descriptor)
sig string-equal? s: (addr array byte), benchmark: (addr array byte) -> result/eax: boolean
sig string-starts-with? s: (addr array byte), benchmark: (addr array byte) -> result/eax: boolean
sig check-strings-equal s: (addr array byte), expected: (addr array byte), msg: (addr array byte)
sig clear-stream f: (addr stream byte)
sig rewind-stream f: (addr stream byte)
sig initialize-trace-stream n: int
sig trace line: (addr array byte)
sig check-trace-contains line: (addr string), msg: (addr string)
sig check-trace-scans-to line: (addr string), msg: (addr string)
sig trace-scan line: (addr array byte) -> result/eax: boolean
sig next-line-matches? t: (addr stream byte), line: (addr array byte) -> result/eax: boolean
sig skip-next-line t: (addr stream byte)
sig clear-trace-stream
#sig write f: fd or (addr stream byte), s: (addr array byte)
sig stream-data-equal? f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
sig check-stream-equal f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
sig next-stream-line-equal? f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
sig check-next-stream-line-equal
sig tailor-exit-descriptor ed: (addr exit-descriptor), nbytes: int
sig stop ed: (addr exit-descriptor), value: int
#sig read f: fd or (addr stream byte), s: (addr stream byte) -> num-bytes-read/eax: int
sig read-byte-buffered f: (addr buffered-file) -> byte-or-Eof/eax: int
#sig write-stream f: fd or (addr stream byte), s: (addr stream byte)
#sig error ed: (addr exit-descriptor), out: fd or (addr stream byte), msg: (addr array byte)
sig write-byte-buffered f: (addr buffered-file), n: int
sig flush f: (addr buffered-file)
sig append-byte f: (addr stream byte), n: int
sig write-buffered f: (addr buffered-file), msg: (addr array byte)
#sig to-hex-char in/eax: int -> out/eax: int
sig append-byte-hex f: (addr stream byte), n: int
sig write-byte-hex-buffered f: (addr buffered-file), n: int
sig write-int32-hex f: (addr stream byte), n: int
sig write-int32-hex-buffered f: (addr buffered-file), n: int
sig is-hex-int? in: (addr slice) -> result/eax: boolean
sig parse-hex-int in: (addr array byte) -> result/eax: int
sig parse-hex-int-from-slice in: (addr slice) -> result/eax: int
#sig parse-hex-int-helper start: (addr byte), end: (addr byte) -> result/eax: int
sig is-hex-digit? c: byte -> result/eax: boolean
#sig from-hex-char in/eax: byte -> out/eax: nibble
sig error-byte ed: (addr exit-descriptor), out: (addr buffered-file), msg: (addr array byte), n: byte
#sig allocate ad: (addr allocation-descriptor), n: int, out: (addr handle)
#sig allocate-raw ad: (addr allocation-descriptor), n: int, out: (addr handle)
sig lookup h: (handle T) -> result/eax: (addr T)
sig handle-equal? a: handle, b: handle -> result/eax: boolean
sig copy-handle src: handle, dest: (addr handle)
sig allocate-region ad: (addr allocation-descriptor), n: int, out: (addr handle allocation-descriptor)
sig allocate-array ad: (addr allocation-descriptor), n: int, out: (addr handle)
sig copy-array ad: (addr allocation-descriptor), src: (addr array), out: (addr handle)
sig zero-out start: (addr byte), len: int
sig new-stream ad: (addr allocation-descriptor), length: int, elemsize: int, out: (addr handle stream _)
sig read-line-buffered f: (addr buffered-file), s: (addr stream byte)
sig read-line f: (addr stream byte), s: (addr stream byte)
sig slice-empty? s: (addr slice) -> result/eax: boolean
sig slice-equal? s: (addr slice), p: (addr array byte) -> result/eax: boolean
sig slice-starts-with? s: (addr slice), head: (addr array byte) -> result/eax: boolean
sig write-slice out: (addr stream byte), s: (addr slice)
sig write-slice-buffered out: (addr buffered-file), s: (addr slice)
sig slice-to-string ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte)
sig next-token in: (addr stream byte), delimiter: byte, out: (addr slice)
sig next-token-from-slice start: (addr byte), end: (addr byte), delimiter: byte, out: (addr slice)
sig skip-chars-matching in: (addr stream byte), delimiter: byte
sig skip-chars-matching-whitespace in: (addr stream byte)
sig skip-chars-not-matching in: (addr stream byte), delimiter: byte
sig skip-chars-not-matching-whitespace in: (addr stream byte)
sig skip-chars-matching-in-slice curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte)
sig skip-chars-matching-whitespace-in-slice curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
sig skip-chars-not-matching-in-slice curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte)
sig skip-chars-not-matching-whitespace-in-slice curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
sig skip-string line: (addr stream byte)
sig skip-string-in-slice curr: (addr byte), end: (addr byte) -> new_curr/eax: (addr byte)
sig skip-until-close-paren line: (addr stream byte)
sig skip-until-close-paren-in-slice curr: (addr byte), end: (addr byte) -> new_curr/eax: (addr byte)
sig write-stream-data f: (addr buffered-file), s: (addr stream byte)
sig write-int32-decimal out: (addr stream byte), n: int32
sig is-decimal-digit? c: byte -> result/eax: boolean
sig to-decimal-digit in: byte -> out/eax: int
sig next-word line: (addr stream byte), out: (addr slice)
sig has-metadata? word: (addr slice), s: (addr string) -> result/eax: boolean
sig is-valid-name? in: (addr slice) -> result/eax: boolean
sig is-label? word: (addr slice) -> result/eax: boolean
sig emit-hex out: (addr buffered-file), n: int, width: int
sig emit out: (addr buffered-file), word: (addr slice), width: int
#sig get table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, abort-message-prefix: (addr array byte) -> result/eax: (addr T)
#sig get-slice table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, abort-message-prefix: (addr array byte) -> result/eax: (addr T)
#sig get-or-insert table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T)
#sig get-or-insert-handle table: (addr stream {(handle array byte), T}), key: (handle array byte), row-size: int -> result/eax: (addr T)
#sig get-or-insert-slice table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int, ad: (addr allocation-descriptor) -> result/eax: (addr T)
#sig get-or-stop table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int,
#sig get-slice-or-stop table: (addr stream {(handle array byte), _}), key: (addr slice), row-size: int,
#sig maybe-get table: (addr stream {(handle array byte), T}), key: (addr array byte), row-size: int -> result/eax: (addr T)
#sig maybe-get-slice table: (addr stream {(handle array byte), T}), key: (addr slice), row-size: int -> result/eax: (addr T)
sig slurp f: (addr buffered-file), s: (addr stream byte)
sig compute-width word: (addr array byte) -> result/eax: int
sig compute-width-of-slice s: (addr slice) -> result/eax: int
sig emit-hex-array out: (addr buffered-file), arr: (addr array byte)
sig next-word-or-string line: (addr stream byte), out: (addr slice)
sig write-int out: (addr stream byte), n: int
sig clear-stack s: (addr stack)
sig push s: (addr stack), n: int
sig pop s: (addr stack) -> n/eax: int
sig top s: (addr stack) -> n/eax: int
sig array-equal? a: (addr array int), b: (addr array int) -> result/eax: boolean
sig parse-array-of-ints ad: (addr allocation-descriptor), s: (addr string), out: (addr handle array int)
sig check-array-equal a: (addr array int), expected: (addr string), msg: (addr string)
#sig push-n-zero-bytes n: int
sig kernel-string-to-string ad: (addr allocation-descriptor), in: (addr kernel-string), out: (addr handle array byte)
sig kernel-string-length in: (addr kernel-string) -> result/eax: int
sig enable-screen-grid-mode
sig enable-screen-type-mode
sig screen-size -> nrows/eax: int, ncols/ecx: int
sig clear-screen
sig move-cursor-on-screen row: int, column: int
sig print-string-to-screen s: (addr array byte)
sig print-byte-to-screen c: byte
sig print-int32-hex-to-screen n: int
sig reset-formatting-on-screen
sig start-color-on-screen fg: int, bg: int
sig start-bold-on-screen
sig start-underline-on-screen
sig start-reverse-video-on-screen
sig start-blinking-on-screen
sig hide-cursor-on-screen
sig show-cursor-on-screen
sig enable-keyboard-immediate-mode
sig enable-keyboard-type-mode
sig read-key -> result/eax: byte
sig open filename: (addr array byte), write?: boolean, out: (addr handle buffered-file)
sig size in: (addr array _) -> result/eax: int

View File

@ -1 +0,0 @@
The 4xx series is for primitives implemented in Mu.

BIN
apps/mu

Binary file not shown.

View File

@ -243,6 +243,10 @@ _Program-types: # (handle typeinfo)
0/imm32
_Program-types->payload:
0/imm32
_Program-signatures: # (handle function)
0/imm32
_Program-signatures->payload:
0/imm32
# Some constants for simulating the data structures described above.
# Many constants here come with a type in a comment.
@ -850,7 +854,6 @@ test-convert-function-with-literal-arg-2:
5d/pop-to-ebp
c3/return
# HERE
test-convert-function-call-with-literal-arg:
# . prologue
55/push-ebp
@ -910,6 +913,48 @@ test-convert-function-call-with-literal-arg:
5d/pop-to-ebp
c3/return
test-convert-function-call-with-signature:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-input-stream)
(clear-stream $_test-input-buffered-file->buffer)
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
#
(write _test-input-stream "fn main -> result/ebx: int {\n")
(write _test-input-stream " result <- do-add 3 4\n")
(write _test-input-stream "}\n")
(write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
# convert
(convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-signature/0")
(check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-call-with-signature/1")
(check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-call-with-signature/2")
(check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-signature/3")
(check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-call-with-signature/4")
(check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:" "F - test-convert-function-call-with-signature/5")
(check-next-stream-line-equal _test-output-stream " (do-add 3 4)" "F - test-convert-function-call-with-signature/6")
(check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-call-with-signature/7")
(check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
(check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-call-with-signature/9")
(check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-signature/10")
(check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-call-with-signature/11")
(check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-call-with-signature/12")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-convert-function-with-local-var-in-mem:
# . prologue
55/push-ebp
@ -5921,6 +5966,7 @@ Curr-block-depth: # (addr int)
parse-mu: # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
# pseudocode
# var curr-function: (addr handle function) = Program->functions
# var curr-signature: (addr handle function) = Program->signatures
# var curr-type: (addr handle typeinfo) = Program->types
# var line: (stream byte 512)
# var word-slice: slice
@ -5941,6 +5987,11 @@ parse-mu: # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit
# assert(vars->top == 0)
# *curr-function = new-function
# curr-function = &new-function->next
# else if slice-equal?(word-slice, "sig")
# var new-function: (handle function) = allocate(function)
# populate-mu-function-signature(line, new-function)
# *curr-signature = new-function
# curr-signature = &new-function->next
# else if slice-equal?(word-slice, "type")
# word-slice = next-mu-token(line)
# type-id = pos-or-insert-slice(Type-id, word-slice)
@ -5953,6 +6004,8 @@ parse-mu: # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# var curr-signature: (addr handle function) at *(ebp-4)
68/push _Program-signatures/imm32
# . save registers
50/push-eax
51/push-ecx
@ -6037,6 +6090,46 @@ $parse-mu:fn:
#
e9/jump $parse-mu:line-loop/disp32
}
# if (slice-equal?(word-slice, "sig")) parse a function signature
# Function signatures are for providing types to SubX functions.
{
$parse-mu:sig:
(slice-equal? %edx "sig") # => eax
3d/compare-eax-and 0/imm32/false
0f 84/jump-if-= break/disp32
# edi = curr-function
57/push-edi
$bb:
8b/-> *(ebp-4) 7/r32/edi
# var new-function/esi: (handle function)
68/push 0/imm32
68/push 0/imm32
89/<- %esi 4/r32/esp
# populate-mu-function(line, in, vars, new-function)
(allocate Heap *Function-size %esi)
# var new-function-addr/eax: (addr function)
(lookup *esi *(esi+4)) # => eax
#
(populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
# *curr-signature = new-function
8b/-> *esi 0/r32/eax
89/<- *edi 0/r32/eax
8b/-> *(esi+4) 0/r32/eax
89/<- *(edi+4) 0/r32/eax
# curr-signature = &new-function->next
# . var tmp/eax: (addr function) = lookup(new-function)
(lookup *esi *(esi+4)) # => eax
# . curr-function = &tmp->next
8d/copy-address *(eax+0x20) 7/r32/edi # Function-next
# reclaim new-function
81 0/subop/add %esp 8/imm32
# save curr-function
89/<- *(ebp-4) 7/r32/edi
# restore edi
5f/pop-to-edi
#
e9/jump $parse-mu:line-loop/disp32
}
# if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
{
$parse-mu:type:
@ -6080,6 +6173,8 @@ $parse-mu:end:
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . reclaim local
81 0/subop/add %esp 4/imm32
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -6167,7 +6262,6 @@ populate-mu-function-header: # first-line: (addr stream byte), out: (addr funct
# read function name
(next-mu-token *(ebp+8) %ecx)
# error checking
# TODO: error if word-slice starts with 'break' or 'loop'
# if (word-slice == '{') abort
(slice-equal? %ecx "{") # => eax
3d/compare-eax-and 0/imm32/false
@ -6274,17 +6368,28 @@ $populate-mu-function-header:error1:
# never gets here
$populate-mu-function-header:error2:
# error("function inout '" var "' cannot be in a register")
(write-buffered *(ebp+0x14) "function inout '")
(write-buffered *(ebp+0x14) *ebx) # Var-name
# error("fn " fn ": function inout '" var "' cannot be in a register")
(write-buffered *(ebp+0x14) "fn ")
50/push-eax
(lookup *edi *(edi+4)) # Function-name Function-name => eax
(write-buffered *(ebp+0x14) %eax)
58/pop-to-eax
(write-buffered *(ebp+0x14) ": function inout '")
(lookup *eax *(eax+4)) # Var-name Var-name => eax
(write-buffered *(ebp+0x10) %eax)
(write-buffered *(ebp+0x14) "' cannot be in a register")
(flush *(ebp+0x14))
(stop *(ebp+0x18) 1)
# never gets here
$populate-mu-function-header:error3:
# error("function output '" var "' must be in a register")
(write-buffered *(ebp+0x14) "function output '")
# error("fn " fn ": function output '" var "' must be in a register")
(write-buffered *(ebp+0x14) "fn ")
50/push-eax
(lookup *edi *(edi+4)) # Function-name Function-name => eax
(write-buffered *(ebp+0x14) %eax)
58/pop-to-eax
(write-buffered *(ebp+0x14) ": function output '")
(lookup *ebx *(ebx+4)) # => eax
(lookup *eax *(eax+4)) # Var-name Var-name => eax
(write-buffered *(ebp+0x14) %eax)
@ -6296,6 +6401,203 @@ $populate-mu-function-header:error3:
(stop *(ebp+0x18) 1)
# never gets here
# scenarios considered:
# ✓ fn foo
# ✗ fn foo {
# ✓ fn foo x
# ✓ fn foo x: int
# ✓ fn foo x: int -> y/eax: int
# TODO:
# disallow outputs of type `(... addr ...)`
# disallow inputs of type `(... addr ... addr ...)`
populate-mu-function-signature: # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
# pseudocode:
# var word-slice: slice
# next-mu-token(first-line, word-slice)
# assert(word-slice not in '{' '}' '->')
# out->name = slice-to-string(word-slice)
# ## inouts
# while true
# word-slice = next-mu-token(first-line)
# if slice-empty?(word-slice) break
# if (word-slice == '->') break
# assert(word-slice not in '{' '}')
# var v: (handle var) = parse-var-with-type(word-slice, first-line)
# assert(v->register == null)
# # v->block-depth is implicitly 0
# out->inouts = append(v, out->inouts)
# ## outputs
# while true
# word-slice = next-mu-token(first-line)
# if slice-empty?(word-slice) break
# assert(word-slice not in '{' '}' '->')
# var v: (handle var) = parse-var-with-type(word-slice, first-line)
# assert(v->register != null)
# out->outputs = append(v, out->outputs)
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
53/push-ebx
57/push-edi
# edi = out
8b/-> *(ebp+0xc) 7/r32/edi
# var word-slice/ecx: slice
68/push 0/imm32/end
68/push 0/imm32/start
89/<- %ecx 4/r32/esp
# var v/ebx: (handle var)
68/push 0/imm32
68/push 0/imm32
89/<- %ebx 4/r32/esp
# read function name
(next-mu-token *(ebp+8) %ecx)
# error checking
# if (word-slice == '{') abort
(slice-equal? %ecx "{") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# if (word-slice == '->') abort
(slice-equal? %ecx "->") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# save function name
(slice-to-string Heap %ecx %edi) # Function-name
# save function inouts
{
$populate-mu-function-signature:check-for-inout:
(next-mu-token *(ebp+8) %ecx)
(slice-empty? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
# if (word-slice == '->') break
(slice-equal? %ecx "->") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
# if (word-slice == '{') abort
(slice-equal? %ecx "{") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# v = parse-var-with-type(word-slice, first-line)
(parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
# assert(v->register == null)
# . eax: (addr var) = lookup(v)
(lookup *ebx *(ebx+4)) # => eax
81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register
0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
# v->block-depth is implicitly 0
#
# out->inouts = append(v, out->inouts)
8d/copy-address *(edi+8) 0/r32/eax # Function-inouts
(append-list Heap *ebx *(ebx+4) *(edi+8) *(edi+0xc) %eax) # Function-inouts, Function-inouts
#
e9/jump loop/disp32
}
# save function outputs
{
$populate-mu-function-signature:check-for-out:
(next-mu-token *(ebp+8) %ecx)
(slice-empty? %ecx) # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= break/disp32
# if (word-slice == '{') abort
(slice-equal? %ecx "{") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# if (word-slice == '->') abort
(slice-equal? %ecx "->") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# if (word-slice == '}') abort
(slice-equal? %ecx "}") # => eax
3d/compare-eax-and 0/imm32/false
0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
# v = parse-var-with-type(word-slice, first-line)
(parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
# assert(var->register != null)
# . eax: (addr var) = lookup(v)
(lookup *ebx *(ebx+4)) # => eax
81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register
0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
# out->outputs = append(v, out->outputs)
8d/copy-address *(edi+0x10) 0/r32/eax # Function-outputs
(append-list Heap *ebx *(ebx+4) *(edi+0x10) *(edi+0x14) %eax) # Function-outputs, Function-outputs
#
e9/jump loop/disp32
}
$populate-mu-function-signature:done:
(check-no-tokens-left *(ebp+8))
$populate-mu-function-signature:end:
# . reclaim locals
81 0/subop/add %esp 0x10/imm32
# . restore registers
5f/pop-to-edi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
$populate-mu-function-signature:error1:
# error("function signature not in form 'fn <name> {'")
(write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
(flush *(ebp+0x10))
(rewind-stream *(ebp+8))
(write-stream-data *(ebp+0x10) *(ebp+8))
(write-buffered *(ebp+0x10) "'\n")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
$populate-mu-function-signature:error2:
# error("fn " fn ": function inout '" var "' cannot be in a register")
(write-buffered *(ebp+0x10) "fn ")
50/push-eax
(lookup *edi *(edi+4)) # Function-name Function-name => eax
(write-buffered *(ebp+0x10) %eax)
58/pop-to-eax
(write-buffered *(ebp+0x10) ": function inout '")
(lookup *eax *(eax+4)) # Var-name Var-name => eax
(write-buffered *(ebp+0x10) %eax)
(write-buffered *(ebp+0x10) "' cannot be in a register")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
$populate-mu-function-signature:error3:
# error("fn " fn ": function output '" var "' must be in a register")
(write-buffered *(ebp+0x10) "fn ")
50/push-eax
(lookup *edi *(edi+4)) # Function-name Function-name => eax
(write-buffered *(ebp+0x10) %eax)
58/pop-to-eax
(write-buffered *(ebp+0x10) ": function output '")
(lookup *ebx *(ebx+4)) # => eax
(lookup *eax *(eax+4)) # Var-name Var-name => eax
(write-buffered *(ebp+0x10) %eax)
(write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
(rewind-stream *(ebp+8))
(write-stream-data *(ebp+0x10) *(ebp+8))
(write-buffered *(ebp+0x10) "'\n")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
test-function-header-with-arg:
# . prologue
55/push-ebp
@ -10478,13 +10780,21 @@ check-mu-types: # err: (addr buffered-file), ed: (addr exit-descriptor)
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
# var curr/eax: (addr function) = *Program->functions
# var curr/eax: (addr function) = lookup(Program->functions)
(lookup *_Program-functions *_Program-functions->payload) # => eax
{
$check-mu-types:loop:
# if (curr == null) break
3d/compare-eax-and 0/imm32
0f 84/jump-if-= break/disp32
#? # dump curr->name {{{
#? 50/push-eax
#? (lookup *eax *(eax+4)) # Function-name Function-name => eax
#? (write-buffered Stderr %eax)
#? (write-buffered Stderr Newline)
#? (flush Stderr)
#? 58/pop-to-eax
#? # }}}
(check-mu-function %eax *(ebp+8) *(ebp+0xc))
# curr = lookup(curr->next)
(lookup *(eax+0x20) *(eax+0x24)) # Function-next Function-next => eax
@ -10610,7 +10920,7 @@ check-mu-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-fi
{
74/jump-if-= break/disp8
(check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
eb/jump $check-mu-stmt:end/disp8
e9/jump $check-mu-stmt:end/disp32
}
# - otherwise find a function to check against
# var f/eax: (addr function) = lookup(*Program->functions)
@ -10622,7 +10932,17 @@ check-mu-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-fi
(check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
eb/jump $check-mu-stmt:end/disp8
}
# TODO: error on unknown function. We need to first type-check calls to SubX functions.
# var f/eax: (addr function) = lookup(*Program->signatures)
(lookup *_Program-signatures *_Program-signatures->payload) # => eax
(find-matching-function %eax *(ebp+8)) # => eax
3d/compare-eax-and 0/imm32
{
74/jump-if-= break/disp8
(check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
eb/jump $check-mu-stmt:end/disp8
}
# - otherwise abort
e9/jump $check-mu-stmt:unknown-call/disp32
$check-mu-stmt:end:
# . restore registers
58/pop-to-eax
@ -10631,6 +10951,16 @@ $check-mu-stmt:end:
5d/pop-to-ebp
c3/return
$check-mu-stmt:unknown-call:
(write-buffered *(ebp+0x10) "unknown function '")
8b/-> *(ebp+8) 0/r32/eax
(lookup *(eax+4) *(eax+8)) # Stmt1-operation Stmt1-operation => eax
(write-buffered *(ebp+0x10) %eax)
(write-buffered *(ebp+0x10) "'\n")
(flush *(ebp+0x10))
(stop *(ebp+0x14) 1)
# never gets here
has-primitive-name?: # stmt: (addr stmt) -> result/eax: boolean
# . prologue
55/push-ebp

2
mu.vim
View File

@ -53,7 +53,7 @@ syntax match muControl "\<loop\>\|\<loop-if[^ ]*"
highlight link muControl PreProc
syntax match muKeyword " -> "
syntax keyword muKeyword fn type var
syntax keyword muKeyword fn type var sig
highlight link muKeyword PreProc
syntax match muFunction "\(fn\s*\)\@<=\(\S\+\)"