package scala.tools.nsc.ast.parser; import scala.tools.util.Position; import scala.collection.mutable.ListBuffer; import symtab.Flags; import Tokens._; abstract class Syntactic: ParserPhase { import global._; import posAssigner.atPos; class Parser(unit: CompilationUnit) { val in = new Scanner(unit); /** the markup parser val xmlp = new MarkupParser(unit, s, this, false); */ /** The current nesting depths of while and do loops. */ var loopNestingDepth = 0; /** this is the general parse method */ def parse(): List[Tree] = { val ts = compilationUnit(); accept(EOF); ts } /////// ERROR HANDLING ////////////////////////////////////////////////////// private def skip(): unit = { //System.out.println(" " + in.token2string(in.token));//DEBUG var nparens = 0; var nbraces = 0; while (true) { in.token match { case EOF => return; case SEMI => if (nparens == 0 && nbraces == 0) return; case RPAREN => nparens = nparens - 1; case RBRACE => if (nbraces == 0) return; nbraces = nbraces - 1; case LPAREN => nparens = nparens + 1; case LBRACE => nbraces = nbraces + 1; case _ => } in.nextToken(); } } def syntaxError(msg: String, skipIt: boolean): unit = syntaxError(in.pos, msg, skipIt); def syntaxError(pos: int, msg: String, skipIt: boolean): unit = { if (pos != in.errpos) { unit.error(pos, msg); in.errpos = pos; } if (skipIt) skip(); } def accept(token: int): int = { val pos = in.pos; if (in.token != token) syntaxError( if (Position.line(in.pos) > Position.line(in.lastpos)) in.lastpos else in.pos, in.token2string(token) + " expected but " + in.token2string(in.token) + " found.", true); if (in.token == token) in.nextToken(); pos } def errorTypeTree = GeneralTypeTree().setType(ErrorType).setPos(in.pos); def errorTermTree = Literal(null).setPos(in.pos); def errorPatternTree = Ident(nme.WILDCARD).setPos(in.pos); /////// TOKEN CLASSES ////////////////////////////////////////////////////// def isModifier: boolean = in.token match { case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE => true case _ => false } def isLocalModifier: boolean = in.token match { case ABSTRACT | FINAL | SEALED => true case _ => false } def isDefIntro: boolean = in.token match { case VAL | VAR | DEF | TYPE | OBJECT | CASEOBJECT | CLASS | CASECLASS | TRAIT => true case _ => false } def isDclIntro: boolean = in.token match { case VAL | VAR | DEF | TYPE => true case _ => false } def isExprIntro: boolean = in.token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER | THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | DO | RETURN | THROW | LPAREN | LBRACE => true case _ => false } /////// COMMENT AND ATTRIBUTE COLLECTION ////////////////////////////////////// /** Join the comment associated with a definition */ def joinComment(def trees: List[Tree]): List[Tree] = { val buf = in.docBuffer; if (buf != null) { in.docBuffer = null; trees map (t => DocDef(buf.toString(), t) setPos t.pos) } else trees } /////// TREE CONSTRUCTION //////////////////////////////////////////////////// def fresh(): Name = unit.fresh.newName("x"); /** Create a tree representing a packaging */ def makePackaging(pkg: Tree, stats: List[Tree]): Tree = atPos(in.pos) { pkg match { case Ident(name) => PackageDef(name, stats) case Select(qual, name) => makePackaging(qual, List(PackageDef(name, stats))) } } /** Create tree representing binary operation expression or pattern. */ def makeBinop(isExpr: boolean, left: Tree, op: Name, right: Tree): Tree = { if (isExpr) { if (isLeftAssoc(op)) { Apply(Select(left, op.encode), List(right)) } else { val x: Name = fresh(); Block( List(ValDef(0, x, EmptyTree, left)), Apply(Select(right, op.encode), List(Ident(x)))) } } else { Apply(Ident(op.encode.toTypeName), List(left, right)) } } def makeAlternative(ts: List[Tree]): Tree = { def alternatives(t: Tree): List[Tree] = t match { case Alternative(ts) => ts case _ => List(t) } Alternative(for (val t <- ts; val a <- alternatives(t)) yield a) } def makeSequence(ts: List[Tree]): Tree = { def elements(t: Tree): List[Tree] = t match { case Sequence(ts) => ts case _ => List(t) } Sequence(for (val t <- ts; val e <- elements(t)) yield e) } def scalaDot(name: Name): Tree = Select(Ident(nme.scala), name); def scalaRuntimeDot(name: Name): Tree = Select(scalaDot(nme.runtime), name); def ScalaRunTimeDot(name: Name): Tree = Select(scalaRuntimeDot(nme.ScalaRunTime), name); def scalaBooleanDot(name: Name): Tree = Select(scalaDot(nme.Boolean), name); def scalaAnyRefConstr(): Tree = Apply(scalaDot(nme.AnyRef.toTypeName), List()); def scalaObjectConstr(): Tree = Apply(scalaDot(nme.ScalaObject.toTypeName), List()); def caseClassConstr(): Tree = Apply(scalaDot(nme.CaseClass.toTypeName), List()); def makeWhile(lname: Name, cond: Tree, body: Tree): Tree = { val continu = Apply(Ident(lname), List()); val rhs = If(cond, Block(List(body), continu), Literal(())); LabelDef(lname, Nil, rhs) } def makeDoWhile(lname: Name, body: Tree, cond: Tree): Tree = { val continu = Apply(Ident(lname), List()); val rhs = Block(List(body), If(cond, continu, Literal(()))); LabelDef(lname, Nil, rhs) } def makeBlock(stats: List[Tree]): Tree = { if (stats.isEmpty) Literal(()) else if (!stats.last.isTerm) Block(stats, Literal(())); else if (stats.length == 1) stats(0) else Block(stats.init, stats.last) } /** Convert tree to formal parameter list */ def convertToParams(t: Tree): List[ValDef] = t match { case Function(params, EmptyTree) => params case Ident(_) | Typed(Ident(_), _) => List(convertToParam(t)); case Literal(x) if x == () => //todo: check with Literal(()) Nil case _ => syntaxError(t.pos, "malformed formal parameter list", false); Nil } /** Convert tree to formal parameter */ def convertToParam(tree: Tree): ValDef = atPos(tree.pos) { tree match { case Ident(name) => ValDef(Flags.PARAM, name, EmptyTree, EmptyTree) case Typed(Ident(name), tpe) => ValDef(Flags.PARAM, name, tpe, EmptyTree) case _ => syntaxError(tree.pos, "not a legal formal parameter", false); ValDef(Flags.PARAM, nme.ERROR, errorTypeTree, EmptyTree) } } /** Convert (qual)ident to type identifier */ def convertToTypeId(tree: Tree): Tree = tree match { case Ident(name) => Ident(name.toTypeName).setPos(tree.pos) case Select(qual, name) => Select(qual, name.toTypeName).setPos(tree.pos) case _ => System.out.println(tree);//debug syntaxError(tree.pos, "identifier expected", false); errorTypeTree } /** Complete unapplied constructor with `()' arguments */ def applyConstr(t: Tree): Tree = t match { case Apply(_, _) => t case _ => Apply(t, List()) setPos t.pos } /** make closure from tree */ def makeClosure(tree: Tree): Tree = { val pname = fresh(); def insertParam(tree: Tree): Tree = tree match { case Ident(name) => Select(Ident(pname), name) case Select(qual, name) => Select(insertParam(qual), name) case Apply(fn, args) => Apply(insertParam(fn), args) case TypeApply(fn, args) => TypeApply(insertParam(fn), args) case _ => syntaxError(tree.pos, "cannot convert to closure", false); errorTermTree } Function( List(ValDef(Flags.PARAM, pname, EmptyTree, EmptyTree)), insertParam(tree)) } /////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// case class OpInfo(operand: Tree, operator: Name, pos: int); var opstack: List[OpInfo] = Nil; def precedence(operator: Name): int = if (operator eq nme.ERROR) -1 else { val firstCh = operator(0); if (((firstCh >= 'A') && (firstCh <= 'Z')) || ((firstCh >= 'a') && (firstCh <= 'z'))) 1 else firstCh match { case '|' => 2 case '^' => 3 case '&' => 4 case '<' | '>' => 5 case '=' | '!' => 6 case ':' => 7 case '+' | '-' => 8; case '*' | '/' | '%' => 9; case _ => 10; } } def isLeftAssoc(operator: Name): boolean = operator.length > 0 && operator(operator.length - 1) != ':'; def reduceStack(isExpr: boolean, base: List[OpInfo], top0: Tree, prec: int, leftAssoc: boolean): Tree = { var top = top0; if (opstack != base && precedence(opstack.head.operator) == prec && isLeftAssoc(opstack.head.operator) != leftAssoc) { syntaxError( opstack.head.pos, "left- and right-associative operators with same precedence may not be mixed", false); } while (opstack != base && (prec < precedence(opstack.head.operator) || (leftAssoc && prec == precedence(opstack.head.operator)))) { top = atPos(opstack.head.pos) { makeBinop(isExpr, opstack.head.operand, opstack.head.operator, top) } opstack = opstack.tail; } top } /////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// final val MINUS: Name = "-"; final val PLUS : Name = "+"; final val BANG : Name = "!"; final val TILDE: Name = "~"; final val STAR : Name = "*"; final val BAR : Name = "|"; final val OPT : Name = "?"; final val LT : Name = "<"; def ident(): Name = if (in.token == IDENTIFIER) { val name = in.name.encode; in.nextToken(); name } else { accept(IDENTIFIER); nme.ERROR } /** StableRef ::= StableId * | [Ident `.'] this * SimpleType ::= StableRef [`.' type] */ def stableRef(thisOK: boolean, typeOK: boolean): Tree = { var t: Tree = null; if (in.token == THIS) { t = atPos(in.skipToken()) { This(nme.EMPTY.toTypeName) } if (!thisOK || in.token == DOT) t = atPos(accept(DOT)) { selectors(t, typeOK) } } else if (in.token == SUPER) { t = atPos(in.skipToken()) { Super(nme.EMPTY.toTypeName, mixinQualifierOpt()) } t = atPos(accept(DOT)) { Select(t, ident()) } if (in.token == DOT) t = atPos(in.skipToken()) { selectors(t, typeOK) } } else { val i = atPos(in.pos) { Ident(ident()) } t = i; if (in.token == DOT) { val pos = in.skipToken(); if (in.token == THIS) { in.nextToken(); t = atPos(i.pos) { This(i.name.toTypeName) } if (!thisOK || in.token == DOT) t = atPos(accept(DOT)) { selectors(t, typeOK) } } else if (in.token == SUPER) { in.nextToken(); t = atPos(i.pos) { Super(i.name.toTypeName, mixinQualifierOpt()) } t = atPos(accept(DOT)) { Select(t, ident())} if (in.token == DOT) t = atPos(in.skipToken()) { selectors(t, typeOK) } } else { t = atPos(pos) { selectors(t, typeOK) } } } } t } def selectors(t: Tree, typeOK: boolean): Tree = if (typeOK && in.token == TYPE) { in.nextToken(); SingletonTypeTree(t) } else { val t1 = Select(t, ident()); if (in.token == DOT) atPos(in.skipToken()) { selectors(t1, typeOK) } else t1 } /** MixinQualifier ::= `[' Id `]' */ def mixinQualifierOpt(): Name = if (in.token == LBRACKET) { in.nextToken(); val name = ident().toTypeName; accept(RBRACKET); name } else { nme.EMPTY.toTypeName } /** StableId ::= Id * | StableRef `.' Id * | [Id '.'] super [MixinQualifier] ` `.' Id */ def stableId(): Tree = stableRef(false, false); /** QualId ::= Id {`.' Id} */ def qualId(): Tree = { val id = atPos(in.pos) { Ident(ident()) } if (in.token == DOT) atPos(in.skipToken()) { selectors(id, false) } else id } /** SimpleExpr ::= literal * | symbol [ArgumentExprs] * | null */ def literal(isPattern: boolean, isNegated: boolean): Tree = { def litToTree() = atPos(in.pos) { Literal( in.token match { case CHARLIT => in.intVal.asInstanceOf[char] case INTLIT => in.intVal(isNegated).asInstanceOf[int] case LONGLIT => in.intVal(isNegated) case FLOATLIT => in.floatVal(isNegated).asInstanceOf[float] case DOUBLELIT => in.floatVal(isNegated) case STRINGLIT | SYMBOLLIT => in.name.toString() case TRUE => true case FALSE => false case NULL => null case _ => syntaxError("illegal literal", true); null }) } val isSymLit = in.token == SYMBOLLIT; val t = litToTree(); val pos = in.skipToken(); if (isSymLit) { atPos(pos) { var symid = scalaDot(nme.Symbol); if (isPattern) { symid = convertToTypeId(symid) } Apply(symid, List(t)) } } else { t } } //////// TYPES /////////////////////////////////////////////////////////////// /** TypedOpt ::= [`:' Type] */ def typedOpt(): Tree = if (in.token == COLON) { in.nextToken(); typ() } else EmptyTree; /** SimpleTypedOpt ::= [`:' SimpleType] */ def simpleTypedOpt(): Tree = if (in.token == COLON) { in.nextToken(); simpleType() } else EmptyTree; /** Types ::= Type {`,' Type} */ def types(): List[Tree] = { val ts = new ListBuffer[Tree] + typ(); while (in.token == COMMA) { in.nextToken(); ts + typ(); } ts.toList } /** Type ::= Type1 `=>' Type * | `(' [Types] `)' `=>' Type * | Type1 */ def typ(): Tree = { val t = if (in.token == LPAREN) { in.nextToken(); if (in.token == RPAREN) { in.nextToken(); atPos(accept(ARROW)) { FunctionTypeTree(List(), typ()) } } else { val t0 = typ(); if (in.token == COMMA) { in.nextToken(); val ts = new ListBuffer[Tree] + t0 ++ types(); accept(RPAREN); atPos (accept(ARROW)) { FunctionTypeTree(ts.toList, typ()) } } else { accept(RPAREN); t0 } } } else { type1() } if (in.token == ARROW) atPos(in.skipToken()) { FunctionTypeTree(List(t), typ()) } else t } /** Type1 ::= SimpleType {with SimpleType} [Refinement] */ def type1(): Tree = { val pos = in.pos; var t = simpleType(); if (in.token == WITH) { val ts = new ListBuffer[Tree] + t; while (in.token == WITH) { in.nextToken(); ts + simpleType() } t = atPos(pos) { IntersectionTypeTree(ts.toList) } } if (in.token == LBRACE) t = atPos(pos) { RefinementTypeTree(t, refinement()) } t } /** SimpleType ::= SimpleType TypeArgs * | SimpleType `#' Id * | StableId * | StableRef `.' type * | `(' Type `)' */ def simpleType(): Tree = { val pos = in.pos; var t: Tree = if (in.token == LPAREN) { in.nextToken(); val t = typ(); accept(RPAREN); t } else { val r = stableRef(false, true); r match { case SingletonTypeTree(_) => r case _ => convertToTypeId(r); } } while (true) { if (in.token == HASH) t = atPos(in.skipToken()) { SelectFromTypeTree(t, ident().toTypeName) } else if (in.token == LBRACKET) t = atPos(pos) { AppliedTypeTree(t, typeArgs()) } else return t } null; //dummy } /** TypeArgs ::= `[' Types `]' */ def typeArgs(): List[Tree] = { accept(LBRACKET); val ts = types(); accept(RBRACKET); ts } //////// EXPRESSIONS //////////////////////////////////////////////////////// /** EqualsExpr ::= `=' Expr */ def equalsExpr(): Tree = { accept(EQUALS); expr() } /** Exprs ::= Expr {`,' Expr} [ `:' `_' `*' ] */ def exprs(): List[Tree] = { val ts = new ListBuffer[Tree] + expr(true, false); while (in.token == COMMA) { in.nextToken(); ts + expr(true, false) } ts.toList } /** Expr ::= Bindings `=>' Expr * | Expr1 * ResultExpr ::= Bindings `=>' Block * | Expr1 * Expr1 ::= (' Expr `)' Expr [[`;'] else Expr] * | try `{' block `}' [catch Expr] [finally Expr] * | while `(' Expr `)' Expr * | do Expr [`;'] while `(' Expr `)' * | for `(' Enumerators `)' (do | yield) Expr * | throw Expr * | return [Expr] * | [SimpleExpr `.'] Id `=' Expr * | SimpleExpr ArgumentExprs `=' Expr * | `.' SimpleExpr * | PostfixExpr [`:' Type1] * Bindings ::= Id [`:' Type1] * | `(' [Binding {`,' Binding}] `)' * Binding ::= Id [`:' Type] */ def expr(): Tree = expr(false, false); def expr(isArgument: boolean, isInBlock: boolean): Tree = { if (in.token == IF) { val pos = in.skipToken(); accept(LPAREN); val cond = expr(); accept(RPAREN); val thenp = expr(); val elsep = if (in.token == ELSE) { in.nextToken(); expr() } else EmptyTree; atPos(pos) { If(cond, thenp, elsep) } } else if (in.token == TRY) { atPos(in.skipToken()) { accept(LBRACE); val body = block(); accept(RBRACE); val catcher = if (in.token == CATCH) { in.nextToken(); expr() } else EmptyTree; val finalizer = if (in.token == FINALLY) { in.nextToken(); expr() } else EmptyTree; Try(body, catcher, finalizer) } } else if (in.token == WHILE) { val lname: Name = "label$" + loopNestingDepth; loopNestingDepth = loopNestingDepth + 1; val pos = in.skipToken(); accept(LPAREN); val cond = expr(); accept(RPAREN); val body = expr(); loopNestingDepth = loopNestingDepth - 1; atPos(pos) { makeWhile(lname, cond, body) } } else if (in.token == DO) { val lname: Name = "label$" + loopNestingDepth; loopNestingDepth = loopNestingDepth + 1; val pos = in.skipToken(); val body = expr(); if (in.token == SEMI) in.nextToken(); accept(WHILE); accept(LPAREN); val cond = expr(); accept(RPAREN); loopNestingDepth = loopNestingDepth - 1; atPos(pos) { makeDoWhile(lname, body, cond) } } else if (in.token == FOR) { atPos(in.skipToken()) { accept(LPAREN); val enums = enumerators(); accept(RPAREN); if (in.token == YIELD) { in.nextToken(); For(enums, expr(), true) } else For(enums, expr(), false) } } else if (in.token == RETURN) { atPos(in.skipToken()) { Return(if (isExprIntro) expr() else Literal(())) } } else if (in.token == THROW) { atPos(in.skipToken()) { Throw(expr()) } } else if (in.token == DOT) { atPos(in.skipToken()) { if (in.token == IDENTIFIER) makeClosure(simpleExpr()) else { syntaxError("identifier expected", true); errorTermTree } } } else { var t = postfixExpr(); if (in.token == EQUALS) { t match { case Ident(_) | Select(_, _) | Apply(_, _) => t = atPos(in.skipToken()) { Assign(t, expr()) } case _ => } } else if (in.token == COLON) { val pos = in.skipToken(); if (isArgument && in.token == USCORE) { val pos1 = in.skipToken(); if (in.token == IDENTIFIER && in.name == nme.STAR) { in.nextToken(); t = atPos(pos) { Typed(t, atPos(pos1) { Ident(nme.WILDCARD_STAR.toTypeName) }) } } else { syntaxError(in.pos, "`*' expected", true); } } else { t = atPos(pos) { Typed(t, type1()) } } } if (in.token == ARROW) { t = atPos(in.skipToken()) { Function(convertToParams(t), if (isInBlock) block() else expr()) } } t } } /** PostfixExpr ::= [`.'] InfixExpr [Id] * InfixExpr ::= PrefixExpr * | InfixExpr Id InfixExpr */ def postfixExpr(): Tree = { val base = opstack; var top = prefixExpr(); while (in.token == IDENTIFIER) { top = reduceStack( true, base, top, precedence(in.name), isLeftAssoc(in.name)); opstack = OpInfo(top, in.name, in.pos) :: opstack; ident(); if (isExprIntro) { top = prefixExpr(); } else { val topinfo = opstack.head; opstack = opstack.tail; return Select( reduceStack(true, base, topinfo.operand, 0, true), topinfo.operator.encode).setPos(topinfo.pos); } } reduceStack(true, base, top, 0, true) } /** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr */ def prefixExpr(): Tree = if (in.token == IDENTIFIER && in.name == MINUS) { val name = ident(); in.token match { case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(false, true) case _ => atPos(in.pos) { Select(simpleExpr(), name) } } } else if (in.token == IDENTIFIER && (in.name == PLUS || in.name == TILDE || in.name == BANG)) { val pos = in.pos; val name = ident(); atPos(pos) { Select(simpleExpr(), name) } } else { simpleExpr() } /* SimpleExpr ::= literal * | xLiteral * | StableRef * | `(' [Expr] `)' * | BlockExpr * | new Template * | SimpleExpr `.' Id * | SimpleExpr TypeArgs * | SimpleExpr ArgumentExprs */ def simpleExpr(): Tree = { var t: Tree = _; in.token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => t = literal(false, false); case IDENTIFIER | THIS | SUPER => t = /*if (s.xStartsXML) xmlp.xLiteral else*/ stableRef(true, false); case LPAREN => val pos = in.skipToken(); if (in.token == RPAREN) { in.nextToken(); t = Literal(()).setPos(pos); } else { t = expr(); if (in.token == COMMA) { val commapos = in.skipToken(); val ts = new ListBuffer[Tree] + t ++ exprs(); accept(RPAREN); if (in.token == ARROW) { t = atPos(pos) { Function(ts.toList map convertToParam, EmptyTree) } } else { syntaxError(commapos, "`)' expected", false); } } else { accept(RPAREN); } } case LBRACE => t = blockExpr() case NEW => t = atPos(in.skipToken()) { val templ = template(); New(if (templ.parents.length == 1 && templ.body.isEmpty) templ.parents.head else templ) } case _ => syntaxError("illegal start of simple expression", true); t = errorTermTree } while (true) { in.token match { case DOT => t = atPos(in.skipToken()) { Select(t, ident()) } case LBRACKET => t match { case Ident(_) | Select(_, _) => t = atPos(in.pos) { TypeApply(t, typeArgs()) } case _ => return t; } case LPAREN | LBRACE => t = atPos(in.pos) { Apply(t, argumentExprs()) } case _ => return t } } null;//dummy } /** ArgumentExprs ::= `(' [Exprs] `)' * | BlockExpr */ def argumentExprs(): List[Tree] = { if (in.token == LBRACE) { List(blockExpr()) } else { accept(LPAREN); val ts = if (in.token == RPAREN) List() else exprs(); accept(RPAREN); ts } } /** BlockExpr ::= `{' CaseClause {CaseClause} `}' * | `{' Block `}' */ def blockExpr(): Tree = { val res = atPos(accept(LBRACE)) { if (in.token == CASE) { var stats: List[CaseDef] = List(); do { stats = caseClause() :: stats; } while (in.token == CASE); Visitor(stats.reverse) } else { block() } } accept(RBRACE); res } /** Block ::= BlockStatSeq */ def block(): Tree = makeBlock(blockStatSeq(new ListBuffer[Tree])); /** caseClause : =>= case Pattern [if PostfixExpr] `=>' Block */ def caseClause(): CaseDef = atPos(accept(CASE)) { val pat = pattern(); val guard = if (in.token == IF) { in.nextToken(); postfixExpr() } else EmptyTree; CaseDef(pat, guard, atPos(accept(ARROW))(block())) } /** Enumerators ::= Generator {`;' Enumerator} * Enumerator ::= Generator * | Expr */ def enumerators(): List[Tree] = { val enums = new ListBuffer[Tree] + generator(); while (in.token == SEMI) { in.nextToken(); enums + (if (in.token == VAL) generator() else expr()) } enums.toList } /** Generator ::= val Pattern1 `<-' Expr */ def generator(): Tree = atPos(accept(VAL)) { PatDef(0, pattern1(false), { accept(LARROW); expr() }) } //////// PATTERNS //////////////////////////////////////////////////////////// /** Patterns ::= SeqPattern { `,' SeqPattern } */ def patterns(): List[Tree] = { val ts = new ListBuffer[Tree]; ts + pattern(true); while (in.token == COMMA) { in.nextToken(); ts + pattern(true); } ts.toList } /** Pattern ::= Pattern1 { `|' Pattern1 } * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } */ def pattern(seqOK: boolean): Tree = { val pos = in.pos; val t = pattern1(seqOK); if (in.token == IDENTIFIER && in.name == BAR) { val ts = new ListBuffer[Tree] + t; while (in.token == IDENTIFIER && in.name == BAR) { in.nextToken(); ts + pattern1(seqOK); } atPos(pos) { makeAlternative(ts.toList) } } else t } def pattern(): Tree = pattern(false); /** Pattern1 ::= varid `:' Type1 * | `_' `:' Type1 * | Pattern2 * SeqPattern1 ::= varid `:' Type1 * | `_' `:' Type1 * | [SeqPattern2] */ def pattern1(seqOK: boolean): Tree = if (seqOK && !isExprIntro) { atPos(in.pos) { Sequence(List()) } } else { val p = pattern2(seqOK); if (in.token == COLON && treeInfo.isVarPattern(p)) atPos(in.skipToken()) { Typed(p, type1()) } else p } /* Pattern2 ::= varid [ @ Pattern3 ] * | Pattern3 * SeqPattern2 ::= varid [ @ SeqPattern3 ] * | SeqPattern3 */ def pattern2(seqOK: boolean): Tree = { val p = pattern3(seqOK); if (in.token == AT) { p match { case Ident(name) => if (name == nme.WILDCARD) { in.nextToken(); pattern3(seqOK) } else if (treeInfo.isVariableName(name)) { atPos(in.skipToken()) { Bind(name, pattern3(seqOK)) } } else { p } case _ => p } } else p } /* Pattern3 ::= SimplePattern * | SimplePattern {Id SimplePattern} * SeqPattern3 ::= SeqSimplePattern [ '*' | '?' | '+' ] * | SeqSimplePattern {Id SeqSimplePattern} */ def pattern3(seqOK: boolean): Tree = { val base = opstack; var top = simplePattern(seqOK); if (seqOK && in.token == IDENTIFIER) { if (in.name == STAR) { /* p* becomes z@( |(p,z)) */ return atPos(in.skipToken()) { val zname = fresh(); Bind( zname, makeAlternative(List( Sequence(List()), makeSequence(List(top, Ident(zname)))))) } } else if (in.name == PLUS) { /* p+ becomes z@(p,(z| )) */ return atPos(in.skipToken()) { val zname = fresh(); Bind( zname, makeSequence(List( top, makeAlternative(List(Ident(zname), Sequence(List())))))) } } else if (in.name == OPT) { /* p? becomes (p| ) */ return atPos(in.skipToken()) { makeAlternative(List(top, Sequence(List()))) } } } while (in.token == IDENTIFIER && in.name != BAR) { top = reduceStack( false, base, top, precedence(in.name), isLeftAssoc(in.name)); opstack = OpInfo(top, in.name, in.pos) :: opstack; ident(); top = simplePattern(seqOK) } reduceStack(false, base, top, 0, true) } /** SimplePattern ::= varid * | `_' * | literal * | `<' xLiteralPattern * | StableId [ `(' Patterns `)' ] * | `(' [Pattern] `)' * SimpleSeqPattern ::= varid * | `_' * | literal * | `<' xLiteralPattern * | StableId [ `(' Patterns `)' ] * | `(' Patterns `)' */ def simplePattern(seqOK: boolean): Tree = in.token match { case IDENTIFIER | THIS => var t = stableId(); in.token match { case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(name) if name == nme.MINUS => return literal(true, true); case _ => } case _ => } if (in.token == LPAREN) { atPos(in.skipToken()) { val ps = if (in.token == RPAREN) List() else patterns(); accept(RPAREN); Apply(convertToTypeId(t), ps) } } else t case USCORE => atPos(in.skipToken()) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => literal(true, false) case LPAREN => val pos = in.skipToken(); val p = if (seqOK) atPos(pos) { makeSequence(patterns()) } else if (in.token != RPAREN) pattern(false); else Literal(()).setPos(pos); accept(RPAREN); p case _ => syntaxError("illegal start of simple pattern", true); errorPatternTree } ////////// MODIFIERS //////////////////////////////////////////////////////////// /** Modifiers ::= {Modifier} * Modifier ::= final * | private * | protected * | override * | abstract */ def modifiers(): int = { def loop(mods: int): int = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) case FINAL => loop(addMod(mods, Flags.FINAL)) case SEALED => loop(addMod(mods, Flags.SEALED)) case PRIVATE => loop(addMod(mods, Flags.PRIVATE)) case PROTECTED => loop(addMod(mods, Flags.PROTECTED)) case OVERRIDE => loop(addMod(mods, Flags.OVERRIDE)) case _ => mods } loop(0); } /** LocalClassModifiers ::= {LocalClassModifier} * LocalClassModifier ::= final * | private */ def localClassModifiers(): int = { def loop(mods: int): int = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) case FINAL => loop(addMod(mods, Flags.FINAL)) case SEALED => loop(addMod(mods, Flags.SEALED)) case _ => mods } loop(0) } private def addMod(mods: int, mod: int): int = { if ((mods & mod) != 0) syntaxError(in.pos, "repeated modifier", false); in.nextToken(); mods | mod; } //////// PARAMETERS ////////////////////////////////////////////////////////// /** ParamClauses ::= {ParamClause} */ def paramClauses(): List[List[ValDef]] = { val vds = new ListBuffer[List[ValDef]]; while (in.token == LPAREN) vds + paramClause(false); vds.toList } /** ParamClauseOpt ::= [ParamClause] */ def paramClauseOpt(ofClass: boolean): List[List[ValDef]] = if (in.token == LPAREN) List(paramClause(ofClass)) else List(); /** ParamClause ::= `(' [Param {`,' Param}] `)' * ClassParamClause ::= `(' [ClassParam {`,' ClassParam}] `)' */ def paramClause(ofClass: boolean): List[ValDef] = { accept(LPAREN); val params = new ListBuffer[ValDef]; if (in.token != RPAREN) { params + param(ofClass); while (in.token == COMMA) { in.nextToken(); params + param(ofClass) } } accept(RPAREN); params.toList } /** Param ::= Id `:' ParamType * ClassParam ::= [[modifiers] val] Param */ def param(ofClass: boolean): ValDef = { atPos(in.pos) { var mods = if (ofClass) modifiers() | Flags.PARAM else Flags.PARAM; if (in.token == VAL) { in.nextToken(); mods = mods | Flags.PARAMACCESSOR; } else if (mods != Flags.PARAM) { accept(VAL); } val name = ident(); accept(COLON); ValDef(mods, name, paramType(), EmptyTree) } } /** ParamType ::= Type | `=>' Type | Type `*' */ def paramType(): Tree = if (in.token == ARROW) atPos(in.skipToken()) { FunctionTypeTree(List(), typ()) } else { val t = typ(); if (in.token == IDENTIFIER && in.name == STAR) { in.nextToken(); atPos(t.pos) { AppliedTypeTree( scalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) } } else t } /** TypeParamClauseOpt ::= [`[' TypeParam {`,' TypeParam} `]'] * FunTypeParamClauseOpt ::= [`[' FunTypeParam {`,' FunTypeParam} `]'] */ def typeParamClauseOpt(ofClass: boolean): List[AbsTypeDef] = { val params = new ListBuffer[AbsTypeDef]; if (in.token == LBRACKET) { in.nextToken(); params + typeParam(ofClass); while (in.token == COMMA) { in.nextToken(); params + typeParam(ofClass); } accept(RBRACKET); } params.toList } /** TypeParam ::= [`+' | `-'] FunTypeParam * FunTypeParam ::= Id TypeBounds */ def typeParam(ofClass: boolean): AbsTypeDef = { var mods = Flags.PARAM; if (ofClass && in.token == IDENTIFIER) { if (in.name == PLUS) { in.nextToken(); mods = mods | Flags.COVARIANT; } else if (in.name == MINUS) { in.nextToken(); mods = mods | Flags.CONTRAVARIANT; } } atPos(in.pos) { typeBounds(mods, ident()) } } /** TypeBounds ::= [`>:' Type] [`<:' Type] [`<%' Type] */ def typeBounds(mods: int, name: Name): AbsTypeDef = { def bound(tok: int, default: Name): Tree = if (in.token == tok) { in.nextToken(); typ() } else scalaDot(default.toTypeName); AbsTypeDef(mods, name.toTypeName, bound(SUPERTYPE, nme.All), bound(SUBTYPE, nme.Any), bound(VIEWBOUND, nme.Any)) } //////// DEFS //////////////////////////////////////////////////////////////// /** Import ::= import ImportExpr {`,' ImportExpr} */ def importClause(): List[Tree] = { accept(IMPORT); val ts = new ListBuffer[Tree] + importExpr(); while (in.token == COMMA) { in.nextToken(); ts + importExpr(); } ts.toList } /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors) */ def importExpr(): Tree = atPos(in.pos) { var t: Tree = null; var pos = 0; if (in.token == THIS) { t = atPos(in.pos) { This(nme.EMPTY.toTypeName) } t = atPos(accept(DOT)) { Select(t, ident()) } pos = accept(DOT); } else { val i = atPos(in.pos) { Ident(ident()) } pos = accept(DOT); if (in.token == THIS) { in.nextToken(); t = atPos(i.pos) { This(i.name.toTypeName) } t = atPos(accept(DOT)) { Select(t, ident()) } pos = accept(DOT); } else { t = i; } } def loop: Tree = if (in.token == USCORE) { in.nextToken(); Import(t, List(nme.WILDCARD)) } else if (in.token == LBRACE) { Import(t, importSelectors()) } else { val name = ident(); if (in.token == DOT) { t = atPos(pos) { Select(t, name) } pos = accept(DOT); loop } else { Import(t, List(name, name)); } } loop } /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' */ def importSelectors(): List[Name] = { val names = new ListBuffer[Name]; accept(LBRACE); var isLast = importSelector(names); while (!isLast && in.token == COMMA) { in.nextToken(); isLast = importSelector(names); } accept(RBRACE); names.toList } /** ImportSelector ::= Id [`=>' Id | `=>' `_'] */ def importSelector(names: ListBuffer[Name]): boolean = if (in.token == USCORE) { in.nextToken(); names + nme.WILDCARD; true } else { val name = ident(); names + name; if (in.token == ARROW) { in.nextToken(); if (in.token == USCORE) { in.nextToken(); names + nme.WILDCARD; } else { names + ident() } } else { names + name } false } /** Def ::= val PatDef * | var VarDef * | def FunDef * | type TypeDef * | TmplDef * Dcl ::= val ValDcl * | var ValDcl * | def FunDcl * | type TypeDcl */ def defOrDcl(mods: int): List[Tree] = { in.token match { case VAL => patDefOrDcl(mods); case VAR => varDefOrDcl(mods); case DEF => funDefOrDcl(mods); case TYPE => in.nextToken(); List(typeDefOrDcl(mods)) case _ => tmplDef(mods) } } /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr * ValDcl ::= Id {`,' Id} `:' Type */ def patDefOrDcl(mods: int): List[Tree] = { var newmods = mods; var lhs = new ListBuffer[Tree]; do { in.nextToken(); lhs + pattern2(false) } while (in.token == COMMA); val tp = typedOpt(); val rhs = if (tp == EmptyTree || in.token == EQUALS) equalsExpr() else { newmods = newmods | Flags.DEFERRED; EmptyTree } for (val p <- lhs.toList) yield { atPos(p.pos) { p match { case Ident(name) => ValDef(mods, name, tp.duplicate, rhs.duplicate) case _ => if (rhs == EmptyTree) { syntaxError(p.pos, "cannot defer pattern definition", false); errorPatternTree } else { PatDef( mods, if (tp == EmptyTree) p else Typed(p, tp), rhs.duplicate) } } } } } /** VarDef ::= Id {`,' Id} [`:' Type] `=' Expr * | Id {`,' Id} `:' Type `=' `_' * VarDcl ::= Id {`,' Id} `:' Type */ def varDefOrDcl(mods: int): List[Tree] = { var newmods = mods | Flags.MUTABLE; val lhs = new ListBuffer[Pair[Int, Name]]; do { lhs + Pair(in.skipToken(), ident()) } while (in.token == COMMA); val tp = typedOpt(); val rhs = if (tp == EmptyTree || in.token == EQUALS) { accept(EQUALS); if (tp != EmptyTree && in.token == USCORE) { in.nextToken(); EmptyTree } else expr(); } else { newmods = newmods | Flags.DEFERRED; EmptyTree } lhs.toList map { case Pair(pos, name) => ValDef(newmods, name, tp.duplicate, rhs.duplicate) setPos pos } } /** FunDef ::= FunSig {`,' FunSig} `:' Type `=' Expr * | this ParamClause `=' ConstrExpr * FunDcl ::= FunSig {`,' FunSig} `:' Type * FunSig ::= id [FunTypeParamClause] ParamClauses */ def funDefOrDcl(mods: int): List[Tree] = { in.nextToken(); if (in.token == THIS) List( atPos(in.skipToken()) { val vparams = List(paramClause(false)); accept(EQUALS); DefDef( mods, nme.CONSTRUCTOR, List(), vparams, EmptyTree, constrExpr()) }) else { var newmods = mods; val lhs = new ListBuffer[Tuple4[Int, Name, List[AbsTypeDef], List[List[ValDef]]]] + Tuple4( in.pos, ident(), typeParamClauseOpt(false), paramClauses()); while (in.token == COMMA) lhs + Tuple4( in.skipToken(), ident(), typeParamClauseOpt(false), paramClauses()); val restype = typedOpt(); val rhs = if (restype == EmptyTree || in.token == EQUALS) equalsExpr(); else { newmods = newmods | Flags.DEFERRED; EmptyTree } for (val Tuple4(pos, name, tparams, vparams) <- lhs.toList) yield DefDef(newmods, name, tparams, vparams, restype.duplicate, rhs.duplicate) setPos pos } } /** ConstrExpr ::= SelfInvocation * | `{' SelfInvocation {`;' BlockStat} `}' * SelfInvocation ::= this ArgumentExpr */ def constrExpr(): Tree = if (in.token == LBRACE) { atPos(in.skipToken()) { val statlist = new ListBuffer[Tree]; statlist + selfInvocation(); val stats = if (in.token == SEMI) { in.nextToken(); blockStatSeq(statlist) } else statlist.toList; accept(RBRACE); makeBlock(stats) } } else selfInvocation(); /** SelfInvocation ::= this ArgumentExprs */ def selfInvocation(): Tree = atPos(accept(THIS)) { Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) } /** TypeDef ::= Id `=' Type * TypeDcl ::= Id TypeBounds */ def typeDefOrDcl(mods: int): Tree = atPos(in.pos) { val name = ident().toTypeName; in.token match { case LBRACKET => val tparams = typeParamClauseOpt(true); accept(EQUALS); AliasTypeDef(mods, name, tparams, typ()) case EQUALS => in.nextToken(); AliasTypeDef(mods, name, List(), typ()) case SUPERTYPE | SUBTYPE | VIEWBOUND | SEMI | COMMA | RBRACE => typeBounds(mods | Flags.DEFERRED, name) case _ => syntaxError("`=', `>:', or `<:' expected", true); EmptyTree } } /** TmplDef ::= ([case] class | trait) ClassDef * | [case] object ObjectDef */ def tmplDef(mods: int): List[Tree] = in.token match { case TRAIT => classDef(mods | Flags.TRAIT | Flags.ABSTRACT); case CLASS => classDef(mods); case CASECLASS => classDef(mods | Flags.CASE); case OBJECT => objectDef(mods); case CASEOBJECT => objectDef(mods | Flags.CASE); case _ => syntaxError("illegal start of definition", true); List() } /** ClassDef ::= ClassSig {`,' ClassSig} [`:' SimpleType] ClassTemplate * ClassSig ::= Id [TypeParamClause] [ClassParamClause] */ def classDef(mods: int): List[Tree] = { val lhs = new ListBuffer[Tuple4[Int, Name, List[AbsTypeDef], List[List[ValDef]]]]; do { lhs + Tuple4(in.skipToken(), ident().toTypeName, typeParamClauseOpt(true), paramClauseOpt(true)) } while (in.token == COMMA); val thistpe = simpleTypedOpt(); val template = classTemplate((mods & Flags.CASE) != 0); for (val Tuple4(pos, name, tparams, vparams) <- lhs.toList) yield ClassDef(mods, name, tparams, vparams, thistpe.duplicate, template.duplicate.asInstanceOf[Template]) setPos pos } /** ObjectDef ::= Id { , Id } [`:' SimpleType] ClassTemplate */ def objectDef(mods: int): List[Tree] = { val lhs = new ListBuffer[Pair[Int, Name]]; do { lhs + Pair(in.skipToken(), ident()); } while (in.token == COMMA); val thistpe = simpleTypedOpt(); val template = classTemplate((mods & Flags.CASE)!= 0); for (val Pair(pos, name) <- lhs.toList) yield ModuleDef(mods, name, thistpe.duplicate, template.duplicate.asInstanceOf[Template]) setPos pos } /** ClassTemplate ::= [`extends' Constr] {`with' Constr} [TemplateBody] */ def classTemplate(isCaseClass:boolean): Template = { atPos(in.pos) { val parents = new ListBuffer[Tree]; if (in.token == EXTENDS) { in.nextToken(); parents + constr() } else { parents + scalaAnyRefConstr() } parents + scalaObjectConstr(); if (isCaseClass) parents + caseClassConstr(); if (in.token == WITH) { in.nextToken(); template(parents) } else if (in.token == LBRACE) { Template(parents.toList, templateBody()) } else { if (!(in.token == SEMI || in.token == COMMA || in.token == RBRACE)) syntaxError("`extends' or `{' expected", true); Template(parents.toList, List()) } } } ////////// TEMPLATES //////////////////////////////////////////////////////////// /** Template ::= Constr {`with' Constr} [TemplateBody] */ def template(): Template = template(new ListBuffer[Tree]); def template(parents: ListBuffer[Tree]): Template = { parents + constr(); while (in.token == WITH) { in.nextToken(); parents + constr() } val stats = if (in.token == LBRACE) templateBody() else List(); Template(parents.toList, stats) } /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)'] */ def constr(): Tree = { var t: Tree = convertToTypeId(stableId()); if (in.token == LBRACKET) t = AppliedTypeTree(t, typeArgs()) setPos in.pos; if (in.token == LPAREN) t = Apply(t, argumentExprs()) setPos in.pos; applyConstr(t) } /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}' */ def templateBody(): List[Tree] = { accept(LBRACE); var body = templateStatSeq(); if (body.length == 0) body = List(EmptyTree); accept(RBRACE); body } /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' */ def refinement(): List[Tree] = { accept(LBRACE); val body = refineStatSeq(); accept(RBRACE); body } /////// STATSEQS ////////////////////////////////////////////////////////////// /** Packaging ::= package QualId `{' TopStatSeq `}' */ def packaging(): Tree = { atPos(accept(PACKAGE)) { val pkg = qualId(); accept(LBRACE); val stats = topStatSeq(); accept(RBRACE); makePackaging(pkg, stats) } } /** TopStatSeq ::= [TopStat {`;' TopStat}] * TopStat ::= AttributeClauses Modifiers ClsDef * | Packaging * | Import * | */ def topStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree]; while (in.token != RBRACE && in.token != EOF) { if (in.token == PACKAGE) { stats + packaging() } else if (in.token == IMPORT) { stats ++ importClause() } else if (in.token == CLASS || in.token == CASECLASS || in.token == TRAIT || in.token == OBJECT || in.token == CASEOBJECT || in.token == LBRACKET || isModifier) { stats ++ joinAttributes(attributeClauses(), joinComment(tmplDef(modifiers()))) } else if (in.token != SEMI) { syntaxError("illegal start of class or object definition", true); } if (in.token != RBRACE && in.token != EOF) accept(SEMI); } stats.toList } /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat} * TemplateStat ::= Import * | AttributeClauses Modifiers Def * | AttributeClauses Modifiers Dcl * | Expr * | */ def templateStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree]; while (in.token != RBRACE && in.token != EOF) { if (in.token == IMPORT) { stats ++ importClause() } else if (isExprIntro) { stats + expr() } else if (isDefIntro || isModifier || in.token == LBRACKET) { stats ++ joinAttributes(attributeClauses(), joinComment(defOrDcl(modifiers()))) } else if (in.token != SEMI) { syntaxError("illegal start of definition", true); } if (in.token != RBRACE) accept(SEMI); } stats.toList } /** AttributeClauses ::= {AttributeClause} * AttributeClause ::= `[' Attribute {`,' Attribute} `]' * Attribute ::= Constr */ def attributeClauses(): List[Tree] = { var attrs = new ListBuffer[Tree]; while (in.token == LBRACKET) { in.nextToken(); attrs + constr(); while (in.token == COMMA) { in.nextToken(); attrs + constr() } accept(RBRACKET); } attrs.toList } def joinAttributes(attrs: List[Tree], defs: List[Tree]): List[Tree] = defs map (defn => (attrs :\ defn) ((attr, tree) => Attributed(attr, tree) setPos attr.pos)); /** RefineStatSeq ::= RefineStat {`;' RefineStat} * RefineStat ::= Dcl * | type TypeDef * | */ def refineStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree]; while (in.token != RBRACE && in.token != EOF) { if (isDclIntro) { stats ++ joinComment(defOrDcl(0)) } else if (in.token != SEMI) { syntaxError("illegal start of declaration", true); } if (in.token != RBRACE) accept(SEMI); } stats.toList } /** BlockStatSeq ::= { BlockStat `;' } [Expr] * BlockStat ::= Import * | Def * | LocalModifiers TmplDef * | Expr * | */ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = { while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE)) { if (in.token == IMPORT) { stats ++ importClause(); accept(SEMI); } else if (isExprIntro) { stats + expr(false, true); if (in.token != RBRACE && in.token != CASE) accept(SEMI); } else if (isDefIntro) { stats ++ defOrDcl(0); accept(SEMI); if (in.token == RBRACE || in.token == CASE) { stats + Literal(()).setPos(in.pos) } } else if (isLocalModifier) { stats ++ tmplDef(localClassModifiers()); accept(SEMI); if (in.token == RBRACE || in.token == CASE) { stats + Literal(()).setPos(in.pos) } } else if (in.token == SEMI) { in.nextToken(); } else { syntaxError("illegal start of statement", true); } } stats.toList } /** CompilationUnit ::= [ package QualId ( `;' | `{' TopStatSeq `}' ) ] TopStatSeq . */ def compilationUnit(): List[Tree] = { if (in.token == PACKAGE) { val pos = in.skipToken(); val pkg = qualId(); if (in.token == SEMI) { in.nextToken(); List(makePackaging(pkg, topStatSeq()) setPos pos); } else { val stats = new ListBuffer[Tree]; accept(LBRACE); stats + atPos(pos) { makePackaging(pkg, topStatSeq()) } accept(RBRACE); stats ++ topStatSeq(); stats.toList } } else { topStatSeq() } } } } // LocalWords: SOcos