diff --git a/sources/zweic/Analyzer.scala b/sources/zweic/Analyzer.scala index 9e6d8ac..ead1998 100755 --- a/sources/zweic/Analyzer.scala +++ b/sources/zweic/Analyzer.scala @@ -25,7 +25,7 @@ // Analyze a program def analyzeProgram(tree: Program): Unit = tree match { - case Program(classes, main) => + case Program(classes, main) => classes.foreach(analyzeClass); analyzeExpr(emptyVarScope, main); () @@ -36,37 +36,35 @@ case ClassDef(name, None, members) => classScope.get(name.name) match { case Some(c) => - Report.error(tree.pos, "Class already defined: " + name) - case None => + Report.error(tree.pos, "class '" + name + "' already defined") + case None => val cs = ClassSymbol(tree.pos, name.name, None); classScope = classScope + name.name -> cs; - //classScope(name.name) = cs; members.foreach(x => analyzeMember(cs,x)) - } + } case ClassDef(name, extend, members) => classScope.get(name.name) match { case Some(c) => - Report.error(tree.pos, "Class already defined: " + name); + Report.error(tree.pos, "class '" + name + "' already defined"); case None => classScope.get(extend.get.name) match { - case None => Report.error(tree.pos, "Superclass not defined: " + extend.get.name) + case None => Report.error(tree.pos, "superclass '" + extend.get.name + "' not defined") case _ => () } val cs = ClassSymbol(tree.pos, name.name, classScope.get(extend.get.name)); classScope = classScope + name.name -> cs; - //classScope(name.name) = cs; members.foreach(x => analyzeMember(cs,x)) } } - + // Analyze a member - private def analyzeMember(ownerClass: ClassSymbol, tree: Member): Unit = + private def analyzeMember(ownerClass: ClassSymbol, tree: Member): Unit = tree.match { case FieldDecl(Formal(name, typ)) => ownerClass.lookupField(name.name) match { case Some(v) => - Report.error(tree.pos, "Class variable already defined: " + name); + Report.error(tree.pos, "class variable '" + name + "' already defined"); case None => name.sym = FieldSymbol(tree.pos, name.name, analyzeType(typ)); ownerClass.enterField(name.sym.asInstanceOf[FieldSymbol]); @@ -76,10 +74,10 @@ myVarScope = myVarScope + "this" -> VarSymbol(ownerClass.pos, "this", IClassType(ownerClass)); - for ( val x <- ownerClass.allFields ) { - Console.println(x); + // TODO: FieldSymbols can't be VarSymbols !!! + /*for ( val x <- ownerClass.allFields ) { myVarScope = myVarScope + x.name -> x.asInstanceOf[VarSymbol]; - } + }*/ val paramtypes = for ( val f <- args ) yield { //TODO: check that there isn't already a class field with the same name @@ -98,7 +96,7 @@ ownerClass.enterNewMethod(name.sym.asInstanceOf[MethodSymbol]); } - checkSubtype(tree.pos, "Return type mismatch", analyzeExpr(myVarScope, expr), rt); + checkSubtype(tree.pos, "returntype mismatch", analyzeExpr(myVarScope, expr), rt); } // Analyze a statement @@ -113,11 +111,11 @@ case Var(name, typ, expr) => varScope.get(name.name) match { case Some(v) => - Report.error(tree.pos, "Variable already defined " + name.name); + Report.error(tree.pos, "variable '" + name + "' already defined"); varScope case None => val mt = analyzeType(typ); - checkSubtype(tree.pos, "Incompatible types", analyzeExpr(varScope, expr), mt); + checkSubtype(tree.pos, "incompatible types", analyzeExpr(varScope, expr), mt); name.sym = VarSymbol(tree.pos, name.name, mt); varScope + name.name -> name.sym.asInstanceOf[VarSymbol]; } @@ -126,9 +124,9 @@ varScope.get(ident.name) match { case Some(v) => ident.sym = v; - checkSubtype(tree.pos, "Incompatible types", analyzeExpr(varScope, expr), v.vartype); + checkSubtype(tree.pos, "incompatible types", analyzeExpr(varScope, expr), v.vartype); case None => - Report.error(tree.pos, "Unknown variable " + ident.name); + Report.error(tree.pos, "unknown variable '" + ident.name + "'"); } varScope @@ -156,7 +154,7 @@ name.sym = c; IClassType(c) case None => - Report.error(tree.pos, "type " + name + " is unknown"); + Report.error(tree.pos, "type '" + name + "' is unknown"); IBadType } } @@ -171,7 +169,7 @@ name.sym = v; v.vartype case None => - Report.error(tree.pos, "Unknown variable " + name); + Report.error(tree.pos, "unknown variable '" + name + "'"); IBadType } @@ -184,41 +182,41 @@ name.sym = v; v.fieldtype case None => - Report.error(tree.pos, "Unknown class variable " + name + " in " + ct); + Report.error(tree.pos, "unknown class variable '" + name + "' in " + ct); IBadType; } case _ => - Report.error(tree.pos, "Field '" + name.name + "' does not exist"); + Report.error(tree.pos, "class variable '" + name.name + "' does not exist"); IBadType; } case Call(expr, name, args) => - val ct = analyzeExpr(varScope, expr); //XXX: this implies checking if class exists + val ct = analyzeExpr(varScope, expr); //XXX: this implies checking if class exists ct match { - case IClassType(c) => + case IClassType(c) => c.lookupMethod(name.name) match { case Some(v) => if (args.length != v.paramtypes.length) { - Report.error(tree.pos, "Wrong number of arguments for class method " + name + " in " + ct); + Report.error(tree.pos, "wrong number of arguments for class method '" + name + "' in " + ct); IBadType } - if ( !args.map(x => analyzeExpr(varScope, x)).zip(v.paramtypes) - .forall( x:Pair[Type,Type] => x._1.isSubtype(x._2)) ) { - Report.error(tree.pos, "Incompatible Types: \nrequired:" + v.paramtypes.foldLeft("")((a,b)=>a + b) + - "\nfound:" + args.foldLeft("")((a,b)=>a + b) ); + val argtypes = args.map(x => analyzeExpr(varScope, x)); + if ( !argtypes.zip(v.paramtypes).forall( x:Pair[Type,Type] => x._1.isSubtype(x._2)) ) { + Report.error(tree.pos, "incompatible argument types for class method: \nrequired:" + v.paramtypes.foldLeft(" ")((a,b)=>a + b) + + "\nfound:" + argtypes.foldLeft(" ")((a,b)=>a + b) ); IBadType; } name.sym = v; v.restype case None => - Report.error(tree.pos, "Unknown class method " + name + " in " + ct); + Report.error(tree.pos, "unknown class method '" + name + "' in " + ct); IBadType } case _ => - Report.error(tree.pos, "Function '" + name.name + "' does not exist"); - IBadType; + Report.error(tree.pos, "method '" + name.name + "' does not exist"); + IBadType; } case New(name, args) => @@ -226,20 +224,21 @@ ct match { case Some(v) => if (args.length != v.allFields.length) { - Report.error(tree.pos, "Wrong number of arguments for class constructor in " + ct); + Report.error(tree.pos, "wrong number of arguments for class constructor in " + ct); IBadType } - if ( !args.map(x => analyzeExpr(varScope, x)).zip(v.allFields.map(y => y.fieldtype)) - .forall( x:Pair[Type, Type] => x._1.isSubtype(x._2)) ) { - Report.error(tree.pos, "Incompatible Types: \nrequired:" + v.allFields + - "\nfound:" + args); + val argtypes = args.map(x => analyzeExpr(varScope, x)); + val fieldtypes = v.allFields.map(y => y.fieldtype); + if ( !argtypes.zip(fieldtypes).forall( x:Pair[Type, Type] => x._1.isSubtype(x._2)) ) { + Report.error(tree.pos, "incompatible argument types for class constructor: \nrequired:" + fieldtypes.foldLeft(" ")((a,b) => a + b) + + "\nfound:" + argtypes.foldLeft(" ")((a,b) => a + b)); IBadType; } - + name.sym = v; IClassType(v) case None => - Report.error(tree.pos, "Class " + name + " is unknown"); + Report.error(tree.pos, "class '" + name + "' is unknown"); IBadType } @@ -258,7 +257,7 @@ 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); + Report.error(tree.pos, "incompatible types: '" + t1 + "' <=> '" + t2 + "'"); } else { checkIntType(left.pos, t1); checkIntType(right.pos, t2); @@ -273,7 +272,10 @@ case If(cond, stata, statb) => checkIntType(cond.pos, analyzeExpr(varScope, cond)); - analyzeExpr(varScope, stata).lub(analyzeExpr(varScope, statb)).get; + analyzeExpr(varScope, stata).lub(analyzeExpr(varScope, statb)) match { + case Some(v) => v + case None => IBadType + } case Block(stats, expr) => analyzeExpr(stats.foldLeft(varScope)(analyzeStat), expr) @@ -284,8 +286,8 @@ * to the found type. */ private def checkSametype(pos: Int, found: Type, expected: Type): Unit = - if (!found.isSametype(expected)) - error(pos, "Type mismatch", found, expected); + if (!found.isSametype(expected)) + error(pos, "type mismatch", found, expected); /** * Generates an error if the found type is not equal to IIntType. @@ -306,6 +308,6 @@ */ private def error(pos: Int, header: String, found: Type, expected: Type) = Report.error(pos, header + "\nexpected type: " + expected + "\n" + - "found type : " + found); + "actual type : " + found); } diff --git a/sources/zweic/Parser.scala b/sources/zweic/Parser.scala index 0c9e37e..8ea4e18 100755 --- a/sources/zweic/Parser.scala +++ b/sources/zweic/Parser.scala @@ -66,7 +66,7 @@ case Some(Triple(p, c, t)) => token = t; chars = c; - start = p; + start = p; pushedBack = None; case _ => return super.nextToken; } @@ -105,7 +105,7 @@ private def program(): Program = { val pos = start; var classes:List[ClassDef] = Nil; - while (token == CLASS) { + while (token == CLASS) { classes = classDecl() :: classes; } val main = expression(); @@ -134,9 +134,9 @@ } /** - * Member = Formal - * (";" | - * "(" [Formal {"," Formal}] ")" Block) + * Member = Formal + * (";" | + * "(" [Formal {"," Formal}] ")" Block) */ private def member(): Member = { val pos = start; @@ -147,7 +147,7 @@ accept(LPAREN); var par:List[Formal] = Nil; if (token == IDENT || token == INT || token == NULLTYPE) { - par = formal() :: par; + par = formal() :: par; while (token != RPAREN) { accept (PERIOD); par = formal() :: par; @@ -177,7 +177,7 @@ val pos = start; accept (LACCOLADE); var s:List[Stat] = Nil; - var e:Expr = NullLit().setPos(pos); + var e:Expr = NullLit().setPos(pos); while (token != RETURN && token != RACCOLADE) { s = statement() :: s; } @@ -193,10 +193,10 @@ */ private def type1(): TypeTree = { val pos = start; - token match { + token match { case INT => nextToken; return IntType().setPos(pos); case NULLTYPE => nextToken; return NullType().setPos(pos); - case IDENT => val name=Name(chars); nextToken; + case IDENT => val name=Name(chars); nextToken; return ClassType(name).setPos(pos); case _ => error("'Int', 'Null' or identifier token"); return null; } @@ -222,7 +222,7 @@ accept(SEMICOLON); return Var(v.name, v.typ, e).setPos(pos); - case EQUALS => + case EQUALS => //affection val name = Name(chars); accept(IDENT); @@ -230,13 +230,13 @@ val e = expression(); accept(SEMICOLON); return Set(name, e).setPos(pos); - + case _ => //expression val e = expression(); accept(SEMICOLON); return Do(e).setPos(pos); - } + } } else { @@ -251,7 +251,7 @@ stats = statement() :: stats; } return While(cond, stats.reverse).setPos(pos); - + } else if (token == NULLTYPE || token == INT) { //type definition and affection val v = formal(); @@ -267,7 +267,7 @@ accept(RPAREN); accept(SEMICOLON); return PrintInt(e).setPos(pos); - + } else if (check(PRINTCHAR)) { //printChar accept(LPAREN); @@ -399,11 +399,11 @@ case NULLFACTOR => nextToken; NullLit().setPos(pos); case READINT => nextToken; ReadInt().setPos(pos); case READCHAR => nextToken; ReadChar().setPos(pos); - case LPAREN => - nextToken; var t = expression(); t.brackets = true; + case LPAREN => + nextToken; var t = expression(); t.brackets = true; accept(RPAREN); t; case LACCOLADE => block(); - case NEW => nextToken; accept(IDENT); + case NEW => nextToken; accept(IDENT); New(Name(chars), params()).setPos(pos); case _ => error("Identifier, Number, String, 'true', 'false', 'this', 'null', 'readInt', 'readChar', '(Expression)', '{Block}' or 'new'"); null; } @@ -433,7 +433,7 @@ rval = expression() :: rval; } rval; - } else Nil).reverse; + } else Nil).reverse; /** * Params = "(" Expressions ")" diff --git a/sources/zweic/Printer.scala b/sources/zweic/Printer.scala index ffa9748..900d9b2 100755 --- a/sources/zweic/Printer.scala +++ b/sources/zweic/Printer.scala @@ -28,9 +28,9 @@ private var level = 0; def joinprint(args:List[Tree], sep: => Printer):Printer = args match { - case h :: Nil => - print(h); - case h :: t => + case h :: Nil => + print(h); + case h :: t => print(h); sep; joinprint(t, sep); @@ -48,12 +48,12 @@ def print(tree: Tree): Printer = { if (tree.isInstanceOf[Expr] && tree.asInstanceOf[Expr].brackets) print("("); - + tree match { case Program(decls, main) => joinprint(decls, println).println; print(main).println; - + // // Tree nodes for definitions // @@ -68,14 +68,14 @@ joinprint(members, println.println); undent.println.print("}").println; - case FieldDecl(formal) => + case FieldDecl(formal) => print(formal).print(";"); - case MethodDef(name, args, returntype, expression) => + case MethodDef(name, args, returntype, expression) => print(returntype).print(" ").print(name); print(" (").joinprint(args, ", ").print(") "); print(expression); - + case Formal(name, typ) => print(typ).print(" ").print(name); @@ -112,7 +112,7 @@ case PrintInt(expr) => print("printInt(").print(expr).print(")").print(";"); - + case PrintChar(expr) => print("printChar(").print(expr).print(")").print(";"); @@ -166,24 +166,24 @@ print("{").indent.println; for (val s <- stats) { print(s).println; - } + } print("return ").print(expression); undent.println.print("}"); - case x => + case x => error("unexpected error in tree"); }; if (tree.isInstanceOf[Expr] && tree.asInstanceOf[Expr].brackets) print(")"); - + print(""); - } + } /** * Print abstract syntax trees separated by commas. */ - private def print(trees: List[Tree]): Printer = trees match { + private def print(trees: List[Tree]): Printer = trees match { case _ => this } diff --git a/sources/zweic/Scanner.scala b/sources/zweic/Scanner.scala index 51a0f33..287f50a 100755 --- a/sources/zweic/Scanner.scala +++ b/sources/zweic/Scanner.scala @@ -111,16 +111,16 @@ } } else { // division - start = Position.encode(line, column); + start = Position.encode(line, column); token = DIV; return } } else { - // whitespace + // whitespace nextCh; } } - + start = Position.encode(line, column); // read the current token token = readToken; @@ -136,41 +136,41 @@ case ')' => nextCh; return RPAREN; case '{' => nextCh; return LACCOLADE; case '}' => nextCh; return RACCOLADE; - - case '-' => nextCh; return SUB; + + case '-' => nextCh; return SUB; case '+' => nextCh; return ADD; case '*' => nextCh; return MUL; - case '%' => nextCh; return MOD; + case '%' => nextCh; return MOD; case '/' => nextCh; return DIV; - + case ';' => nextCh; return SEMICOLON; - case ',' => nextCh; return PERIOD; - case '.' => nextCh; return DOT; - + case ',' => nextCh; return PERIOD; + case '.' => nextCh; return DOT; + case '!' => nextCh; if (ch == '=') { nextCh; return NE; } else return NOT; - + case '=' => nextCh; if (ch == '=') { nextCh; return EQ; } else return EQUALS; - + case '<' => nextCh; if (ch == '=') { nextCh; return LE; } else return LT; - + case '>' => nextCh; if (ch == '=') { nextCh; return GE; } else return GT; - + case '&' => nextCh; if (ch == '&') { nextCh; @@ -179,7 +179,7 @@ Report.fail(start, "error: parse error on '&' token"); return BAD; } - + case '|' => nextCh; if (ch == '|') { nextCh; @@ -188,7 +188,7 @@ Report.fail(start, "error: parse error on '|' token"); return BAD; } - + case '"' => nextCh; while(ch!='"' && ch!='\n' && ch!='\r' && ch!=EOF_CH) { buf.append(ch); @@ -199,16 +199,16 @@ nextCh; return STRING; } else { - if (ch == EOF_CH) + if (ch == EOF_CH) Report.fail(start, "error: unexpected EOF"); - else { - nextCh; + else { + nextCh; Report.fail(start, "error: parse error on '"+ch+"' token. expected \""); } return BAD; } - - case _ if (Character.isLetter (ch)) => + + case _ if (Character.isLetter (ch)) => while(Character.isLetter(ch) || Character.isDigit(ch) || ch == '_') { buf.append(ch); nextCh; @@ -218,7 +218,7 @@ case Some(t) => return t; case _ => return IDENT; } - + case _ if (Character.isDigit (ch)) => if (ch == '0') { buf.append (ch); @@ -235,7 +235,7 @@ case EOF_CH => EOF; - case _ => + case _ => nextCh; Report.fail(start, "error: parse error on '"+ch+"' token"); return BAD; diff --git a/sources/zweic/Symbol.scala b/sources/zweic/Symbol.scala index 796dd95..7798372 100755 --- a/sources/zweic/Symbol.scala +++ b/sources/zweic/Symbol.scala @@ -77,7 +77,7 @@ def allMethods: List[MethodSymbol] = methods.values.toList; - + override def toString() = "class " + name; } diff --git a/sources/zweic/Type.scala b/sources/zweic/Type.scala index a6884d8..e008145 100755 --- a/sources/zweic/Type.scala +++ b/sources/zweic/Type.scala @@ -15,25 +15,25 @@ } override def toString(): String = this match { - case IClassType(c) => "ClassType: " + c.name; + case IClassType(c) => "ClassType(" + c.toString()+")"; case IIntType => "IntType" case INullType => "NullType" - case IBadType => "" + case IBadType => "" } def isSubtype(that: Type): Boolean = Pair(this, that) match { case Pair(INullType, x) => true case Pair(x, INullType) => false - case Pair(x, y) => - x.lub(y) match { - case Some(a) => a.isSametype(x) - case None => false - } + case Pair(IIntType, IIntType) => true + case Pair(IClassType(c1), IClassType(c2)) => c1.superclasses.contains(c2) + case _ => false } def isSametype(that: Type): Boolean = Pair(this, that) match { - case Pair(x, y) => x == y - case _ => false + case Pair(IIntType, IIntType) => true + case Pair(INullType, INullType) => true + case Pair(IClassType(c1), IClassType(c2)) => c1 == c2 + case _ => false } def lub(that: Type): Option[Type] = Pair(this, that) match { @@ -43,9 +43,9 @@ case Pair(IClassType(c1), IClassType(c2)) => intersection(c1.superclasses, c2.superclasses) match { case t :: ts => Some(IClassType(t)) - case List() => Some(IBadType) + case List() => None } - case x => Some(IBadType) + case x => None } }