diff options
author | Kartik Agaram <vc@akkartik.com> | 2020-11-03 14:04:35 -0800 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2020-11-03 14:04:35 -0800 |
commit | da791479a0bd7f1d34c0ba06309cc1fb48bbe7a5 (patch) | |
tree | b702c6eb9873f929270814dd29a64b4f3ca56ae8 /apps/mu.subx | |
parent | 85a29a4e4ed68e7ae35321113ff3d7aedb6afc4b (diff) | |
download | mu-da791479a0bd7f1d34c0ba06309cc1fb48bbe7a5.tar.gz |
7165
All tasks of https://github.com/akkartik/mu/issues/45#issuecomment-719990879 should now be complete.
Diffstat (limited to 'apps/mu.subx')
-rw-r--r-- | apps/mu.subx | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/apps/mu.subx b/apps/mu.subx index 2bf74e73..ec868027 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -21,7 +21,7 @@ # A program is a sequence of function and type definitions. # # Function example: -# fn foo n: int -> result/eax: int { +# fn foo n: int -> _/eax: int { # ... # } # @@ -35,7 +35,8 @@ # Variables not explicitly placed in a register are on the stack. # # Function inputs are always passed in memory (on the stack), while outputs -# are always returned in registers. +# are always returned in registers. Outputs can't be named; they use the +# dummy value '_'. # # Blocks mostly consist of statements. # @@ -757,7 +758,7 @@ test-convert-function-with-return-literal: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " return 0\n") (write _test-input-stream "}\n") # convert @@ -799,7 +800,7 @@ test-convert-function-with-return: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " var y: int\n") (write _test-input-stream " return y\n") (write _test-input-stream "}\n") @@ -844,7 +845,7 @@ test-convert-function-with-return-register: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " var y/eax: int <- copy 3\n") (write _test-input-stream " return y\n") (write _test-input-stream "}\n") @@ -880,6 +881,50 @@ test-convert-function-with-return-register: 5d/pop-to-ebp c3/return +test-function-with-named-output: + # . 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) + (clear-stream _test-error-stream) + (clear-stream $_test-error-buffered-file->buffer) + # var ed/edx: exit-descriptor = tailor-exit-descriptor(16) + 68/push 0/imm32 + 68/push 0/imm32 + 89/<- %edx 4/r32/esp + (tailor-exit-descriptor %edx 0x10) + # + (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream " return 0\n") + (write _test-input-stream "}\n") + # convert + (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) + # registers except esp clobbered at this point + # restore ed + 89/<- %edx 4/r32/esp + (flush _test-output-buffered-file) + (flush _test-error-buffered-file) +#? # dump _test-error-stream {{{ +#? (write 2 "^") +#? (write-stream 2 _test-error-stream) +#? (write 2 "$\n") +#? (rewind-stream _test-error-stream) +#? # }}} + # check output + (check-stream-equal _test-output-stream "" "F - test-function-with-named-output: output should be empty") + (check-next-stream-line-equal _test-error-stream "fn foo: function outputs cannot be named; rename 'x' in the header to '_'" "F - test-function-with-named-output: error message") + # check that stop(1) was called + (check-ints-equal *(edx+4) 2 "F - test-function-with-named-output: exit status") + # don't restore from ebp + 81 0/subop/add %esp 8/imm32 + # . epilogue + 5d/pop-to-ebp + c3/return + test-return-with-wrong-type: # . prologue 55/push-ebp @@ -1687,7 +1732,7 @@ test-convert-function-call: (write _test-input-stream " var result/ebx: int <- foo\n") (write _test-input-stream " return result\n") (write _test-input-stream "}\n") - (write _test-input-stream "fn foo -> result/ebx: int {\n") + (write _test-input-stream "fn foo -> _/ebx: int {\n") (write _test-input-stream " var result/ebx: int <- copy 3\n") (write _test-input-stream " return result\n") (write _test-input-stream "}\n") @@ -2178,7 +2223,7 @@ test-convert-function-call-with-incorrect-output-type: (write _test-input-stream "fn f {\n") (write _test-input-stream " var x/eax: int <- g\n") (write _test-input-stream "}\n") - (write _test-input-stream "fn g -> a/eax: foo {\n") + (write _test-input-stream "fn g -> _/eax: foo {\n") (write _test-input-stream "}\n") # convert (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) @@ -2223,7 +2268,7 @@ test-convert-function-call-with-too-few-outputs: (write _test-input-stream "fn f {\n") (write _test-input-stream " g\n") (write _test-input-stream "}\n") - (write _test-input-stream "fn g -> a/eax: int {\n") + (write _test-input-stream "fn g -> _/eax: int {\n") (write _test-input-stream "}\n") # convert (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) @@ -2314,7 +2359,7 @@ test-convert-function-call-with-missing-output-register: (write _test-input-stream " var x: int\n") (write _test-input-stream " x <- g\n") (write _test-input-stream "}\n") - (write _test-input-stream "fn g -> a/eax: int {\n") + (write _test-input-stream "fn g -> _/eax: int {\n") (write _test-input-stream "}\n") # convert (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) @@ -2359,7 +2404,7 @@ test-convert-function-call-with-incorrect-output-register: (write _test-input-stream "fn f {\n") (write _test-input-stream " var x/ecx: int <- g\n") (write _test-input-stream "}\n") - (write _test-input-stream "fn g -> a/eax: int {\n") + (write _test-input-stream "fn g -> _/eax: int {\n") (write _test-input-stream "}\n") # convert (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx) @@ -10110,7 +10155,7 @@ test-convert-function-with-return-register-and-local: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " var y/eax: int <- copy 3\n") (write _test-input-stream " var z/ecx: int <- copy 4\n") (write _test-input-stream " return y\n") @@ -10160,7 +10205,7 @@ test-convert-function-with-return-register-and-local-2: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> x/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " var y/eax: int <- copy 3\n") (write _test-input-stream " var z/ecx: int <- copy 4\n") (write _test-input-stream " return z\n") @@ -10210,7 +10255,7 @@ test-convert-function-with-return-float-register-and-local: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> f/xmm1: float {\n") + (write _test-input-stream "fn foo -> _/xmm1: float {\n") (write _test-input-stream " var y/eax: int <- copy 3\n") (write _test-input-stream " var g/xmm0: float <- convert y\n") (write _test-input-stream " var h/xmm1: float <- convert y\n") @@ -10267,7 +10312,7 @@ test-convert-function-with-return-and-local-vars: (clear-stream _test-output-stream) (clear-stream $_test-output-buffered-file->buffer) # - (write _test-input-stream "fn foo -> a/eax: int {\n") + (write _test-input-stream "fn foo -> _/eax: int {\n") (write _test-input-stream " {\n") (write _test-input-stream " var x: int\n") (write _test-input-stream " {\n") @@ -10579,7 +10624,7 @@ $parse-mu:error2: # ✗ fn foo x: { # ✓ fn foo x: int { # ✓ fn foo x: int { -# ✓ fn foo x: int -> y/eax: int { +# ✓ fn foo x: int -> _/eax: int { # TODO: # disallow outputs of type `(... addr ...)` # disallow inputs of type `(... addr ... addr ...)` @@ -10610,6 +10655,7 @@ populate-mu-function-header: # first-line: (addr stream byte), out: (addr funct # assert(word-slice not in '}' '->') # var v: (handle var) = parse-var-with-type(word-slice, first-line) # assert(v->register != null) + # assert(v->name == "_") # out->outputs = append(v, out->outputs) # done: # @@ -10719,6 +10765,11 @@ $populate-mu-function-header:check-for-out: (lookup *ebx *(ebx+4)) # => eax 81 7/subop/compare *(eax+0x18) 0/imm32 # Var-register 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 + # assert(var->name == "_") + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (string-equal? %eax "_") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $populate-mu-function-header:error4/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 @@ -10786,12 +10837,28 @@ $populate-mu-function-header:error3: (stop *(ebp+0x18) 1) # never gets here +$populate-mu-function-header:error4: + # error("fn " fn ": function outputs cannot be named; rename '" var "' in the header to '_'") + (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 outputs cannot be named; rename '") + (lookup *ebx *(ebx+4)) # => eax + (lookup *eax *(eax+4)) # Var-name Var-name => eax + (write-buffered *(ebp+0x14) %eax) + (write-buffered *(ebp+0x14) "' in the header to '_'\n") + (flush *(ebp+0x14)) + (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 +# ✓ fn foo x: int -> _/eax: int # TODO: # disallow outputs of type `(... addr ...)` # disallow inputs of type `(... addr ... addr ...)` @@ -11104,7 +11171,7 @@ test-function-header-with-multiple-args-and-outputs: 8b/-> *Primitive-type-ids 0/r32/eax 89/<- *Type-id 0/r32/eax # stream-write (clear-stream _test-input-stream) - (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") + (write _test-input-stream "foo a: int, b: int, c: int -> _/ecx: int _/edx: int {\n") # result/ecx: function 2b/subtract *Function-size 4/r32/esp 89/<- %ecx 4/r32/esp @@ -11173,7 +11240,7 @@ $test-function-header-with-multiple-args-and-outputs:out0: 89/<- %ebx 0/r32/eax # check v->name (lookup *ebx *(ebx+4)) # Var-name Var-name => eax - (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") + (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:0") # check v->register (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") @@ -11191,7 +11258,7 @@ $test-function-header-with-multiple-args-and-outputs:out1: 89/<- %ebx 0/r32/eax # check v->name (lookup *ebx *(ebx+4)) # Var-name Var-name => eax - (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") + (check-strings-equal %eax "_" "F - test-function-header-with-multiple-args-and-outputs/output:1") # check v->register (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register") |