Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iife parse #343

Merged
merged 4 commits into from
Feb 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/files/BrsFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -383,6 +383,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<BrsFile>(destPath, '');
Expand Down
5 changes: 3 additions & 2 deletions src/files/BrsFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,12 +648,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
Copy link
Member Author

@TwitchBronBron TwitchBronBron Feb 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the fix for the crash. IIFEs don't have a name, but further down in this function we expected the expression.callee to have a name token. So now we guard against any callee without a name.

) {
continue;
}
Expand Down
35 changes: 35 additions & 0 deletions src/parser/Parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -95,6 +96,40 @@ 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 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)
Expand Down
8 changes: 7 additions & 1 deletion src/parser/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roku supports non-grouped IIFE. example:

print function()
    return true
end function()

This adds parser support for that pattern.

} else {
return func;
}
}

//template string
Expand Down