]> git.mdlowis.com Git - proto/cerise-c.git/commitdiff
added typedef validation and checking
authorMike Lowis <mike.lowis@gentex.com>
Wed, 6 Nov 2024 20:51:06 +0000 (15:51 -0500)
committerMike Lowis <mike.lowis@gentex.com>
Wed, 6 Nov 2024 20:51:06 +0000 (15:51 -0500)
TODO.md [new file with mode: 0644]
cerise-c.rb
lib/codegen.rb
lib/type_checker.rb

diff --git a/TODO.md b/TODO.md
new file mode 100644 (file)
index 0000000..19ca776
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,32 @@
+# DOING
+
+# TODO
+
+* Fix type designation in symbol table
+* Add Import/Export statements
+* Add constant definitions
+* Add type definitions
+* Add/Sub for arrays
+* for/in statement for arrays
+* for/in statement for dictionaries
+
+* Implement sets
+* for/in statement for sets
+
+* Add unary operators for integers
+* Add type checking to operators on constants
+* Add optimization of constant operators
+* Add increment/decrement optimization
+* Implement tail call optimization?
+
+* add type checking for empty array literals
+
+
+# Compiler Stages
+
+* Parsing
+* Type validation, checking, inference
+* SSA-conversion
+* Reference counting or ownership checking
+* Optimization
+* code generation
\ No newline at end of file
index 4bf7db74e976e5181ebd8e3eb3f7ead4b6ba4661..c68d7368eba4ef712a1e5a14ff3fbb590ed62f15 100755 (executable)
@@ -1,26 +1,6 @@
 #!/usr/bin/env ruby
 
 # TODO:
-#
-# * Fix type designation in symbol table
-# * Add Import/Export statements
-# * Add constant definitions
-# * Add type definitions
-# * Add/Sub for arrays
-# * for/in statement for arrays
-# * for/in statement for dictionaries
-#
-# * Implement sets
-# * for/in statement for sets
-#
-# * Add unary operators for integers
-# * Add type checking to operators on constants
-# * Add optimization of constant operators
-# * Add increment/decrement optimization
-# * Implement tail call optimization?
-#
-# * add type checking for empty array literals
-
 require 'stringio'
 require 'strscan'
 
index 45a4fab976c93873a1daf78ce438ff7b95b25fa9..aa259d03c089ccf0435c1b2b254ca3f24b9dd556 100644 (file)
@@ -15,12 +15,17 @@ class Codegen
   end
 
   def type_to_s(type)
+    # TODO: lookup fully qualified type here or make sure it's a var?
+
+
     if type == :string
       "_string"
     elsif type.is_a? Symbol
       type
-    elsif type.is_a? IR::Var
+    elsif type.is_a? IR::Var and type.module
       "#{type.module || @parser.module}_#{type.name}"
+    elsif type.is_a? IR::Var and not type.module
+      "#{type.name}"
     elsif type.form == :array
       "_array"
     elsif type.form == :hash
index 439bf50af8e4c45310145e5ba3be00820b9e7ba1..899be5dd7b733b4b22bc7813020b5be9fb3d9247 100644 (file)
@@ -93,9 +93,17 @@ class TypeChecker
   def initialize(parser)
     @parser = parser
     env = parser.syms
+
+    env.add_builtin(:int, :int, :int, nil)
+
     parser.symbols.each do |sym, data|
-      next if env[sym].kind == :type
-      env[sym].type = infer(env, env[sym].value)
+      if env[sym].kind == :type
+        validate(env, env[sym].value)
+      elsif  env[sym].type
+        check(env, env[sym].value, env[sym].type)
+      else
+        env[sym].type = infer(env, env[sym].value)
+      end
     end
   end
 
@@ -103,7 +111,42 @@ class TypeChecker
     @parser.error(msg, loc)
   end
 
+  def validate(env, type)
+    if type.is_a? IR::Var
+      if type.module.nil?
+        if env.global? type.name
+          type.module = @parser.module
+        elsif env.builtin? type.name
+          # leave it alone
+        else
+          error(type.loc, "unknown type '#{type.name}'")
+        end
+      else
+        if not env[type.module]
+          env.error(type.loc, "unknown module '#{type.module}'")
+        end
+        if not env[type.module].fields[type.name]
+          env.error(type.loc, "module '#{type.module}' has no exported symbol '#{type.name}'")
+        end
+      end
+    else
+      case type.form
+      when :alias
+        validate(env, type.base)
+      when :record
+        validate(env, type.base) if type.base
+        type.fields.each {|name,type| validate(env, type) }
+      else
+        raise "unimplemented"
+#        pp type.form
+      end
+    end
+  end
+
   def check(env, expr, type)
+#    if type.is_a? IR::Var
+#      type = typename(type)
+#    end
     if expr.is_a? IR::Const
       check_const(env, expr, type)
     elsif (expr.is_a? IR::Op)
@@ -297,6 +340,23 @@ class TypeChecker
   # TYPE CHECKING
   ##
 
+  def types_equal(a,b)
+    a = typename(a) if a.is_a? IR::Var
+    b = typename(b) if b.is_a? IR::Var
+    a == b
+  end
+
+  def typename(var)
+    if var.is_a? Symbol
+      var
+    elsif var.module.nil?
+      var.name.to_sym
+    else
+      "#{var.module}_#{var.name}".to_sym
+    end
+  end
+
+
   def check_func(env, expr, type)
     raise "unimplemented"
     error(expr.loc, "unimplemented")
@@ -308,7 +368,7 @@ class TypeChecker
   end
 
   def check_const(env, expr, type)
-    if expr.type != type
+    if not types_equal(expr.type, type)
       error(expr.loc, "expected #{type}, received #{expr.type}")
     end
     type
@@ -319,7 +379,7 @@ class TypeChecker
     if (etype.class == String)
       expr.type = type
       env[expr.name].type = type
-    elsif expr.type != type
+    elsif not types_equal(expr.type, type)
       error(expr.loc, "expected #{type}, received #{etype}")
     end
     type
@@ -327,7 +387,7 @@ class TypeChecker
 
   def check_op(env, expr, type)
     expr.type = expr.type || infer(env, expr)
-    if expr.type != type
+    if not types_equal(expr.type, type)
       error(expr.loc, "expect #{type}, received #{expr.type}")
     end
     type
@@ -385,14 +445,6 @@ class TypeChecker
     expr.type = optype[-1]
   end
 
-  def typename(var)
-    if var.module.nil?
-      var.name.to_sym
-    else
-      "#{var.module}_#{var.name}".to_sym
-    end
-  end
-
   def check_binary(env, expr, vtype)
     if expr.op == "["
       left_type = infer(env, expr.left)