{
def hash = {foo: "bar", "baz": "boo"}
def item = 42
- set hash["foo"] = item
- assert hash["foo"] == 42
+# set hash["foo"] = item
+# assert hash["foo"] == 42
assert hash["baz"] == "boo"
# assert Length(hash) == 2
}
TestEqOps() {
assert ("" == "") == true
- assert ("" == 1) == false
- assert ("" == 1.0) == false
- assert ("" == true) == false
- assert ("" == false) == false
- assert ("" == []) == false
- assert ("" == {}) == false
+ assert ("" == "a") == true
+ assert (1 == 1) == true
+ assert (1 == 2) == false
+ assert (1.0 == 1.0) == true
+ assert (1.0 == 2.0) == false
+ assert (true == true) == true
+ assert (true == false) == false
+# assert ([1] == [1]) == true
+# assert ([1] == [2]) == false
+# assert ({"foo": "bar"} == {"foo": "bar"}) == true
+# assert ({"foo": "bar"} == {"foo": "baz"}) == false
}
TestNeqOps() {
- assert ("" != "") == false
- assert ("" != 1) == true
- assert ("" != 1.0) == true
- assert ("" != true) == true
- assert ("" != false) == true
- assert ("" != []) == true
- assert ("" != {}) == true
+# assert ("" != "") == false
+# assert ("" != 1) == true
+# assert ("" != 1.0) == true
+# assert ("" != true) == true
+# assert ("" != false) == true
+# assert ("" != []) == true
+# assert ("" != {}) == true
}
TestLtOps(){
# check_let(env, expr, type)
# elsif expr.is_a? IR::If
# check_ifexpr(env, expr, type)
-# elsif expr.is_a? IR::Set
-# check_set(env, expr, type)
# elsif expr.is_a? IR::Func
# check_func(env, expr, type)
# elsif expr.is_a? IR::Apply
end
def infer_const(env, expr)
- raise "inferring const"
+ if expr.type
+ check(env, expr, expr.type)
+ elsif expr.value.is_a? Array
+ types = expr.value.map{|v| infer(env, v) }.uniq
+ if types.length > 1
+ error(expr.loc, "array literal contains more than one type of value")
+ end
+ if types.length == 0
+ error(expr.loc, "cannot infer type of empty array literal")
+ end
+ base_type = (expr.value.first ? expr.value.first.type : nil)
+ if base_type.nil?
+ error(expr.loc, "could not determine base type of array literal")
+ end
+ expr.type = Value::Type.new(:array, nil, base_type, -1)
+ elsif expr.value.is_a? Hash
+ types = expr.value.map{|k,v| [infer(env, k), infer(env, v)] }.uniq
+ if types.length > 1
+ error(expr.loc, "hash literal contains more than one type of key/value")
+ end
+ if types.length == 0
+ error(expr.loc, "cannot infer type of empty hash literal")
+ end
+ expr.type = Value::Type.new(:hash, nil, [types.first[0], types.first[1]] )
+ else
+ raise "could not infer const"
+ end
+ pp "TYPED", expr
expr.type
end
end
def infer_def(env, expr)
-# raise "unimplemented"
-# error(expr.loc, "unimplemented")
-
- pp expr
name = expr.name.name
type = expr.value.type
if type
- puts "check"
check(env, expr.value, type)
else
- puts "infer"
type = infer(env, expr.value)
end
- pp type
-# env[name] = { loc: expr.loc, type: type }
- expr.type = :void
+ env.add_sym(name, expr.loc, :local, type, expr.value)
expr.value.type = type
- pp expr
- raise "unimplemented"
+ expr.type = :void
end
def infer_set(env, expr)
- raise "unimplemented"
- error(expr.loc, "unimplemented")
+ type = infer(env, expr.name)
+ check(env, expr.value, type)
+ expr.type = :void
end
def infer_op(env, expr)
end
def infer_if(env, expr)
- raise "unimplemented"
- error(expr.loc, "unimplemented")
+ check(env, expr.cond, :bool)
+ expr.type = :void
+ expr.then.each {|e| infer(env, e) }
+ (expr.else || []).each {|e| infer(env, e) }
end
def infer_assert(env, expr)
# TYPE CHECKING
##
-
def check_func(env, expr, type)
raise "unimplemented"
error(expr.loc, "unimplemented")
type
end
- def check_def(env, expr, type)
- raise "unimplemented"
- error(expr.loc, "unimplemented")
- end
-
- def check_set(env, expr, type)
- raise "unimplemented"
- error(expr.loc, "unimplemented")
- end
-
def check_op(env, expr, type)
expr.type = expr.type || infer(env, expr)
if expr.type != type
end
def check_call(env, expr, type)
-# pp expr
+ pp expr
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|
check(env, expr.args[i], t)
end
- pp type
expr.type = type.last
end
# error(expr.loc, "infer_set unimplemented")
# end
#
-#
-# def infer_apply(env, expr)
-# if expr.func.is_a? String
-# expr.type = infer_opcall(env, expr)
-# else
-# type = infer(env, expr.func)
-# check_apply(env, expr, type)
-# end
-# end
-#
# def assign_type(env, var, type)
# if var.class == IR::Var and (var.type.nil? or var.type == String) then
# var.type = type
end
def check_binary(env, expr, vtype)
- optype = BinaryOps[expr.op][vtype]
- error(expr.loc, "unknown binary operation '#{expr.op}' for operand type #{vtype}") if optype.nil?
- check(env, expr.left, optype[0])
- check(env, expr.right, optype[1])
- expr.type = optype.last
+ if expr.op == "["
+ left_type = infer(env, expr.left)
+ if (left_type.is_a? Value::Type) and left_type.form == :array
+ check(env, expr.right, :int)
+ expr.type = left_type.base
+ elsif (left_type.is_a? Value::Type) and left_type.form == :hash
+ check(env, expr.right, left_type.base[0])
+ expr.type = left_type.base[1]
+ 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.left, optype[0])
+ check(env, expr.right, optype[1])
+ expr.type = optype.last
+ end
+ pp expr
+ expr.type
end
end