@@ -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 ) {
@@ -164,9 +164,9 @@ object Parsers {
164
164
}
165
165
}
166
166
167
- class Parser (source : SourceFile )(implicit ctx : Context ) extends ParserCommon (source) {
167
+ class Parser (source : SourceFile , startFrom : Offset = 0 )(implicit ctx : Context ) extends ParserCommon (source) {
168
168
169
- val in : Scanner = new Scanner (source)
169
+ val in : Scanner = new Scanner (source, startFrom )
170
170
171
171
val openParens : ParensCounters = new ParensCounters
172
172
@@ -813,20 +813,20 @@ object Parsers {
813
813
else span
814
814
}
815
815
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
- }
816
+ /** Drop current token, if it is a `then` or `do`. */
817
+ def dropTerminator (): Unit =
818
+ if in.token == THEN || in.token == DO then
819
+ var startOffset = in.offset
820
+ var endOffset = in.lastCharOffset
821
+ if (in.isAfterLineEnd) {
822
+ if (testChar( endOffset, ' ' ))
823
+ endOffset += 1
824
+ }
825
+ else
826
+ if (testChar (startOffset - 1 , ' ' ) &&
827
+ ! overlapsPatch(source, Span ( startOffset - 1 , endOffset)))
828
+ startOffset -= 1
829
+ patch(source, widenIfWholeLine( Span (startOffset, endOffset)), " " )
830
830
831
831
/** rewrite code with (...) around the source code of `t` */
832
832
def revertToParens (t : Tree ): Unit =
@@ -1251,7 +1251,7 @@ object Parsers {
1251
1251
}
1252
1252
1253
1253
def possibleTemplateStart (): Unit = {
1254
- in.observeIndented(noIndentTemplateTokens, nme.derives )
1254
+ in.observeIndented(unless = noIndentTemplateTokens, unlessSoftKW = nme.derives )
1255
1255
newLineOptWhenFollowedBy(LBRACE )
1256
1256
}
1257
1257
@@ -1650,35 +1650,87 @@ object Parsers {
1650
1650
1651
1651
/* ----------- EXPRESSIONS ------------------------------------------------ */
1652
1652
1653
+ def condExprRest (t : Tree ) =
1654
+ inSepRegion(LBRACE , RBRACE ) {
1655
+ newLineOpt()
1656
+ expr1Rest(postfixExprRest(simpleExprRest(t)), Location .ElseWhere )
1657
+ }
1658
+
1659
+ /** A then part can start after `)` if the next token can start a statement
1660
+ * and is not a leading infix operator.
1661
+ */
1662
+ def canStartThenPart =
1663
+ canStartStatTokens.contains(in.token)
1664
+ && ! in.isLeadingInfixOperator(inConditional = true )
1665
+
1666
+ /** Does the current conditional expression continue after
1667
+ * the initially parsed (...) region?
1668
+ */
1669
+ def toBeContinued (t : Tree , altToken : Token ): Boolean =
1670
+ if in.token == altToken || in.isNewLine then
1671
+ false // a newline token means the expression is finished
1672
+ else if ! canStartThenPart then
1673
+ true // since it can't be a then-part continue on the asumption that the expression continues
1674
+ else if ! canFollowParensTokens.contains(in.token) then
1675
+ false // the next token cannot follow `)` in an expression
1676
+ else
1677
+ val curIndentWidth = in.currentRegion.indentWidth
1678
+
1679
+ // Try a complete the expression in a separate parser
1680
+ object lookahead extends Parser (source, in.offset)
1681
+ private var hasErrors = false
1682
+ override def syntaxError (msg : => Message , span : Span ): Unit =
1683
+ hasErrors = true
1684
+
1685
+ def isCondSeparator =
1686
+ in.token == altToken
1687
+ || altToken == THEN
1688
+ && in.isNewLine
1689
+ && curIndentWidth < in.indentWidth(in.next.offset)
1690
+
1691
+ def isCondSuffix (): Boolean =
1692
+ while in.token == LPAREN || in.token == LBRACE || in.token == LBRACKET do
1693
+ in.skipParens()
1694
+ if isCondSeparator then
1695
+ true
1696
+ else if in.isNewLine then
1697
+ false // expression is finished, but no altToken was found
1698
+ else // try to complete expression
1699
+ condExprRest(t)
1700
+ ! hasErrors && isCondSeparator
1701
+ end lookahead
1702
+ lookahead.isCondSuffix()
1703
+ end toBeContinued
1704
+
1653
1705
def condExpr (altToken : Token ): Tree =
1654
- if ( in.token == LPAREN ) {
1706
+ if in.token == LPAREN then
1655
1707
var t : Tree = atSpan(in.offset) { Parens (inParens(exprInParens())) }
1656
- if (in.token != altToken && followedByToken(altToken))
1657
- t = inSepRegion(LPAREN , RPAREN ) {
1658
- newLineOpt()
1659
- expr1Rest(postfixExprRest(simpleExprRest(t)), Location .ElseWhere )
1660
- }
1661
- if (in.token == altToken) {
1662
- if (rewriteToOldSyntax()) revertToParens(t)
1708
+ val newSyntax = toBeContinued(t, altToken)
1709
+ if newSyntax then condExprRest(t)
1710
+ if in.token == altToken then
1711
+ if rewriteToOldSyntax() then revertToParens(t)
1663
1712
in.nextToken()
1664
- }
1665
- else {
1666
- in.observeIndented(noIndentAfterConditionTokens)
1713
+ else
1714
+ if (altToken == THEN || ! newSyntax) && in.isNewLine then
1715
+ in.observeIndented()
1716
+ if newSyntax && in.token != INDENT then accept(altToken)
1667
1717
if (rewriteToNewSyntax(t.span))
1668
1718
dropParensOrBraces(t.span.start, s " ${tokenString(altToken)}" )
1669
- }
1670
1719
t
1671
- }
1672
- else {
1720
+ else
1673
1721
val t =
1674
- if ( in.isNestedStart)
1722
+ if in.isNestedStart then
1675
1723
try expr() finally newLinesOpt()
1676
1724
else
1677
- inSepRegion(LPAREN , RPAREN )(expr())
1678
- if (rewriteToOldSyntax(t.span.startPos)) revertToParens(t)
1679
- accept(altToken)
1725
+ inSepRegion(LBRACE , RBRACE )(expr())
1726
+ if rewriteToOldSyntax(t.span.startPos) then
1727
+ revertToParens(t)
1728
+ if altToken == THEN && in.isNewLine then
1729
+ // don't require a `then` at the end of a line
1730
+ in.observeIndented()
1731
+ if in.token != INDENT then accept(altToken)
1680
1732
t
1681
- }
1733
+ end condExpr
1682
1734
1683
1735
/** Expr ::= [`implicit'] FunParams =>' Expr
1684
1736
* | Expr1
@@ -2327,7 +2379,7 @@ object Parsers {
2327
2379
dropParensOrBraces(start, if (in.token == YIELD || in.token == DO ) " " else " do" )
2328
2380
}
2329
2381
}
2330
- in.observeIndented(noIndentAfterEnumeratorTokens)
2382
+ in.observeIndented(unless = noIndentAfterEnumeratorTokens)
2331
2383
res
2332
2384
}
2333
2385
else {
0 commit comments