about summary refs log tree commit diff stats
path: root/apps/mu.subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-11-28 23:20:39 -0800
committerKartik Agaram <vc@akkartik.com>2019-11-28 23:20:39 -0800
commit31ed455886aefa1403d3fca2e2041a1786e75f2c (patch)
treef856066b22e5d5873fd608d70ddde3338ef56b76 /apps/mu.subx
parent0c24aa334e419789a40f44f61d889928f0154030 (diff)
downloadmu-31ed455886aefa1403d3fca2e2041a1786e75f2c.tar.gz
5773
Rudimentary support for parsing variable declarations.
Diffstat (limited to 'apps/mu.subx')
-rw-r--r--apps/mu.subx205
1 files changed, 205 insertions, 0 deletions
diff --git a/apps/mu.subx b/apps/mu.subx
index 4a449e67..d9fbac97 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -795,6 +795,211 @@ $populate-mu-function-header:abort:
     cd/syscall  0x80/imm8
     # never gets here
 
+# format for variables with types
+#   x : int
+#   x: int
+parse-var-with-type:  # name: slice, first-line: (address stream) -> result/eax: (address var)
+    # pseudocode:
+    #   var v : (address var) = allocate(Heap, Var-size)
+    #   var s : slice
+    #   next-token-from-slice(name->start, name->end, '/', s)
+    #   if (slice-ends-with(s, ":"))
+    #     decrement s->end
+    #   v->name = slice-to-string(s)
+    #   ## register
+    #   next-token-from-slice(s->end, name->end, '/', s)
+    #   if (!slice-empty?(s))
+    #     v->register = slice-to-string(s)
+    #   ## type
+    #   s = next-word-or-sexpression(first-line)
+    #   assert(type not in '{' '}' '->')
+    #   if (slice-equal?(type, ":")) {
+    #     s = next-word-or-sexpression(first-line)
+    #     assert(type not in '{' '}' '->')
+    #   }
+    #   type = type-for(s)
+    #   v->type = type
+    #   return v
+    #
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    51/push-ecx
+    52/push-edx
+    53/push-ebx
+    56/push-esi
+    57/push-edi
+    # var result/edi : (address var) = allocate(Heap, Var-size)
+    (allocate Heap *Var-size)
+    89/<- %edi 0/r32/eax
+    # esi = name
+    8b/-> *(ebp+8) 6/r32/esi
+    # var s/ecx : slice
+    68/push 0/imm32/end
+    68/push 0/imm32/start
+    89/<- %ecx 4/r32/esp
+    # save v->name
+    (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
+    # . end/edx = s->end
+    8b/-> *(ecx+4) 2/r32/edx
+    # . if s ends with ':', decrement s->end
+    {
+      8b/-> *(ecx+4) 0/r32/eax
+      48/decrement-eax
+      8a/copy-byte *eax 3/r32/BL
+      81 4/subop/and %ebx 0xff/imm32
+      81 7/subop/compare %ebx 0x3a/imm32/colon
+      75/jump-if-not-equal break/disp8
+      89/<- *(ecx+4) 0/r32/eax
+    }
+    (slice-to-string Heap %ecx)  # => eax
+    89/<- *edi 0/r32/eax  # Var-name
+    # save v->register
+    (next-token-from-slice %edx *(esi+4) 0x2f %ecx)  # end, name->end, '/'
+    # if (!slice-empty?(s)) v->register = slice-to-string(s)
+    {
+      (slice-empty? %ecx)
+      3d/compare-eax-and 0/imm32
+      75/jump-if-not-equal break/disp8
+      (slice-to-string Heap %ecx)
+      89/<- *(edi+0x10) 0/r32/eax  # Var-register
+    }
+    # save v->type
+    (next-word *(ebp+0xc) %ecx)  # TODO: support type s-expressions
+    # if (word-slice == '{') abort
+    (slice-equal? %ecx "{")   # => eax
+    3d/compare-eax-and 0/imm32
+    0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+    # if (word-slice == '->') abort
+    (slice-equal? %ecx "->")   # => eax
+    3d/compare-eax-and 0/imm32
+    0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+    # if (word-slice == '}') abort
+    (slice-equal? %ecx "}")   # => eax
+    3d/compare-eax-and 0/imm32
+    0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+    # if (slice-equal?(type, ":")) skip
+    (slice-equal? %ecx ":")
+    {
+      3d/compare-eax-and 0/imm32
+      74/jump-if-equal break/disp8
+      (next-word *(ebp+0xc) %ecx)
+      # if (word-slice == '{') abort
+      (slice-equal? %ecx "{")   # => eax
+      3d/compare-eax-and 0/imm32
+      0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+      # if (word-slice == '->') abort
+      (slice-equal? %ecx "->")   # => eax
+      3d/compare-eax-and 0/imm32
+      0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+      # if (word-slice == '}') abort
+      (slice-equal? %ecx "}")   # => eax
+      3d/compare-eax-and 0/imm32
+      0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
+      eb/jump $parse-var-with-type:end/disp8
+    }
+    (type-for %ecx)
+    89/<- *(edi+4) 0/r32/eax  # Var-type
+$parse-var-with-type:end:
+    # return result
+    89/<- %eax 7/r32/edi
+    # . restore registers
+    5f/pop-to-edi
+    5e/pop-to-esi
+    5b/pop-to-ebx
+    5a/pop-to-edx
+    59/pop-to-ecx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+$parse-var-with-type:abort:
+    # error("function header not in form 'fn <name> {'")
+    (write-buffered Stderr "var should have form 'name: type' in '")
+    (flush Stderr)
+    (rewind-stream *(ebp+0xc))
+    (write-stream 2 *(ebp+0xc))
+    (write-buffered Stderr "'\n")
+    (flush Stderr)
+    # . syscall(exit, 1)
+    bb/copy-to-ebx  1/imm32
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+type-for:  # name: slice -> result/eax: type-tree
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+$type-for:end:
+    b8/copy-to-eax 1/imm32/int
+    # . restore registers
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+test-parse-var-with-type:
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # (eax..ecx) = "x:"
+    b8/copy-to-eax "x:"/imm32
+    8b/-> *eax 1/r32/ecx
+    8d/copy-address *(eax+ecx+4) 1/r32/ecx
+    05/add-to-eax 4/imm32
+    # var slice/ecx = {eax, ecx}
+    51/push-ecx
+    50/push-eax
+    89/<- %ecx 4/r32/esp
+    # _test-input-stream contains "int"
+    (clear-stream _test-input-stream)
+    (clear-stream _test-input-buffered-file->buffer)
+    (write _test-input-stream "int")
+    #
+    (parse-var-with-type %ecx _test-input-buffered-file)
+    8b/-> *eax 2/r32/edx  # Var-name
+    (check-string-equal %edx "x" "F - test-var-with-type/name")
+    8b/-> *(eax+4) 2/r32/edx  # Var-type
+    (check-ints-equal %edx 1 "F - test-var-with-type/type")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+test-parse-var-with-type-and-register:
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # (eax..ecx) = "x/eax"
+    b8/copy-to-eax "x/eax"/imm32
+    8b/-> *eax 1/r32/ecx
+    8d/copy-address *(eax+ecx+4) 1/r32/ecx
+    05/add-to-eax 4/imm32
+    # var slice/ecx = {eax, ecx}
+    51/push-ecx
+    50/push-eax
+    89/<- %ecx 4/r32/esp
+    # _test-input-stream contains ": int"
+    (clear-stream _test-input-stream)
+    (clear-stream _test-input-buffered-file->buffer)
+    (write _test-input-stream ": int")
+    #
+    (parse-var-with-type %ecx _test-input-buffered-file)
+    8b/-> *eax 2/r32/edx  # Var-name
+    (check-string-equal %edx "x" "F - test-var-with-type-and-register/name")
+    8b/-> *(eax+0x10) 2/r32/edx  # Var-register
+    (check-string-equal %edx "eax" "F - test-var-with-type-and-register/register")
+    8b/-> *(eax+4) 2/r32/edx  # Var-type
+    (check-ints-equal %edx 1 "F - test-var-with-type-and-register/type")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 # identifier starts with a letter or '$' or '_'
 # no constraints at the moment on later letters
 # all we really want to do so far is exclude '{', '}' and '->'