Changes:
* fixed isSubtype()
* removed trailing whitespaces
1 parent c921b15 commit 572619359b4247d240bcf908bd0b3572a6ba78bc
@ajaggi ajaggi authored on 27 Dec 2005
Showing 6 changed files
View
96
sources/zweic/Analyzer.scala
val emptyVarScope: VarScope = ListMap.Empty;
 
// Analyze a program
def analyzeProgram(tree: Program): Unit = tree match {
case Program(classes, main) =>
case Program(classes, main) =>
classes.foreach(analyzeClass);
analyzeExpr(emptyVarScope, main);
()
}
private def analyzeClass(tree: ClassDef): Unit = tree match {
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]);
}
var myVarScope = emptyVarScope;
 
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
f.name.sym = VarSymbol(f.pos, f.name.name, analyzeType(f.typ));
case None =>
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
private def analyzeStat(varScope: VarScope, tree: Stat): VarScope =
 
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];
}
 
case Set(ident, expr) =>
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
 
case Do(expr) =>
case Some(c) =>
name.sym = c;
IClassType(c)
case None =>
Report.error(tree.pos, "type " + name + " is unknown");
Report.error(tree.pos, "type '" + name + "' is unknown");
IBadType
}
}
 
case Some(v) =>
name.sym = v;
v.vartype
case None =>
Report.error(tree.pos, "Unknown variable " + name);
Report.error(tree.pos, "unknown variable '" + name + "'");
IBadType
}
 
case Select(expr, name) =>
case Some(v) =>
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) =>
val ct = classScope.get(name.name);
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
}
 
case NullLit() =>
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);
Report.error(tree.pos, "incompatible types: '" + t1 + "' <=> '" + t2 + "'");
} else {
checkIntType(left.pos, t1);
checkIntType(right.pos, t2);
}
IIntType
 
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)
}
* 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);
if (!found.isSametype(expected))
error(pos, "type mismatch", found, expected);
 
/**
* Generates an error if the found type is not equal to IIntType.
*/
* 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" +
"found type : " + found);
"actual type : " + found);
 
}
View
36
sources/zweic/Parser.scala
pushedBack match {
case Some(Triple(p, c, t)) =>
token = t;
chars = c;
start = p;
start = p;
pushedBack = None;
case _ => return super.nextToken;
}
}
*/
private def program(): Program = {
val pos = start;
var classes:List[ClassDef] = Nil;
while (token == CLASS) {
while (token == CLASS) {
classes = classDecl() :: classes;
}
val main = expression();
return Program(classes.reverse, main).setPos(pos);
return ClassDef (name, extend, members.reverse).setPos(pos);
}
 
/**
* Member = Formal
* (";" |
* "(" [Formal {"," Formal}] ")" Block)
* Member = Formal
* (";" |
* "(" [Formal {"," Formal}] ")" Block)
*/
private def member(): Member = {
val pos = start;
val f:Formal = formal();
} else {
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;
}
private def block(): Block = {
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;
}
if (check (RETURN)) {
* Type1 = "Int" | "Null" | ident
*/
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;
}
}
val e = expression();
accept(SEMICOLON);
return Var(v.name, v.typ, e).setPos(pos);
 
case EQUALS =>
case EQUALS =>
//affection
val name = Name(chars);
accept(IDENT);
accept(EQUALS);
val e = expression();
accept(SEMICOLON);
return Set(name, e).setPos(pos);
 
case _ =>
//expression
val e = expression();
accept(SEMICOLON);
return Do(e).setPos(pos);
}
}
 
} else {
 
if (check(WHILE)) {
while ( !check(RACCOLADE) ) {
stats = statement() :: stats;
}
return While(cond, stats.reverse).setPos(pos);
 
} else if (token == NULLTYPE || token == INT) {
//type definition and affection
val v = formal();
accept(EQUALS);
val e = expression();
accept(RPAREN);
accept(SEMICOLON);
return PrintInt(e).setPos(pos);
 
} else if (check(PRINTCHAR)) {
//printChar
accept(LPAREN);
val e = expression();
case THIS => nextToken; Ident(Name("this")).setPos(pos);
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;
}
 
while ( check(PERIOD) ) {
rval = expression() :: rval;
}
rval;
} else Nil).reverse;
} else Nil).reverse;
 
/**
* Params = "(" Expressions ")"
*/
View
28
sources/zweic/Printer.scala
*/
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);
case Nil =>
*/
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
//
 
print(" {").indent.println;
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);
 
//
print(expr).print(";");
 
case PrintInt(expr) =>
print("printInt(").print(expr).print(")").print(";");
 
case PrintChar(expr) =>
print("printChar(").print(expr).print(")").print(";");
 
//
case Block(stats, expression) =>
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
}
 
/**
View
sources/zweic/Scanner.scala
View
sources/zweic/Symbol.scala
View
sources/zweic/Type.scala