Skip to content

Commit e1a2930

Browse files
alxhubzarend
authored andcommitted
fix(compiler): avoid parsing EmptyExpr with a backwards span (#41581)
`EmptyExpr` is somewhat unique, in that it's constructed in a circumstance where the parser has been looking for a particular token or string of tokens and has failed to find any. This means the parser state when constructing `EmptyExpr` is fairly unique. This gives rise to a bug where the parser constructs `EmptyExpr` with a backwards span - a `start` value that's beyond the `end` value. This likely happens because of the strange state the parser is in when recovering with `EmptyExpr`. This commit adds a backstop/workaround to avoid constructing such broken `EmptyExpr` spans (or any other kind of span). Eventually, the parser state should be fixed such that this does not occur, but that requires a significant change to the parser's functionality, so a simple fix in th interim is in order. PR Close #41581
1 parent 34545ad commit e1a2930

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

packages/compiler/src/expression_parser/parser.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,19 @@ export class _ParseAST {
461461
if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
462462
endIndex = artificialEndIndex;
463463
}
464+
465+
// In some unusual parsing scenarios (like when certain tokens are missing and an `EmptyExpr` is
466+
// being created), the current token may already be advanced beyond the `currentEndIndex`. This
467+
// appears to be a deep-seated parser bug.
468+
//
469+
// As a workaround for now, swap the start and end indices to ensure a valid `ParseSpan`.
470+
// TODO(alxhub): fix the bug upstream in the parser state, and remove this workaround.
471+
if (start > endIndex) {
472+
const tmp = endIndex;
473+
endIndex = start;
474+
start = tmp;
475+
}
476+
464477
return new ParseSpan(start, endIndex);
465478
}
466479

packages/compiler/test/expression_parser/parser_spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ describe('parser', () => {
188188
checkAction('a.add(1, 2)');
189189
checkAction('fn().add(1, 2)');
190190
});
191+
192+
it('should parse an EmptyExpr with a correct span for a trailing empty argument', () => {
193+
const ast = parseAction('fn(1, )').ast as MethodCall;
194+
expect(ast.args[1]).toBeAnInstanceOf(EmptyExpr);
195+
const sourceSpan = (ast.args[1] as EmptyExpr).sourceSpan;
196+
expect([sourceSpan.start, sourceSpan.end]).toEqual([5, 6]);
197+
});
191198
});
192199

193200
describe('functional calls', () => {

0 commit comments

Comments
 (0)