]> git.mdlowis.com Git - proto/cerise-c.git/commitdiff
started implementing records
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 29 Oct 2024 04:10:10 +0000 (00:10 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 29 Oct 2024 04:10:10 +0000 (00:10 -0400)
Int.c
Int.m
Records.c [new file with mode: 0644]
Records.m [new file with mode: 0644]
cerise-c.m
cerise-c.rb
lib/codegen.rb
lib/compiler.rb
lib/lexer.rb
lib/parser.rb
lib/type_checker.rb

diff --git a/Int.c b/Int.c
index 1e8de55d32251ddea75bc143b5a037eefbce8ba1..af75d41f77f05b32cdeb643db96a7f5b1904d750 100644 (file)
--- a/Int.c
+++ b/Int.c
@@ -2,7 +2,8 @@
 
 int Foo_Bar();
 
-int Int_SumInts(int a, int b);
+typedef int Int_T;
+int Int_SumInts(int, int);
 
 int Int_SumInts(int a, int b) {
     int _t0 = (a + b);
diff --git a/Int.m b/Int.m
index 12ae3f643d37fe3b5f521eaa89f77e03e11b848e..71cd36487f78dc01dc214988fab676d9f04efd8b 100644 (file)
--- a/Int.m
+++ b/Int.m
@@ -6,6 +6,8 @@ imports (
 
 exports (SumInts)
 
+T is int
+
 SumInts(a : int, b : int) : int
 {
     return a + b + Foo.Bar()
diff --git a/Records.c b/Records.c
new file mode 100644 (file)
index 0000000..9ca090e
--- /dev/null
+++ b/Records.c
@@ -0,0 +1,12 @@
+#include <runtime.h>
+
+typedef struct Records_Rec1 Records_Rec1;
+typedef struct Records_Rec2 Records_Rec2;
+
+struct Records_Rec1 {
+    int foo;
+};
+struct Records_Rec2 {
+    Records_Rec1 _base;
+    int bar;
+};
diff --git a/Records.m b/Records.m
new file mode 100644 (file)
index 0000000..31efe66
--- /dev/null
+++ b/Records.m
@@ -0,0 +1,9 @@
+module Records
+
+Rec1 is record {
+    foo = int
+}
+
+Rec2 is record (Rec1) {
+    bar = int
+}
\ No newline at end of file
index 1c1afd4983d662811c1bbe084fedd87f5d461aba..710527a75464bf152dae232d5af839829d980a45 100644 (file)
@@ -1,11 +1,14 @@
 module TestSuite
 
 imports (
-    "Int.m"
+    "Int.m",
+    "Records.m"
 )
 
 exports (Main)
 
+Foo is record {}
+
 TestBoolOps()
 {
     assert true == true
@@ -90,10 +93,10 @@ TestArrayOps()
 {
     def array = [1,2,3]
     def item = 42
-#    set array[0] = item
-#    assert array[0] == 42
-#    assert array[1] == 2
-#    assert array[2] == 3
+    set array[0] = item
+    assert array[0] == 42
+    assert array[1] == 2
+    assert array[2] == 3
 #    assert Length(array) == 3
 }
 
index 6e2a3c0815f76bb122a904c31e9f6a96bb184bcb..4bf7db74e976e5181ebd8e3eb3f7ead4b6ba4661 100755 (executable)
@@ -18,6 +18,8 @@
 # * 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 c5e67ee7e5078de665fa5039a161b2e3ecf83c9b..45a4fab976c93873a1daf78ce438ff7b95b25fa9 100644 (file)
@@ -19,6 +19,8 @@ class Codegen
       "_string"
     elsif type.is_a? Symbol
       type
+    elsif type.is_a? IR::Var
+      "#{type.module || @parser.module}_#{type.name}"
     elsif type.form == :array
       "_array"
     elsif type.form == :hash
@@ -28,38 +30,90 @@ class Codegen
     end
   end
 
+  def declare_sym(sym)
+    if sym.kind == :type
+      type = sym.value
+      if type.form == :alias
+        puts "typedef #{type_to_s(type.base)} #{symname(sym)};"
+      elsif type.form == :record
+        puts "typedef struct #{symname(sym)} #{symname(sym)};"
+      else
+        raise "unimplemented"
+      end
+    elsif sym.kind == :func
+      args = sym.type[0..-2].map{|e| type_to_s(e) }.join(", ")
+      puts "#{type_to_s(sym.type.last)} #{symname(sym)}(#{args});"
+    else
+      puts "// #{sym.name}"
+    end
+  end
+
+  def define_sym(sym)
+    if sym.kind == :type
+      define_type(sym)
+    elsif sym.kind == :func
+      define_func(sym)
+    else
+      puts "// #{sym.name}"
+    end
+  end
+
+  def define_type(sym)
+    type = sym.value
+    if type.form == :record
+      puts "struct #{symname(sym)} {"
+      if (type.base)
+        puts "    #{type_to_s(type.base)} _base;"
+      end
+      type.fields.each do |k,v|
+        puts "    #{type_to_s(v)} #{k};"
+      end
+      puts "};"
+    end
+  end
+
+  def define_func(sym)
+    args = sym.value.args.map{|e| "#{type_to_s(e.type)} #{e.name}" }.join(", ")
+    puts "#{type_to_s(sym.type.last)} #{symname(sym)}(#{args}) {"
+    @syms.open_scope
+    @locals = sym.value.locals
+    sym.value.args.each_with_index do |name, idx|
+      @syms.add_sym(name.name, name.loc, :param, name.type, idx)
+    end
+    sym.value.body.each do |stmnt|
+      emit(stmnt)
+    end
+    puts "}\n\n"
+    @syms.close_scope
+  end
+
+
   def output(outpath)
     @output = File.open(outpath, "wb")
 
     puts "#include <runtime.h>\n\n"
-    (@parser.imported_modules || {}).values.each do |mod|
+
+    # output imported symbol declarations
+    imported_mods = (@parser.imported_modules || {}).values
+    imported_mods.each do |mod|
       @syms[mod[:name]].type.exports.each do |name, val|
-        args = val.type[0..-2].map{|e| type_to_s(e) }.join(", ")
-        puts "#{type_to_s(val.type.last)} #{symname(val)}(#{args});"
+        declare_sym(val)
       end
       puts ""
     end
 
-    @syms.each do |name, val|
-      args = val.value.args.map{|e| "#{type_to_s(e.type)} #{e.name}" }.join(", ")
-      puts "#{type_to_s(val.type.last)} #{symname(val)}(#{args});"
-    end
-    puts ""
+#    # output imported record declarations
+#    imported_mods.each do |mod|
+#      @syms[mod[:name]].type.exports.each do |name, val|
+#        define_sym(val) if val.kind == :type
+#      end
+#      puts ""
+#    end
 
-    @syms.each do |name, val|
-      args = val.value.args.map{|e| "#{type_to_s(e.type)} #{e.name}" }.join(", ")
-      puts "#{type_to_s(val.type.last)} #{symname(val)}(#{args}) {"
-      @syms.open_scope
-      @locals = val.value.locals
-      val.value.args.each_with_index do |name, idx|
-        @syms.add_sym(name.name, name.loc, :param, name.type, idx)
-      end
-      val.value.body.each do |stmnt|
-        emit(stmnt)
-      end
-      puts "}\n\n"
-      @syms.close_scope
-    end
+    # output this modules symbol declarations
+    @syms.each { |name, val| declare_sym(val) }
+    puts ""
+    @syms.each {|name, val| define_sym(val) }
 
     @output.close
   end
index 55d2cb44c1021c7c6231d57a116371ee6b94ac40..1c1308a4bcc351b493f8b1dfc9059dcea9e03378 100644 (file)
@@ -29,7 +29,7 @@ module Compiler
   end
 
   def self.dependency_list(imports)
-    imports.map {|k,v| dependency_list(v[:deps]) + [v[:out_path]] }
+    (imports || {}).map {|k,v| dependency_list(v[:deps]) + [v[:out_path]] }
   end
 
   def self.compile_and_link(path)
index 550528076f57522d6567ab5267d4370f638d838b..34b076c164494e45b4f49433b7d76bd61af8746d 100644 (file)
@@ -33,17 +33,19 @@ class Lexer
   STRING = /"(\\"|[^"])*"/
   CHAR = /'(\\'|[^'])'/
   ID_TYPES = {
-    "true"   => :bool,
-    "false"  => :bool,
-    "if"     => :if,
-    "else"   => :else,
-    "def"    => :def,
-    "set"    => :set,
-    "return" => :return,
-    "assert" => :assert,
-    "module" => :module,
+    "true"    => :bool,
+    "false"   => :bool,
+    "if"      => :if,
+    "is"      => :is,
+    "else"    => :else,
+    "def"     => :def,
+    "set"     => :set,
+    "return"  => :return,
+    "assert"  => :assert,
+    "module"  => :module,
     "imports" => :imports,
-    "exports" => :exports
+    "exports" => :exports,
+    "record" => :record
   }
 
   def next
index 3ded9bfb61720d7f316dbddfc6a6278d6ce67626..a33731bb899b31a73492b0f632d45437fa696c03 100644 (file)
@@ -19,7 +19,7 @@ class Parser
     syms = SymTable.new
     syms.module_name = @module
     @syms.globals.each do |k,v|
-      syms.add_sym(k, v.loc, v.kind, v.type, nil)
+      syms.add_sym(k, v.loc, v.kind, v.type, (v.kind == :func ? nil : v.value))
     end
     syms
   end
@@ -122,8 +122,8 @@ class Parser
         kind = :var
       elsif mod_def.value.is_a? IR::Func
         kind = :func
-#      elsif mod_def.value.is_a? IR::Type
-#        kind = :type
+      elsif mod_def.value.is_a? Value::Type
+        kind = :type
       else
         raise "invalid toplevel definition #{mod_def.value.class}"
       end
@@ -182,6 +182,8 @@ class Parser
     ident = identifier()
     if matches("(") then
       val = function_definition(ident)
+    elsif accept(:is)
+      val = type_definition(ident)
     elsif matches("=") then
       val = constant_definition(ident)
     else
@@ -196,6 +198,8 @@ class Parser
     defs = []
     if accept(":")
       func.type = type_specifier()
+    else
+      func.type = :void
     end
     expect("{")
     while matches(:def)
@@ -210,6 +214,32 @@ class Parser
     func
   end
 
+  def type_definition(name)
+    if accept(:record)
+      base_type = nil
+      if accept("(")
+        base_type = identifier()
+        expect(")")
+      end
+      type = Value::Type.new(:record, {}, base_type, 0)
+      expect("{")
+      while not matches("}")
+        name = expect(:ident).text.to_sym
+        if type.fields[name]
+          error("field #{name} already defined in record")
+        end
+        expect("=")
+        type.fields[name] = type_specifier()
+      end
+      # parse fields here
+      expect("}")
+    else
+      type = type_specifier()
+      type = Value::Type.new(:alias, nil, type, 0)
+    end
+    type
+  end
+
   def constant_definition(name)
     error("constant definitions not yet supported")
   end
@@ -219,9 +249,8 @@ class Parser
     expect("(")
     while !matches(")")
       id = identifier()
-      if accept(":")
-        id.type = type_specifier()
-      end
+      expect(":")
+      id.type = type_specifier()
       args << id
       expect(",") if !matches(")")
     end
@@ -235,10 +264,16 @@ class Parser
   end
 
   def type_specifier()
-    expect(:ident).text.to_sym
+    if accept("[")
+      base_type = type_specifier()
+      type = Value::Type.new(:array, nil, base_type, 0)
+      expect("]")
+    else
+      type = expect(:ident).text.to_sym
+    end
+    type
   end
 
-
   ##
   # Statements
   ##
index 6a550317c1100da6303f732b475f9009708ea452..a4eba9dd07410d1583628213bac5b21f84fe3795 100644 (file)
@@ -94,6 +94,7 @@ class TypeChecker
     @parser = parser
     env = parser.syms
     parser.symbols.each do |sym, data|
+      next if env[sym].kind == :type
       env[sym].type = infer(env, env[sym].value)
     end
   end