From c158a680b545acc58376a91fe6d9e90f353af981 Mon Sep 17 00:00:00 2001 From: Bronley Date: Fri, 26 Feb 2021 22:30:22 -0500 Subject: [PATCH 1/2] Support ungrouped IIFE --- src/parser/Parser.spec.ts | 25 +++++++++++++++++++++++++ src/parser/Parser.ts | 8 +++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts index c990c1eae..03f2e7835 100644 --- a/src/parser/Parser.spec.ts +++ b/src/parser/Parser.spec.ts @@ -7,6 +7,7 @@ import { PrintStatement, FunctionStatement, NamespaceStatement, ImportStatement import { Range } from 'vscode-languageserver'; import { DiagnosticMessages } from '../DiagnosticMessages'; import { isBlock, isCommentStatement, isFunctionStatement, isIfStatement } from '../astUtils'; +import { expectZeroDiagnostics } from '../testHelpers.spec'; describe('parser', () => { it('emits empty object when empty token list is provided', () => { @@ -95,6 +96,30 @@ describe('parser', () => { }); describe('parse', () => { + it('supports ungrouped iife in assignment', () => { + const parser = parse(` + sub main() + result = sub() + end sub() + result = function() + end function() + end sub + `); + expectZeroDiagnostics(parser); + }); + + it('supports grouped iife in assignment', () => { + const parser = parse(` + sub main() + result = (sub() + end sub)() + result = (function() + end function)() + end sub + `); + expectZeroDiagnostics(parser); + }); + it('supports using "interface" as parameter name', () => { expect(parse(` sub main(interface as object) diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index 8cd0f4608..a13a34dbe 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -1937,7 +1937,13 @@ export class Parser { private anonymousFunction(): Expression { if (this.checkAny(TokenKind.Sub, TokenKind.Function)) { - return this.functionDeclaration(true); + const func = this.functionDeclaration(true); + //if there's an open paren after this, this is an IIFE + if (this.check(TokenKind.LeftParen)) { + return this.finishCall(this.advance(), func); + } else { + return func; + } } //template string From 4b3659d82d98b1b02aa06b137d37660fb272f5fc Mon Sep 17 00:00:00 2001 From: Bronley Date: Fri, 26 Feb 2021 22:34:57 -0500 Subject: [PATCH 2/2] fix critical failure parsing iife in BrsFile --- src/files/BrsFile.spec.ts | 14 +++++++++++++- src/files/BrsFile.ts | 5 +++-- src/parser/Parser.spec.ts | 10 ++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts index 4e1c173f9..cf9d06017 100644 --- a/src/files/BrsFile.spec.ts +++ b/src/files/BrsFile.spec.ts @@ -16,7 +16,7 @@ import { DiagnosticMessages } from '../DiagnosticMessages'; import type { StandardizedFileEntry } from 'roku-deploy'; import util, { standardizePath as s } from '../util'; import PluginInterface from '../PluginInterface'; -import { trim, trimMap } from '../testHelpers.spec'; +import { expectZeroDiagnostics, trim, trimMap } from '../testHelpers.spec'; import { ParseMode } from '../parser/Parser'; import { Logger } from '../Logger'; @@ -375,6 +375,18 @@ describe('BrsFile', () => { }); describe('parse', () => { + it('supports iife in assignment', () => { + program.addOrReplaceFile('source/main.brs', ` + sub main() + result = sub() + end sub() + result = (sub() + end sub)() + end sub + `); + expectZeroDiagnostics(program); + }); + it('uses the proper parse mode based on file extension', () => { function testParseMode(destPath: string, expectedParseMode: ParseMode) { const file = program.addOrReplaceFile(destPath, ''); diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 81137dcd0..d23295ff8 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -649,12 +649,13 @@ export class BrsFile { for (let func of this._parser.references.functionExpressions) { //for all function calls in this function for (let expression of func.callExpressions) { - if ( //filter out dotted function invocations (i.e. object.doSomething()) (not currently supported. TODO support it) (expression.callee as any).obj || //filter out method calls on method calls for now (i.e. getSomething().getSomethingElse()) - (expression.callee as any).callee + (expression.callee as any).callee || + //filter out callees without a name (immediately-invoked function expressions) + !(expression.callee as any).name ) { continue; } diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts index 03f2e7835..c4d6fa7dc 100644 --- a/src/parser/Parser.spec.ts +++ b/src/parser/Parser.spec.ts @@ -120,6 +120,16 @@ describe('parser', () => { expectZeroDiagnostics(parser); }); + it('supports returning iife call', () => { + const parser = parse(` + sub main() + return (sub() + end sub)() + end sub + `); + expectZeroDiagnostics(parser); + }); + it('supports using "interface" as parameter name', () => { expect(parse(` sub main(interface as object)