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
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
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
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}'")
end
def const_or_ident()
- if matches("[")
+ if matches(:new)
+ record_literal()
+ elsif matches("[")
array_literal()
elsif matches("{")
hash_literal()
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("[")
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)
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)
end
end
-
def check_func(env, expr, type)
raise "unimplemented"
error(expr.loc, "unimplemented")