@@ -69,7 +69,7 @@ object Parsers {
69
69
* if not, the AST will be supplemented.
70
70
*/
71
71
def parser (source : SourceFile )(implicit ctx : Context ): Parser =
72
- if ( source.isSelfContained) new ScriptParser (source)
72
+ if source.isSelfContained then new ScriptParser (source)
73
73
else new Parser (source)
74
74
75
75
abstract class ParserCommon (val source : SourceFile )(implicit ctx : Context ) {
@@ -181,7 +181,7 @@ object Parsers {
181
181
182
182
/* -------------- TOKEN CLASSES ------------------------------------------- */
183
183
184
- def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT
184
+ def isIdent = in.isIdent
185
185
def isIdent (name : Name ) = in.token == IDENTIFIER && in.name == name
186
186
def isSimpleLiteral = simpleLiteralTokens contains in.token
187
187
def isLiteral = literalTokens contains in.token
@@ -207,16 +207,15 @@ object Parsers {
207
207
} && ! in.isSoftModifierInModifierPosition
208
208
209
209
def isExprIntro : Boolean =
210
- canStartExpressionTokens .contains(in.token) && ! in.isSoftModifierInModifierPosition
210
+ in.canStartExprTokens .contains(in.token) && ! in.isSoftModifierInModifierPosition
211
211
212
212
def isDefIntro (allowedMods : BitSet , excludedSoftModifiers : Set [TermName ] = Set .empty): Boolean =
213
213
in.token == AT ||
214
214
(defIntroTokens `contains` in.token) ||
215
215
(allowedMods `contains` in.token) ||
216
216
in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
217
217
218
- def isStatSep : Boolean =
219
- in.token == NEWLINE || in.token == NEWLINES || in.token == SEMI
218
+ def isStatSep : Boolean = in.isNewLine || in.token == SEMI
220
219
221
220
/** A '$' identifier is treated as a splice if followed by a `{`.
222
221
* A longer identifier starting with `$` is treated as a splice/id combination
@@ -341,10 +340,8 @@ object Parsers {
341
340
/** semi = nl {nl} | `;'
342
341
* nl = `\n' // where allowed
343
342
*/
344
- def acceptStatSep (): Unit = in.token match {
345
- case NEWLINE | NEWLINES => in.nextToken()
346
- case _ => accept(SEMI )
347
- }
343
+ def acceptStatSep (): Unit =
344
+ if in.isNewLine then in.nextToken() else accept(SEMI )
348
345
349
346
def acceptStatSepUnlessAtEnd (altEnd : Token = EOF ): Unit =
350
347
if (! isStatSeqEnd)
@@ -354,7 +351,7 @@ object Parsers {
354
351
case NEWLINE | NEWLINES => in.nextToken()
355
352
case SEMI => in.nextToken()
356
353
case _ =>
357
- syntaxError(i " end of statement expected but $in found " )
354
+ syntaxError(i " end of statement expected but ${showToken(in.token)} found " )
358
355
in.nextToken() // needed to ensure progress; otherwise we might cycle forever
359
356
accept(SEMI )
360
357
}
@@ -603,9 +600,7 @@ object Parsers {
603
600
val t = body()
604
601
// Therefore, make sure there would be a matching <outdent>
605
602
def nextIndentWidth = in.indentWidth(in.next.offset)
606
- if (in.token == NEWLINE || in.token == NEWLINES )
607
- && ! (nextIndentWidth < startIndentWidth)
608
- then
603
+ if in.isNewLine && ! (nextIndentWidth < startIndentWidth) then
609
604
warning(
610
605
if startIndentWidth <= nextIndentWidth then
611
606
i """ Line is indented too far to the right, or a `{' is missing before:
@@ -623,7 +618,7 @@ object Parsers {
623
618
* statement that's indented relative to the current region.
624
619
*/
625
620
def checkNextNotIndented (): Unit = in.currentRegion match
626
- case r : InBraces if in.token == NEWLINE || in.token == NEWLINES =>
621
+ case r : IndentSignificantRegion if in.isNewLine =>
627
622
val nextIndentWidth = in.indentWidth(in.next.offset)
628
623
if r.indentWidth < nextIndentWidth then
629
624
warning(i " Line is indented too far to the right, or a `{' is missing " , in.next.offset)
@@ -813,20 +808,20 @@ object Parsers {
813
808
else span
814
809
}
815
810
816
- /** Drop current token, which is assumed to be `then` or `do`. */
817
- def dropTerminator (): Unit = {
818
- var startOffset = in.offset
819
- var endOffset = in.lastCharOffset
820
- if ( in.isAfterLineEnd) {
821
- if (testChar(endOffset, ' ' ))
822
- endOffset += 1
823
- }
824
- else
825
- if (testChar(startOffset - 1 , ' ' ) &&
826
- ! overlapsPatch(source, Span (startOffset - 1 , endOffset)))
827
- startOffset -= 1
828
- patch(source, widenIfWholeLine( Span ( startOffset, endOffset)), " " )
829
- }
811
+ /** Drop current token, if it is a `then` or `do`. */
812
+ def dropTerminator (): Unit =
813
+ if in.token == THEN || in.token == DO then
814
+ var startOffset = in.offset
815
+ var endOffset = in.lastCharOffset
816
+ if (in.isAfterLineEnd) {
817
+ if (testChar( endOffset, ' ' ))
818
+ endOffset += 1
819
+ }
820
+ else
821
+ if (testChar (startOffset - 1 , ' ' ) &&
822
+ ! overlapsPatch(source, Span ( startOffset - 1 , endOffset)))
823
+ startOffset -= 1
824
+ patch(source, widenIfWholeLine( Span (startOffset, endOffset)), " " )
830
825
831
826
/** rewrite code with (...) around the source code of `t` */
832
827
def revertToParens (t : Tree ): Unit =
@@ -841,7 +836,8 @@ object Parsers {
841
836
/** In the tokens following the current one, does `query` precede any of the tokens that
842
837
* - must start a statement, or
843
838
* - separate two statements, or
844
- * - continue a statement (e.g. `else`, catch`)?
839
+ * - continue a statement (e.g. `else`, catch`), or
840
+ * - terminate the current scope?
845
841
*/
846
842
def followedByToken (query : Token ): Boolean = {
847
843
val lookahead = in.LookaheadScanner ()
@@ -875,7 +871,7 @@ object Parsers {
875
871
}
876
872
if (lookahead.token == LARROW )
877
873
false // it's a pattern
878
- else if (lookahead.token != IDENTIFIER && lookahead.token != BACKQUOTED_IDENT )
874
+ else if (lookahead.isIdent )
879
875
true // it's not a pattern since token cannot be an infix operator
880
876
else
881
877
followedByToken(LARROW ) // `<-` comes before possible statement starts
@@ -903,7 +899,7 @@ object Parsers {
903
899
*/
904
900
def followingIsGivenSig () =
905
901
val lookahead = in.LookaheadScanner ()
906
- if lookahead.token == IDENTIFIER || lookahead.token == BACKQUOTED_IDENT then
902
+ if lookahead.isIdent then
907
903
lookahead.nextToken()
908
904
while lookahead.token == LPAREN || lookahead.token == LBRACKET do
909
905
lookahead.skipParens()
@@ -1229,13 +1225,16 @@ object Parsers {
1229
1225
if (in.token == NEWLINE ) in.nextToken()
1230
1226
1231
1227
def newLinesOpt (): Unit =
1232
- if (in.token == NEWLINE || in.token == NEWLINES )
1233
- in.nextToken()
1228
+ if in.isNewLine then in.nextToken()
1234
1229
1235
1230
def newLineOptWhenFollowedBy (token : Int ): Unit =
1236
1231
// note: next is defined here because current == NEWLINE
1237
1232
if (in.token == NEWLINE && in.next.token == token) in.nextToken()
1238
1233
1234
+ def newLinesOptWhenFollowedBy (name : Name ): Unit =
1235
+ if in.isNewLine && in.next.token == IDENTIFIER && in.next.name == name then
1236
+ in.nextToken()
1237
+
1239
1238
def newLineOptWhenFollowing (p : Int => Boolean ): Unit =
1240
1239
// note: next is defined here because current == NEWLINE
1241
1240
if (in.token == NEWLINE && p(in.next.token)) newLineOpt()
@@ -1251,7 +1250,7 @@ object Parsers {
1251
1250
}
1252
1251
1253
1252
def possibleTemplateStart (): Unit = {
1254
- in.observeIndented(noIndentTemplateTokens, nme. derives )
1253
+ in.observeIndented()
1255
1254
newLineOptWhenFollowedBy(LBRACE )
1256
1255
}
1257
1256
@@ -1650,35 +1649,51 @@ object Parsers {
1650
1649
1651
1650
/* ----------- EXPRESSIONS ------------------------------------------------ */
1652
1651
1652
+ /** Does the current conditional expression continue after
1653
+ * the initially parsed (...) region?
1654
+ */
1655
+ def toBeContinued (altToken : Token ): Boolean =
1656
+ if in.token == altToken || in.isNewLine || in.isScala2Mode then
1657
+ false // a newline token means the expression is finished
1658
+ else if ! in.canStartStatTokens.contains(in.token)
1659
+ || in.isLeadingInfixOperator(inConditional = true )
1660
+ then
1661
+ true
1662
+ else
1663
+ followedByToken(altToken) // scan ahead to see whether we find a `then` or `do`
1664
+
1653
1665
def condExpr (altToken : Token ): Tree =
1654
- if ( in.token == LPAREN ) {
1666
+ if in.token == LPAREN then
1655
1667
var t : Tree = atSpan(in.offset) { Parens (inParens(exprInParens())) }
1656
- if (in.token != altToken && followedByToken (altToken) )
1657
- t = inSepRegion( LPAREN , RPAREN ) {
1658
- newLineOpt()
1668
+ val enclosedInParens = ! toBeContinued (altToken)
1669
+ if ! enclosedInParens then
1670
+ t = inSepRegion( LBRACE , RBRACE ) {
1659
1671
expr1Rest(postfixExprRest(simpleExprRest(t)), Location .ElseWhere )
1660
1672
}
1661
- if ( in.token == altToken) {
1662
- if ( rewriteToOldSyntax()) revertToParens(t)
1673
+ if in.token == altToken then
1674
+ if rewriteToOldSyntax() then revertToParens(t)
1663
1675
in.nextToken()
1664
- }
1665
- else {
1666
- in.observeIndented(noIndentAfterConditionTokens)
1676
+ else
1677
+ if (altToken == THEN || enclosedInParens) && in.isNewLine then
1678
+ in.observeIndented()
1679
+ if ! enclosedInParens && in.token != INDENT then accept(altToken)
1667
1680
if (rewriteToNewSyntax(t.span))
1668
1681
dropParensOrBraces(t.span.start, s " ${tokenString(altToken)}" )
1669
- }
1670
1682
t
1671
- }
1672
- else {
1683
+ else
1673
1684
val t =
1674
- if ( in.isNestedStart)
1685
+ if in.isNestedStart then
1675
1686
try expr() finally newLinesOpt()
1676
1687
else
1677
- inSepRegion(LPAREN , RPAREN )(expr())
1678
- if (rewriteToOldSyntax(t.span.startPos)) revertToParens(t)
1679
- accept(altToken)
1688
+ inSepRegion(LBRACE , RBRACE )(expr())
1689
+ if rewriteToOldSyntax(t.span.startPos) then
1690
+ revertToParens(t)
1691
+ if altToken == THEN && in.isNewLine then
1692
+ // don't require a `then` at the end of a line
1693
+ in.observeIndented()
1694
+ if in.token != INDENT then accept(altToken)
1680
1695
t
1681
- }
1696
+ end condExpr
1682
1697
1683
1698
/** Expr ::= [`implicit'] FunParams =>' Expr
1684
1699
* | Expr1
@@ -1841,20 +1856,20 @@ object Parsers {
1841
1856
}
1842
1857
}
1843
1858
case _ =>
1844
- if (isIdent(nme.inline) && ! in.inModifierPosition() && in.lookaheadIn(canStartExpressionTokens)) {
1859
+ if isIdent(nme.inline)
1860
+ && ! in.inModifierPosition()
1861
+ && in.lookaheadIn(in.canStartExprTokens)
1862
+ then
1845
1863
val start = in.skipToken()
1846
- in.token match {
1864
+ in.token match
1847
1865
case IF =>
1848
1866
ifExpr(start, InlineIf )
1849
1867
case _ =>
1850
1868
val t = postfixExpr()
1851
1869
if (in.token == MATCH ) matchExpr(t, start, InlineMatch )
1852
- else {
1870
+ else
1853
1871
syntaxErrorOrIncomplete(i " `match` or `if` expected but ${in.token} found " )
1854
1872
t
1855
- }
1856
- }
1857
- }
1858
1873
else expr1Rest(postfixExpr(), location)
1859
1874
}
1860
1875
@@ -2001,7 +2016,7 @@ object Parsers {
2001
2016
def postfixExpr (): Tree = postfixExprRest(prefixExpr())
2002
2017
2003
2018
def postfixExprRest (t : Tree ): Tree =
2004
- infixOps(t, canStartExpressionTokens , prefixExpr, maybePostfix = true )
2019
+ infixOps(t, in.canStartExprTokens , prefixExpr, maybePostfix = true )
2005
2020
2006
2021
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
2007
2022
*/
@@ -2198,7 +2213,7 @@ object Parsers {
2198
2213
lookahead.nextToken()
2199
2214
lookahead.token != COLON
2200
2215
}
2201
- else canStartExpressionTokens .contains(lookahead.token)
2216
+ else in.canStartExprTokens .contains(lookahead.token)
2202
2217
}
2203
2218
}
2204
2219
if (in.token == LPAREN && (! inClassConstrAnnots || isLegalAnnotArg))
@@ -2327,7 +2342,7 @@ object Parsers {
2327
2342
dropParensOrBraces(start, if (in.token == YIELD || in.token == DO ) " " else " do" )
2328
2343
}
2329
2344
}
2330
- in.observeIndented(noIndentAfterEnumeratorTokens )
2345
+ in.observeIndented()
2331
2346
res
2332
2347
}
2333
2348
else {
@@ -2473,7 +2488,7 @@ object Parsers {
2473
2488
/** InfixPattern ::= SimplePattern {id [nl] SimplePattern}
2474
2489
*/
2475
2490
def infixPattern (): Tree =
2476
- infixOps(simplePattern(), canStartExpressionTokens , simplePattern, isOperator = in.name != nme.raw.BAR )
2491
+ infixOps(simplePattern(), in.canStartExprTokens , simplePattern, isOperator = in.name != nme.raw.BAR )
2477
2492
2478
2493
/** SimplePattern ::= PatVar
2479
2494
* | Literal
@@ -3459,6 +3474,7 @@ object Parsers {
3459
3474
/** Template ::= InheritClauses [TemplateBody]
3460
3475
*/
3461
3476
def template (constr : DefDef , isEnum : Boolean = false ): Template = {
3477
+ newLinesOptWhenFollowedBy(nme.derives )
3462
3478
val (parents, derived) = inheritClauses()
3463
3479
possibleTemplateStart()
3464
3480
if (isEnum) {
@@ -3471,10 +3487,11 @@ object Parsers {
3471
3487
/** TemplateOpt = [Template]
3472
3488
*/
3473
3489
def templateOpt (constr : DefDef ): Template =
3474
- possibleTemplateStart( )
3490
+ newLinesOptWhenFollowedBy(nme. derives )
3475
3491
if in.token == EXTENDS || isIdent(nme.derives ) then
3476
3492
template(constr)
3477
3493
else
3494
+ possibleTemplateStart()
3478
3495
if in.isNestedStart then
3479
3496
template(constr)
3480
3497
else
0 commit comments