|
|
|
@ -7,6 +7,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
* Primitive functions that do not need to be defined or declared.
|
|
|
|
|
*/
|
|
|
|
|
val primitives = Map[String,(Boolean,Type)](
|
|
|
|
|
"toInt" -> (false, FunType(List(("", CharType)), IntType)),
|
|
|
|
|
"toChar" -> (false, FunType(List(("", IntType)), CharType)),
|
|
|
|
|
"getchar" -> (false, FunType(List(), IntType)),
|
|
|
|
|
"putchar" -> (false, FunType(List(("", IntType)), UnitType))
|
|
|
|
|
)
|
|
|
|
@ -163,7 +165,10 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
* TODO: implement the remaining binary operators for typeBinOperator
|
|
|
|
|
*/
|
|
|
|
|
def typeBinOperator(op: String)(pos: Position) = op match {
|
|
|
|
|
case "+" => FunType(List(("", IntType), ("", IntType)), IntType)
|
|
|
|
|
case "+" | "-" | "*" | "/" =>
|
|
|
|
|
FunType(List(("", IntType), ("", IntType)), IntType)
|
|
|
|
|
case ">=" | "<=" | ">" | "<" | "==" | "!=" =>
|
|
|
|
|
FunType(List(("", IntType), ("", IntType)), BooleanType)
|
|
|
|
|
case _ =>
|
|
|
|
|
error("undefined binary operator", pos)
|
|
|
|
|
UnknownType
|
|
|
|
@ -177,6 +182,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
* TODO: implement typeUnOperator
|
|
|
|
|
*/
|
|
|
|
|
def typeUnOperator(op: String)(pos: Position) = op match {
|
|
|
|
|
case "+" | "-" => FunType(List(("", IntType)), IntType)
|
|
|
|
|
// case "!" => FunType(List(("", BooleanType)), BooleanType)
|
|
|
|
|
case _ =>
|
|
|
|
|
error(s"undefined unary operator", pos)
|
|
|
|
|
UnknownType
|
|
|
|
@ -188,6 +195,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
* operators: block-set
|
|
|
|
|
*/
|
|
|
|
|
def typeTerOperator(op: String)(pos: Position) = op match {
|
|
|
|
|
case "block-set" =>
|
|
|
|
|
FunType(List(("", ArrayType(IntType)), ("", IntType)), IntType)
|
|
|
|
|
case _ =>
|
|
|
|
|
error(s"undefined ternary operator", pos)
|
|
|
|
|
UnknownType
|
|
|
|
@ -215,7 +224,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
case (_, UnknownType) => typeWellFormed(tp)(env, pos) // tp <: Any
|
|
|
|
|
case (UnknownType, _) => typeWellFormed(pt)(env, pos) // for function arguments
|
|
|
|
|
case (FunType(args1, rtp1), FunType(args2, rtp2)) if args1.length == args2.length =>
|
|
|
|
|
??? // TODO: Function type conformity
|
|
|
|
|
FunType(typeConform(args1, args2)(env, pos), typeConforms(rtp1, rtp2)(env, pos))
|
|
|
|
|
// Done: Function type conformity
|
|
|
|
|
case (ArrayType(tp), ArrayType(pt)) => ArrayType(typeConforms(tp, pt)(env, pos))
|
|
|
|
|
case _ => error(s"type mismatch;\nfound : $tp\nexpected: $pt", pos); pt
|
|
|
|
|
}
|
|
|
|
@ -281,12 +291,22 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
|
|
|
|
|
def typeInfer(exp: Exp, pt: Type)(env: TypeEnv): Exp = exp match {
|
|
|
|
|
case Lit(_: Int) => exp.withType(IntType)
|
|
|
|
|
case Lit(_: Boolean) => ???
|
|
|
|
|
case Lit(_: Unit) => ???
|
|
|
|
|
case Prim("block-set", args) => ???
|
|
|
|
|
case Lit(_: Boolean) => exp.withType(BooleanType)
|
|
|
|
|
case Lit(_: Char) => exp.withType(CharType)
|
|
|
|
|
case Lit(_: Unit) => exp.withType(UnitType)
|
|
|
|
|
case Prim("block-set", args) =>
|
|
|
|
|
Prim("block-set", List(
|
|
|
|
|
typeCheck(args(0), ArrayType(pt))(env),
|
|
|
|
|
typeCheck(args(1), IntType)(env),
|
|
|
|
|
typeCheck(args(2), pt)(env)
|
|
|
|
|
)).withType(UnitType)
|
|
|
|
|
case Prim(op, args) =>
|
|
|
|
|
typeOperator(op, args.length)(exp.pos) match {
|
|
|
|
|
case FunType(atps, rtp) => ???
|
|
|
|
|
case FunType(atps, rtp) =>
|
|
|
|
|
val args_checked = (args zip atps) map {
|
|
|
|
|
case (arg, (_, param)) => typeCheck(arg, param)(env)
|
|
|
|
|
}
|
|
|
|
|
Prim(op, args_checked).withType(rtp)
|
|
|
|
|
case UnknownType => exp.withType(UnknownType)
|
|
|
|
|
case _ => BUG("operator's type needs to be FunType")
|
|
|
|
|
}
|
|
|
|
@ -298,18 +318,28 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
Let(x, nrhs.tp, nrhs, nbody).withType(nbody.tp)
|
|
|
|
|
case Ref(x) =>
|
|
|
|
|
env(x) match {
|
|
|
|
|
case Some(tp) => ??? // Remember to check that the type taken from the environment is welformed
|
|
|
|
|
case Some(tp) =>
|
|
|
|
|
exp.withType(typeWellFormed(tp)(env, exp.pos))
|
|
|
|
|
// Remember to check that the type taken from the environment is wellformed
|
|
|
|
|
case _ =>
|
|
|
|
|
error("undefined identifier", exp.pos)
|
|
|
|
|
???
|
|
|
|
|
exp.withType(UnknownType)
|
|
|
|
|
}
|
|
|
|
|
case If(cond, tBranch, eBranch) =>
|
|
|
|
|
// Hint: type check the else branch before the then branch.
|
|
|
|
|
???
|
|
|
|
|
val condChecked = typeCheck(cond, BooleanType)(env)
|
|
|
|
|
val elseChecked = typeCheck(eBranch, pt)(env)
|
|
|
|
|
val thenChecked = typeCheck(tBranch, elseChecked.tp)(env)
|
|
|
|
|
If(condChecked, thenChecked, elseChecked).withType(elseChecked.tp)
|
|
|
|
|
|
|
|
|
|
case VarDec(x, tp, rhs, body) =>
|
|
|
|
|
if (env.isDefined(x))
|
|
|
|
|
warn("reuse of variable name", exp.pos)
|
|
|
|
|
???
|
|
|
|
|
val rhsChecked = typeCheck(rhs, tp)(env)
|
|
|
|
|
val _env = env.withVar(x, rhsChecked.tp)
|
|
|
|
|
val bodyChecked = typeCheck(body, pt)(_env)
|
|
|
|
|
VarDec(x, rhsChecked.tp, rhsChecked, bodyChecked).withType(bodyChecked.tp)
|
|
|
|
|
|
|
|
|
|
case VarAssign(x, rhs) =>
|
|
|
|
|
val xtp = if (!env.isDefined(x)) {
|
|
|
|
|
error("undefined identifier", exp.pos)
|
|
|
|
@ -320,7 +350,7 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
env(x).get
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
???
|
|
|
|
|
val rhsChecked = typeCheck(rhs, xtp)(env)
|
|
|
|
|
|
|
|
|
|
/* Because of syntactic sugar, a variable assignment
|
|
|
|
|
* statement can be accepted as an expression
|
|
|
|
@ -338,18 +368,35 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
* Without changing the semantics!
|
|
|
|
|
*/
|
|
|
|
|
pt match {
|
|
|
|
|
case UnitType => ???
|
|
|
|
|
case _ => ???
|
|
|
|
|
}
|
|
|
|
|
case While(cond, lbody, body) => ???
|
|
|
|
|
case FunDef(fname, args, rtp, fbody) => ???
|
|
|
|
|
case UnitType | IntType | BooleanType | CharType => VarAssign(x, rhsChecked).withType(rhsChecked.tp)
|
|
|
|
|
case _ => exp.withType(UnknownType)
|
|
|
|
|
}
|
|
|
|
|
case While(cond, lbody, body) =>
|
|
|
|
|
val condChecked = typeCheck(cond, BooleanType)(env)
|
|
|
|
|
val lbodyChecked = typeCheck(lbody, UnitType)(env)
|
|
|
|
|
val bodyChecked = typeCheck(body, pt)(env)
|
|
|
|
|
While(condChecked, lbodyChecked, bodyChecked).withType(bodyChecked.tp)
|
|
|
|
|
|
|
|
|
|
case FunDef(fname, args, rtp, fbody) =>
|
|
|
|
|
checkDuplicateNames(args)
|
|
|
|
|
val argsWType = args map {
|
|
|
|
|
a => (a.name, typeWellFormed(a.tp)(env, a.pos))
|
|
|
|
|
}
|
|
|
|
|
val bodyChecked = typeCheck(fbody, rtp)(env.withVals(argsWType)) // check rtp w/ pt?
|
|
|
|
|
FunDef(fname, args, bodyChecked.tp, bodyChecked).withType(
|
|
|
|
|
FunType(argsWType, bodyChecked.tp)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
case LetRec(funs, body) =>
|
|
|
|
|
// TODO modify to handle general case
|
|
|
|
|
val nbody = typeCheck(body, pt)(env)
|
|
|
|
|
LetRec(Nil, nbody).withType(nbody.tp)
|
|
|
|
|
val _env = env.withVals(funs.map {case FunDef(name, _, rtp, _) => (name, rtp)})
|
|
|
|
|
val funsChecked = funs map {case f@FunDef(_, _, rtp, _) => typeCheck(f, rtp)(_env) }
|
|
|
|
|
val bodyChecked = typeCheck(body, pt)( env.withVals(funsChecked map {case FunDef(name, _, rtp, _) => (name, rtp)}))
|
|
|
|
|
LetRec(funsChecked, bodyChecked).withType(bodyChecked.tp)
|
|
|
|
|
|
|
|
|
|
case App(fun, args) =>
|
|
|
|
|
// TODO Check fun type
|
|
|
|
|
val nFun: Exp = ???
|
|
|
|
|
val nFun: Exp = typeCheck(fun, fun.tp)(env)
|
|
|
|
|
|
|
|
|
|
// Handling some errors
|
|
|
|
|
val ftp = nFun.tp match {
|
|
|
|
@ -369,7 +416,9 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Check arguments type
|
|
|
|
|
val nargs: List[Exp] = ???
|
|
|
|
|
val nargs: List[Exp] = (args zip ftp.args) map {
|
|
|
|
|
case (arg, (_, param)) => typeCheck(arg, param)(env)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Transform some function applications into primitives on arrays.
|
|
|
|
|
nFun.tp match {
|
|
|
|
@ -380,7 +429,7 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
|
|
|
|
|
case ArrayDec(size: Exp, etp: Type) =>
|
|
|
|
|
// TODO: Check array declaration
|
|
|
|
|
// Note that etp is the type of elements
|
|
|
|
|
???
|
|
|
|
|
ArrayDec(typeCheck(size, IntType)(env), etp).withType(etp)
|
|
|
|
|
case _ => BUG(s"malformed expresstion $exp")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|