8000 Make sure statement-continuing keywords are indented the same as thei… · aposteriorist/python@6df51c0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6df51c0

Browse files
committed
Make sure statement-continuing keywords are indented the same as their statement
FIX: Fix a bug where keywords like `else` or `except` would be consumed even if they don't match the indentation of the parent statement. Closes lezer-parser#3
1 parent c7e0bc9 commit 6df51c0
8000

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

src/python.grammar

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,19 @@ compoundStatement[@export] {
7878
DecoratedStatement { Decorator+ (ClassDefinition | FunctionDefinition) }
7979
}
8080

81-
elseClause { kw<"else"> Body }
81+
elseClause { _else Body }
8282

8383
IfStatement {
8484
kw<"if"> testNamed Body
85-
(kw<"elif"> testNamed? Body)*
85+
(_elif testNamed? Body)*
8686
elseClause?
8787
}
8888

8989
TryStatement {
9090
kw<"try"> Body
91-
(kw<"except"> (test ((kw<"as"> | ",") VariableName)?)? Body)*
91+
(_except (test ((kw<"as"> | ",") VariableName)?)? Body)*
9292
elseClause?
93-
(kw<"finally"> Body)?
93+
(_finally Body)?
9494
}
9595

9696
Body { ":" (simpleStatement | newline continueBody statement (continueBody statement)* (endBody | eof)) }
@@ -206,6 +206,13 @@ FormatReplacement { "{" (YieldExpression | commaSep<"*"? test>) FormatConversion
206206

207207
@external tokens legacyPrint from "./tokens.js" { printKeyword[@name="print"] }
208208

209+
@external tokens statementContinueKeyword from "./tokens" {
210+
_else[@name="else"],
211+
_elif[@name="elif"],
212+
_except[@name="except"],
213+
_finally[@name="finally"]
214+
}
215+
209216
@tokens {
210217
CompareOp { "<" | ">" | $[<>=!] "=" | "<>" }
211218

src/tokens.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {ExternalTokenizer} from "lezer"
22
import {
33
newline as newlineToken, eof, newlineEmpty, newlineBracketed, continueBody, endBody,
4+
_else, _elif, _except, _finally,
45
ParenthesizedExpression, TupleExpression, ComprehensionExpression, ArrayExpression, ArrayComprehensionExpression,
56
DictionaryExpression, DictionaryComprehensionExpression, SetExpression, SetComprehensionExpression,
67
compoundStatement,
@@ -113,6 +114,20 @@ export const bodyContinue = new ExternalTokenizer((input, token, stack) => {
113114
token.accept(indentHere <= parentIndent ? endBody : continueBody, token.start)
114115
}, {contextual: true, fallback: true})
115116

117+
let keywords = {else: _else, elif: _elif, except: _except, finally: _finally}
118+
119+
// Matches else/elif/except/finally, but only when at same indentation
120+
// as their parent statement
121+
export const statementContinueKeyword = new ExternalTokenizer((input, token, stack) => {
122+
let pos = token.start, next = input.get(token.start), m
123+
if (next == 101 /* 'e' */ && (m = /^(?:else|elif|except)\b/.exec(input.read(pos, pos + 7))) ||
124+
next == 102 /* 'f' */ && (m = /^finally\b/.exec(input.read(pos, pos + 8)))) {
125+
let parent = stack.startOf(parentStatement)
126+
let parentIndent = parent == null ? 0 : getIndent(input, parent)
127+
if (getIndent(input, token.start) == parentIndent) token.accept(keywords[m[0]], pos + m[0].length)
128+
}
129+
}, {contextual: true, fallback: true})
130+
116131
export const legacyPrint = new ExternalTokenizer((input, token) => {
117132
let pos = token.start
118133
for (let print = "print", i = 0; i < print.length; i++, pos++)

test/statement.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,17 @@ pass
296296
==>
297297

298298
Script(FunctionDefinition(def,VariableName,ParamList,Body(⚠)), PassStatement(pass))
299+
300+
# Nested else
301+
302+
if a:
303+
if b:
304+
pass
305+
else:
306+
pass
307+
308+
==>
309+
310+
Script(IfStatement(if, VariableName, Body(
311+
IfStatement(if, VariableName, Body(PassStatement(pass)))),
312+
else, Body(PassStatement(pass))))

0 commit comments

Comments
 (0)
0