Skip to content

Commit 58259ec

Browse files
committed
Add test for pre compiler issues with parentheses
1 parent 6236665 commit 58259ec

File tree

5 files changed

+139
-1
lines changed

5 files changed

+139
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ template*
1212

1313
# Workspace settings
1414
.vscode-test
15-
.vscode/settings.json
15+
.vscode/settings.json
16+
server/out/

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
"test:textMate:unit": "vscode-tmgrammar-test ./test/textmate/**/*.vba",
163163
"test:textMate:snap": "vscode-tmgrammar-snap ./test/textmate/snapshot/*.??s",
164164
"test:vsc:unit": "vscode-test",
165+
"test:antlr:unit": "tsc --project server/tsconfig.json && npx mocha server/out/test/**/*.test.js",
165166
"testsh": "sh ./scripts/e2e.sh",
166167
"testps": "powershell ./scripts/e2e.ps1"
167168
},
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* Direct ANTLR parser test for VBA preprocessor grammar.
3+
*
4+
* This test directly uses the ANTLR parser to catch syntax errors and undesired implicit tokens (T__1, T__2, etc.)
5+
* without going through the VS Code diagnostics layer.
6+
*/
7+
8+
import { describe, it } from 'mocha';
9+
import * as assert from 'assert';
10+
import * as fs from 'fs';
11+
import * as path from 'path';
12+
import { VbaPreParser, VbaPreLexer } from '../project/parser/vbaAntlr';
13+
import { CharStream, CommonTokenStream } from 'antlr4ng';
14+
15+
describe('ANTLR VBA Preprocessor Parser', () => {
16+
17+
/**
18+
* Helper function to check and report implicit tokens
19+
*/
20+
function checkImplicitTokens(result: ReturnType<typeof parseAndGetErrors>): Array<{type: number, text: string, typeName: string}> {
21+
const implicitTokens = result.tokenInfo.filter(t => t.typeName.startsWith('T__'));
22+
if (implicitTokens.length > 0) {
23+
console.log(` ❌ Found ${implicitTokens.length} implicit token(s): ${implicitTokens.map(t => t.typeName).join(', ')}`);
24+
} else {
25+
console.log(' ✅ No implicit tokens found');
26+
}
27+
return implicitTokens;
28+
}
29+
30+
/**
31+
* Helper function to log parsing results consistently
32+
*/
33+
function logParsingResults(input: string, result: ReturnType<typeof parseAndGetErrors>) {
34+
console.log('\n 📝 Input:');
35+
const inputLines = input.split('\n');
36+
inputLines.forEach((line, index) => {
37+
// Show line numbers and preserve exact whitespace
38+
if (line.trim() || index < inputLines.length - 1) { // Show non-empty lines and all but the last empty line
39+
console.log(` ${(index + 1).toString().padStart(2)}: ${line}`);
40+
}
41+
});
42+
console.log(' 🔤 Tokens:');
43+
result.tokenInfo.forEach((t, i) => {
44+
const displayText = t.text.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
45+
console.log(` ${i.toString().padStart(2)}: ${t.typeName.padEnd(12)} = "${displayText}"`);
46+
});
47+
if (result.lexerErrors.length > 0) {
48+
console.log(' ❌ Lexer errors:', result.lexerErrors);
49+
}
50+
if (result.errors.length > 0) {
51+
console.log(' ❌ Parser errors:', result.errors);
52+
}
53+
console.log(` 📊 Syntax errors: ${result.syntaxErrors}`);
54+
}
55+
56+
/**
57+
* Test helper to parse input and collect syntax errors
58+
*/
59+
function parseAndGetErrors(input: string) {
60+
const lexer = VbaPreLexer.create(input);
61+
const tokens = new CommonTokenStream(lexer);
62+
const parser = new VbaPreParser(tokens);
63+
64+
// Collect all error information
65+
const errors: string[] = [];
66+
const lexerErrors: string[] = [];
67+
const tokenInfo: Array<{type: number, text: string, typeName: string}> = [];
68+
69+
lexer.removeErrorListeners();
70+
parser.removeErrorListeners();
71+
72+
// Get tokens for inspection
73+
tokens.fill();
74+
const allTokens = tokens.getTokens();
75+
for (const token of allTokens) {
76+
if (token.type !== -1) { // Skip EOF
77+
const typeName = lexer.vocabulary.getSymbolicName(token.type) || `T__${token.type - 1}`;
78+
tokenInfo.push({
79+
type: token.type,
80+
text: token.text || '',
81+
typeName: typeName
82+
});
83+
}
84+
}
85+
86+
// Try to parse
87+
let parseTree = null;
88+
try {
89+
parseTree = parser.startRule();
90+
} catch (error) {
91+
errors.push(`Parse exception: ${error}`);
92+
}
93+
94+
return {
95+
errors,
96+
lexerErrors,
97+
tokenInfo,
98+
syntaxErrors: parser.numberOfSyntaxErrors,
99+
parseTree
100+
};
101+
}
102+
103+
it('should parse function call with string literal and parentheses', () => {
104+
const testFilePath = path.join(__dirname, '../../../test/parser/pre/ParsingParentheses.bas');
105+
const input = fs.readFileSync(testFilePath, 'utf8');
106+
107+
const result = parseAndGetErrors(input);
108+
109+
logParsingResults(input, result);
110+
const implicitTokens = checkImplicitTokens(result);
111+
112+
// The test should fail if there are implicit T__ tokens for parentheses
113+
assert.strictEqual(result.syntaxErrors, 0, `Expected no syntax errors, but found: ${result.errors.join(', ')}`);
114+
assert.strictEqual(implicitTokens.length, 0, `Found implicit tokens: ${implicitTokens.map(t => t.typeName).join(', ')}`);
115+
});
116+
117+
it('should parse multiple function calls correctly', () => {
118+
const testFilePath = path.join(__dirname, '../../../test/parser/pre/TwoFunctionCalls.bas');
119+
const input = fs.readFileSync(testFilePath, 'utf8');
120+
121+
const result = parseAndGetErrors(input);
122+
123+
logParsingResults(input, result);
124+
const implicitTokens = checkImplicitTokens(result);
125+
126+
assert.strictEqual(result.syntaxErrors, 0);
127+
assert.strictEqual(implicitTokens.length, 0);
128+
});
129+
130+
131+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
y = Format( "Test '<'")
2+
3+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
result = Trim("hello")
2+
val = Left("test", 2)

0 commit comments

Comments
 (0)