about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--403unicode.mu2
-rw-r--r--405screen.mu4
-rw-r--r--apps/arith.mu12
-rwxr-xr-xapps/mubin481604 -> 482587 bytes
-rw-r--r--apps/mu.subx105
-rw-r--r--apps/raytracing/vec.mu2
-rw-r--r--apps/tile/word.mu2
7 files changed, 97 insertions, 30 deletions
diff --git a/403unicode.mu b/403unicode.mu
index b512fb4f..94710be6 100644
--- a/403unicode.mu
+++ b/403unicode.mu
@@ -369,7 +369,7 @@ fn test-shift-left-bytes-5 {
 
 # To run all tests, uncomment this and run:
 #   $ ./translate_mu  &&  ./a.elf
-#? fn main -> r/ebx: int {
+#? fn main -> _/ebx: int {
 #?   run-tests
 #?   r <- copy 0
 #? }
diff --git a/405screen.mu b/405screen.mu
index a742cc7b..7007e704 100644
--- a/405screen.mu
+++ b/405screen.mu
@@ -1424,8 +1424,8 @@ fn test-check-screen-blinking {
   check-screen-row-in-blinking screen, 1, "a c", "F - test-check-screen-blinking"
 }
 
-#? fn main -> exit-status/ebx: int {
+#? fn main -> _/ebx: int {
 #? #?   test-check-screen-color
 #?   run-tests
-#?   exit-status <- copy 0
+#?   return 0
 #? }
diff --git a/apps/arith.mu b/apps/arith.mu
index 6fbd3745..2bfec1db 100644
--- a/apps/arith.mu
+++ b/apps/arith.mu
@@ -55,7 +55,7 @@ fn main -> _/ebx: int {
   return 0
 }
 
-fn simplify -> _/eax: int, _2/esi: grapheme {
+fn simplify -> _/eax: int, _/esi: grapheme {
   # prime the pump
   var look/esi: grapheme <- get-char
   # do it
@@ -64,7 +64,7 @@ fn simplify -> _/eax: int, _2/esi: grapheme {
   return result, look
 }
 
-fn expression _look: grapheme -> _/eax: int, _2/esi: grapheme {
+fn expression _look: grapheme -> _/eax: int, _/esi: grapheme {
   var look/esi: grapheme <- copy _look
   # read arg
   var result/eax: int <- copy 0
@@ -109,7 +109,7 @@ fn expression _look: grapheme -> _/eax: int, _2/esi: grapheme {
   return result, look
 }
 
-fn term _look: grapheme -> _/eax: int, _2/esi: grapheme {
+fn term _look: grapheme -> _/eax: int, _/esi: grapheme {
   var look/esi: grapheme <- copy _look
   # read arg
   look <- skip-spaces look
@@ -154,7 +154,7 @@ fn term _look: grapheme -> _/eax: int, _2/esi: grapheme {
   return result, look
 }
 
-fn factor _look: grapheme -> _/eax: int, _2/esi: grapheme {
+fn factor _look: grapheme -> _/eax: int, _/esi: grapheme {
   var look/esi: grapheme <- copy _look  # should be a no-op
   look <- skip-spaces look
   # if next char is not '(', parse a number
@@ -202,13 +202,13 @@ fn is-add-or-sub? c: grapheme -> _/eax: boolean {
   return 0  # false
 }
 
-fn operator _look: grapheme -> _/ecx: byte, _2/esi: grapheme {
+fn operator _look: grapheme -> _/ecx: byte, _/esi: grapheme {
   var op/ecx: byte <- copy _look
   var look/esi: grapheme <- get-char
   return op, look
 }
 
-fn num _look: grapheme -> _/eax: int, _2/esi: grapheme {
+fn num _look: grapheme -> _/eax: int, _/esi: grapheme {
   var look/esi: grapheme <- copy _look
   var result/edi: int <- copy 0
   {
diff --git a/apps/mu b/apps/mu
index 11b896d8..aa6bc3e8 100755
--- a/apps/mu
+++ b/apps/mu
Binary files differdiff --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")
diff --git a/apps/raytracing/vec.mu b/apps/raytracing/vec.mu
index c93bab91..c641d2b2 100644
--- a/apps/raytracing/vec.mu
+++ b/apps/raytracing/vec.mu
@@ -128,7 +128,7 @@ fn vec3-length-squared _v: (addr vec3) -> _/xmm0: float {
   return result
 }
 
-fn vec3-dot _v1: (addr vec3), _v2: (addr vec3) -> result/xmm0: float {
+fn vec3-dot _v1: (addr vec3), _v2: (addr vec3) -> _/xmm0: float {
 }
 
 fn vec3-cross _v1: (addr vec3), _v2: (addr vec3), out: (addr vec3) {
diff --git a/apps/tile/word.mu b/apps/tile/word.mu
index c51c4bf4..64d03ff8 100644
--- a/apps/tile/word.mu
+++ b/apps/tile/word.mu
@@ -176,7 +176,7 @@ fn cursor-at-start? _self: (addr word) -> _/eax: boolean {
   return result
 }
 
-fn cursor-at-end? _self: (addr word) -> result/eax: boolean {
+fn cursor-at-end? _self: (addr word) -> _/eax: boolean {
   var self/esi: (addr word) <- copy _self
   var data-ah/eax: (addr handle gap-buffer) <- get self, scalar-data
   var data/eax: (addr gap-buffer) <- lookup *data-ah