class SymTable < Hash
attr_accessor :is_func
+ attr_accessor :freevars
def initialize(parent = nil)
@parent = (parent || {})
+ @is_func = false
+ @freevars = []
end
def clone
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
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)
expect(",") if not matches(")")
end
expect(")")
- Func.new(loc, nil, args, block())
+ Func.new(loc, nil, args, block(), nil)
end
def constant()
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
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
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)
+