From c2819ea713ea1d1e749b6dbeae34d992f530d064 Mon Sep 17 00:00:00 2001 From: Bronley Date: Tue, 26 Jan 2021 03:01:26 -0500 Subject: [PATCH] Fix infinite loop when parsing empty @ symbol for annotation --- src/parser/Parser.spec.ts | 14 +++++++++++++- src/parser/Parser.ts | 12 +++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts index d9d782aba..c990c1eae 100644 --- a/src/parser/Parser.spec.ts +++ b/src/parser/Parser.spec.ts @@ -644,7 +644,19 @@ describe('parser', () => { sub main() end sub `, ParseMode.BrighterScript); - expect(diagnostics[0]?.code).to.equal(1081); //unexpected token '@' + expect(diagnostics[0]?.message).to.equal(DiagnosticMessages.foundUnexpectedToken('@').message); + }); + + it('properly handles empty annotation above class method', () => { + //this code used to cause an infinite loop, so the fact that the test passes/fails on its own is a success! + let { diagnostics } = parse(` + class Person + @ + sub new() + end sub + end class + `, ParseMode.BrighterScript); + expect(diagnostics[0]?.message).to.equal(DiagnosticMessages.expectedIdentifier().message); }); it('parses with error if annotation is not followed by a statement', () => { diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index dedee75d9..f4884a4b8 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -382,7 +382,7 @@ export class Parser { let decl: Statement; let accessModifier: Token; - if (this.check(TokenKind.At) && this.checkNext(TokenKind.Identifier)) { + if (this.check(TokenKind.At)) { this.annotationExpression(); } @@ -1174,10 +1174,12 @@ export class Parser { } private annotationExpression() { - let annotation = new AnnotationExpression( - this.advance(), - this.advance() - ); + const atToken = this.advance(); + const identifier = this.tryConsume(DiagnosticMessages.expectedIdentifier(), TokenKind.Identifier, ...AllowedProperties); + if (identifier) { + identifier.kind = TokenKind.Identifier; + } + let annotation = new AnnotationExpression(atToken, identifier); this.pendingAnnotations.push(annotation); //optional arguments