about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xapps/mubin360708 -> 362394 bytes
-rw-r--r--apps/mu.subx157
2 files changed, 150 insertions, 7 deletions
diff --git a/apps/mu b/apps/mu
index da78d1a4..8faa96c9 100755
--- a/apps/mu
+++ b/apps/mu
Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx
index c8de423b..389aa9e2 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -407,6 +407,7 @@ Type-id:  # (stream (addr array byte))
            # Not to be used directly, so we don't include a name here.
   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
            # Not to be used directly, so we don't include a name here.
+  # Keep Primitive-type-ids in sync if you add types here.
                           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
@@ -416,7 +417,7 @@ Type-id:  # (stream (addr array byte))
   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
 
 Primitive-type-ids:  # (addr int)
-  0x24
+  0x2c
 
 # == Type definitions
 # Program->types contains some typeinfo for each type definition.
@@ -4893,6 +4894,94 @@ test-convert-function-and-type-definition:
     5d/pop-to-ebp
     c3/return
 
+test-type-definition-with-array:
+    # . 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 "type t {\n")
+    (write _test-input-stream "  a: (array int 3)\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-type-definition-with-array: output should be empty")
+    (check-next-stream-line-equal _test-error-stream  "type t: invalid type 'array'"  "F - test-type-definition-with-array: error message")
+    # check that stop(1) was called
+    (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
+    # don't restore from ebp
+    81 0/subop/add %esp 8/imm32
+    # . epilogue
+    5d/pop-to-ebp
+    c3/return
+
+test-type-definition-with-addr:
+    # . 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 "type t {\n")
+    (write _test-input-stream "  a: (addr int)\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-type-definition-with-addr: output should be empty")
+    (check-next-stream-line-equal _test-error-stream  "type t: invalid type 'addr'"  "F - test-type-definition-with-addr: error message")
+    # check that stop(1) was called
+    (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
+    # don't restore from ebp
+    81 0/subop/add %esp 8/imm32
+    # . epilogue
+    5d/pop-to-ebp
+    c3/return
+
 test-convert-function-with-local-var-with-user-defined-type:
     # . prologue
     55/push-ebp
@@ -6566,7 +6655,6 @@ $parse-mu:sig:
         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
@@ -10667,7 +10755,7 @@ $populate-mu-type:line-loop:
       (read-line-buffered *(ebp+8) %ecx)
       # if (line->write == 0) abort
       81 7/subop/compare *ecx 0/imm32
-      0f 84/jump-if-= $populate-mu-type:abort/disp32
+      0f 84/jump-if-= $populate-mu-type:error1/disp32
 #?       # dump line {{{
 #?       (write 2 "parse-mu: ^")
 #?       (write-stream 2 %ecx)
@@ -10688,7 +10776,19 @@ $populate-mu-type:parse-element:
       # must do this first to strip the trailing ':' from word-slice before
       # using it in find-or-create-typeinfo-fields below
       # TODO: clean up that mutation in parse-var-with-type
-      (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
+      (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
+      # if v is an addr, abort
+      (lookup *esi *(esi+4))  # => eax
+      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
+      (is-mu-addr-type? %eax)  # => eax
+      3d/compare-eax-and 0/imm32/false
+      0f 85/jump-if-!= $populate-mu-type:error2/disp32
+      # if v is an array, abort  (we could support it, but initialization gets complex)
+      (lookup *esi *(esi+4))  # => eax
+      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
+      (is-mu-array-type? %eax)  # => eax
+      3d/compare-eax-and 0/imm32/false
+      0f 85/jump-if-!= $populate-mu-type:error3/disp32
       # var tmp/ecx
       51/push-ecx
 $populate-mu-type:create-typeinfo-fields:
@@ -10712,6 +10812,7 @@ $populate-mu-type:set-input-type:
       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
       8b/-> *(esi+4) 1/r32/ecx
       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
+      # restore line
       59/pop-to-ecx
       {
 $populate-mu-type:create-output-type:
@@ -10745,8 +10846,8 @@ $populate-mu-type:end:
     5d/pop-to-ebp
     c3/return
 
-$populate-mu-type:abort:
-    # error("unexpected top-level command: " word-slice "\n")
+$populate-mu-type:error1:
+    # error("incomplete type definition '" t->name "'\n")
     (write-buffered *(ebp+0x10) "incomplete type definition '")
     (type-name *edi)  # Typeinfo-id => eax
     (write-buffered *(ebp+0x10) %eax)
@@ -10755,6 +10856,26 @@ $populate-mu-type:abort:
     (stop *(ebp+0x14) 1)
     # never gets here
 
+$populate-mu-type:error2:
+    # error("type " t->name ": invalid type 'addr'\n")
+    (write-buffered *(ebp+0x10) "type ")
+    (type-name *edi)  # Typeinfo-id => eax
+    (write-buffered *(ebp+0x10) %eax)
+    (write-buffered *(ebp+0x10) ": invalid type 'addr'\n")
+    (flush *(ebp+0x10))
+    (stop *(ebp+0x14) 1)
+    # never gets here
+
+$populate-mu-type:error3:
+    # error("type " t->name ": invalid type 'array'\n")
+    (write-buffered *(ebp+0x10) "type ")
+    (type-name *edi)  # Typeinfo-id => eax
+    (write-buffered *(ebp+0x10) %eax)
+    (write-buffered *(ebp+0x10) ": invalid type 'array'\n")
+    (flush *(ebp+0x10))
+    (stop *(ebp+0x14) 1)
+    # never gets here
+
 type-name:  # index: int -> result/eax: (addr array byte)
     # . prologue
     55/push-ebp
@@ -10779,7 +10900,7 @@ index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (add
     # eax = index
     8b/-> *(ebp+0xc) 0/r32/eax
     # eax = *(arr + 12 + index)
-    8b/-> *(esi+eax+0xc) 0/r32/eax
+    8b/-> *(esi+eax<<2+0xc) 0/r32/eax
 $index:end:
     # . restore registers
     5e/pop-to-esi
@@ -19449,6 +19570,28 @@ $is-mu-addr-type?:end:
     5d/pop-to-ebp
     c3/return
 
+is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # eax = a
+    8b/-> *(ebp+8) 0/r32/eax
+    # if (!a->is-atom?) a = a->left
+    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
+    {
+      75/jump-if-!= break/disp8
+      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
+    }
+    # return (a->value == array)
+    81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
+    0f 94/set-byte-if-= %al
+    81 4/subop/and %eax 0xff/imm32
+$is-mu-array-type?:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 test-emit-subx-stmt-primitive:
     # Primitive operation on a variable on the stack.
     #   increment foo