]> git.mdlowis.com Git - proto/sclpl-rb.git/commitdiff
added start of free variable tracking to type checker
authorMichael D. Lowis <mike.lowis@gentex.com>
Mon, 13 Jul 2020 20:51:49 +0000 (16:51 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Mon, 13 Jul 2020 20:51:49 +0000 (16:51 -0400)
lib/dyn.rb

index dbeab155722c43031c5de294f7267aea98bacc06..d86cf19397a38dca877a8b532361606e14b61f8c 100755 (executable)
@@ -26,9 +26,12 @@ end
 
 class SymTable < Hash
   attr_accessor :is_func
+  attr_accessor :freevars
 
   def initialize(parent = nil)
     @parent = (parent || {})
+    @is_func = false
+    @freevars = []
   end
 
   def clone
@@ -75,6 +78,11 @@ class SymTable < Hash
     end
   end
 
+  def free?(key)
+    puts "#{key}: local? #{local? key}  global? #{global? key}"
+    (not local?(key)) && (not global?(key))
+  end
+
   def merge!(env)
     env.each {|k,v| self[k] = v }
   end
@@ -227,7 +235,7 @@ class Parser
   Ident = Struct.new(:loc, :type, :name)
   Val    = Struct.new(:loc, :type, :value)
   Def    = Struct.new(:loc, :type, :name, :value)
-  Func   = Struct.new(:loc, :type, :args, :body)
+  Func   = Struct.new(:loc, :type, :args, :body, :freevars)
   Call   = Struct.new(:loc, :type, :func, :args)
   IfExpr = Struct.new(:loc, :type, :cond, :br1, :br2)
   Ann    = Struct.new(:loc, :type, :expr)
@@ -329,7 +337,7 @@ class Parser
       expect(",") if not matches(")")
     end
     expect(")")
-    Func.new(loc, nil, args, block())
+    Func.new(loc, nil, args, block(), nil)
   end
 
   def constant()
@@ -561,7 +569,9 @@ module TypeChecker
 
   def self.check_call(env, expr, type)
     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|
+      pp expr
       check(env, expr.args[i], t)
     end
     expr.type = type.last
@@ -593,6 +603,8 @@ module TypeChecker
 
   def self.infer_symbol(env, expr)
     error(expr.loc, "undefined symbol '#{expr.name}'") if not env.defined? expr.name
+    env.freevars << expr.name if env.free? expr.name
+    pp env.freevars
     expr.type = env[expr.name][:type]
   end
 
@@ -807,3 +819,26 @@ class Codegen
     var
   end
 end
+
+STRING = <<-eos
+
+a = 123
+
+foo : int -> int
+foo = fun(b){
+  bar : int -> int
+  bar = fun(c){
+    a + b + c
+  }
+  bar(1)
+}
+
+eos
+
+#syms = SymTable.new
+#syms[:a] = {}
+#pp syms.global? :a
+
+tree = Parser.new.parse_string(STRING)
+TypeChecker.infer_block(SymTable.new, tree, false)
+