summaryrefslogtreecommitdiff
path: root/sources/scalac/ast/parser/Parser.java
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac/ast/parser/Parser.java')
-rw-r--r--sources/scalac/ast/parser/Parser.java1704
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();
+ }
+ }
+}
+