@parser = parser
env = parser.syms
parser.symbols.each do |sym, data|
- type = infer(env, env[sym].value)
+ env[sym].type = infer(env, env[sym].value)
end
end
##
def infer_func(env, expr)
- env = env.clone
@typevar = 0
+ env.open_scope()
expr.args.each do |a|
a.type ||= make_typevar()
- env.add_sym(a.name, a.loc, :arg, a.type)
+ env.add_sym(a.name, a.loc, :arg, a.type, a)
end
+ env.open_scope()
expr.body.each do |expr|
infer(env, expr)
end
-
-# infer(env, expr.body)
type = (expr.args + [expr.body.last]).map {|v| v.type }
- type.unshift(:void) if type.length == 1
# the body may have inferred an arg type, fix it up here
expr.args.each_with_index do |a,i|
a.type = env[a.name][:type]
type[i] = a.type
end
+
+ env.close_scope()
+ env.close_scope()
expr.type = type
end
def infer_return(env, expr)
- if expr.type
+ if expr.value
expr.type = infer(env, expr.value)
else
expr.type = :void
else
raise "could not infer const"
end
- pp "TYPED", expr
expr.type
end
def infer_if(env, expr)
check(env, expr.cond, :bool)
expr.type = :void
+ env.open_scope()
expr.then.each {|e| infer(env, e) }
+ env.close_scope()
+ env.open_scope()
(expr.else || []).each {|e| infer(env, e) }
- end
+ env.close_scope()
+ end
def infer_assert(env, expr)
check(env, expr.value, :bool)
etype = infer(env, expr)
if (etype.class == String)
expr.type = type
- env.set_type(expr.name, type)
+ env[expr.name].type = type
elsif expr.type != type
error(expr.loc, "expected #{type}, received #{etype}")
end
end
def check_call(env, expr, type)
- pp expr
+ # Handle global functions that haven't been typed yet but are
+ # being called. We pause to infer their type.
+ if untyped_global_func?(env, expr.func, type)
+ puts "\nUNTYPED FUNC\n\n"
+ value = env[expr.func.name][:value]
+ env[expr.func.name][:value] = nil
+ infer(@parser.syms, value)
+ env[expr.func.name][:value] = value
+ env[expr.func.name][:type] = value.type
+ type = infer(env, expr.func)
+ end
+
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|
-# def make_typevar()
-# @typevar ||= 0
-# var = "abcdefghijklmnopqrstuvwxyz"[@typevar]
-# @typevar += 1
-# var
-# end
-#
-# def var?(expr)
-# expr.class == IR::Var
-# end
-#
-# def untyped_global_func?(env, func, type)
-# type.nil? and
-# var?(func) and
-# env.global?(func.name) and
-# env[func.name][:value]
-# end
-#
+ def make_typevar()
+ @typevar ||= 0
+ var = "abcdefghijklmnopqrstuvwxyz"[@typevar]
+ @typevar += 1
+ var
+ end
+
+ def var?(expr)
+ expr.class == IR::Var
+ end
+
+ def untyped_global_func?(env, func, type)
+ type.nil? and
+ var?(func) and
+ env.global?(func.name) and
+ env[func.name][:value]
+ end
+
# def check_apply(env, expr, type)
# # Handle global functions that haven't been typed yet but are
# # being called. We pause to infer their type.
else
error(expr.loc, "don't know how to index into type: #{left_type}")
end
-# pp left_type
-# raise "array access"
else
optype = BinaryOps[expr.op][vtype]
error(expr.loc, "unknown binary operation '#{expr.op}' for operand type #{vtype}") if optype.nil?
check(env, expr.right, optype[1])
expr.type = optype.last
end
- pp expr
expr.type
end
end