Skip to content

Commit e0a5be3

Browse files
committed
Better error messages for invalid syntax
1 parent f0a939d commit e0a5be3

File tree

3 files changed

+41
-24
lines changed

3 files changed

+41
-24
lines changed

client/src/test/diagnostics.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ suite('Should get diagnostics', () => {
9191
range: toRange(28, 7, 32, 8),
9292
severity: vscode.DiagnosticSeverity.Error,
9393
source: 'ex'
94+
},
95+
{
96+
message: 'Invalid syntax: InvalidSubCall(arg)',
97+
range: toRange(43, 4, 43, 23),
98+
severity: vscode.DiagnosticSeverity.Error,
99+
source: 'ex'
94100
}
95101
]);
96102
});
@@ -156,8 +162,8 @@ async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: vscode.D
156162

157163
expectedDiagnostics.forEach((expectedDiagnostic, i) => {
158164
const actualDiagnostic = actualDiagnostics[i];
159-
assert.equal(actualDiagnostic.message, expectedDiagnostic.message, "Message");
160-
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range, "Range");
161-
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity, "Severity");
165+
assert.equal(actualDiagnostic.message, expectedDiagnostic.message, `Message: expected '${expectedDiagnostic.message}' got '${actualDiagnostic.message}'.`);
166+
assert.deepEqual(actualDiagnostic.range, expectedDiagnostic.range, `Range: expected '${JSON.stringify(expectedDiagnostic.range)}' got '${JSON.stringify(actualDiagnostic.range)}'.`);
167+
assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity, `Severity: expected '${expectedDiagnostic.severity}' got '${actualDiagnostic.severity}'.`);
162168
});
163169
}

server/src/project/parser/vbaAntlr.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -90,48 +90,47 @@ export class VbaFmtParser extends vbafmtParser {
9090

9191
export class VbaErrorHandler extends DefaultErrorStrategy {
9292
override recover(recognizer: Parser, e: RecognitionException): void {
93+
// Try base recovery for some reason.
94+
super.recover(recognizer, e);
95+
9396
// Consume the error token if look-ahead is not EOF.
9497
const inputStream = recognizer.inputStream;
9598
if (inputStream.LA(1) !== Token.EOF) {
99+
const intervalSet = this.getErrorRecoverySet(recognizer);
100+
console.log(`recover consuming ${recognizer.getCurrentToken()}`);
96101
inputStream.consume();
102+
// this.consumeUntil(recognizer, intervalSet);
97103
}
98104
this.endErrorCondition(recognizer);
99105
}
100106

101107
override recoverInline(recognizer: Parser): Token {
102-
const stream = recognizer.inputStream;
103-
const thisToken = recognizer.getCurrentToken();
104-
105-
// Recover using deletion strategy.
106-
const nextToken = stream.LT(2);
107-
const expectedTokens = recognizer.getExpectedTokens();
108-
if (nextToken && expectedTokens.contains(nextToken.type)) {
109-
recognizer.consume();
110-
this.reportMatch(recognizer);
111-
return thisToken;
108+
// Attempt to recover using token deletion.
109+
const matchedSymbol = this.singleTokenDeletion(recognizer);
110+
if (matchedSymbol) {
111+
recognizer.consume();
112+
return matchedSymbol;
112113
}
113-
114-
// Failsafe to prevent circular insertions.
115-
const MAXRECURSION = -20;
116-
for (let i = -1; i >= MAXRECURSION; i--) {
117-
if (i <= -20) {
118-
throw new InputMismatchException(recognizer);
119-
}
120-
const wasInsertedToken = this.isTokenPositionMatch(thisToken, recognizer.inputStream.LT(i));
121-
if (!wasInsertedToken) {
122-
break;
123-
}
114+
// Attempt to recover using token insertion.
115+
if (this.singleTokenInsertion(recognizer)) {
116+
return this.getMissingSymbol(recognizer);
124117
}
125118

126119
// When we don't know what could come next, invalidate the entire line.
120+
const stream = recognizer.inputStream;
121+
const expectedTokens = recognizer.getExpectedTokens();
127122
if (expectedTokens.minElement === -1) {
128123
const invalidTokens: Token[] = [];
129124
while (![vbaLexer.NEWLINE, vbaLexer.EOF].includes(stream.LA(1))) {
130125
invalidTokens.push(stream.LT(1)!);
126+
console.log(`inline consuming ${recognizer.getCurrentToken()}`);
131127
recognizer.consume();
132128
}
133129
if (invalidTokens.length > 0) {
134130
const missingToken = this.createErrorToken(recognizer, invalidTokens);
131+
this.reportMatch(recognizer);
132+
console.log(`inline consuming ${recognizer.getCurrentToken()}`);
133+
recognizer.consume();
135134
return missingToken;
136135
}
137136
}

test/fixtures/Diagnostics.bas

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,15 @@ Public Enum UniqueNameEnumFoo
3030
Enum2
3131
Enum3
3232
End Enum
33+
34+
Public Sub CallsBadSub()
35+
Attribute CallsBadSub.VB_Description = "docstring."
36+
' docstring.
37+
'
38+
' Args:
39+
' param1:
40+
'
41+
' Raises:
42+
'
43+
InvalidSubCall(arg)
44+
End Sub

0 commit comments

Comments
 (0)