Fix error recovery on early finished statements #453

This commit is contained in:
Simon Binder 2020-03-21 22:02:27 +01:00
parent 5d6fcec438
commit d533a0a254
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
2 changed files with 30 additions and 8 deletions

View File

@ -376,20 +376,27 @@ class Parser extends ParserBase
T result; T result;
try { try {
result = parser(); result = parser();
if (result != null) {
result.semicolon = _consume(TokenType.semicolon,
'Expected a semicolon after the statement ended');
result.setSpan(first, _previous);
}
} on ParsingError { } on ParsingError {
_lastStmtHadParsingError = true; _lastStmtHadParsingError = true;
// the error is added to the list errors, so ignore. We skip after the // the error is added to the list errors, so ignore. We skip after the
// next semicolon to parse the next statement. // next semicolon to parse the next statement.
_synchronize(TokenType.semicolon, skipTarget: true); _synchronize(TokenType.semicolon, skipTarget: true);
if (result == null) return null;
if (_matchOne(TokenType.semicolon)) {
result.semicolon = _previous;
}
result.setSpan(first, _previous);
} }
if (result == null) return null;
if (_matchOne(TokenType.semicolon)) {
result.semicolon = _previous;
}
result.setSpan(first, _previous);
return result; return result;
} }

View File

@ -11,7 +11,7 @@ CREATE TABLE tbl (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT, id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
-- this is a single-line comment -- this is a single-line comment
place VARCHAR REFERENCES other(location) place VARCHAR REFERENCES other(location)
) AS RowName ) AS RowName;
all: SELECT /* COUNT(*), */ * FROM tbl WHERE $predicate; all: SELECT /* COUNT(*), */ * FROM tbl WHERE $predicate;
@special: SELECT * FROM tbl; @special: SELECT * FROM tbl;
@ -111,4 +111,19 @@ void main() {
isNot(contains(const TypeMatcher<DeclaredStatement>())), isNot(contains(const TypeMatcher<DeclaredStatement>())),
); );
}); });
test('syntax errors contain correct position', () {
final engine = SqlEngine(EngineOptions(useMoorExtensions: true));
final result = engine.parseMoorFile('''
worksByComposer:
SELECT DISTINCT A.* FROM works A, works B ON A.id = B.part_of
WHERE A.composer = :id OR B.composer = :id;
''');
expect(result.errors, hasLength(1));
expect(
result.errors.single,
isA<ParsingError>()
.having((e) => e.token.lexeme, 'token.lexeme', 'ON'));
});
} }