]> git.mdlowis.com Git - proto/cerise-c.git/commitdiff
added records and record constructors. Code generation for record construction still...
authorMike Lowis <mike.lowis@gentex.com>
Thu, 21 Nov 2024 20:50:39 +0000 (15:50 -0500)
committerMike Lowis <mike.lowis@gentex.com>
Thu, 21 Nov 2024 20:50:39 +0000 (15:50 -0500)
Int.m
Records.c
Records.m
cerise-c.m
lib/codegen.rb
lib/lexer.rb
lib/parser.rb
lib/type_checker.rb

diff --git a/Int.m b/Int.m
index 71cd36487f78dc01dc214988fab676d9f04efd8b..22b553d4c2c9385c7a24a4ea4629a8c2d8f09d4f 100644 (file)
--- a/Int.m
+++ b/Int.m
@@ -10,5 +10,5 @@ T is int
 
 SumInts(a : int, b : int) : int
 {
-    return a + b + Foo.Bar()
+    return a + b + Foo:Bar()
 }
index 9ca090e670a62547f76242968d09738a654702b8..8838061837620db8cafbcd78efb7c83636ab2ca9 100644 (file)
--- a/Records.c
+++ b/Records.c
@@ -9,4 +9,5 @@ struct Records_Rec1 {
 struct Records_Rec2 {
     Records_Rec1 _base;
     int bar;
+    Records_Rec2* baz;
 };
index 31efe6676783841d87d9e663618a46e9f3178efd..614fe0222034cdae8962e08489d9634e27a2dc57 100644 (file)
--- a/Records.m
+++ b/Records.m
@@ -6,4 +6,5 @@ Rec1 is record {
 
 Rec2 is record (Rec1) {
     bar = int
+    baz = Rec2
 }
\ No newline at end of file
index 710527a75464bf152dae232d5af839829d980a45..05d842f10219b7d38b7151ec1e2e2956b87f09d5 100644 (file)
@@ -188,6 +188,13 @@ TestIfBlocks(){
     }
 }
 
+TestRecords(){
+    def foo = new Records:Rec1 { foo = 42 }
+#    assert foo.foo == 42
+#    set foo.foo = 43
+#    assert foo.foo == 43
+}
+
 AddTwoNums(a : int, b : int)
 {
     return a + b
@@ -209,5 +216,5 @@ Main()
     TestGtEqOps()
     TestNeqOps()
     TestIfBlocks()
-    Int.SumInts(1,2)
+    Int:SumInts(1,2)
 }
index aa259d03c089ccf0435c1b2b254ca3f24b9dd556..ec097596cff7920a3ddab29d7f4356f1f0eba8fa 100644 (file)
@@ -15,9 +15,6 @@ 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
@@ -63,6 +60,24 @@ class Codegen
     end
   end
 
+  def reference_type?(type)
+    if type == :string
+      true
+    elsif type.is_a? Symbol
+      false
+    elsif type.is_a? IR::Var
+      if (not type.module) || (type.module == @parser.module)
+        reference_type?(@syms[type.name].value || @syms[type.name].type)
+      else
+        reference_type?(@syms[type.module].exports[env.name].type)
+      end
+    elsif [:array, :hash, :record].include? type.form
+      true
+    else
+      false
+    end
+  end
+
   def define_type(sym)
     type = sym.value
     if type.form == :record
@@ -71,7 +86,8 @@ class Codegen
         puts "    #{type_to_s(type.base)} _base;"
       end
       type.fields.each do |k,v|
-        puts "    #{type_to_s(v)} #{k};"
+        is_ref = reference_type?(v)
+        puts "    #{type_to_s(v)}#{is_ref ? "*" : ""} #{k};"
       end
       puts "};"
     end
index 34b076c164494e45b4f49433b7d76bd61af8746d..8f2f7469da1f9ec84032472272eb0f6dd7a85ca7 100644 (file)
@@ -45,7 +45,8 @@ class Lexer
     "module"  => :module,
     "imports" => :imports,
     "exports" => :exports,
-    "record" => :record
+    "record"  => :record,
+    "new"     => :new,
   }
 
   def next
index af775721d600cc7a669524685cf6a71d819a64eb..6d4e31ddcd2b07dbdba4b7b9b7009cffa9445081 100644 (file)
@@ -262,7 +262,7 @@ class Parser
   def qualified_identifier()
     tok = expect(:ident)
     varname = IR::Var.new(tok.pos, nil, tok.text.to_sym, nil)
-    if accept(".")
+    if accept(":")
       mod = syms[varname.name]
       if mod.nil?
         error("no such module: '#{varname.name}'")
@@ -488,7 +488,9 @@ class Parser
   end
 
   def const_or_ident()
-    if matches("[")
+    if matches(:new)
+      record_literal()
+    elsif matches("[")
       array_literal()
     elsif matches("{")
       hash_literal()
@@ -518,6 +520,22 @@ class Parser
     end
   end
 
+  def record_literal()
+    expect(:new)
+    name = qualified_identifier()
+    op = IR::Op.new(name.loc, nil, :new, name, {})
+    expect("{")
+    while !matches("}")
+      fname = identifier()
+      expect("=")
+      value = expression()
+      op.right[fname.name] = value
+      expect(",") if not matches("}")
+    end
+    expect("}")
+    op
+  end
+
   def array_literal()
     exprs = []
     expect("[")
index 899be5dd7b733b4b22bc7813020b5be9fb3d9247..69f3085251e8ec94e05de0b39b3c0af551e3b667 100644 (file)
@@ -143,6 +143,17 @@ class TypeChecker
     end
   end
 
+  def lookup_type(env, type)
+    if type.is_a? IR::Var
+      if type.module.nil?
+        type = env[type.name].value
+      else
+        type = env[type.module].type.exports[type.name].value
+      end
+    end
+    type
+  end
+
   def check(env, expr, type)
 #    if type.is_a? IR::Var
 #      type = typename(type)
@@ -307,12 +318,32 @@ class TypeChecker
 
   def infer_op(env, expr)
     # infer the operand type first
-    vtype = infer(env, expr.left)
-    if (expr.left and expr.right)
-      check_binary(env, expr, vtype)
+    if expr.op == :new
+      infer_new(env, expr)
     else
-      check_unary(env, expr, vtype)
+      vtype = infer(env, expr.left)
+      if (expr.left and expr.right)
+        check_binary(env, expr, vtype)
+      else
+        check_unary(env, expr, vtype)
+      end
+    end
+  end
+
+  def infer_new(env, expr)
+    type = lookup_type(env, expr.left)
+    if type.nil?
+      error(expr.loc, "unknown record type: #{expr.left}")
+    end
+    expr.right.each do |field, value|
+      field_type = type.fields[field]
+      if field_type.nil?
+        error(expr.loc, "record type #{expr.left} has no such field '#{k}'")
+      end
+      check(env, value, field_type)
+      value.type = field_type
     end
+    expr.type = expr.left
   end
 
   def infer_call(env, expr)
@@ -356,7 +387,6 @@ class TypeChecker
     end
   end
 
-
   def check_func(env, expr, type)
     raise "unimplemented"
     error(expr.loc, "unimplemented")