ValuePtr BWhile::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() == 2); auto& cond = args[0]; auto& body = args[1]; checker.Visit(cond.get()); if(!cond->value) return {}; TypeSubst condSubst; checker.subst.swap(condSubst); bool lastInsideLoop = checker.insideLoop; checker.insideLoop = true; checker.Visit(body.get()); checker.insideLoop = lastInsideLoop; if(!body->value) return {}; Compose(condSubst, checker.subst); Compose(Unify(*cond->value->type, *BooleanType), checker.subst); return VoidValue; // TODO should a while yield a value? }
ValuePtr BArithmetic<Operation>::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() == 2); auto& left = args[0]; auto& right = args[1]; checker.Visit(left.get()); if(!left->value) return {}; TypeSubst leftSubst; checker.subst.swap(leftSubst); checker.Visit(right.get()); if(!right->value) return {}; Compose(leftSubst, checker.subst); Compose(Unify(*left->value->type, *right->value->type), checker.subst); auto type = left->value->type.get(); if(!isa<TInteger>(type) && !isa<TFloat>(type)) { Error() << "Arithmetic operation requires float or integer operands"; return {}; } ValuePtr value = new VTemporary; value->type = ResultType<typename Operation::IsCompare>(type); return value; }
ValuePtr BIf::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() >= 2 && args.size() % 2 == 0); // conditions for(size_t i = 0; i < args.size(); i += 2) { TypeSubst lastSubst; checker.subst.swap(lastSubst); checker.Visit(args[i].get()); if(!args[i]->value) return {}; Compose(lastSubst, checker.subst); Compose(Unify(*args[i]->value->type, *BooleanType), checker.subst); } // clauses for(size_t i = 1; i < args.size(); i += 2) { TypeSubst lastSubst; checker.subst.swap(lastSubst); checker.Visit(args[i].get()); if(!args[i]->value) return {}; Compose(lastSubst, checker.subst); if(i != 1) Compose(Unify(*args[i]->value->type, *args[i - 2]->value->type), checker.subst); } for(auto& e : args) e->value->type = xra::Apply(checker.subst, *e->value->type); if(args.size() == 2) return VoidValue; ValuePtr value = new VTemporary; value->type = args[1]->value->type; return value; }
ValuePtr BModule::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { auto module = static_cast<EVariable&>(*args[0]).name; module = AbsoluteModule(checker.moduleName, module); checker.moduleName.swap(module); checker.Visit(args[1].get()); checker.moduleName.swap(module); return VoidValue; }
ValuePtr BAssign::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() == 2); auto& left = args[0]; auto& right = args[1]; checker.Visit(right.get()); if(!right->value) return {}; TypeSubst rightSubst; checker.subst.swap(rightSubst); // if the left side is a plain variable not in the environment, create a fresh local if(isa<EVariable>(left.get())) { auto& name = static_cast<EVariable&>(*left).name; if(!checker.env[name]) { left->value = new VLocal; left->value->type = MakeTypeVar(); checker.env.AddValue(name, left->value); } } if(!left->value) { checker.Visit(left.get()); if(!left->value) return {}; } Compose(rightSubst, checker.subst); auto unifySubst = Unify(*left->value->type, *right->value->type); left->value->type = xra::Apply(unifySubst, *left->value->type); Compose(unifySubst, checker.subst); return left->value; }
ValuePtr BUsing::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { auto module = static_cast<EVariable&>(*args[0]).name; module = AbsoluteModule(checker.moduleName, module); if(!checker.usingModules.insert(module).second) { Error() << "duplicate using: " << module; return {}; } checker.Visit(args[1].get()); checker.usingModules.erase(module); return VoidValue; }
ValuePtr BSequence::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { for(auto& e : args) { TypeSubst lastSubst; checker.subst.swap(lastSubst); checker.Visit(e.get()); if(!e->value) return {}; Compose(lastSubst, checker.subst); } return args.back()->value; }
ValuePtr BReturn::Infer(TypeChecker& checker, const vector<ExprPtr>& args) { assert(args.size() == 0 || args.size() == 1); TypePtr rty = VoidType; if(!args.empty()) { checker.Visit(args[0].get()); if(!args[0]->value) return {}; rty = args[0]->value->type; } if(checker.returnType) Compose(Unify(*rty, *checker.returnType), checker.subst); else checker.returnType = rty; return VoidValue; }