diff options
author | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
commit | 4177daab2f54bdb20c71f623296a8bb32616fd12 (patch) | |
tree | 23f08b43f3758e825d5965b336030603a65bbcf7 /sources/scalac/ast/parser/Parser.java | |
parent | 33d6e170c97ca7b2f991896a0729941a7240b6d6 (diff) | |
download | scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.gz scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.bz2 scala-4177daab2f54bdb20c71f623296a8bb32616fd12.zip |
Initial version.
Diffstat (limited to 'sources/scalac/ast/parser/Parser.java')
-rw-r--r-- | sources/scalac/ast/parser/Parser.java | 1704 |
1 files changed, 1704 insertions, 0 deletions
diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java new file mode 100644 index 0000000000..cd491e2af9 --- /dev/null +++ b/sources/scalac/ast/parser/Parser.java @@ -0,0 +1,1704 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +import java.util.*; +import scalac.*; +import scalac.util.*; +import scalac.symtab.Modifiers; +import scalac.ast.*; +import Tree.*; + +/** A recursive descent parser for the programming language Scala. + * + * @author Martin Odersky, Matthias Zenger + * @version 1.2 + */ +public class Parser implements Tokens { + + /** the lexical analyzer + */ + Scanner s; + + /** the tree factory + */ + TreeFactory make; + + public Parser(Unit unit) { + s = new Scanner(unit); + make = unit.global.make; + } + + /** this is the general parse method + */ + public Tree[] parse() { + Tree[] ts = compilationUnit(); + accept(EOF); + return ts; + } + +/////// ERROR HANDLING ////////////////////////////////////////////////////// + + private void skip() { + //System.out.println("<skipping> " + s.token2string(s.token));//DEBUG + int nparens = 0; + int nbraces = 0; + while (true) { + switch (s.token) { + case EOF: + return; + case SEMI: + if (nparens == 0 && nbraces == 0) + return; + break; + case RPAREN: + nparens--; + break; + case RBRACE: + if (nbraces == 0) + return; + nbraces--; + break; + case LPAREN: + nparens++; + break; + case LBRACE: + nbraces++; + break; + } + //System.out.println("skipped: " + s.token2string(s.token));//DEBUG + s.nextToken(); + } + } + + Tree syntaxError(String msg, boolean skip) { + return syntaxError(s.pos, msg, skip); + } + + Tree syntaxError(int pos, String msg, boolean skip) { + if (pos != s.errpos) { + s.unit.error(pos, msg); + s.errpos = pos; + } + if (skip) skip(); + return make.Bad(pos); + } + + int accept(int token) { + int pos = s.pos; + if (s.token != token) { + int errpos = ((s.pos >>> Position.LINESHIFT) > + (s.lastpos >>> Position.LINESHIFT)) ? + s.lastpos : s.pos; + syntaxError(errpos, s.token2string(token) + " expected but " + + s.token2string(s.token) + " found.", true); + } + if (s.token == token) s.nextToken(); + return pos; + } + +/////// TOKEN CLASSES ////////////////////////////////////////////////////// + + boolean isModifier() { + return (s.token == ABSTRACT) + || (s.token == FINAL) + || (s.token == PRIVATE) + || (s.token == PROTECTED) +// || (s.token == QUALIFIED) + || (s.token == OVERRIDE); + } + + boolean isLocalClassModifier() { + return (s.token == ABSTRACT) + || (s.token == FINAL); + } + + boolean isDefIntro() { + switch (s.token) { + case VAL: case VAR: case DEF: case CONSTR: case TYPE: + case MODULE: case CLASS: case CASECLASS: case TRAIT: + return true; + default: + return false; + } + } + + boolean isDclIntro() { + switch (s.token) { + case VAL: case VAR: case DEF: case CONSTR: case TYPE: + return true; + default: + return false; + } + } + + boolean isExprIntro() { + switch (s.token) { + case CHARLIT: case INTLIT: case LONGLIT: + case FLOATLIT: case DOUBLELIT: case STRINGLIT: case NULL: + case IDENTIFIER: case THIS: case SUPER: + case IF: case FOR: case NEW: case USCORE: + case LPAREN: case LBRACKET: case LBRACE: + return true; + default: + return false; + } + } + +/////// TREE CONSTRUCTION //////////////////////////////////////////////////// + + /** Name supply + */ + int fresh = 0; + + Name fresh() { + return Name.fromString("x$" + (fresh++)); + } + + /** Create tree representing binary operation expression or pattern. + */ + Tree makeBinop(boolean isExpr, int pos, Tree left, Name op, Tree right) { + if (isExpr) { + if (op.leftAssoc()) { + return make.Apply(pos, + make.Select(pos, left, NameTransformer.encode(op)), + new Tree[]{right}); + } else { + Name x = fresh(); + return make.Block(pos, + new Tree[]{ + make.ValDef(pos, 0, x, Tree.Empty, left), + make.Apply(pos, + make.Select(pos, right, NameTransformer.encode(op)), + new Tree[]{make.Ident(left.pos, x)})}); + } + } else { + return make.Apply(pos, + make.Ident(pos, NameTransformer.encode(op).toTypeName()), + new Tree[]{left, right}); + } + } + + /** Create tree representing type scala.Any + */ + Tree scalaAnyType(int pos) { + return make.Select(pos, make.Ident(pos, Names.scala), Names.Any.toTypeName()); + } + + /** Create tree representing constructor scala.Object + */ + Tree scalaObjectConstr(int pos) { + return make.Select(pos, make.Ident(pos, Names.scala), Names.Object.toConstrName()); + } + + /** Create tree for for-comprehension <for (enums) do body> or + * <for (enums) yield body> where mapName and flatmapName are chosen + * corresponding to whether this is a for-do or a for-yield. + */ + Tree makeFor(Tree[] enums, Name mapName, Name flatmapName, Tree body) { + switch (enums[0]) { + case PatDef(int mods, Tree pat, Tree rhs): + if (enums.length == 1) + return makeFor1(enums[0].pos, mapName, pat, rhs, body); + Tree[] newenums = new Tree[enums.length - 1]; + switch (enums[1]) { + case PatDef(int mods2, Tree pat2, Tree rhs2): + System.arraycopy(enums, 1, newenums, 0, newenums.length); + return makeFor1(enums[0].pos, flatmapName, pat, rhs, + makeFor(newenums, mapName, flatmapName, body)); + default: + System.arraycopy(enums, 2, newenums, 1, newenums.length - 1); + newenums[0] = make.PatDef( + enums[0].pos, mods, pat, + makeFor1(enums[0].pos, Names.filter, pat, rhs, enums[1])); + return makeFor(newenums, mapName, flatmapName, body); + } + default: + throw new ApplicationError(); + } + } + + //where + Tree makeFor1(int pos, Name name, Tree pat, Tree rhs, Tree body) { + Tree cont; + switch (pat) { + case Ident(Name name1): + cont = make.Function(pos, + new Tree.ValDef[]{ + (ValDef) + make.ValDef(pat.pos, Modifiers.PARAM, name1, Tree.Empty, Tree.Empty)}, + body); + break; + default: + cont = make.Visitor(pos, new Tree.CaseDef[]{ + (CaseDef)make.CaseDef(pos, pat, Tree.Empty, body)}); + } + return make.Apply(pos, make.Select(pos, rhs, name), new Tree[]{cont}); + } + + /** Convert tree to formal parameter list + */ + ValDef[] convertToParams(Tree t) { + switch (t) { + case Function(ValDef[] params, Tree.Empty): + return params; + case Ident(_): + case Typed(Ident(_), _): + return new ValDef[]{convertToParam(t)}; + case Block(Tree[] stats): + if (stats.length == 0) return Tree.ExtValDef.EMPTY_ARRAY; + } + syntaxError(t.pos, "malformed formal parameter list", false); + return Tree.ExtValDef.EMPTY_ARRAY; + } + + /** Convert list of trees to formal parameter list + */ + ValDef[] convertToParams(Tree[] ts) { + ValDef[] res = new ValDef[ts.length]; + for (int i = 0; i < res.length; i++) + res[i] = convertToParam(ts[i]); + return res; + } + + /** Convert tree to formal parameter + */ + ValDef convertToParam(Tree tree) { + switch (tree) { + case Ident(Name name): + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, name, Tree.Empty, Tree.Empty); + case Typed(Ident(Name name), Tree tpe): + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, name, tpe, Tree.Empty); + default: + Tree tpe = syntaxError(tree.pos, "not a legal formal parameter", false); + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, Names.ERROR, tpe, Tree.Empty); + } + } + + /** Convert (qual)ident to type identifier + */ + Tree convertToTypeId(Tree t) { + switch (t) { + case Ident(Name name): + return make.Ident(t.pos, name.toTypeName()); + case Select(Tree qual, Name name): + return make.Select(t.pos, qual, name.toTypeName()); + default: + return t; + } + } + + /** Convert (qual)ident to constructor identifier + */ + Tree convertToConstr(Tree t) { + switch (t) { + case Apply(Tree fn, Tree[] args): + return make.Apply(t.pos, convertToConstr(fn), args); + case TypeApply(Tree fn, Tree[] args): + return make.TypeApply(t.pos, convertToConstr(fn), args); + case Ident(Name name): + return make.Ident(t.pos, name.toConstrName()); + case Select(Tree qual, Name name): + return make.Select(t.pos, qual, name.toConstrName()); + default: + return syntaxError(t.pos, "class constructor expected", false); + } + } + +/////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// + + Tree[] operands = new Tree[8]; + int[] positions = new int[8]; + Name[] operators = new Name[8]; + int sp = 0; + + void push(Tree od, int pos, Name op) { + if (sp == operands.length) { + Tree[] operands1 = new Tree[sp * 2]; + System.arraycopy(operands, 0, operands1, 0, sp); + operands = operands1; + int[] positions1 = new int[sp * 2]; + System.arraycopy(positions, 0, positions1, 0, sp); + positions = positions1; + Name[] operators1 = new Name[sp * 2]; + System.arraycopy(operators, 0, operators1, 0, sp); + operators = operators1; + } + operands[sp] = od; + positions[sp] = pos; + operators[sp] = op; + sp++; + } + + Tree reduceStack(boolean isExpr, int base, Tree top, + int prec, boolean leftAssoc) { + if (sp != base && + operators[sp-1].precedence() == prec && + operators[sp-1].leftAssoc() != leftAssoc) { + syntaxError( + positions[sp-1], + "left- and right-associative operators with same precedence may not be mixed", + false); + } + while (sp != base && + (prec < operators[sp-1].precedence() || + (leftAssoc && prec == operators[sp-1].precedence()))) { + sp--; + top = makeBinop(isExpr, positions[sp], operands[sp], operators[sp], top); + } + return top; + } + +/////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// + + static final Name MINUS = Name.fromString("-"); + static final Name PLUS = Name.fromString("+"); + static final Name BANG = Name.fromString("!"); + static final Name TILDE = Name.fromString("~"); + + Name ident() { + if (s.token == IDENTIFIER) { + Name name = NameTransformer.encode(s.name); + s.nextToken(); + return name; + } else { + accept(IDENTIFIER); + return Names.ERROR; + } + } + + /** StableRef ::= StableId + * | [Ident `.'] this + * SimpleType ::= StableRef [`.' type] + */ + Tree stableRef(boolean thisOK, boolean typeOK) { + Tree t; + if (s.token == THIS) { + t = make.This(s.skipToken(), Tree.Empty); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else { + t = make.Ident(s.pos, ident()); + if (s.token == DOT) { + int pos = s.skipToken(); + if (s.token == THIS) { + s.nextToken(); + t = make.This(pos, convertToTypeId(t)); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else { + t = selectors(pos, t, typeOK); + } + } + } + return t; + } + + Tree selectors(int pos, Tree t, boolean typeOK) { + if (typeOK && s.token == TYPE) { + s.nextToken(); + return make.SingletonType(pos, t); + } else { + t = make.Select(pos, t, ident()); + if (s.token == DOT) { + t = selectors(s.skipToken(), t, typeOK); + } + return t; + } + } + + /** StableId ::= [[Ident `.'] this `.'] {Id `.'} Id + */ + Tree stableId() { + return stableRef(false, false); + } + + /** QualId ::= Id {`.' Id} + */ + Tree qualId() { + Tree id = make.Ident(s.pos, ident()); + if (s.token == DOT) return selectors(s.skipToken(), id, false); + else return id; + } + + /** SimpleExpr ::= literal + * | null + */ + Tree literal() { + Tree t; + switch (s.token) { + case CHARLIT: + t = make.Literal(s.pos, new Character((char)s.intVal)); + break; + case INTLIT: + t = make.Literal(s.pos, new Integer((int)s.intVal)); + break; + case LONGLIT: + t = make.Literal(s.pos, new Long(s.intVal)); + break; + case FLOATLIT: + t = make.Literal(s.pos, new Float((float)s.floatVal)); + break; + case DOUBLELIT: + t = make.Literal(s.pos, new Double(s.floatVal)); + break; + case STRINGLIT: + t = make.Literal(s.pos, s.name.toString()); + break; + case NULL: + t = make.Ident(s.pos, Names.null_); + break; + default: + return syntaxError("illegal literal", true); + } + s.nextToken(); + return t; + } + +//////// TYPES /////////////////////////////////////////////////////////////// + + /** TypedOpt ::= [`:' Type] + */ + Tree typedOpt() { + if (s.token == COLON) { + s.nextToken(); + return type(); + } else { + return Tree.Empty; + } + } + + /** Types ::= Type {`,' Type} + */ + Tree[] types() { + TreeList ts = new TreeList(); + ts.append(type()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(type()); + } + return ts.toArray(); + } + + /** Type ::= Type1 `=>' Type + * | `(' [Types] `)' `=>' Type + * | Type1 + */ + Tree type() { + Tree t; + if (s.token == LPAREN) { + s.nextToken(); + if (s.token == RPAREN) { + s.nextToken(); + int pos = accept(ARROW); + return make.FunType(pos, Tree.EMPTY_ARRAY, type()); + } else { + t = type(); + if (s.token == COMMA) { + s.nextToken(); + TreeList ts = new TreeList(); + ts.append(t); + ts.append(types()); + accept(RPAREN); + int pos = accept(ARROW); + return make.FunType(pos, ts.toArray(), type()); + } else { + accept(RPAREN); + } + } + } else { + t = type1(); + } + if (s.token == ARROW) + return make.FunType(s.skipToken(), new Tree[]{t}, type()); + else + return t; + } + + /** Type1 ::= SimpleType {with SimpleType} [with Refinement] + */ + Tree type1() { + int pos = s.pos; + Tree t = simpleType(); + if (s.token == WITH) { + TreeList ts = new TreeList(); + ts.append(t); + while (s.token == WITH) { + s.nextToken(); + if (s.token == LBRACE) + return make.CompoundType(pos, ts.toArray(), refinement()); + else + ts.append(simpleType()); + } + return make.CompoundType(pos, ts.toArray(), Tree.EMPTY_ARRAY); + } else { + return t; + } + } + + /** SimpleType ::= SimpleType TypeArgs + * | SimpleType `#' Id + * | StableId + * | StableRef `.' type + * | `[' Types `]' + * | `(' Type `)' + */ + Tree simpleType() { + int pos = s.pos; + Tree t; + if (s.token == LPAREN) { + s.nextToken(); + t = type(); + accept(RPAREN); + } else if (s.token == LBRACKET) { + s.nextToken(); + Tree[] ts = types(); + accept(RBRACKET); + t = make.TupleType(pos, ts); + } else { + t = convertToTypeId(stableRef(false, true)); + } + while (true) { + if (s.token == HASH) + t = make.SelectFromType(s.skipToken(), t, ident().toTypeName()); + else if (s.token == LBRACKET) + t = make.AppliedType(pos, t, varTypeArgs()); + else break; + } + return t; + } + + /** TypeArgs ::= `[' Types `]' + */ + Tree[] typeArgs() { + accept(LBRACKET); + Tree[] ts = types(); + accept(RBRACKET); + return ts; + } + + /** VarTypeArgs ::= `[' VarType {`,' VarType} `]' + */ + Tree[] varTypeArgs() { + int pos = accept(LBRACKET); + TreeList ts = new TreeList(); + ts.append(varType()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(varType()); + } + accept(RBRACKET); + return ts.toArray(); + } + + /** VarType ::= [`+'] Type + */ + Tree varType() { + int pos = s.pos; + if (s.token == IDENTIFIER && s.name == PLUS) + return make.CovariantType(s.skipToken(), type()); + else + return type(); + } + +//////// EXPRESSIONS //////////////////////////////////////////////////////// + + /** EqualsExpr ::= `=' Expr + */ + Tree equalsExpr() { + accept(EQUALS); + return expr(); + } + + /** Exprs ::= Expr {`,' Expr} + */ + Tree[] exprs() { + TreeList ts = new TreeList(); + ts.append(expr()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(expr()); + } + return ts.toArray(); + } + + /** Expr ::= [Bindings `=>'] Expr + * | if `(' Expr `)' Expr [[`;'] else Expr] + * | for `(' Enumerators `)' [do | yield] Expr + * | Designator `=' Expr + * | SimpleExpr ArgumentExprs `=' Expr + * | PostfixExpr [`:' Type1 | as Type1 | is Type1] + * Bindings ::= Id [`:' Type1] + * | `(' [Binding {`,' Binding}] `)' + */ + Tree expr() { + if (s.token == IF) { + int pos = s.skipToken(); + accept(LPAREN); + Tree cond = expr(); + accept(RPAREN); + Tree thenp = expr(); + Tree elsep = Tree.Empty; + if (s.token == ELSE) { + s.nextToken(); + elsep = expr(); + } else { + elsep = Tree.Empty; + } + return make.If(pos, cond, thenp, elsep) ; + } else if (s.token == FOR) { + s.nextToken(); + accept(LPAREN); + Tree[] enums = enumerators(); + accept(RPAREN); + if (s.token == DO) { + s.nextToken(); + return makeFor(enums, Names.foreach, Names.foreach, expr()); + } else if (s.token == YIELD) { + s.nextToken(); + return makeFor(enums, Names.map, Names.flatmap, expr()); + } else { + return syntaxError("`do' or `yield' expected", true); + } +// } else if (s.token == ARROW) { +// return make.Function(s.skipToken(), new ValDef[]{}, expr()); + } else { + Tree t = postfixExpr(); + if (s.token == EQUALS) { + switch (t) { + case Ident(_): + case Select(_, _): + case Apply(_, _): + t = make.Assign(s.skipToken(), t, expr()); + } + } else if (s.token == COLON) { + int pos = s.skipToken(); + Tree tp = type1(); + t = make.Typed(pos, t, tp); + } else if (s.token == AS || s.token == IS) { + Name op = (s.token == AS) ? Names.as : Names.is; + int pos = s.skipToken(); + t = make.TypeApply(pos, make.Select(pos, t, op), new Tree[]{type1()}); + } + if (s.token == ARROW) { + t = make.Function(s.skipToken(), convertToParams(t), expr()); + } + return t; + } + } + + /** PostfixExpr ::= InfixExpr [Id] + * InfixExpr ::= PrefixExpr + * | InfixExpr Id InfixExpr + */ + Tree postfixExpr() { + int base = sp; + Tree top = prefixExpr(); + while (s.token == IDENTIFIER) { + top = reduceStack( + true, base, top, s.name.precedence(), s.name.leftAssoc()); + push(top, s.pos, s.name); + ident(); + if (isExprIntro()) { + top = prefixExpr(); + } else { + sp--; + int pos = positions[sp]; + Name postOp = operators[sp]; + top = reduceStack(true, base, operands[sp], 0, true); + return make.Select(pos, top, postOp); + } + } + return reduceStack(true, base, top, 0, true); + } + + /** PrefixExpr ::= [op] SimpleExpr + */ + Tree prefixExpr() { + Tree t; + if (s.token == IDENTIFIER && + (s.name == MINUS || + s.name == PLUS || + s.name == TILDE || + s.name == BANG)) { + Name name = ident(); + t = make.Select(s.pos, simpleExpr(), name); + } else { + t = simpleExpr(); + } + return t; + } + + /* SimpleExpr ::= literal + * | null + * | StableRef + * | super `.' Id + * | SimpleExpr `.' Id + * | `(' [Expr] `)' + * | `[' [Exprs] `]' + * | BlockExpr + * | SimpleExpr `@' TypeArgs + * | SimpleExpr ArgumentExprs + * | new Template + * | `_' + */ + Tree simpleExpr() { + Tree t; + switch (s.token) { + case CHARLIT: + case INTLIT: + case LONGLIT: + case FLOATLIT: + case DOUBLELIT: + case STRINGLIT: + case NULL: + t = literal(); + break; + case IDENTIFIER: + case THIS: + t = stableRef(true, false); + break; + case SUPER: + int pos = s.skipToken(); + t = make.Select(accept(DOT), make.Super(pos, Tree.Empty), ident()); + break; + case LPAREN: + int pos = s.skipToken(); + if (s.token == RPAREN) { + s.nextToken(); + t = make.Block(pos, Tree.EMPTY_ARRAY); + } else { + t = expr(); + if (s.token == COMMA) { + int commapos = s.skipToken(); + TreeList ts = new TreeList(); + ts.append(t); + ts.append(exprs()); + accept(RPAREN); + if (s.token == ARROW) { + t = make.Function(pos, convertToParams(ts.toArray()), Tree.Empty); + } else { + t = syntaxError(commapos, "`)' expected", false); + } + } else { + accept(RPAREN); + } + } + break; + case LBRACKET: + int pos = s.skipToken(); + Tree[] ts; + if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY; + else ts = exprs(); + t = make.Tuple(pos, ts); + accept(RBRACKET); + break; + case LBRACE: + t = blockExpr(); + break; + case NEW: + t = make.New(s.skipToken(), template()); + break; + default: + return syntaxError("illegal start of expression", true); + } + while (true) { + switch (s.token) { + case DOT: + t = make.Select(s.skipToken(), t, ident()); + break; + case AT: + int pos = s.skipToken(); + t = make.TypeApply(pos, t, typeArgs()); + break; + case LPAREN: + case LBRACKET: + case LBRACE: + t = make.Apply(s.pos, t, argumentExprs()); + break; + default: + return t; + } + } + } + + /** ArgumentExprs ::= `(' [Exprs] `)' + * | `[' [Exprs] `]' + * | BlockExpr + */ + Tree[] argumentExprs() { + Tree[] ts = Tree.EMPTY_ARRAY; + if (s.token == LBRACE) { + ts = new Tree[]{blockExpr()}; + } else if (s.token == LBRACKET) { + int pos = s.skipToken(); + if (s.token != RBRACKET) + ts = exprs(); + accept(RBRACKET); + ts = new Tree[]{make.Tuple(pos, ts)}; + } else { + accept(LPAREN); + if (s.token != RPAREN) + ts = exprs(); + accept(RPAREN); + } + return ts; + } + + /** BlockExpr ::= `{' CaseClause {CaseClause} `}' + * | `{' Block `}' + */ + Tree blockExpr() { + Tree res; + int pos = accept(LBRACE); + if (s.token == CASE) { + TreeList stats = new TreeList(); + do { + stats.append(caseClause()); + } while (s.token == CASE); + res = make.Visitor( + pos, (CaseDef[]) stats.copyTo(new CaseDef[stats.length()])); + } else { + res = block(pos); + } + accept(RBRACE); + return res; + } + + /** BlockConstr ::= `{' Block `}' + */ + Tree blockConstr() { + int pos = accept(LBRACE); + Tree res = block(pos); + switch (res) { + case Block(Tree[] stats): + if (stats.length > 0) + stats[stats.length - 1] = convertToConstr(stats[stats.length - 1]); + else + syntaxError(res.pos, "class constructor expected", false); + } + accept(RBRACE); + return res; + } + + /** Block ::= BlockStatSeq + */ + Tree block(int pos) { + Tree[] stats = blockStatSeq(new TreeList()); + if (stats.length == 1) return stats[0]; + else return make.Block(pos, stats); + } + + /** CaseClause ::= case Pattern [if `(' Expr `)'] `=>' Block + */ + Tree caseClause() { + int pos = accept(CASE); + Tree pat = pattern(); + Tree guard = Tree.Empty; + if (s.token == IF) { + s.nextToken(); + accept(LPAREN); + guard = expr(); + accept(RPAREN); + } + accept(ARROW); + return make.CaseDef(pos, pat, guard, block(s.pos)); + } + + /** Enumerators ::= Generator {`;' Enumerator} + * Enumerator ::= Generator + * | Expr + */ + Tree[] enumerators() { + TreeList enums = new TreeList(); + enums.append(generator()); + while (s.token == SEMI) { + s.nextToken(); + if (s.token == VAL) enums.append(generator()); + else enums.append(expr()); + } + return enums.toArray(); + } + + /** Generator ::= val Pattern `<-' Expr + */ + Tree generator() { + int pos = accept(VAL); + Tree p = pattern(); + accept(LARROW); + return make.PatDef(pos, 0, p, expr()); + } + +//////// PATTERNS //////////////////////////////////////////////////////////// + + /** Patterns ::= Pattern {`,' Pattern} + */ + Tree[] patterns() { + TreeList ts = new TreeList(); + ts.append(pattern()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(pattern()); + } + return ts.toArray(); + } + + /** Pattern ::= varid `:' Type1 + * | `_' `:' Type1 + * | SimplePattern {Id SimplePattern} + */ + Tree pattern() { + int base = sp; + Tree top = simplePattern(); + if (s.token == COLON) { + switch (top) { + case Ident(Name name): + if (name.isVariable()) + return make.Typed(s.skipToken(), top, type1()); + } + } + while (s.token == IDENTIFIER) { + top = reduceStack( + false, base, top, s.name.precedence(), s.name.leftAssoc()); + push(top, s.pos, s.name); + ident(); + top = simplePattern(); + } + return reduceStack(false, base, top, 0, true); + } + + /** SimplePattern ::= varid + * | `_' + * | literal + * | null + * | StableId {ArgumentPatterns} + * | `(' Pattern `)' + * | `[' [Patterns] `]' + */ + Tree simplePattern() { + switch (s.token) { + case IDENTIFIER: + case THIS: + Tree t = stableId(); + while (s.token == LPAREN || s.token == LBRACKET) { + t = make.Apply(s.pos, convertToConstr(t), argumentPatterns()); + } + return t; + case USCORE: + return make.Ident(s.skipToken(), Names.WILDCARD); + case CHARLIT: + case INTLIT: + case LONGLIT: + case FLOATLIT: + case DOUBLELIT: + case STRINGLIT: + case NULL: + return literal(); + case LPAREN: + s.nextToken(); + Tree t = pattern(); + accept(RPAREN); + return t; + case LBRACKET: + return tuplePattern(); + default: + return syntaxError("illegal start of pattern", true); + } + } + + /** SimplePattern ::= `[' [Patterns] ']' + */ + Tree tuplePattern() { + int pos = accept(LBRACKET); + Tree[] ts; + if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY; + else ts = patterns(); + accept(RBRACKET); + return make.Tuple(pos, ts); + } + + /** ArgumentPatterns ::= `(' [Patterns] `)' + * | `[' [Patterns] `]' + */ + Tree[] argumentPatterns() { + if (s.token == LBRACKET) { + return new Tree[]{tuplePattern()}; + } else { + Tree[] ts = Tree.EMPTY_ARRAY; + accept(LPAREN); + if (s.token != RPAREN) + ts = patterns(); + accept(RPAREN); + return ts; + } + } + +////////// MODIFIERS //////////////////////////////////////////////////////////// + + /** Modifiers ::= {Modifier} + * Modifier ::= final + * | private + * | protected + * | override + * | abstract + */ + int modifiers() { + int mods = 0; + while (true) { + int mod; + switch (s.token) { + case ABSTRACT: + mod = Modifiers.ABSTRACTCLASS; + break; + case FINAL: + mod = Modifiers.FINAL; + break; + case PRIVATE: + mod = Modifiers.PRIVATE; + break; + case PROTECTED: + mod = Modifiers.PROTECTED; + break; + case OVERRIDE: + mod = Modifiers.OVERRIDE; + break; + default: + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods |= mod; + s.nextToken(); + } + } + + /** LocalClassModifiers ::= {LocalClassModifier} + * LocalClassModifier ::= final + * | private + */ + int localClassModifiers() { + int mods = 0; + while (true) { + int mod; + switch (s.token) { + case ABSTRACT: + mod = Modifiers.ABSTRACTCLASS; + break; + case FINAL: + mod = Modifiers.FINAL; + break; + default: + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods |= mod; + s.nextToken(); + } + } + +//////// PARAMETERS ////////////////////////////////////////////////////////// + + /** ParamClauses ::= {ParamClause} + */ + ValDef[][] paramClauses() { + ArrayList ts = new ArrayList(); + while (s.token == LPAREN) + ts.add(paramClause()); + return (ValDef[][])ts.toArray(new ValDef[ts.size()][]); + } + + /** ParamClause ::= `(' [Param {`,' Param}] `)' + */ + ValDef[] paramClause() { + int pos = accept(LPAREN); + TreeList params = new TreeList(); + if (s.token != RPAREN) { + params.append(param()); + while (s.token == COMMA) { + s.nextToken(); + params.append(param()); + } + } + accept(RPAREN); + return (ValDef[])params.copyTo(new ValDef[params.length()]); + } + + /** Param ::= [def] Id `:' Type + */ + ValDef param() { + int pos = s.pos; + int mods = Modifiers.PARAM; + if (s.token == DEF) { + mods |= Modifiers.DEF; + s.nextToken(); + } + Name name = ident(); + accept(COLON); + return (ValDef)make.ValDef(pos, mods, name, type(), Tree.Empty); + } + + /** TypeParamClauseOpt ::= [`[' TypeSig {`,' TypeSig} `]'] + */ + TypeDef[] typeParamClauseOpt() { + TreeList params = new TreeList(); + if (s.token == LBRACKET) { + s.nextToken(); + params.append(typeParam()); + while (s.token == COMMA) { + s.nextToken(); + params.append(typeParam()); + } + accept(RBRACKET); + } + return (TypeDef[])params.copyTo(new TypeDef[params.length()]); + } + + /** TypeSig ::= Id [<: Type] + */ + Tree typeParam() { + int pos = s.pos; + Name name = ident(); + Tree tp; + if (s.token == SUBTYPE) { + s.nextToken(); + tp = type(); + } else { + tp = scalaAnyType(pos); + } + return make.TypeDef(pos, Modifiers.PARAM, name.toTypeName(), + Tree.ExtTypeDef.EMPTY_ARRAY, tp); + } + +//////// DEFS //////////////////////////////////////////////////////////////// + + /** Import ::= import ImportRef {`,' ImportRef} + */ + Tree[] importClause() { + accept(IMPORT); + TreeList ts = new TreeList(); + ts.append(importRef()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(importRef()); + } + return ts.toArray(); + } + + /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors) + */ + Tree importRef() { + Tree t; + int startpos = s.pos; + int pos; + if (s.token == THIS) { + t = make.This(s.skipToken(), Tree.Empty); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } else { + t = make.Ident(s.pos, ident()); + pos = accept(DOT); + if (s.token == THIS) { + s.nextToken(); + t = make.This(pos, convertToTypeId(t)); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } + } + while (true) { + if (s.token == USCORE) { + s.nextToken(); + return make.Import(startpos, t, new Name[]{Names.WILDCARD}); + } else if (s.token == LBRACE) { + return make.Import(startpos, t, importSelectors()); + } else { + Name name = ident(); + if (s.token == DOT) { + t = make.Select(pos, t, name); + pos = accept(DOT); + } else { + return make.Import(startpos, t, new Name[]{name, name}); + } + } + } + } + + /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' + */ + Name[] importSelectors() { + LinkedList/*<Name>*/ names = new LinkedList(); + accept(LBRACE); + boolean isLast = importSelector(names); + while (!isLast && s.token == COMMA) { + s.nextToken(); + isLast = importSelector(names); + } + accept(RBRACE); + return (Name[])names.toArray(new Name[]{}); + } + + /** ImportSelector ::= Id [`=>' [Id | `_']] + */ + boolean importSelector(LinkedList/*<Name>*/ names) { + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.WILDCARD); + return true; + } else { + Name name = ident(); + names.add(name); + if (s.token == ARROW) { + s.nextToken(); + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.WILDCARD); + } else { + names.add(ident()); + } + } else { + names.add(name); + } + return false; + } + } + + /** Def ::= val PatDef {`,' PatDef} + * | var VarDef {`,' VarDef} + * | def FunDef {`,' FunDef} + * | constr ConstrDef {`,' ConstrDef} + * | type TypeDef {`,' TypeDef} + * | TopDef + * Dcl ::= val ValSig {`,' ValSig} + * | var ValSig {`,' ValSig} + * | def FunSig {`,' FunSig} + * | constr ConstrSig {`,' ConstrSig} + * | type TypeSig {`,' TypeSig} + */ + Tree[] defOrDcl(int mods) { + TreeList ts = new TreeList(); + switch (s.token) { + case VAL: + do { + s.nextToken(); + ts.append(patDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case VAR: + do { + s.nextToken(); + ts.append(varDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case DEF: + do { + s.nextToken(); + ts.append(funDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case CONSTR: + do { + s.nextToken(); + ts.append(constrDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case TYPE: + do { + s.nextToken(); + ts.append(typeDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + default: + return topDef(mods); + } + } + + /** TopDef ::= ([case] class) ClassDef {`,' ClassDef} + * | trait TraitDef {`,' TraitDef} + * | module ModuleDef {`,' ModuleDef} + * LocalTopDef ::= class ClassDef {`,' ClassDef} + * | trait TraitDef {`,' TraitDef} + * | module ModuleDef {`,' ModuleDef} + */ + Tree[] topDef(int mods) { + TreeList ts = new TreeList(); + switch (s.token) { + case CLASS: + case CASECLASS: + case TRAIT: + if (s.token == CASECLASS) mods |= Modifiers.CASE; + else if (s.token == TRAIT) mods |= Modifiers.TRAIT | Modifiers.ABSTRACTCLASS; + do { + s.nextToken(); + ts.append(classDef(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case MODULE: + do { + s.nextToken(); + ts.append(moduleDef(mods)); + } while (s.token == COMMA); + return ts.toArray(); + default: + return new Tree[]{syntaxError("illegal start of definition", true)}; + } + } + + /** PatDef ::= Pattern `=' Expr + * ValSig ::= Id `:' Type + */ + Tree patDefOrSig(int mods) { + int pos = s.pos; + Tree pat = pattern(); + Tree tp; + switch (pat) { + case Typed(Tree pat1, Tree tp1): + pat = pat1; + tp = tp1; + break; + default: + if (s.token == COLON) tp = typedOpt(); + else tp = Tree.Empty; + } + switch (pat) { + case Ident(Name name): + if (tp == Tree.Empty || s.token == EQUALS) + return make.ValDef(pos, mods, name, tp, equalsExpr()); + else + return make.ValDef(pos, mods | Modifiers.ABSTRACT, name, tp, Tree.Empty); + default: + return make.PatDef(pos, mods, pat, equalsExpr()); + } + } + + /** VarDef ::= Id [`:' Type] `=' Expr + * | Id `:' Type `=' `_' + * VarSig ::= Id `:' Type + */ + Tree varDefOrSig(int mods) { + int pos = s.pos; + Name name = ident(); + Tree type = typedOpt(); + if (type == Tree.Empty || s.token == EQUALS) { + accept(EQUALS); + Tree rhs; + if (type != Tree.Empty && s.token == USCORE) { + rhs = Tree.Empty; + s.nextToken(); + } else { + rhs = expr(); + } + return make.ValDef(pos, mods | Modifiers.MUTABLE, name, type, rhs); + } else { + return make.ValDef(pos, mods | Modifiers.MUTABLE | Modifiers.ABSTRACT, + name, type, Tree.Empty); + } + } + + /** FunDef ::= Id [TypeParamClause] {ParamClause} [`:' Type] + * (`=' Expr | BlockExpr) + * FunSig ::= Id [TypeParamClause] {ParamClause} `:' Type + */ + Tree funDefOrSig(int mods) { + int pos = s.pos; + Name name = ident(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] vparams = paramClauses(); + Tree restype = typedOpt(); + if (s.token == LBRACE) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, blockExpr()); + else if (s.token == EQUALS || restype == Tree.Empty) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, equalsExpr()); + else + return make.DefDef(pos, mods | Modifiers.ABSTRACT, name, + tparams, vparams, restype, Tree.Empty); + } + + /* ConstrDef ::= Id [TypeParamClause] [ParamClause] [`:' Type] + * (`=' Constr | `=' BlockConstr | BlockConstr) + */ + Tree constrDefOrSig(int mods) { + int pos = s.pos; + Name name = ident().toConstrName(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] vparams = new ValDef[][]{paramClause()}; + Tree restype = typedOpt(); + if (s.token == LBRACE) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, blockConstr()); + else if (s.token == EQUALS || restype == Tree.Empty) { + accept(EQUALS); + return make.DefDef(pos, mods, name, tparams, vparams, + restype, (s.token == LBRACE) ? blockConstr() : constr()); + } else + return make.DefDef(pos, mods | Modifiers.ABSTRACT, name, + tparams, vparams, restype, Tree.Empty); + } + + /** TypeDef ::= Id [TypeParamClause] `=' Type + * TypeSig ::= Id [`<:' Type] + */ + Tree typeDefOrSig(int mods) { + int pos = s.pos; + Name name = ident().toTypeName(); + if (s.token == SUBTYPE) { + s.nextToken(); + return make.TypeDef(pos, mods | Modifiers.ABSTRACT, name, + Tree.ExtTypeDef.EMPTY_ARRAY, type()); + } else if (s.token == LBRACKET) { + TypeDef[] tparams = typeParamClauseOpt(); + accept(EQUALS); + return make.TypeDef(pos, mods, name, tparams, type()); + } else if (s.token == EQUALS) { + s.nextToken(); + return make.TypeDef(pos, mods, name, + Tree.ExtTypeDef.EMPTY_ARRAY, type()); + } else if (s.token == SEMI || s.token == COMMA) { + return make.TypeDef( + pos, mods | Modifiers.ABSTRACT, name, + Tree.ExtTypeDef.EMPTY_ARRAY, scalaAnyType(pos)); + } else { + return syntaxError("`=' or `<:' expected", true); + } + } + + /** ClassDef ::= Id [TypeParamClause] ParamClause [`:' Type] ClassTemplate + * TraitDef ::= Id [TypeParamClause] [`:' Type] ClassTemplate + */ + Tree classDef(int mods) { + int pos = s.pos; + Name name = ident(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] params; + if ((mods & Modifiers.TRAIT) == 0) params = new ValDef[][]{paramClause()}; + else params = new ValDef[][]{}; + return make.ClassDef(pos, mods, name.toTypeName(), tparams, params, + typedOpt(), classTemplate()); + } + + /** ModuleDef ::= Id [`:' Type] ClassTemplate + */ + Tree moduleDef(int mods) { + return make.ModuleDef( + s.pos, mods, ident(), typedOpt(), classTemplate()); + } + + /** ClassTemplate ::= extends Template + * | TemplateBody + */ + Template classTemplate() { + int pos = s.pos; + if (s.token == EXTENDS) { + s.nextToken(); + return template(); + } else if (s.token == LBRACE) { + return (Template)make.Template( + pos, new Tree[]{scalaObjectConstr(pos)}, templateBody()); + } else { + syntaxError("`extends' or `{' expected", true); + return (Template)make.Template( + pos, new Tree[]{scalaObjectConstr(pos)}, Tree.EMPTY_ARRAY); + } + } + +////////// TEMPLATES //////////////////////////////////////////////////////////// + + + /** Template ::= Constr {`with' Constr} [TemplateBody] + */ + Template template() { + int pos = s.pos; + TreeList parents = new TreeList(); + parents.append(constr()); + while (s.token == WITH) { + s.nextToken(); + if (s.token == LBRACE) + return (Template)make.Template(pos, parents.toArray(), templateBody()); + else + parents.append(constr()); + } + Tree[] stats = (s.token == LBRACE) ? templateBody() : Tree.EMPTY_ARRAY; + return (Template)make.Template(pos, parents.toArray(), stats); + } + + /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)'] + */ + Tree constr() { + Tree t = convertToConstr(stableId()); + if (s.token == LBRACKET) + t = make.TypeApply(s.pos, t, typeArgs()); + if (s.token == LPAREN) + t = make.Apply(s.pos, t, argumentExprs()); + return t; + } + + /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}' + */ + Tree[] templateBody() { + accept(LBRACE); + Tree[] body = templateStatSeq(); + accept(RBRACE); + return body; + } + + /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + */ + Tree[] refinement() { + accept(LBRACE); + Tree[] body = refineStatSeq(); + accept(RBRACE); + return body; + } + +/////// STATSEQS ////////////////////////////////////////////////////////////// + + /** Packaging ::= package QualId `{' TopStatSeq `}' + */ + Tree packaging() { + int pos = accept(PACKAGE); + Tree pkg = qualId(); + accept(LBRACE); + Tree[] stats = topStatSeq(); + accept(RBRACE); + return + make.PackageDef(pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, stats)); + } + + /** TopStatSeq ::= [TopStat {`;' TopStat}] + * TopStat ::= Modifiers TopDef + * | Packaging + * | Import + * | + */ + Tree[] topStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (s.token == PACKAGE) { + stats.append(packaging()); + } else if (s.token == IMPORT) { + stats.append(importClause()); + } else if (s.token == CLASS || + s.token == CASECLASS || + s.token == TRAIT || + s.token == MODULE || + isModifier()) { + stats.append(topDef(modifiers())); + } else if (s.token != SEMI) { + syntaxError("illegal start of class or module definition", true); + } + if (s.token != RBRACE && s.token != EOF) accept(SEMI); + } + return stats.toArray(); + } + + /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat} + * TemplateStat ::= Import + * | Modifiers Def + * | Modifiers Dcl + * | Expr + * % | val this `:' Type + * | + */ + Tree[] templateStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (s.token == IMPORT) { + stats.append(importClause()); + } else if (isExprIntro()) { + stats.append(expr()); + } else if (isDefIntro() || isModifier()) { + stats.append(defOrDcl(modifiers())); + } else if (s.token != SEMI) { + syntaxError("illegal start of definition", true); + } + if (s.token != RBRACE) accept(SEMI); + } + return stats.toArray(); + } + + /** RefineStatSeq ::= RefineStat {`;' RefineStat} + * RefineStat ::= Dcl + * | type TypeDef {`,' TypeDef} + * | + */ + Tree[] refineStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (isDclIntro()) { + stats.append(defOrDcl(0)); + } else if (s.token != SEMI) { + syntaxError("illegal start of declaration", true); + } + if (s.token != RBRACE) accept(SEMI); + } + return stats.toArray(); + } + + /** BlockStatSeq ::= { BlockStat `;' } [Expr] + * BlockStat ::= Import + * | Def + * | LocalClassModifiers LocalTopDef + * | Expr + * | + */ + Tree[] blockStatSeq(TreeList stats) { + while ((s.token != RBRACE) && (s.token != EOF) && (s.token != CASE)) { + if (s.token == IMPORT) { + stats.append(importClause()); + accept(SEMI); + } else if (isExprIntro()) { + stats.append(expr()); + if (s.token != RBRACE && s.token != CASE) accept(SEMI); + } else if (isDefIntro()) { + stats.append(defOrDcl(0)); + accept(SEMI); + } else if (isLocalClassModifier()) { + stats.append(topDef(localClassModifiers())); + accept(SEMI); + } else if (s.token == SEMI) { + s.nextToken(); + } else { + syntaxError("illegal start of statement", true); + } + } + return stats.toArray(); + } + + + /** CompilationUnit = [package QualId `;'] TopStatSeq + */ + Tree[] compilationUnit() { + if (s.token == PACKAGE) { + int pos = s.skipToken(); + Tree pkg = qualId(); + if (s.token == SEMI) { + s.nextToken(); + return new Tree[]{ + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))}; + } else { + TreeList stats = new TreeList(); + accept(LBRACE); + stats.append( + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))); + accept(RBRACE); + stats.append(topStatSeq()); + return stats.toArray(); + } + } else { + return topStatSeq(); + } + } +} + |