Skip to content

Commit c098148

Browse files
committed
Enforce balanced parens
Added check and forced a parsing error if parens are not matched Added notes to do a large refactor in the future for better parsing of parens resolves #80
1 parent c44c27b commit c098148

File tree

4 files changed

+74
-2
lines changed

4 files changed

+74
-2
lines changed

src/parser/lexer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ export const UsingScopeEnumeration = createToken({
8989
pattern: Lexer.NA,
9090
});
9191

92+
// This is a token that will be invoked to force a parsing error if there is a paren mismatch
93+
export const RParenMismatch = createToken({
94+
name: 'RParenMismatch',
95+
pattern: Lexer.NA,
96+
});
97+
9298
const identifierRegex = /[a-zA-Z][a-zA-Z0-9_.]*/y;
9399

94100
/**

src/parser/parser.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ export class SoqlParser extends CstParser {
166166
this.SUBRULE(this.whereClauseExpression, { ARGS: [parenCount] });
167167
},
168168
});
169+
170+
// TODO: this is a hack and the paren expressions should be re-worked, but it is a significant amount of work and difficult to handle in the visitor
171+
// If There are more open parens than closing parens, force parsing error - RParenMismatch is not a valid token and does not have a pattern
172+
// Because we are not actually doing any calculations with results, our strategy for calculating parens within an expression is semi-ok
173+
// but should be considered for a refactor at some point
174+
this.ACTION(() => {
175+
const parenMatch = parenCount.left - parenCount.right;
176+
if (parenMatch !== 0) {
177+
this.CONSUME(lexer.RParenMismatch);
178+
}
179+
});
169180
});
170181

171182
private whereClauseSubqueryIdentifier = this.RULE('whereClauseSubqueryIdentifier', () => {

test/test-cases-for-is-valid.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,60 @@ export const testCases: TestCaseForFormat[] = [
286286
soql: `SELECT Id, Name FROM Opportunity WHERE Amount > USD5000`,
287287
isValid: true,
288288
},
289+
{
290+
testCase: 123,
291+
soql: `SELECT Id, Name FROM Opportunity WHERE (((((Amount > USD5000`,
292+
isValid: false,
293+
},
294+
{
295+
testCase: 124,
296+
soql: `SELECT Id, Name FROM Opportunity WHERE (((((Amount > USD5000))))`,
297+
isValid: false,
298+
},
299+
{
300+
testCase: 125,
301+
soql: `SELECT Id, Name FROM Opportunity WHERE (((((Amount > USD5000)))))`,
302+
isValid: true,
303+
},
304+
{
305+
testCase: 126,
306+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3')) AND (((Description = '4') OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
307+
isValid: true,
308+
},
309+
{
310+
testCase: 127,
311+
soql: `SELECT Id FROM Account WHERE ((Name = '1' OR Name = '2') AND Name = '3')) AND (((Description = '4') OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
312+
isValid: false,
313+
},
314+
{
315+
testCase: 128,
316+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2' AND Name = '3')) AND (((Description = '4') OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
317+
isValid: false,
318+
},
319+
{
320+
testCase: 129,
321+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3') AND (((Description = '4') OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
322+
isValid: false,
323+
},
324+
{
325+
testCase: 130,
326+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3') AND (((Description = '4') OR (Id = '5' AND Id = '6')) AND Id = '7'`,
327+
isValid: false,
328+
},
329+
{
330+
testCase: 131,
331+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3')) AND ((Description = '4') OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
332+
isValid: false,
333+
},
334+
{
335+
testCase: 132,
336+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3')) AND (((Description = '4' OR (Id = '5' AND Id = '6'))) AND Id = '7'`,
337+
isValid: false,
338+
},
339+
{
340+
testCase: 133,
341+
soql: `SELECT Id FROM Account WHERE (((Name = '1' OR Name = '2') AND Name = '3')) AND (((Description = '4') OR Id = '5' AND Id = '6'))) AND Id = '7'`,
342+
isValid: false,
343+
},
289344
];
290345
export default testCases;

test/test.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ describe('parse queries', () => {
4040

4141
// describe.only('Test valid queries', () => {
4242
// testCasesForIsValid
43-
// .filter(testCase => testCase.testCase === 122)
43+
// .filter(testCase => testCase.testCase === 123)
4444
// .forEach(testCase => {
4545
// it(`should identify validity of query - test case ${testCase.testCase} - ${testCase.soql}`, () => {
46-
// const soqlQuery = parseQuery(testCase.soql, testCase.options);
46+
// // const soqlQuery = parseQuery(testCase.soql, testCase.options);
4747
// const isValid = isQueryValid(testCase.soql);
4848
// expect(isValid).equal(testCase.isValid);
4949
// });

0 commit comments

Comments
 (0)