@@ -35,7 +35,7 @@ grammar Python3;
35
35
// All comments that start with "///" are copy-pasted from
36
36
// The Python Language Reference
37
37
38
- tokens { INDENT, DEDENT }
38
+ tokens { INDENT, DEDENT, INDENT_ERROR }
39
39
40
40
@lexer::members {
41
41
// new version with semantic actions in parser
@@ -167,6 +167,20 @@ tokens { INDENT, DEDENT }
167
167
return dedent;
168
168
}
169
169
170
+ private Token createIndentError() {
171
+ // For some reason, CPython sets the error position to the end of line
172
+ int cur = getCharIndex();
173
+ String s;
174
+ do {
175
+ s = _input.getText(new Interval(cur, cur));
176
+ cur++;
177
+ } while (!s.isEmpty() && s.charAt(0) != ' \n ' );
178
+ cur--;
179
+ CommonToken error = new CommonToken(this._tokenFactorySourcePair, Python3Parser.INDENT_ERROR , DEFAULT_TOKEN_CHANNEL , cur, cur);
180
+ error.setLine(this.lastToken.getLine());
181
+ return error;
182
+ }
183
+
170
184
private CommonToken commonToken(int type, String text) {
171
185
int stop = Math.max(this.getCharIndex() - 1 , 0 );
172
186
int start = Math.max(text.isEmpty() ? stop : stop - text.length() + 1 , 0 );
@@ -1773,10 +1787,14 @@ NEWLINE
1773
1787
}
1774
1788
else {
1775
1789
// Possibly emit more than 1 DEDENT token.
1776
- while (!indents.isEmpty() && indents.peek() > indent) {
1790
+ while (!indents.isEmpty() && indents.peek() > indent) {
1777
1791
this.emit(createDedent());
1778
1792
indents.pop();
1779
1793
}
1794
+ int expectedIndent = indents.empty() ? 0 : indents.peek();
1795
+ if (expectedIndent != indent) {
1796
+ this.emit(createIndentError());
1797
+ }
1780
1798
}
1781
1799
}
1782
1800
}
0 commit comments