]> git.mdlowis.com Git - proto/cerise-c.git/commitdiff
type checker fleshed out more. test file can compile now.
authorMike Lowis <mike.lowis@gentex.com>
Fri, 18 Oct 2024 16:55:14 +0000 (12:55 -0400)
committerMike Lowis <mike.lowis@gentex.com>
Fri, 18 Oct 2024 16:55:14 +0000 (12:55 -0400)
cerise-c.m
lib/parser.rb
lib/type_checker.rb

index 40081a626d1a2e26ffc1ad611364913a9a4c7796..9727244eed5164e93172b64f9130b1c86fbdcb8d 100644 (file)
@@ -182,6 +182,11 @@ TestIfBlocks(){
     }
 }
 
+AddTwoNums(a : int, b : int)
+{
+    return a + b
+}
+
 Main()
 {
     TestLiterals()
index 2ab631c140105cf85c60e919962b281353bf9a99..6188d99062c8ccf3a9434f30898b3317674b90e0 100644 (file)
@@ -168,9 +168,9 @@ class Parser
     args = function_arglist()
     func = IR::Func.new(name.loc, :void, args, [], [])
     defs = []
-#    if accept(":")
-#      func.type = expect(:ident).text.to_sym
-#    end
+    if accept(":")
+      func.type = type_specifier()
+    end
     expect("{")
     while matches(:def)
       local = variable_definition()
@@ -193,8 +193,9 @@ class Parser
     expect("(")
     while !matches(")")
       id = identifier()
-#      expect(":")
-#      id.type = expect(:ident).text.to_sym
+      if accept(":")
+        id.type = type_specifier()
+      end
       args << id
       expect(",") if !matches(")")
     end
@@ -207,6 +208,10 @@ class Parser
     IR::Var.new(name.pos, nil, name.text.to_sym)
   end
 
+  def type_specifier()
+    expect(:ident).text.to_sym
+  end
+
 
   ##
   # Statements
index a05df208521dff8d0410a8e64060f19549d95455..3915cddf2c860032690a15c5f8c0829dab188f59 100644 (file)
@@ -94,7 +94,7 @@ class TypeChecker
     @parser = parser
     env = parser.syms
     parser.symbols.each do |sym, data|
-      type = infer(env, env[sym].value)
+      env[sym].type = infer(env, env[sym].value)
     end
   end
 
@@ -160,31 +160,32 @@ class TypeChecker
   ##
 
   def infer_func(env, expr)
-    env = env.clone
     @typevar = 0
+    env.open_scope()
     expr.args.each do |a|
       a.type ||= make_typevar()
-      env.add_sym(a.name, a.loc, :arg, a.type)
+      env.add_sym(a.name, a.loc, :arg, a.type, a)
     end
+    env.open_scope()
     expr.body.each do |expr|
       infer(env, expr)
     end
 
-
-#    infer(env, expr.body)
     type = (expr.args + [expr.body.last]).map {|v| v.type }
-    type.unshift(:void) if type.length == 1
 
     # the body may have inferred an arg type, fix it up here
     expr.args.each_with_index do |a,i|
       a.type = env[a.name][:type]
       type[i] = a.type
     end
+
+    env.close_scope()
+    env.close_scope()
     expr.type = type
   end
 
   def infer_return(env, expr)
-    if expr.type
+    if expr.value
       expr.type = infer(env, expr.value)
     else
       expr.type = :void
@@ -219,7 +220,6 @@ class TypeChecker
     else
       raise "could not infer const"
     end
-    pp "TYPED", expr
     expr.type
   end
 
@@ -267,9 +267,13 @@ class TypeChecker
   def infer_if(env, expr)
     check(env, expr.cond, :bool)
     expr.type = :void
+    env.open_scope()
     expr.then.each {|e| infer(env, e) }
+    env.close_scope()
+    env.open_scope()
     (expr.else || []).each {|e| infer(env, e) }
-  end
+    env.close_scope()
+ end
 
   def infer_assert(env, expr)
     check(env, expr.value, :bool)
@@ -301,7 +305,7 @@ class TypeChecker
     etype = infer(env, expr)
     if (etype.class == String)
       expr.type = type
-      env.set_type(expr.name, type)
+      env[expr.name].type = type
     elsif expr.type != type
       error(expr.loc, "expected #{type}, received #{etype}")
     end
@@ -317,7 +321,18 @@ class TypeChecker
   end
 
   def check_call(env, expr, type)
-    pp expr
+    # Handle global functions that haven't been typed yet but are
+    # being called. We pause to infer their type.
+    if untyped_global_func?(env, expr.func, type)
+      puts "\nUNTYPED FUNC\n\n"
+      value = env[expr.func.name][:value]
+      env[expr.func.name][:value] = nil
+      infer(@parser.syms, value)
+      env[expr.func.name][:value] = value
+      env[expr.func.name][:type]  = value.type
+      type = infer(env, expr.func)
+    end
+
     error(expr.loc, "object being applied is not a function (has type: #{type.to_s})") if not type.is_a? Array
     error(expr.loc, "wrong number of arguments to function call") if (type.length - 1) != expr.args.length
     type[0..-2].each_with_index do |t,i|
@@ -333,24 +348,24 @@ class TypeChecker
 
 
 
-#  def make_typevar()
-#    @typevar ||= 0
-#    var = "abcdefghijklmnopqrstuvwxyz"[@typevar]
-#    @typevar += 1
-#    var
-#  end
-#
-#  def var?(expr)
-#    expr.class == IR::Var
-#  end
-#
-#  def untyped_global_func?(env, func, type)
-#    type.nil? and
-#    var?(func) and
-#    env.global?(func.name) and
-#    env[func.name][:value]
-#  end
-#
+  def make_typevar()
+    @typevar ||= 0
+    var = "abcdefghijklmnopqrstuvwxyz"[@typevar]
+    @typevar += 1
+    var
+  end
+
+  def var?(expr)
+    expr.class == IR::Var
+  end
+
+  def untyped_global_func?(env, func, type)
+    type.nil? and
+    var?(func) and
+    env.global?(func.name) and
+    env[func.name][:value]
+  end
+
 #  def check_apply(env, expr, type)
 #    # Handle global functions that haven't been typed yet but are
 #    # being called. We pause to infer their type.
@@ -468,8 +483,6 @@ class TypeChecker
       else
         error(expr.loc, "don't know how to index into type: #{left_type}")
       end
-#      pp left_type
-#      raise "array access"
     else
       optype = BinaryOps[expr.op][vtype]
       error(expr.loc, "unknown binary operation '#{expr.op}' for operand type #{vtype}") if optype.nil?
@@ -477,7 +490,6 @@ class TypeChecker
       check(env, expr.right, optype[1])
       expr.type = optype.last
     end
-    pp expr
     expr.type
   end
 end