Skip to content

Commit 0e696ac

Browse files
oderskyneko-kai
authored andcommitted
Treat end markers as separate tokens
Detect end markers in Scanner
1 parent f236904 commit 0e696ac

File tree

5 files changed

+44
-27
lines changed

5 files changed

+44
-27
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ object Parsers {
167167
class Parser(source: SourceFile)(using Context) extends ParserCommon(source) {
168168

169169
val in: Scanner = new Scanner(source)
170+
// in.debugTokenStream = true // uncomment to see the token stream of the standard scanner, but not syntax highlighting
170171

171172
/** This is the general parse entry point.
172173
* Overridden by ScriptParser
@@ -1242,7 +1243,7 @@ object Parsers {
12421243
def possibleTemplateStart(isNew: Boolean = false): Unit =
12431244
in.observeColonEOL()
12441245
if in.token == COLONEOL then
1245-
if in.lookahead.isIdent(nme.end) then in.token = NEWLINE
1246+
if in.lookahead.token == END then in.token = NEWLINE
12461247
else
12471248
in.nextToken()
12481249
if in.token != INDENT && in.token != LBRACE then
@@ -1272,25 +1273,12 @@ object Parsers {
12721273
case _: (ForYield | ForDo) => in.token == FOR
12731274
case _ => false
12741275

1275-
if isIdent(nme.end) then
1276-
val start = in.offset
1277-
val isEndMarker =
1278-
val endLine = source.offsetToLine(start)
1279-
val lookahead = in.LookaheadScanner()
1280-
lookahead.nextToken()
1281-
source.offsetToLine(lookahead.offset) == endLine
1282-
&& endMarkerTokens.contains(in.token)
1283-
&& {
1284-
lookahead.nextToken()
1285-
lookahead.token == EOF
1286-
|| source.offsetToLine(lookahead.offset) > endLine
1287-
}
1288-
if isEndMarker then
1289-
in.nextToken()
1290-
if stats.isEmpty || !matches(stats.last) then
1291-
syntaxError("misaligned end marker", Span(start, in.lastCharOffset))
1292-
in.token = IDENTIFIER // Leaving it as the original token can confuse newline insertion
1293-
in.nextToken()
1276+
if in.token == END then
1277+
val start = in.skipToken()
1278+
if stats.isEmpty || !matches(stats.last) then
1279+
syntaxError("misaligned end marker", Span(start, in.lastCharOffset))
1280+
in.token = IDENTIFIER // Leaving it as the original token can confuse newline insertion
1281+
in.nextToken()
12941282
end checkEndMarker
12951283

12961284
/* ------------- TYPES ------------------------------------------------------ */

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,16 @@ object Scanners {
135135
*/
136136
protected def putChar(c: Char): Unit = litBuf.append(c)
137137

138-
/** Clear buffer and set name and token */
139-
def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = {
138+
/** Clear buffer and set name and token
139+
* If `target` is different from `this`, don't treat identifiers as end tokens
140+
*/
141+
def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit =
140142
target.name = termName(litBuf.chars, 0, litBuf.length)
141143
litBuf.clear()
142144
target.token = idtoken
143-
if (idtoken == IDENTIFIER)
144-
target.token = toToken(target.name)
145-
}
145+
if idtoken == IDENTIFIER then
146+
val converted = toToken(target.name)
147+
if converted != END || (target eq this) then target.token = converted
146148

147149
/** The token for given `name`. Either IDENTIFIER or a keyword. */
148150
def toToken(name: SimpleName): Token
@@ -656,6 +658,8 @@ object Scanners {
656658
() /* skip the trailing comma */
657659
else
658660
reset()
661+
case END =>
662+
if !isEndMarker then token = IDENTIFIER
659663
case COLON =>
660664
if fewerBracesEnabled then observeColonEOL()
661665
case RBRACE | RPAREN | RBRACKET =>
@@ -666,6 +670,21 @@ object Scanners {
666670
}
667671
}
668672

673+
protected def isEndMarker: Boolean =
674+
if isAfterLineEnd then
675+
val endLine = source.offsetToLine(offset)
676+
val lookahead = new LookaheadScanner():
677+
override def isEndMarker = false
678+
lookahead.nextToken()
679+
if endMarkerTokens.contains(lookahead.token)
680+
&& source.offsetToLine(lookahead.offset) == endLine
681+
then
682+
lookahead.nextToken()
683+
if lookahead.token == EOF
684+
|| source.offsetToLine(lookahead.offset) > endLine
685+
then return true
686+
false
687+
669688
/** Is there a blank line between the current token and the last one?
670689
* A blank line consists only of characters <= ' '.
671690
* @pre afterLineEnd().

compiler/src/dotty/tools/dotc/parsing/Tokens.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ object Tokens extends TokensCommon {
183183
final val GIVEN = 63; enter(GIVEN, "given")
184184
final val EXPORT = 64; enter(EXPORT, "export")
185185
final val MACRO = 65; enter(MACRO, "macro") // TODO: remove
186+
final val END = 66; enter(END, "end")
186187

187188
/** special symbols */
188189
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
@@ -207,7 +208,7 @@ object Tokens extends TokensCommon {
207208
/** XML mode */
208209
final val XMLSTART = 99; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
209210

210-
final val alphaKeywords: TokenSet = tokenRange(IF, MACRO)
211+
final val alphaKeywords: TokenSet = tokenRange(IF, END)
211212
final val symbolicKeywords: TokenSet = tokenRange(USCORE, CTXARROW)
212213
final val keywords: TokenSet = alphaKeywords | symbolicKeywords
213214

@@ -256,7 +257,7 @@ object Tokens extends TokensCommon {
256257
final val canStartStatTokens2: TokenSet = canStartExprTokens2 | mustStartStatTokens | BitSet(
257258
AT, CASE)
258259
final val canStartStatTokens3: TokenSet = canStartExprTokens3 | mustStartStatTokens | BitSet(
259-
AT, CASE)
260+
AT, CASE, END)
260261

261262
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT)
262263

tests/neg/i12150.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E018] Syntax Error: tests/neg/i12150.scala:1:13 --------------------------------------------------------------------
2+
1 |def f: Unit = // error
3+
| ^
4+
| expression expected but end found
5+
6+
longer explanation available when compiling with `-explain`

tests/neg/i12150.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def f: Unit = // error
2+
3+
end f

0 commit comments

Comments
 (0)