
scalariform.parser.ScalaParser.scala Maven / Gradle / Ivy
The newest version!
package scalariform.parser
import scalariform.lexer.Tokens._
import scalariform.lexer._
import scalariform.utils.Utils._
import scala.collection.mutable.ListBuffer
import PartialFunction._
class ScalaParser(tokens: Array[Token]) {
private val logging: Boolean = false
private val forgiving: Boolean = true
import ScalaParser._
def safeParse[T](production: ⇒ T): Option[T] = try Some(production) catch { case e: ScalaParserException ⇒ None }
require(!tokens.isEmpty) // at least EOF
def inParens[T](body: ⇒ T): (Token, T, Token) = {
val openToken = accept(LPAREN)
val contents = body
val closeToken = accept(RPAREN)
(openToken, contents, closeToken)
}
def inBraces[T](body: ⇒ T): (Token, T, Token) = {
val openToken = accept(LBRACE)
val contents = body
val closeToken = accept(RBRACE)
(openToken, contents, closeToken)
}
def inBrackets[T](body: ⇒ T): (Token, T, Token) = {
val openToken = accept(LBRACKET)
val contents = body
val closeToken = accept(RBRACKET)
(openToken, contents, closeToken)
}
def makeParens[T](body: ⇒ T) = inParens { if (RPAREN) None else Some(body) }
def compilationUnitOrScript(): CompilationUnit = {
val originalPos = pos
try {
compilationUnit()
} catch {
case e: ScalaParserException ⇒
pos = originalPos
if (logging) println("Rewinding to try alternative: " + currentToken)
try {
scriptBody()
} catch { case e2: ScalaParserException ⇒ throw e }
}
}
def scriptBody(): CompilationUnit = {
val stmts = templateStatSeq()
accept(EOF)
CompilationUnit(stmts)
}
private def accept(tokenType: TokenType): Token =
if (currentTokenType == tokenType)
nextToken()
else
throw new ScalaParserException("Expected token " + tokenType + " but got " + currentToken)
private def acceptStatSep(): Token = currentTokenType match {
case NEWLINE | NEWLINES ⇒ nextToken
case _ ⇒ accept(SEMI)
}
private def acceptStatSepOpt(): Option[Token] = if (!isStatSeqEnd) Some(acceptStatSep()) else None
private def isModifier = currentTokenType match {
case ABSTRACT | FINAL | SEALED | PRIVATE |
PROTECTED | OVERRIDE | IMPLICIT | LAZY ⇒ true
case _ ⇒ false
}
private def isLocalModifier: Boolean = currentTokenType match {
case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY ⇒ true
case _ ⇒ false
}
private def isTemplateIntro: Boolean = currentTokenType match {
case OBJECT | CLASS | TRAIT ⇒ true
case CASE if caseObject ⇒ true
case CASE if caseClass ⇒ true
case _ ⇒ false
}
private def isDclIntro: Boolean = currentTokenType match {
case VAL | VAR | DEF | TYPE ⇒ true
case _ ⇒ false
}
private def isDefIntro: Boolean = isTemplateIntro || isDclIntro
private def isNumericLit: Boolean = currentTokenType match {
case INTEGER_LITERAL | FLOATING_POINT_LITERAL ⇒ true
case _ ⇒ false
}
private def isUnaryOp: Boolean = currentTokenType match {
case MINUS | PLUS | TILDE | EXCLAMATION ⇒ true
case _ ⇒ false
}
private def isIdent: Boolean = isIdent(currentTokenType)
private def isIdent(tokenType: TokenType) = tokenType match {
case VARID | OTHERID | PLUS | MINUS | STAR | PIPE | TILDE | EXCLAMATION ⇒ true
case _ ⇒ false
}
private def isLiteralToken(tokenType: TokenType): Boolean = tokenType match {
case CHARACTER_LITERAL | INTEGER_LITERAL | FLOATING_POINT_LITERAL |
STRING_LITERAL | SYMBOL_LITERAL | TRUE | FALSE | NULL ⇒ true
case _ ⇒ false
}
private def isLiteral = isLiteralToken(currentTokenType)
private def isExprIntroToken(tokenType: TokenType) =
isLiteralToken(tokenType) || (tokenType match {
case THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE |
DO | RETURN | THROW | LPAREN | LBRACE ⇒ true
case XML_START_OPEN | XML_UNPARSED | XML_COMMENT | XML_CDATA | XML_PROCESSING_INSTRUCTION ⇒ true
case _ if isIdent(tokenType) ⇒ true
case _ ⇒ false
})
private def isExprIntro: Boolean = isExprIntroToken(currentTokenType)
private def isTypeIntroToken(tokenType: TokenType): Boolean = tokenType match {
case THIS | SUPER | USCORE | LPAREN | AT ⇒ true
case _ if isIdent(tokenType) ⇒ true
case _ ⇒ false
}
private def isTypeIntro: Boolean = isTypeIntroToken(currentTokenType)
private def isStatSeqEnd = RBRACE || EOF
private def isStatSep(tokenType: TokenType) =
tokenType == NEWLINE || tokenType == NEWLINES || tokenType == SEMI
private def isStatSep: Boolean = isStatSep(currentTokenType)
private def tokenSeparated[T](separator: TokenType, sepFirst: Boolean, part: ⇒ T): (Option[T], List[(Token, T)]) = {
val ts = new ListBuffer[(Token, T)]
val firstOpt = if (sepFirst) None else Some(part)
while (separator) {
val separatorToken = nextToken()
val nextPart = part
ts += ((separatorToken, nextPart))
}
(firstOpt, ts.toList)
}
private def commaSeparated[T](part: ⇒ T) =
tokenSeparated(COMMA, false, part) match { case (firstOpt, rest) ⇒ (firstOpt.get, rest) }
private def caseSeparated[T](part: ⇒ T) = tokenSeparated(CASE, true, part)._2
private def readAnnots[T](part: ⇒ T) = tokenSeparated(AT, true, part)._2
trait PatternContextSensitive {
def argType(): List[TypeElement]
def functionArgType(): List[TypeElement]
private def tupleInfixType() = {
val lparen = nextToken()
if (RPAREN) {
val rparen = nextToken()
val arrowToken = accept(ARROW)
val typ_ = typ()
typeElementFlatten3(lparen, rparen, arrowToken, typ_)
} else {
val types_ = functionTypes()
val rparen = accept(RPAREN)
val others = if (ARROW) {
val arrowToken = nextToken()
val typ_ = typ()
typeElementFlatten3(arrowToken, typ_)
} else {
val simpleTypeRest_ = simpleTypeRest()
val annotTypeRest_ = annotTypeRest()
val compoundTypeRest_ = compoundTypeRest()
val infixTypeRest_ = infixTypeRest()
typeElementFlatten3(simpleTypeRest_, annotTypeRest_, compoundTypeRest_, infixTypeRest_)
}
typeElementFlatten3(lparen, types_, rparen, others)
}
}
private def makeExistentialTypeTree() = refinement()
def typ(): Type = {
val others2 =
if (LPAREN) tupleInfixType()
else infixType()
val others3 = currentTokenType match {
case ARROW ⇒
val arrowToken = nextToken()
val typ_ = typ()
typeElementFlatten3(arrowToken, typ_)
case FORSOME ⇒
val forSomeToken = nextToken()
val refinement_ = makeExistentialTypeTree()
typeElementFlatten3(forSomeToken, refinement_)
case _ ⇒
Nil
}
Type(typeElementFlatten3(others2, others3))
}
def typeArgs(): List[TypeElement] = {
val (lbracket, types_, rbracket) = inBrackets(types())
typeElementFlatten3(lbracket, types_, rbracket)
}
def annotType(): List[TypeElement] = {
val simpleType_ = simpleType()
val annotTypeRest_ = annotTypeRest()
typeElementFlatten3(simpleType_, annotTypeRest_)
}
def simpleType(): List[TypeElement] = {
val firstPart = currentTokenType match {
case LPAREN ⇒
val (lparen, types_, rparen) = inParens(types())
typeElementFlatten3(lparen, types_, rparen)
case USCORE ⇒
val uscore = nextToken()
val wildcardType_ = wildcardType()
typeElementFlatten3(uscore, wildcardType_)
case _ ⇒
typeElementFlatten3(path(thisOK = false, typeOK = true))
}
val simpleTypeRest_ = simpleTypeRest()
typeElementFlatten3(firstPart, simpleTypeRest_)
}
private def typeProjection() = {
val hashToken = nextToken()
val id = ident()
(hashToken, id)
}
private def simpleTypeRest(): List[TypeElement] = currentTokenType match {
case HASH ⇒
val (hashToken, id) = typeProjection()
val simpleTypeRest_ = simpleTypeRest()
typeElementFlatten3(hashToken, id, simpleTypeRest_)
case LBRACKET ⇒
val typeArgs_ = typeArgs()
val simpleTypeRest_ = simpleTypeRest()
typeElementFlatten3(typeArgs_, simpleTypeRest_)
case _ ⇒
Nil
}
def compoundType(): List[TypeElement] = {
val annotTypeOpt = if (LBRACE) None else Some(annotType())
val rest = compoundTypeRest()
typeElementFlatten3(annotTypeOpt, rest)
}
private def compoundTypeRest(): List[TypeElement] = {
val withTypes = ListBuffer[(Token, List[TypeElement])]()
while (WITH) {
val withToken = nextToken()
val annotType_ = annotType()
withTypes += ((withToken, annotType_))
}
val newLineOpt = newLineOptWhenFollowedBy(LBRACE)
val refinementOpt = if (LBRACE) Some(refinement()) else None
typeElementFlatten3(withTypes.toList, newLineOpt, refinementOpt)
}
def infixTypeRest(): List[TypeElement] = {
if (isIdent && !STAR) {
val identToken = currentToken
val id = InfixTypeConstructor(ident())
val newLineOpt = newLineOptWhenFollowing(isTypeIntroToken)
if (isLeftAssoc(identToken)) {
val compoundType_ = compoundType()
val infixTypeRest_ = infixTypeRest()
typeElementFlatten3(id, newLineOpt, compoundType_, infixTypeRest_)
} else {
val infixType_ = infixType()
typeElementFlatten3(id, newLineOpt, infixType_)
}
} else
Nil
}
def infixType(): List[TypeElement] = {
val compoundType_ = compoundType()
val infixTypeRest_ = infixTypeRest()
typeElementFlatten3(compoundType_, infixTypeRest_)
}
private def types(): List[TypeElement] =
typeElementFlatten3(commaSeparated(argType()))
private def functionTypes(): List[TypeElement] =
typeElementFlatten3(commaSeparated(functionArgType()))
}
private def ident(): Token =
if (isIdent)
nextToken()
else
throw new ScalaParserException("Expected identifier, but got " + currentToken)
private def selector(): Token = ident()
private def pathC(thisOK: Boolean, typeOK: Boolean): CallExpr = {
if (THIS) {
val thisToken = nextToken()
val baseCall = CallExpr(None, thisToken)
if (!thisOK || DOT) {
val dot = accept(DOT)
selectors((baseCall, dot), typeOK)
} else
baseCall
} else if (SUPER) {
val superToken = nextToken()
val mixinQualifierOpt_ = mixinQualifierOpt()
val dot = accept(DOT)
val id = selector()
val subBaseCall = CallExpr(None, superToken, mixinQualifierOpt_)
val baseCall = CallExpr(Some(List(subBaseCall), dot), id)
if (DOT) {
val dot2 = nextToken()
selectors((baseCall, dot2), typeOK)
} else
baseCall
} else {
val id = ident()
val baseCall = CallExpr(None, id)
if (DOT) {
val dot = nextToken()
if (THIS) {
val thisToken = nextToken()
val baseCall2 = CallExpr(Some(List(baseCall), dot), thisToken)
if (!thisOK || DOT) {
val dot2 = accept(DOT)
selectors((baseCall2, dot2), typeOK)
} else
baseCall2
} else if (SUPER) {
val superToken = nextToken()
val mixinQualifierOpt_ = mixinQualifierOpt()
val dot2 = accept(DOT)
val id2 = selector()
val baseCall2 = CallExpr(Some(List(CallExpr(Some(List(baseCall), dot), superToken, mixinQualifierOpt_)), dot2), id2)
if (DOT) {
val dot3 = nextToken()
selectors((baseCall2, dot3), typeOK)
} else
baseCall2
} else
selectors((baseCall, dot), typeOK)
} else
baseCall
}
}
private def path(thisOK: Boolean, typeOK: Boolean): List[Token] = pathC(thisOK, typeOK).tokens
private def selectors(previousAndDot: (CallExpr, Token), typeOK: Boolean): CallExpr = {
val exprDotOpt = Some(exprElementFlatten2(previousAndDot._1), previousAndDot._2)
if (typeOK && TYPE)
CallExpr(exprDotOpt, nextToken())
else {
val id = selector()
val baseCall = CallExpr(exprDotOpt, id)
if (DOT) {
val dot = nextToken()
selectors((baseCall, dot), typeOK)
} else
baseCall
}
}
private def mixinQualifierOpt(): Option[TypeExprElement] =
if (LBRACKET) Some(TypeExprElement(typeElementFlatten3(inBrackets(ident)))) else None
private def stableId(): List[Token] = path(thisOK = false, typeOK = false)
private def qualId(): CallExpr = {
val id = ident()
val baseCall = CallExpr(None, id)
if (DOT) {
val dot = nextToken()
selectors((baseCall, dot), typeOK = false)
} else
baseCall
}
private def pkgQualId(): (CallExpr, Option[Token]) = {
val pkg = qualId()
val newLineOpt = newLineOptWhenFollowedBy(LBRACE)
(pkg, newLineOpt)
}
private def literal(): Token =
if (CHARACTER_LITERAL || INTEGER_LITERAL || FLOATING_POINT_LITERAL || STRING_LITERAL || SYMBOL_LITERAL || TRUE || FALSE || NULL)
nextToken()
else
throw new ScalaParserException("illegal literal: " + currentToken)
private def newLineOpt(): Option[Token] = if (NEWLINE) Some(nextToken()) else None
private def newLinesOpt() = if (NEWLINE || NEWLINES) Some(nextToken()) else None
private def newLineOptWhenFollowedBy(tokenType: TokenType) =
if (NEWLINE && lookahead(1) == tokenType)
newLineOpt()
else
None
private def newLineOptWhenFollowing(pred: TokenType ⇒ Boolean) =
if (NEWLINE && pred(lookahead(1)))
newLineOpt()
else
None
private def typedOpt(): Option[(Token, Type)] =
if (COLON) {
val colonToken = nextToken()
val typ_ = typ()
Some(colonToken, typ_)
} else
None
private def typeOrInfixType(location: Location): TypeExprElement =
TypeExprElement(
if (location == Local)
typ().contents
else
startInfixType())
private def annotTypeRest(): List[TypeElement] =
typeElementFlatten3(annotations(skipNewLines = false))
private def wildcardType(): List[TypeElement] = {
typeBounds()
}
private def equalsExpr() = {
val equalsToken = accept(EQUALS)
val expr_ = expr()
(equalsToken, expr_)
}
private def condExpr(): CondExpr = {
if (LPAREN) {
val lparen = nextToken()
val expr_ = expr()
val rparen = accept(RPAREN)
CondExpr(lparen, expr_, rparen)
} else {
val lparen = accept(LPAREN)
// Seriously, WTF?
throw new ScalaParserException("Straggling lparen thing")
}
}
private def statement(location: Location): Expr = expr(location)
def expr(): Expr = { expr(Local) }
private def expr(location: Location): Expr = {
expr0(location)
}
private def expr0(location: Location): Expr = {
makeExpr(currentTokenType match {
case IF ⇒
val ifToken = nextToken()
val condExpr_ = condExpr()
val newLinesOpt_ = newLinesOpt()
val body = expr()
// nsc has merged the SEMI into the ELSE by this point:
val semiOpt = if (SEMI && lookahead(1) == ELSE) Some(nextToken()) else None
val elseClauseOption = if (ELSE) {
val elseToken = nextToken()
val expr_ = expr()
Some(ElseClause(semiOpt, elseToken, expr_))
} else
None
List(IfExpr(ifToken, condExpr_, newLinesOpt_, body, elseClauseOption))
case TRY ⇒
val tryToken = nextToken()
val body: Expr = currentTokenType match {
case LBRACE ⇒
val (lbrace, block_, rbrace) = inBraces(block())
makeExpr(BlockExpr(lbrace, Right(block_), rbrace))
case LPAREN ⇒ makeExpr(inParens(expr()))
case _ ⇒ expr
}
val catchClauseOption: Option[CatchClause] =
if (!CATCH)
None
else {
val catchToken = nextToken()
if (!LBRACE)
Some(CatchClause(catchToken, Right(expr())))
else {
val (lbrace, caseClausesOrStatSeq, rbrace) = inBraces {
if (CASE)
Left(caseClauses())
else
Right(StatSeq(selfReferenceOpt = None, firstStatOpt = Some(expr()), otherStats = Nil))
}
Some(CatchClause(catchToken, Left(BlockExpr(lbrace, caseClausesOrStatSeq, rbrace))))
}
}
val finallyClauseOption = currentTokenType match {
case FINALLY ⇒
val finallyToken = nextToken()
val finallyExpr = expr()
Some(finallyToken, finallyExpr)
case _ ⇒
None
}
List(TryExpr(tryToken, body, catchClauseOption, finallyClauseOption))
case WHILE ⇒
val whileToken = nextToken()
val condExpr_ = condExpr()
val newLinesOpt_ = newLinesOpt()
val body = expr()
List(WhileExpr(whileToken, condExpr_, newLinesOpt_, body))
case DO ⇒
val doToken = nextToken()
val body = expr()
val statSepOpt = if (isStatSep) Some(nextToken()) else None
val whileToken = accept(WHILE)
val condExpr_ = condExpr()
List(DoExpr(doToken, body, statSepOpt, whileToken, condExpr_))
case FOR ⇒
val forToken = nextToken()
val (open, close) = if (LBRACE) (LBRACE, RBRACE) else (LPAREN, RPAREN)
val (lParenOrBrace, enumerators_, rParenOrBrace) =
if (LBRACE) inBraces(enumerators())
else inParens(enumerators())
val newlinesOption = newLinesOpt()
val (yieldOption, body) = if (YIELD) {
val yieldToken = nextToken()
(Some(yieldToken), expr())
} else
(None, expr())
List(ForExpr(forToken, lParenOrBrace, enumerators_, rParenOrBrace, newlinesOption, yieldOption, body))
case RETURN ⇒
val returnToken = nextToken()
val returnExpr = if (isExprIntro) Some(expr()) else None
exprElementFlatten2(returnToken, returnExpr) // TODO: <-- use a different type?
case THROW ⇒
val throwToken = nextToken()
val throwExpr = expr()
exprElementFlatten2(throwToken, throwExpr)
case IMPLICIT ⇒
val implicitToken = nextToken()
List(implicitClosure(location, implicitToken))
case _ ⇒
val postfixExpr_ = postfixExpr()
val intermediateResult = if (EQUALS) {
optional { /* TODO: case Ident(_) | Select(_, _) | Apply(_, _) => */
(accept(EQUALS), expr())
} match {
case Some((equalsToken, equalsExpr)) ⇒ List(EqualsExpr(postfixExpr_, equalsToken, equalsExpr))
case None ⇒ postfixExpr_
}
} else if (COLON) {
val colonToken = nextToken()
val rhs = if (USCORE) {
val uscore = nextToken()
val star = accept(STAR)
exprElementFlatten2(uscore, star)
} else if (AT) {
annotations(skipNewLines = false)
} else {
val type_ = typeOrInfixType(location)
List(type_)
}
List(AscriptionExpr(postfixExpr_, colonToken, rhs))
} else if (MATCH) {
val matchToken = nextToken()
val (lbrace, caseClauses_, rbrace) = inBraces(caseClauses())
val blockExpr_ = BlockExpr(lbrace, Left(caseClauses_), rbrace)
List(MatchExpr(postfixExpr_, matchToken, blockExpr_))
} else
postfixExpr_
if (logging)
println("in expr0, postfixExpr = " + postfixExpr_)
val lhsIsTypedParamList = cond(postfixExpr_) { case List(ParenExpr(_, _, _)) ⇒ true } // TODO: is this check sufficient?
if (ARROW && (location != InTemplate || lhsIsTypedParamList)) {
val anonFuncOpt: Option[List[ExprElement]] = optional {
val arrowToken = nextToken()
val postArrow: StatSeq = if (location != InBlock) StatSeq(None, Some(expr()), Nil) else block()
exprElementFlatten2(AnonymousFunction(intermediateResult, arrowToken, postArrow))
}
anonFuncOpt match {
case None ⇒ intermediateResult
case Some(stuff) ⇒ stuff
} // erk, why can't I use getOrElse here!?
} else
intermediateResult
})
}
private def implicitClosure(location: Location, implicitToken: Token): AnonymousFunction = {
val id = ident()
val colonTypeOpt = if (COLON) {
val colonToken = nextToken()
val type_ = typeOrInfixType(location)
Some(colonToken, type_)
} else
None
val arrowToken = accept(ARROW)
val body: StatSeq = if (location != InBlock) StatSeq(None, Some(expr()), Nil) else block()
AnonymousFunction(exprElementFlatten2(implicitToken, id, colonTypeOpt), arrowToken, body)
}
private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_'
private final val letterGroups = {
import java.lang.Character._
Set[Byte](LOWERCASE_LETTER, UPPERCASE_LETTER, OTHER_LETTER, TITLECASE_LETTER, LETTER_NUMBER)
}
private def isScalaLetter(ch: Char) = letterGroups(java.lang.Character.getType(ch).toByte) || otherLetters(ch)
private def isOpAssignmentName(name: String) = name match {
case "!=" | "<=" | ">=" | "" ⇒ false
case _ ⇒ name.endsWith("=") && !name.startsWith("=") && ScalaOnlyLexer.isOperatorPart(name(0))
}
private def precedence(id: String) = id(0) match {
case _ if isOpAssignmentName(id) ⇒ 0
case c if isScalaLetter(c) ⇒ 1
case '|' ⇒ 2
case '^' ⇒ 3
case '&' ⇒ 4
case '=' | '!' ⇒ 5
case '<' | '>' ⇒ 6
case ':' ⇒ 7
case '+' | '-' ⇒ 8
case '*' | '/' | '%' ⇒ 9
case _ ⇒ 10
}
private def hasSamePrecedence(token1: Token, token2: Token) = precedence(token1.text) == precedence(token2.text)
private def hasHigherPrecedence(token1: Token, token2: Token) = precedence(token1.text) > precedence(token2.text)
private def isRightAssociative(token: Token) = token.text.endsWith(":")
private object NestedInfixExpr {
def unapply(infixExpr: InfixExpr) = condOpt(infixExpr) {
case InfixExpr(List(InfixExpr(x, op1, newLineOpt1, y)), op2, newLineOpt2, z) ⇒ (x, op1, newLineOpt1, y, op2, newLineOpt2, z)
}
}
private def rotateRight(infixExpr: InfixExpr): InfixExpr = {
val NestedInfixExpr(x, op1, newLineOpt1, y, op2, newLineOpt2, z) = infixExpr
InfixExpr(x, op1, newLineOpt1, List(InfixExpr(y, op2, newLineOpt2, z)))
}
private def performRotationsForPrecedence(infixExpr: InfixExpr): InfixExpr = infixExpr match {
case NestedInfixExpr(x, op1, newLineOpt1, y, op2, newLineOpt2, z) if hasHigherPrecedence(op2, op1) ⇒
InfixExpr(x, op1, newLineOpt1, List(performRotationsForPrecedence(InfixExpr(y, op2, newLineOpt2, z))))
case _ ⇒ infixExpr
}
private def performRotationsForRightAssociativity(infixExpr: InfixExpr): InfixExpr = infixExpr match {
case NestedInfixExpr(x, op1, newLineOpt1, y, op2, newLineOpt2, z) if hasSamePrecedence(op1, op2) && isRightAssociative(op1) && isRightAssociative(op2) ⇒
InfixExpr(x, op1, newLineOpt1, List(performRotationsForRightAssociativity(InfixExpr(y, op2, newLineOpt2, z))))
case _ ⇒ infixExpr
}
private def postfixExpr(): List[ExprElement] = {
var soFar: List[ExprElement] = prefixExpr()
while (isIdent) {
val id = ident()
val newLineOpt = newLineOptWhenFollowing(isExprIntroToken)
if (isExprIntro) {
val prefixExpr_ = prefixExpr()
var infixExpr_ = InfixExpr(soFar, id, newLineOpt, prefixExpr_)
infixExpr_ = performRotationsForPrecedence(infixExpr_)
infixExpr_ = performRotationsForRightAssociativity(infixExpr_)
soFar = List(infixExpr_)
} else
soFar = List(PostfixExpr(soFar, id))
}
soFar
}
private def prefixExpr(): List[ExprElement] = {
if (isUnaryOp) {
val isMinus = MINUS
val unaryId = PrefixExprElement(ident())
if (isMinus && isNumericLit) {
val literal_ = literal()
simpleExprRest(exprElementFlatten2(unaryId, literal_), true)
} else
exprElementFlatten2(unaryId, simpleExpr())
} else
simpleExpr()
}
private object PathEndingWithDotId {
def unapply(tokens: List[Token]) = condOpt(tokens.reverse) {
case (lastId @ Token(tokenType, _, _, _)) :: dot :: rest if (tokenType.isId || tokenType == THIS) && dot.tokenType == DOT ⇒
(rest.reverse, dot, lastId)
}
}
private object JustIdOrThis {
def unapply(tokens: List[Token]) = condOpt(tokens) {
case List(id @ Token(tokenType, _, _, _)) if (tokenType.isId || tokenType == THIS) ⇒ id
}
}
private def simpleExpr(): List[ExprElement] = {
var canApply = true
val firstPart =
if (isLiteral) exprElementFlatten2(literal())
else currentTokenType match {
case XML_START_OPEN | XML_COMMENT | XML_CDATA | XML_UNPARSED | XML_PROCESSING_INSTRUCTION ⇒
exprElementFlatten2(xmlLiteral())
case VARID | OTHERID | PLUS | MINUS | STAR | PIPE | TILDE | EXCLAMATION | THIS | SUPER ⇒
// val callExpr = CallExpr(Some(previousPart, dot), selector_, None, Nil, None)
List(pathC(thisOK = true, typeOK = false))
case USCORE ⇒
exprElementFlatten2(nextToken())
case LPAREN ⇒
val (lparen, parenBody, rparen) = makeParens(commaSeparated(expr))
exprElementFlatten2(ParenExpr(lparen, exprElementFlatten2(parenBody), rparen))
case LBRACE ⇒
canApply = false
exprElementFlatten2(blockExpr())
case NEW ⇒
canApply = false
val newToken = nextToken()
val template_ = template(isTrait = false)
List(New(newToken, template_))
case _ ⇒
throw new ScalaParserException("illegal start of simple expression: " + currentToken)
}
simpleExprRest(firstPart, canApply)
}
private def simpleExprRest(previousPart: List[ExprElement], canApply: Boolean): List[ExprElement] = {
val newLineOpt = if (canApply) newLineOptWhenFollowedBy(LBRACE) else None
currentTokenType match {
case DOT ⇒
require(newLineOpt.isEmpty)
val dot = nextToken()
val selector_ = selector()
val callExpr = CallExpr(Some(previousPart, dot), selector_, None, Nil, None)
simpleExprRest(List(callExpr), canApply = true)
case LBRACKET ⇒
require(newLineOpt.isEmpty)
val identifierCond = true // TODO: missing check: case Ident(_) | Select(_, _) => OK, just means we accept multiple type param [X][Y] clauses
if (identifierCond) {
val typeArgs_ = TypeExprElement(exprTypeArgs())
val updatedPart = previousPart match {
case List(callExpr: CallExpr) ⇒ List(callExpr.copy(typeArgsOpt = Some(typeArgs_)))
case _ ⇒ exprElementFlatten2(previousPart, newLineOpt, typeArgs_)
}
simpleExprRest(updatedPart, canApply = true)
} else
exprElementFlatten2(previousPart)
case LPAREN | LBRACE if canApply ⇒
val argumentExprs_ = argumentExprs().get
val updatedPart = previousPart match {
case List(callExpr: CallExpr) ⇒ List(callExpr.copy(newLineOptsAndArgumentExprss = callExpr.newLineOptsAndArgumentExprss :+ (newLineOpt, argumentExprs_)))
case _ ⇒ exprElementFlatten2(previousPart, newLineOpt, argumentExprs_)
}
simpleExprRest(updatedPart, canApply = true)
case USCORE ⇒
require(newLineOpt.isEmpty)
val uscore = nextToken()
previousPart match {
case List(callExpr: CallExpr) ⇒ List(callExpr.copy(uscoreOpt = Some(uscore)))
case _ ⇒ List(PostfixExpr(previousPart, uscore))
}
case _ ⇒
require(newLineOpt.isEmpty)
previousPart
}
}
/**
* @return Some(..) if next token is LBRACE or LPAREN
*/
private def argumentExprs(): Option[ArgumentExprs] = {
// println("argumentExprs(): " + currentToken)
def argument() = Argument(expr())
def args() = commaSeparated(argument())
condOpt(currentTokenType) {
case LBRACE ⇒ BlockArgumentExprs(exprElementFlatten2(blockExpr()))
case LPAREN ⇒
val (lparen, body, rparen) = inParens { if (RPAREN) Nil else exprElementFlatten2(args()) }
ParenArgumentExprs(lparen, body, rparen)
}
}
private def multipleArgumentExprs(): List[ArgumentExprs] =
if (!LPAREN) Nil
else argumentExprs().get :: multipleArgumentExprs()
private def blockExpr(): BlockExpr = {
val (lbrace, body, rbrace) = inBraces {
if (justCase) Left(caseClauses())
else Right(block())
}
BlockExpr(lbrace, body, rbrace)
}
private def block(): StatSeq = blockStatSeq()
private def caseClauses(): CaseClauses = {
val caseClauses_ = caseSeparated {
(pattern(), guard(), caseBlock())
} map {
case (caseToken, (pattern_, guardOption, (arrow, blockStatSeq_))) ⇒
CaseClause(CasePattern(caseToken, pattern_, guardOption, arrow), blockStatSeq_)
}
if (caseClauses_.isEmpty)
accept(CASE)
CaseClauses(caseClauses_)
}
private def caseBlock(): (Token, StatSeq) = {
val arrowToken = accept(ARROW)
val blockStatSeq_ = block()
(arrowToken, blockStatSeq_)
}
private def guard(): Option[Guard] = {
if (IF) {
val ifToken = nextToken()
val postfixExpr_ = postfixExpr()
Some(Guard(ifToken, Expr(postfixExpr_)))
} else
None
}
private def enumerators(): Enumerators = {
val newStyle = !VAL
val initialGenerator = generator(eqOK = false)
val otherEnumerators = ListBuffer[(Token, Enumerator)]()
while (isStatSep) {
val statSep = nextToken()
val enumerator = if (newStyle) {
if (IF) guard().get
else generator(eqOK = true)
} else {
if (VAL) generator(eqOK = true)
else expr()
}
otherEnumerators += ((statSep, enumerator))
}
Enumerators(initialGenerator, otherEnumerators.toList)
}
private def generator(eqOK: Boolean): Generator = {
val valOption = if (VAL) Some(nextToken()) else None
val pattern_ = noSeq.pattern1()
val equalsOrArrowToken = if (EQUALS && eqOK) nextToken() else accept(LARROW)
val expr_ = expr()
val guards = ListBuffer[Guard]()
while (IF) guards += guard().get
Generator(valOption, pattern_, equalsOrArrowToken, expr_, guards.toList)
}
trait SeqContextSensitive extends PatternContextSensitive {
def interceptStarPattern(): Option[Token]
def functionArgType() = argType()
def argType(): List[TypeElement] = currentTokenType match {
case USCORE ⇒
val uscore = nextToken()
val wildcardTypeOpt = if (SUBTYPE || SUPERTYPE) Some(wildcardType()) else None
typeElementFlatten3(uscore, wildcardTypeOpt)
case _ if isIdent && isVariableName(currentToken.getText) ⇒
typeElementFlatten3(ident())
case _ ⇒
List(typ())
}
def patterns(): List[ExprElement] = {
exprElementFlatten2(commaSeparated(pattern()))
}
def pattern(): Expr = { // Scalac now uses a loop() method, but this is still OK:
val firstPattern = pattern1()
var currentExpr: ExprElement = firstPattern
if (PIPE)
while (PIPE) {
val pipeToken = nextToken()
val otherPattern = pattern1()
currentExpr = InfixExpr(List(currentExpr), pipeToken, None, List(otherPattern))
}
makeExpr(currentExpr)
}
def pattern1(): Expr = {
val firstPattern = pattern2()
val colonTypeOpt = if (COLON) { // TODO: case Ident(name) if (treeInfo.isVarPattern(p) && in.token == COLON)
val colonToken = nextToken()
val compoundType_ = Some(TypeExprElement(compoundType()))
Some(colonToken, compoundType_)
} else
None
makeExpr(firstPattern, colonTypeOpt)
}
def pattern2(): Expr = {
val firstPattern = pattern3()
val atOtherOpt = if (AT) {
// TODO: Compare Parsers.scala
optional {
val atToken = nextToken()
val otherPattern = pattern3()
(atToken, otherPattern)
}
} else
None
makeExpr(firstPattern, atOtherOpt)
}
def pattern3(): List[ExprElement] = {
val simplePattern1 = simplePattern()
interceptStarPattern() foreach { x ⇒ return exprElementFlatten2(simplePattern1, x) }
var soFar: List[ExprElement] = simplePattern1
while (isIdent && !PIPE) {
val id = ident()
val otherSimplePattern = simplePattern()
var infixExpr_ = InfixExpr(soFar, id, None, otherSimplePattern)
infixExpr_ = performRotationsForPrecedence(infixExpr_)
infixExpr_ = performRotationsForRightAssociativity(infixExpr_)
soFar = List(infixExpr_)
}
soFar
}
def simplePattern(): List[ExprElement] = {
// println("simplePattern: " + currentToken)
currentTokenType match {
case VARID | OTHERID | PLUS | MINUS | STAR | PIPE | TILDE | EXCLAMATION | THIS ⇒
val nameIsMinus: Boolean = MINUS // TODO case Ident(name) if name == nme.MINUS =>
val id = stableId()
val literalOpt = condOpt(currentTokenType) {
case INTEGER_LITERAL | FLOATING_POINT_LITERAL if nameIsMinus ⇒ literal()
}
val typeArgsOpt: Option[List[ExprElement]] =
if (LBRACKET) Some(List(TypeExprElement(typeArgs())))
else None
val argumentPatternsOpt = if (LPAREN) Some(argumentPatterns()) else None
exprElementFlatten2((id, literalOpt), typeArgsOpt, argumentPatternsOpt)
case USCORE ⇒
exprElementFlatten2(nextToken())
case CHARACTER_LITERAL | INTEGER_LITERAL | FLOATING_POINT_LITERAL | STRING_LITERAL | SYMBOL_LITERAL | TRUE | FALSE | NULL ⇒
exprElementFlatten2(literal())
case LPAREN ⇒
val (lparen, patterns_, rparen) = makeParens(noSeq.patterns)
exprElementFlatten2(lparen, patterns_, rparen)
case XML_START_OPEN | XML_COMMENT | XML_CDATA | XML_UNPARSED | XML_PROCESSING_INSTRUCTION ⇒
exprElementFlatten2(xmlLiteralPattern())
case _ ⇒
throw new ScalaParserException("illegal start of simple pattern: " + currentToken)
}
}
}
object outPattern extends PatternContextSensitive {
def argType() = List(typ())
def functionArgType() = List(paramType())
}
object seqOK extends SeqContextSensitive {
def interceptStarPattern() = if (STAR) Some(nextToken()) else None
}
object noSeq extends SeqContextSensitive {
def interceptStarPattern() = None
}
def typ() = outPattern.typ()
def startInfixType() = outPattern.infixType()
def startAnnotType() = outPattern.annotType()
def exprTypeArgs() = outPattern.typeArgs()
def exprSimpleType() = outPattern.simpleType()
def pattern() = noSeq.pattern()
def patterns() = noSeq.patterns()
def seqPatterns() = seqOK.patterns()
private def argumentPatterns(): List[ExprElement] = {
val (lparen, patterns_, rparen) = inParens { if (RPAREN) Nil else seqPatterns() }
exprElementFlatten2(lparen, patterns_, rparen)
}
private def accessQualifierOpt(): Option[AccessQualifier] =
if (LBRACKET) {
val lbracket = nextToken()
val thisOrId = if (THIS)
nextToken()
else
ident()
val rbracket = accept(RBRACKET)
Some(AccessQualifier(lbracket, thisOrId, rbracket))
} else
None
private def accessModifierOpt(): Option[AccessModifier] = {
currentTokenType match {
case PRIVATE | PROTECTED ⇒
val privateOrProtected = nextToken()
val accessQualifierOpt_ = accessQualifierOpt()
Some(AccessModifier(privateOrProtected, accessQualifierOpt_))
case _ ⇒
None
}
}
private def modifiers(): List[Modifier] = {
val modifiers = ListBuffer[Modifier]()
def loop() {
currentTokenType match {
case PRIVATE | PROTECTED ⇒
val privateOrProtected = nextToken()
val accessQualifierOpt_ = accessQualifierOpt()
modifiers += AccessModifier(privateOrProtected, accessQualifierOpt_)
loop()
case ABSTRACT | FINAL | SEALED | OVERRIDE | IMPLICIT | LAZY ⇒
modifiers += SimpleModifier(nextToken())
loop()
case NEWLINE ⇒
modifiers += SimpleModifier(nextToken()) // Investigate
loop()
case _ ⇒
}
}
loop()
modifiers.toList
}
private def localModifiers(): List[Modifier] =
if (isLocalModifier) SimpleModifier(nextToken()) :: localModifiers()
else Nil
private def annotations(skipNewLines: Boolean): List[Annotation] =
readAnnots {
val (annotationType, argumentExprss) = annotationExpr()
val newLineOpt_ = if (skipNewLines) newLineOpt() else None
(annotationType, argumentExprss, newLineOpt_)
} map {
case (atToken, (annotationType, argumentExprss, newLineOpt_)) ⇒
Annotation(atToken, annotationType, argumentExprss, newLineOpt_)
}
private def constructorAnnotations() =
readAnnots {
val annotationType = Type(exprSimpleType())
val argumentExprss = argumentExprs().toList
(annotationType, argumentExprss)
} map {
case (atToken, (annotationType, argumentExprss)) ⇒
Annotation(atToken, annotationType, argumentExprss, newlineOption = None)
}
private def annotationExpr(): (Type, List[ArgumentExprs]) = {
val annotationType = Type(exprSimpleType())
val argumentExprss = if (LPAREN) multipleArgumentExprs() else Nil
(annotationType, argumentExprss)
}
private def paramClauses(): ParamClauses = {
var implicitmod = false
def param(): Param = {
val annotations_ = annotations(skipNewLines = false)
val ownerIsTypeName = true // TODO: if (owner.isTypeName)
val modifiers_ = ListBuffer[Modifier]()
val valOrVarOpt = if (ownerIsTypeName) {
modifiers_ ++= modifiers()
currentTokenType match {
case VAL | VAR ⇒ Some(nextToken())
case _ ⇒ None
}
} else
None
val id = ident()
if (COLON || !forgiving) {
val colonToken = accept(COLON)
val paramType_ = paramType()
val paramTypeOpt = Some(colonToken, paramType_)
val defaultValueOpt = if (EQUALS) {
val equalsToken = nextToken()
val expr_ = expr()
Some(equalsToken, expr_)
} else
None
Param(annotations_, modifiers_.toList, valOrVarOpt, id, paramTypeOpt, defaultValueOpt)
} else
Param(annotations_, modifiers_.toList, valOrVarOpt, id, paramTypeOpt = None, defaultValueOpt = None)
}
// Differs from nsc in that we've pulled in lparen/rparen
def paramClause(): ParamClause = {
val lparen = accept(LPAREN)
if (RPAREN) {
val rparen = accept(RPAREN)
ParamClause(lparen, None, None, Nil, rparen)
} else {
val implicitOption = if (IMPLICIT) {
val implicitToken = nextToken()
implicitmod = true
Some(implicitToken)
} else
None
val (param_, otherParams) = commaSeparated(param())
val rparen = accept(RPAREN)
ParamClause(lparen, implicitOption, Some(param_), otherParams, rparen)
}
}
val newLineOpt = newLineOptWhenFollowedBy(LPAREN)
val paramClausesAndNewline = ListBuffer[(ParamClause, Option[Token])]()
while (!implicitmod && LPAREN) {
val paramClause_ = paramClause()
val newLineOpt2 = newLineOptWhenFollowedBy(LPAREN)
paramClausesAndNewline += ((paramClause_, newLineOpt2))
}
ParamClauses(newLineOpt, paramClausesAndNewline.toList)
}
private def paramType(): Type = {
val typeElements = ListBuffer[TypeElementFlattenable]()
currentTokenType match {
case ARROW ⇒
typeElements += nextToken()
typeElements += typ()
case _ ⇒
typeElements += typ()
if (STAR)
typeElements += VarargsTypeElement(nextToken())
}
Type(typeElementFlatten3(typeElements.toList))
}
private def typeParamClauseOpt(allowVariance: Boolean): Option[TypeParamClause] = {
def typeParam(): TypeParam = {
val typeElements = ListBuffer[TypeElementFlattenable]()
if (allowVariance && isIdent) { // TODO: condition
if (PLUS)
typeElements += VarianceTypeElement(nextToken())
else if (MINUS)
typeElements += VarianceTypeElement(nextToken())
}
typeElements += wildcardOrIdent()
typeElements += typeParamClauseOpt(allowVariance = true)
typeElements += typeBounds()
while (VIEWBOUND) {
typeElements += nextToken()
typeElements += typ()
}
while (COLON) {
typeElements += nextToken()
typeElements += typ()
}
TypeParam(typeElementFlatten3(typeElements.toList))
}
val newLineOpt = newLineOptWhenFollowedBy(LBRACKET)
if (LBRACKET) {
val bracketsContents =
inBrackets(commaSeparated((annotations(skipNewLines = true), typeParam())))
Some(TypeParamClause(typeElementFlatten3(newLineOpt, bracketsContents)))
} else
None
}
private def typeBounds(): List[TypeElement] = {
val superTypeOpt = bound(SUPERTYPE)
val subTypeOpt = bound(SUBTYPE)
typeElementFlatten3(superTypeOpt, subTypeOpt)
}
private def bound(tokenType: TokenType): Option[(Token, Type)] = {
if (tokenType) {
val token = nextToken()
val type_ = typ()
Some(token, type_)
} else
None
}
private def importClause(): ImportClause = {
val importToken = accept(IMPORT)
val (importExpr_, otherImportExprs) = commaSeparated(importExpr())
ImportClause(importToken, importExpr_, otherImportExprs)
}
private def importExpr(): ImportExpr = {
def thisDotted(): Expr = {
val thisToken = nextToken()
val dot1 = accept(DOT)
val selector_ = selector()
val dot2 = accept(DOT)
makeExpr(thisToken, dot1, selector_, dot2)
}
val initialSelection = currentTokenType match {
case THIS ⇒ thisDotted()
case _ ⇒
val id = ident()
val dot = accept(DOT)
val thisOpt = if (THIS) Some(thisDotted()) else None
makeExpr(id, dot, thisOpt)
}
def loop(idDots: Vector[(Token, Token)]): ImportExpr = currentTokenType match {
case USCORE ⇒
val uscore = nextToken()
makeExpr(initialSelection, idDots, uscore)
case LBRACE ⇒
val importSelectors_ = importSelectors()
BlockImportExpr(makeExpr(initialSelection, idDots), importSelectors_)
case _ ⇒
val id = ident()
if (DOT) {
val dot = nextToken()
loop(idDots :+ (id, dot))
} else
makeExpr(initialSelection, idDots, id)
}
loop(Vector())
}
private def importSelectors(): ImportSelectors = {
val (lbrace, (firstImportSelector, otherImportSelectors), rbrace) = inBraces(commaSeparated(importSelector()))
ImportSelectors(lbrace, firstImportSelector, otherImportSelectors, rbrace)
}
private def wildcardOrIdent(): Token =
if (USCORE) nextToken()
else ident()
private def importSelector(): Expr = {
val first = wildcardOrIdent()
currentTokenType match {
case ARROW ⇒
val arrowToken = nextToken()
val rename = wildcardOrIdent()
makeExpr(first, arrowToken, rename)
case _ ⇒
makeExpr(first)
}
}
private def defOrDcl(localDef: Boolean = false): DefOrDcl = currentTokenType match {
case VAL ⇒ patDefOrDcl()
case VAR ⇒ patDefOrDcl()
case DEF ⇒ funDefOrDcl(localDef)
case TYPE ⇒ typeDefOrDcl()
case _ ⇒ tmplDef()
}
def nonLocalDefOrDcl(): FullDefOrDcl = {
val annotations_ = annotations(skipNewLines = true)
val modifiers_ = modifiers()
val defOrDcl_ = defOrDcl()
FullDefOrDcl(annotations_, modifiers_, defOrDcl_)
}
private def patDefOrDcl(): PatDefOrDcl = {
val valOrVarToken = nextToken()
val (pattern_, otherPatterns) = commaSeparated(noSeq.pattern2())
val typedOpt_ = typedOpt()
val equalsClauseOption = if (EQUALS) { // TODO: Check cond
val equalsToken = accept(EQUALS)
// Skip USCORE check: will be handled by expr() anyway
// if (USCORE) { // TODO: check cond
// nextToken()
// } else
val clause = expr()
Some(equalsToken, clause)
} else
None
PatDefOrDcl(valOrVarToken, pattern_, otherPatterns.toList, typedOpt_, equalsClauseOption)
}
private def funDefOrDcl(localDef: Boolean): FunDefOrDcl = {
val defToken = accept(DEF)
if (THIS) {
val thisToken = nextToken()
val paramClauses_ = paramClauses()
val newLineOpt_ = newLineOptWhenFollowedBy(LBRACE)
val funBody = currentTokenType match {
case LBRACE ⇒
val blockExpr_ = constrBlock()
ProcFunBody(newLineOpt_, blockExpr_)
case _ ⇒
val equalsToken = accept(EQUALS)
val constrExpr_ = constrExpr()
ExprFunBody(equalsToken, constrExpr_)
}
FunDefOrDcl(defToken, thisToken, None, paramClauses_, None, Some(funBody), localDef)
} else {
val nameToken = ident()
val typeParamClauseOpt_ = typeParamClauseOpt(allowVariance = false)
val paramClauses_ = paramClauses()
val newLineOpt_ = newLineOptWhenFollowedBy(LBRACE)
val returnTypeOpt = typedOpt()
val funBodyOpt = if (isStatSep || RBRACE || EOF /* for our tests */ )
None
else if (LBRACE) { // TODO: check cond
val blockExpr_ = blockExpr()
Some(ProcFunBody(newLineOpt_, blockExpr_))
} else {
val (equalsToken, expr_) = equalsExpr()
Some(ExprFunBody(equalsToken, expr_))
}
FunDefOrDcl(defToken, nameToken, typeParamClauseOpt_, paramClauses_, returnTypeOpt, funBodyOpt, localDef)
}
}
private def constrExpr(): Expr = {
if (LBRACE)
makeExpr(constrBlock())
else
selfInvocation()
}
private def selfInvocation(): Expr = {
val thisToken = accept(THIS)
val newLineOpt_ = newLineOptWhenFollowedBy(LBRACE)
val argumentExprs_ = argumentExprs()
val newLineOpt2 = newLineOptWhenFollowedBy(LBRACE)
var argumentExprsAndNewLines: Vector[(ArgumentExprs, Option[Token])] = Vector()
while (LPAREN || LBRACE) {
val argumentExprs_ = argumentExprs().get
val anotherNewLineOpt = newLineOptWhenFollowedBy(LBRACE)
argumentExprsAndNewLines = argumentExprsAndNewLines :+ ((argumentExprs_, anotherNewLineOpt))
}
makeExpr(thisToken, newLineOpt_, argumentExprs_, newLineOpt2, argumentExprsAndNewLines.toList)
}
private def constrBlock(): BlockExpr = {
val lbrace = accept(LBRACE)
val selfInvocation_ = selfInvocation()
val statSeq = if (isStatSep) {
val statSep = nextToken()
val blockStatSeq_ = blockStatSeq()
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(selfInvocation_), otherStats = (statSep, blockStatSeq_.firstStatOpt) :: blockStatSeq_.otherStats)
} else
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(selfInvocation_), otherStats = Nil)
val rbrace = accept(RBRACE)
BlockExpr(lbrace, Right(statSeq), rbrace)
}
private def typeDefOrDcl(): TypeDefOrDcl = {
val typeToken = accept(TYPE)
val newLinesOpt_ = newLinesOpt()
val name = ident()
val typeParamClauseOpt_ = typeParamClauseOpt(allowVariance = true)
val extraTypeDclStuff = currentTokenType match {
case EQUALS ⇒
val equalsToken = nextToken()
val typ_ = typ()
Left(equalsToken, typ_)
case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF /* <-- for Scalariform tests */ ⇒
val typeBounds_ = typeBounds()
Right(typeBounds_)
case _ ⇒
throw new ScalaParserException("`=', `>:', or `<:' expected, but got " + currentToken)
}
TypeDefOrDcl(typeElementFlatten3(typeToken, newLinesOpt_, name, typeParamClauseOpt_, extraTypeDclStuff))
}
private def topLevelTmplDef(): FullDefOrDcl = {
val annotations_ = annotations(skipNewLines = true)
val modifiers_ = modifiers()
val tmplDef_ = tmplDef()
FullDefOrDcl(annotations_, modifiers_, tmplDef_)
}
private def tmplDef(): TmplDef = {
currentTokenType match {
case TRAIT ⇒ classDef()
case CLASS ⇒ classDef()
case CASE if lookahead(1) == CLASS ⇒ classDef()
case OBJECT ⇒ objectDef()
case CASE if lookahead(1) == OBJECT ⇒ objectDef()
case _ ⇒ throw new ScalaParserException("expected start of definition, but was " + currentTokenType)
}
}
private def classDef(): TmplDef = {
var markerTokens: List[Token] = Nil
if (CASE)
markerTokens = markerTokens :+ nextToken() // We use two tokens whereas nsc uses CASEOBJECT
val isTrait: Boolean = TRAIT
markerTokens = markerTokens :+ nextToken()
val name = ident()
val typeParamClauseOpt_ = typeParamClauseOpt(allowVariance = true)
val annotations_ = constructorAnnotations()
val (accessModifierOpt_, paramClausesOpt) = if (isTrait)
(None, None)
else {
val accessModifierOpt_ = accessModifierOpt()
val paramClauses_ = paramClauses()
(accessModifierOpt_, Some(paramClauses_))
}
val templateOpt_ = templateOpt(isTrait)
TmplDef(markerTokens, name, typeParamClauseOpt_, annotations_, accessModifierOpt_, paramClausesOpt,
templateOpt_.templateInheritanceSectionOpt, templateOpt_.templateBodyOpt)
}
private def objectDef(): TmplDef = {
var markerTokens: List[Token] = Nil
if (CASE)
markerTokens = markerTokens :+ nextToken() // We use two tokens whereas nsc uses CASEOBJECT
markerTokens = markerTokens :+ accept(OBJECT)
val name = ident()
val templateOpt_ = templateOpt(isTrait = false)
TmplDef(
markerTokens = markerTokens,
name = name,
typeParamClauseOpt = None,
annotations = Nil,
accessModifierOpt = None,
paramClausesOpt = None,
templateInheritanceSectionOpt = templateOpt_.templateInheritanceSectionOpt,
templateBodyOption = templateOpt_.templateBodyOpt)
}
private def templateParents(isTrait: Boolean): TemplateParents = {
val type1 = Type(startAnnotType())
val argumentExprs_ =
if (LPAREN && !isTrait) multipleArgumentExprs()
else Nil
val withTypes = ListBuffer[(Token, Type)]()
while (WITH) {
val withToken = nextToken()
val withType = Type(startAnnotType())
withTypes += ((withToken, withType))
}
TemplateParents(type1, argumentExprs_, withTypes.toList)
}
private def template(isTrait: Boolean): Template = {
val newLineOpt = newLineOptWhenFollowedBy(LBRACE)
if (LBRACE) {
val templateBody_ = templateBody().copy(newlineOpt = newLineOpt)
if (WITH) { // TODO check cond
val withToken = nextToken()
val templateParents_ = templateParents(isTrait)
val templateBodyOpt_ = templateBodyOpt()
Template(Some(EarlyDefs(templateBody_, Some(withToken))), Some(templateParents_), templateBodyOpt_)
} else
Template(Some(EarlyDefs(templateBody_, withOpt = None)), templateParentsOpt = None, templateBodyOpt = None)
} else {
val templateParents_ = templateParents(isTrait)
val templateBodyOpt_ = templateBodyOpt()
Template(earlyDefsOpt = None, Some(templateParents_), templateBodyOpt_)
}
}
private def templateOpt(isTrait: Boolean): TemplateOpt = {
if (EXTENDS || SUBTYPE && isTrait) {
val extendsOrSubtypeToken = nextToken()
template(isTrait) match {
case Template(earlyDefsOpt, templateParentsOpt, templateBodyOpt) ⇒
TemplateOpt(Some(TemplateInheritanceSection(extendsOrSubtypeToken, earlyDefsOpt, templateParentsOpt)), templateBodyOpt)
}
} else {
// val newLineOpt = newLineOptWhenFollowedBy(LBRACE) // Will be picked up by templateBodyOpt ... TODO: double check this
val templateBodyOpt_ = templateBodyOpt()
TemplateOpt(templateInheritanceSectionOpt = None, templateBodyOpt = templateBodyOpt_)
}
}
private def templateBody(): TemplateBody = {
val (lbrace, templateStatSeq_, rbrace) = inBraces(templateStatSeq())
val newLineOpt_ = None
TemplateBody(newLineOpt_, lbrace, templateStatSeq_, rbrace)
}
private def templateBodyOpt(): Option[TemplateBody] = {
val newLineOpt = newLineOptWhenFollowedBy(LBRACE)
if (LBRACE)
Some(templateBody().copy(newlineOpt = newLineOpt))
else if (LPAREN)
throw new ScalaParserException("traits or objects may not have parametsrs")
else
None
}
private def refinement(): Refinement = {
val (lbrace, statSeq, rbrace) = inBraces(refineStatSeq())
Refinement(lbrace, statSeq, rbrace)
}
private def packaging(): PrePackageBlock = {
val (packageName, newLineOpt_) = pkgQualId()
val (lbrace, statSeq, rbrace) = inBraces(topStatSeq())
PrePackageBlock(packageName, newLineOpt_, lbrace, statSeq, rbrace)
}
private def topStatSeq(): StatSeq = {
val statAndStatSeps = ListBuffer[(Option[Stat], Option[Token])]()
while (!isStatSeqEnd) {
val statOpt = currentTokenType match {
case PACKAGE ⇒
val packageToken = nextToken()
if (OBJECT) {
val objDef = objectDef()
Some(FullDefOrDcl(annotations = Nil, modifiers = List(SimpleModifier(packageToken)), defOrDcl = objDef))
} else
Some(packaging().complete(packageToken))
case IMPORT ⇒
Some(importClause())
case x if x == AT || isTemplateIntro || isModifier ⇒
Some(topLevelTmplDef())
case _ ⇒
if (!isStatSep)
throw new ScalaParserException("expected class or object definition")
else
None
}
val statSepOpt = if (!RBRACE && !EOF) Some(acceptStatSep()) else None
statAndStatSeps += ((statOpt, statSepOpt))
}
rearrangeStatsAndSeps(statAndStatSeps)
}
private def templateStatSeq(): StatSeq = {
val statAndStatSeps = ListBuffer[(Option[Stat], Option[Token])]()
var selfReferenceOpt = if (isExprIntro) {
val expr_ = expr(InTemplate)
if (ARROW) {
val arrowToken = nextToken()
Some((expr_, arrowToken))
} else {
val statSepOpt = acceptStatSepOpt()
statAndStatSeps += ((Some(expr_), statSepOpt))
None
}
} else
None
while (!isStatSeqEnd) {
val statOpt = if (IMPORT)
Some(importClause())
else if (isExprIntro)
Some(statement(InTemplate))
else if (isDefIntro || isModifier || AT)
Some(nonLocalDefOrDcl())
else if (!isStatSep)
throw new ScalaParserException("illegal start of definition: " + currentToken)
else
None
val statSepOpt = acceptStatSepOpt()
statAndStatSeps += ((statOpt, statSepOpt))
}
rearrangeStatsAndSeps(statAndStatSeps).copy(selfReferenceOpt = selfReferenceOpt)
}
private def refineStatSeq(): StatSeq = {
val statAndStatSeps = ListBuffer[(Option[Stat], Option[Token])]()
while (!isStatSeqEnd) {
val statOpt =
if (isDclIntro) {
val defOrDcl_ = defOrDcl()
Some(FullDefOrDcl(annotations = Nil, modifiers = Nil, defOrDcl = defOrDcl_))
} else if (!isStatSep)
throw new ScalaParserException("illegal start of definition: " + currentToken)
else
None
val statSepOpt = if (!RBRACE) Some(acceptStatSep()) else None
statAndStatSeps += ((statOpt, statSepOpt))
}
rearrangeStatsAndSeps(statAndStatSeps)
}
private def localDef(): FullDefOrDcl = {
val annotations_ = annotations(skipNewLines = true)
val localModifiers_ = localModifiers()
// val modifierCondition = true // TODO: !!!!
val defOrDcl_ = or(defOrDcl(localDef = true), tmplDef())
FullDefOrDcl(annotations_, localModifiers_, defOrDcl_)
}
private def blockStatSeq(): StatSeq = {
val statAndStatSeps = ListBuffer[(Option[Stat], Option[Token])]()
while (!isStatSeqEnd && !justCase) {
if (IMPORT) {
val importStat = importClause()
val statSep = acceptStatSep()
statAndStatSeps += ((Some(importStat), Some(statSep)))
} else if (isExprIntro) {
val stat = statement(InBlock)
val statSepOpt = if (!RBRACE && !justCase) Some(acceptStatSep()) else None
statAndStatSeps += ((Some(stat), statSepOpt))
} else if (isDefIntro || isLocalModifier || AT) {
val defStat: Stat = if (IMPLICIT) {
val implicitToken = nextToken()
if (isIdent)
makeExpr(implicitClosure(InBlock, implicitToken))
else {
val localDef_ = localDef()
localDef_.copy(modifiers = SimpleModifier(implicitToken) :: localDef_.modifiers)
}
} else
localDef()
val statSepOpt = acceptStatSepOpt()
statAndStatSeps += ((Some(defStat), statSepOpt))
} else if (isStatSep) {
val statSep = nextToken()
statAndStatSeps += ((None, Some(statSep)))
} else
throw new ScalaParserException("illegal start of statement: " + currentToken)
}
rearrangeStatsAndSeps(statAndStatSeps)
}
private def rearrangeStatsAndSeps(statAndStatSeps: Iterable[(Option[Stat], Option[Token])]): StatSeq = {
var firstStatOpt: Option[Stat] = None
var firstStatSeen = false
val otherStats = ListBuffer[(Token, Option[Stat])]()
var previousStatSepOpt: Option[Token] = None
for ((statOpt, statSepOpt) ← statAndStatSeps) {
if (!firstStatSeen) {
firstStatSeen = true
firstStatOpt = statOpt
} else {
val statSep = previousStatSepOpt.get
otherStats += ((statSep, statOpt))
}
previousStatSepOpt = statSepOpt
}
for (statSep ← previousStatSepOpt)
otherStats += ((statSep, None))
StatSeq(selfReferenceOpt = None, firstStatOpt = firstStatOpt, otherStats = otherStats.toList)
}
def compilationUnit(): CompilationUnit = {
def topstats(): StatSeq = {
val initialSemis = ListBuffer[Token]()
while (SEMI)
initialSemis += nextToken()
val otherStatSeq = if (PACKAGE) {
val packageToken = nextToken()
if (OBJECT) {
val objDef = objectDef()
val packageObjectStat = FullDefOrDcl(annotations = Nil, modifiers = List(SimpleModifier(packageToken)), defOrDcl = objDef)
if (EOF)
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(packageObjectStat), otherStats = Nil)
else {
val statSep = acceptStatSep()
val statSeq = topStatSeq()
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(packageObjectStat), otherStats = (statSep, statSeq.firstStatOpt) :: statSeq.otherStats)
}
} else {
val (packageName, newLineOpt_) = pkgQualId()
if (EOF)
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(PackageStat(packageToken, packageName)), otherStats = Nil)
else if (isStatSep) {
val statSep = nextToken()
val otherStatSeq = topstats()
StatSeq(selfReferenceOpt = None, firstStatOpt = Some(PackageStat(packageToken, packageName)), (statSep, otherStatSeq.firstStatOpt) :: otherStatSeq.otherStats)
} else {
val (lbrace, packageBlockStats, rbrace) = inBraces(topStatSeq())
val otherStatSeq = topStatSeq()
val packageBlock = PackageBlock(packageToken, packageName, newLineOpt_, lbrace, packageBlockStats, rbrace)
StatSeq(None, Some(packageBlock), otherStatSeq.otherStats)
}
}
} else
topStatSeq()
if (initialSemis.isEmpty)
otherStatSeq
else {
val otherStats = (initialSemis.init.toList.map((_, None)) :+ (initialSemis.last, otherStatSeq.firstStatOpt)) ++ otherStatSeq.otherStats
StatSeq(selfReferenceOpt = None, firstStatOpt = None, otherStats = otherStats)
}
}
val topStats_ = topstats()
accept(EOF)
CompilationUnit(topStats_)
}
private def xmlStartTag(isPattern: Boolean): XmlStartTag = {
val startOpen = accept(XML_START_OPEN)
val name = accept(XML_NAME)
val attributes = ListBuffer[(Option[Token], XmlAttribute)]()
var whitespaceOption: Option[Token] = None
while (!XML_TAG_CLOSE) {
whitespaceOption = nextTokenIf(XML_WHITESPACE)
currentTokenType match {
case XML_NAME ⇒
val attribute = xmlAttribute(isPattern)
attributes += ((whitespaceOption, attribute))
whitespaceOption = None
case XML_TAG_CLOSE ⇒
// End loop
case _ ⇒
throw new ScalaParserException("Expected XML attribute or end of tag: " + currentToken)
}
}
val tagClose = accept(XML_TAG_CLOSE)
XmlStartTag(startOpen, name, attributes.toList, whitespaceOption, tagClose)
}
private def xmlAttribute(isPattern: Boolean): XmlAttribute = {
val name = accept(XML_NAME)
val whitespaceOption = nextTokenIf(XML_WHITESPACE)
val equals = accept(XML_ATTR_EQ)
val whitespaceOption2 = nextTokenIf(XML_WHITESPACE)
val valueOrEmbeddedScala = currentTokenType match {
case XML_ATTR_VALUE ⇒
Left(nextToken())
case LBRACE ⇒
Right(xmlEmbeddedScala(isPattern))
}
XmlAttribute(name, whitespaceOption, equals, whitespaceOption2, valueOrEmbeddedScala)
}
private def xmlEmptyElement(isPattern: Boolean): XmlEmptyElement = {
val startOpen = accept(XML_START_OPEN)
val name = accept(XML_NAME)
val attributes = ListBuffer[(Option[Token], XmlAttribute)]()
var whitespaceOption: Option[Token] = None
while (!XML_EMPTY_CLOSE) {
whitespaceOption = nextTokenIf(XML_WHITESPACE)
currentTokenType match {
case XML_NAME ⇒
val attribute = xmlAttribute(isPattern)
attributes += ((whitespaceOption, attribute))
whitespaceOption = None
case XML_EMPTY_CLOSE ⇒
// End loop
case _ ⇒
throw new ScalaParserException("Expected XML attribute or end of tag: " + currentToken)
}
}
val emptyClose = accept(XML_EMPTY_CLOSE)
XmlEmptyElement(startOpen, name, attributes.toList, whitespaceOption, emptyClose)
}
private def xmlEmbeddedScala(isPattern: Boolean): Expr = {
if (isPattern) {
val lbrace = accept(LBRACE)
val pats = seqPatterns()
val rbrace = accept(RBRACE)
makeExpr(lbrace, pats, rbrace)
} else
makeExpr(blockExpr())
}
private def xmlEndTag(): XmlEndTag = {
val endOpen = accept(XML_END_OPEN)
val name = accept(XML_NAME)
val whitespaceOption = nextTokenIf(XML_WHITESPACE)
val tagClose = accept(XML_TAG_CLOSE)
XmlEndTag(endOpen, name, whitespaceOption, tagClose)
}
private def xmlNonEmptyElement(isPattern: Boolean): XmlNonEmptyElement = {
val startTag = xmlStartTag(isPattern)
val contents = ListBuffer[XmlContents]()
while (!XML_END_OPEN) {
val content = currentTokenType match {
case XML_START_OPEN ⇒ xmlElement(isPattern)
case XML_PCDATA ⇒ XmlPCDATA(nextToken())
case XML_COMMENT ⇒ XmlComment(nextToken())
case XML_CDATA ⇒ XmlCDATA(nextToken())
case XML_UNPARSED ⇒ XmlUnparsed(nextToken())
case XML_PROCESSING_INSTRUCTION ⇒ XmlProcessingInstruction(nextToken())
case LBRACE ⇒ xmlEmbeddedScala(isPattern)
case _ ⇒ throw new ScalaParserException("Unexpected token in XML: " + currentToken)
}
contents += content
}
val endTag = xmlEndTag()
XmlNonEmptyElement(startTag, contents.toList, endTag)
}
private def xmlElement(isPattern: Boolean): XmlElement = {
or(xmlNonEmptyElement(isPattern), xmlEmptyElement(isPattern))
}
private def xml(isPattern: Boolean): XmlExpr = {
def xmlContent(): XmlContents =
currentTokenType match {
case XML_START_OPEN ⇒ xmlElement(isPattern)
case XML_PCDATA ⇒ XmlPCDATA(nextToken())
case XML_COMMENT ⇒ XmlComment(nextToken())
case XML_CDATA ⇒ XmlCDATA(nextToken())
case XML_UNPARSED ⇒ XmlUnparsed(nextToken())
case XML_PROCESSING_INSTRUCTION ⇒ XmlProcessingInstruction(nextToken())
case _ ⇒ throw new ScalaParserException("Expected XML: " + currentToken)
}
val first = xmlContent()
val otherContents = ListBuffer[XmlContents]()
while (XML_START_OPEN || XML_PCDATA) {
val content = if (XML_START_OPEN)
xmlElement(isPattern)
else
XmlPCDATA(accept(XML_PCDATA))
otherContents += content
}
XmlExpr(first, otherContents.toList)
}
private def xmlLiteral() = xml(isPattern = false)
private def xmlLiteralPattern() = xml(isPattern = true)
private var tokensArray: Array[Token] = tokens.toArray
private var pos = 0
private def currentToken: Token = this(pos)
private def apply(pos: Int): Token =
if (pos < tokensArray.length)
tokensArray(pos)
else
tokens.last
private def currentTokenType = currentToken.tokenType
/** @return the token before advancing */
private def nextToken(): Token = {
val token = currentToken
pos += 1
if (logging)
println("nextToken(): " + token + " --> " + currentToken)
token
}
private def lookahead(n: Int): TokenType = this(pos + n).tokenType
private implicit def tokenType2Boolean(tokenType: TokenType): Boolean = currentTokenType == tokenType
private def caseClass = CASE && lookahead(1) == CLASS
private def caseObject = CASE && lookahead(1) == OBJECT
private def justCase = CASE && lookahead(1) != CLASS && lookahead(1) != OBJECT
private abstract sealed class Location
private case object Local extends Location
private case object InBlock extends Location
private case object InTemplate extends Location
private def isLeftAssoc(token: Token) =
token.getText.size > 0 && token.getText.last != ':'
private def isVariableName(name: String): Boolean = {
val first = name(0)
((first.isLower && first.isLetter) || first == '_')
}
private def isVarPattern(token: Token) = {
isIdent(token.tokenType) &&
isVariableName(token.getText) &&
!token.getText.startsWith("`")
}
private def optional[T](p: ⇒ T): Option[T] =
or(Some(p), None)
private def or[T](p1: ⇒ T, p2: ⇒ T): T = {
val originalPos = pos
try {
p1
} catch {
case e: ScalaParserException ⇒
pos = originalPos
if (logging) println("Rewinding to try alternative: " + currentToken)
p2
}
}
private def nextTokenIf(tokenType: TokenType): Option[Token] = {
if (tokenType) {
val token = currentToken
nextToken()
Some(token)
} else
None
}
private def log[T](s: String)(f: ⇒ T): T = {
if (logging) {
println("Enter " + s + " [" + currentToken + "]")
val result = f
println("Exit " + s + " [" + currentToken + "]")
result
} else
f
}
}
object ScalaParser {
/**
* Parse the given text as a compilation unit or script
* @return None if there is a parse error.
*/
def parse(text: String): Option[AstNode] = {
val parser = new ScalaParser(ScalaLexer.tokenise(text).toArray)
parser.safeParse(parser.compilationUnitOrScript)
}
trait ExprElementFlattenable { def elements: List[ExprElement] }
case class ExprElements(elements: List[ExprElement]) extends ExprElementFlattenable
def exprElementFlatten[T <% ExprElementFlattenable]: (T ⇒ List[ExprElement]) = t ⇒ { exprElementFlatten2(t) }
def exprElementFlatten2[T <% ExprElementFlattenable](t: T): List[ExprElement] = groupGeneralTokens(t.elements)
def groupGeneralTokens(xs: List[ExprElement]): List[ExprElement] = {
val eq = (x: ExprElement, y: ExprElement) ⇒ (x, y) match {
case (GeneralTokens(_), GeneralTokens(_)) ⇒ true
case _ ⇒ false
}
val groups = groupBy(eq, xs)
groups map { group ⇒
{
val item = group.head
var tokens: List[Token] = List()
if (item.isInstanceOf[GeneralTokens]) {
for (groupItem ← group)
tokens = tokens ::: groupItem.asInstanceOf[GeneralTokens].tokens
val result = GeneralTokens(tokens)
result
} else
item
}
}
}
implicit def tokenToExprFlattenable(token: Token): ExprElementFlattenable = GeneralTokens(List(token))
implicit def listOfTokenToExprFlattenable(tokens: List[Token]): ExprElementFlattenable = GeneralTokens(tokens)
implicit def exprToExprFlattenable(expr: Expr): ExprElementFlattenable = expr.contents
implicit def exprElementToExprFlattenable(exprElement: ExprElement): ExprElementFlattenable = ExprElements(List(exprElement))
implicit def ordinaryPairToExprFlattenable[A <% ExprElementFlattenable, B <% ExprElementFlattenable](pair: (A, B)): ExprElementFlattenable =
ExprElements(pair._1.elements ::: pair._2.elements)
implicit def tripleToExprFlattenable[A <% ExprElementFlattenable, B <% ExprElementFlattenable, C <% ExprElementFlattenable](triple: (A, B, C)): ExprElementFlattenable =
ExprElements(triple._1.elements ::: triple._2.elements ::: triple._3.elements)
implicit def eitherToExprFlattenable[A <% ExprElementFlattenable, B <% ExprElementFlattenable](either: Either[A, B]): ExprElementFlattenable = ExprElements(either match {
case Left(x) ⇒ x.elements
case Right(x) ⇒ x.elements
})
implicit def optionToExprFlattenable[T <% ExprElementFlattenable](option: Option[T]): ExprElementFlattenable = option.toList
implicit def listToExprFlattenable[T <% ExprElementFlattenable](list: List[T]): ExprElementFlattenable = ExprElements(list flatMap { _.elements })
implicit def vectorToExprFlattenable[T <% ExprElementFlattenable](vector: Vector[T]): ExprElementFlattenable = ExprElements(vector.toList flatMap { _.elements })
def makeExpr(flattenables: ExprElementFlattenable*): Expr =
Expr(flattenables.toList flatMap { _.elements })
trait TypeElementFlattenable { def elements: List[TypeElement] }
case class TypeElements(val elements: List[TypeElement]) extends TypeElementFlattenable
def typeElementFlatten[T <% TypeElementFlattenable]: (T ⇒ List[TypeElement]) = _.elements
def typeElementFlatten2[T <% TypeElementFlattenable](t: T): List[TypeElement] = t.elements
def typeElementFlatten3(flattenables: TypeElementFlattenable*): List[TypeElement] = flattenables.toList flatMap { _.elements }
implicit def tokenToTypeFlattenable(token: Token): TypeElementFlattenable = GeneralTokens(List(token))
implicit def listOfTokenToTypeFlattenable(tokens: List[Token]): TypeElementFlattenable = GeneralTokens(tokens)
implicit def typeElementToTypeFlattenable(typeElement: TypeElement): TypeElementFlattenable = TypeElements(List(typeElement))
implicit def eitherToTypeFlattenable[A <% TypeElementFlattenable, B <% TypeElementFlattenable](either: Either[A, B]): TypeElementFlattenable = TypeElements(either match {
case Left(x) ⇒ x.elements
case Right(x) ⇒ x.elements
})
implicit def pairToTypeFlattenable[A <% TypeElementFlattenable, B <% TypeElementFlattenable](pair: (A, B)): TypeElementFlattenable =
TypeElements(pair._1.elements ::: pair._2.elements)
implicit def tripleToTypeFlattenable[A <% TypeElementFlattenable, B <% TypeElementFlattenable, C <% TypeElementFlattenable](triple: (A, B, C)): TypeElementFlattenable =
TypeElements(triple._1.elements ::: triple._2.elements ::: triple._3.elements)
implicit def optionToTypeFlattenable[T <% TypeElementFlattenable](option: Option[T]): TypeElementFlattenable = option.toList
implicit def listToTypeFlattenable[T <% TypeElementFlattenable](list: List[T]): TypeElementFlattenable = TypeElements(list flatMap { _.elements })
}
// Not AST nodes, used as an intermediate structures during parsing:
case class TemplateOpt(templateInheritanceSectionOpt: Option[TemplateInheritanceSection], templateBodyOpt: Option[TemplateBody])
case class PrePackageBlock(name: CallExpr, newlineOpt: Option[Token], lbrace: Token, topStats: StatSeq, rbrace: Token) {
def complete(packageToken: Token) = PackageBlock(packageToken, name, newlineOpt, lbrace, topStats, rbrace)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy