/* zweic -- a compiler for Zwei * * Stephane Micheloud & LAMP * * $Id$ */ package zweic; /** * This class implements the semantic analyzer of zweic. */ class Analyzer { import Operators._; import scala.collection.immutable.{Map, ListMap}; // Global scope of classes type ClassScope = Map[String, ClassSymbol]; var classScope: ClassScope = ListMap.Empty; // For local scopes of variables type VarScope = Map[String, VarSymbol]; val emptyVarScope: VarScope = ListMap.Empty; // Analyze a program def analyzeProgram(tree: Program): Unit = tree match { case Program(classes, main) => classes.foreach(analyzeClass); analyzeExpr(emptyVarScope, main); () } // Analyze a class private def analyzeClass(tree: ClassDef): Unit = tree match { case ClassDef(name, None, members) => Console.println("hallo") case ClassDef(name, extend, members) => Console.println("println") } // Analyze a member private def analyzeMember(ownerClass: ClassSymbol, tree: Member): Unit = tree.match { case FieldDecl(Formal(name, typ)) => // TODO check that field does not yet exist! ownerClass.enterField(FieldSymbol(tree.pos, name.name, analyzeType(typ))) case MethodDef(name, args, rtype, expr) => ownerClass.lookupMethod(name.name) match { case Some(z) => var paramtypes = for ( val Formal(x,y) <- args ) yield analyzeType(y); ownerClass.enterMethod(MethodSymbol(tree.pos, name.name, paramtypes, analyzeType(rtype))) } } // Analyze a statement private def analyzeStat(varScope: VarScope, tree: Stat): VarScope = tree match { case While(cond, stats) => checkIntType(cond.pos, analyzeExpr(varScope, cond)); stats.foldLeft(varScope)(analyzeStat); varScope case Var(name, typ, expr) => varScope.get(name.name) match { case Some(v) => Report.error(tree.pos, "Variable already defined " + name.name); case None => val mv = VarSymbol(tree.pos, name.name, typ); val et = analyzeExpr(varScope, expr); varScope = varScope + name -> VarSymbol(); } varScope // ... à compléter ... case Set(ident, expr) => varScope.get(ident.name) match { case Some(v) => ident.sym = v; if ( !analyzeExpr(varScope, expr).isSubtype(v.vartype) ) Report.error(tree.pos, "Incompatible_types"); case None => Report.error(tree.pos, "Unknown variable " + ident.name); } varScope } // Analyze a type private def analyzeType(tree: TypeTree): Type = tree match { case IntType() => IIntType case NullType() => INullType case ClassType(name) => classScope.get(name.name) match { case Some(c) => name.sym = c; IClassType(c) case None => Report.error(tree.pos, "Class " + name + " is unknown"); IBadType } } // Analyze an expression private def analyzeExpr(varScope: VarScope, tree: Expr): Type = tree match { // ... à compléter ... case NullLit() => INullType case IntLit(_) => IIntType // ... à compléter ... case Ident(name) => varScope.get(name.name) match { case Some(v) => name.sym = v; v.vartype case None => Report.error(tree.pos, "Unknown variable " + name); IBadType } case Binop(op, left, right) => val t1 = analyzeExpr(varScope, left); val t2 = analyzeExpr(varScope, right); if ( op == EQ || op == NE ) { if ( !(t1.isSubtype(t2) || t2.isSubtype(t1)) ) Report.error(tree.pos, "Incompatible types: " + t1 + " <=> " + t2); } else { checkIntType(left.pos, t1); checkIntType(right.pos, t2); } IIntType } /** * Generates an error if the expected type is not equal * to the found type. */ private def checkSametype(pos: Int, found: Type, expected: Type): Unit = if (!found.isSametype(expected)) error(pos, "Type mismatch", found, expected); /** * Generates an error if the found type is not equal to IIntType. */ private def checkIntType(pos: Int, found: Type): Unit = checkSametype(pos, found, IIntType); /** * Generates an error if the expected type is not a super type * of the found type. */ private def checkSubtype(pos: Int, header: String, found: Type, expected: Type) = if (!found.isSubtype(expected)) error(pos, header, found, expected); /** * Generates an error message for unexpected types. */ private def error(pos: Int, header: String, found: Type, expected: Type) = Report.error(pos, header + "\nexpected type: " + expected + "\n" + "actual type : " + found); }