Skip to content

Commit

Permalink
Merge branch 'master' into pkg-completion-in-strings
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron committed Feb 27, 2021
2 parents b626b37 + 0c6b7f4 commit 39ff28d
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 26 deletions.
3 changes: 1 addition & 2 deletions src/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,6 @@ export class Program {
public getStatementsByName(name: string, originFile: BrsFile, namespaceName?: string): FileLink<Statement>[] {
let results = new Map<Statement, FileLink<Statement>>();
const filesSearched = new Set<BrsFile>();
let parseMode = originFile.getParseMode();
let lowerNamespaceName = namespaceName?.toLowerCase();
let lowerName = name?.toLowerCase();
//look through all files in scope for matches
Expand All @@ -606,7 +605,7 @@ export class Program {
filesSearched.add(file);

for (const statement of [...file.parser.references.functionStatements, ...file.parser.references.classStatements.flatMap((cs) => cs.methods)]) {
let parentNamespaceName = statement.namespaceName?.getName(parseMode)?.toLowerCase();
let parentNamespaceName = statement.namespaceName?.getName(originFile.parseMode)?.toLowerCase();
if (statement.name.text.toLowerCase() === lowerName && (!parentNamespaceName || parentNamespaceName === lowerNamespaceName)) {
if (!results.has(statement)) {
results.set(statement, { item: statement, file: file });
Expand Down
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 @@ -422,6 +422,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
36 changes: 14 additions & 22 deletions src/files/BrsFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ export class BrsFile {
this.pkgPath = s`${this.pkgPath}`;
this.dependencyGraphKey = this.pkgPath.toLowerCase();

this.extension = util.getExtension(this.pkgPath);
this.extension = util.getExtension(this.pathAbsolute);

//all BrighterScript files need to be transpiled
if (this.extension?.endsWith('.bs')) {
this.needsTranspiled = true;
this.parseMode = ParseMode.BrighterScript;
}
this.isTypedef = this.extension === '.d.bs';
if (!this.isTypedef) {
Expand All @@ -63,9 +64,7 @@ export class BrsFile {
/**
* The parseMode used for the parser for this file
*/
public get parseMode() {
return this.extension.endsWith('.bs') ? ParseMode.BrighterScript : ParseMode.BrightScript;
}
public parseMode = ParseMode.BrightScript;

/**
* The key used to identify this file in the dependency graph
Expand Down Expand Up @@ -649,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
) {
continue;
}
Expand Down Expand Up @@ -755,7 +755,6 @@ export class BrsFile {
*/
public getCompletions(position: Position, scope?: Scope): CompletionItem[] {
let result = [] as CompletionItem[];
let parseMode = this.getParseMode();

//a map of lower-case names of all added options
let names = {} as Record<string, boolean>;
Expand Down Expand Up @@ -801,7 +800,7 @@ export class BrsFile {
}
}

let namespaceCompletions = this.getNamespaceCompletions(currentToken, parseMode, scope);
let namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
if (namespaceCompletions.length > 0) {
return namespaceCompletions;
}
Expand All @@ -811,13 +810,13 @@ export class BrsFile {
//we aren't in any function scope, so return the keyword completions and namespaces
if (this.getTokenBefore(currentToken, TokenKind.New)) {
// there's a new keyword, so only class types are viable here
return [...this.getGlobalClassStatementCompletions(currentToken, parseMode)];
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
} else {
return [...KeywordCompletions, ...this.getGlobalClassStatementCompletions(currentToken, parseMode), ...namespaceCompletions];
return [...KeywordCompletions, ...this.getGlobalClassStatementCompletions(currentToken, this.parseMode), ...namespaceCompletions];
}
}

const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, parseMode);
const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
const newToken = this.getTokenBefore(currentToken, TokenKind.New);
if (newToken) {
//we are after a new keyword; so we can only be namespaces or classes at this point
Expand Down Expand Up @@ -858,7 +857,7 @@ export class BrsFile {
result.push(...classNameCompletions);

//include the global callables
result.push(...scope.getCallablesAsCompletions(parseMode));
result.push(...scope.getCallablesAsCompletions(this.parseMode));

//add `m` because that's always valid within a function
result.push({
Expand All @@ -883,7 +882,7 @@ export class BrsFile {
});
}

if (parseMode === ParseMode.BrighterScript) {
if (this.parseMode === ParseMode.BrighterScript) {
//include the first part of namespaces
let namespaces = scope.getAllNamespaceStatements();
for (let stmt of namespaces) {
Expand Down Expand Up @@ -1094,13 +1093,6 @@ export class BrsFile {
}
}

/**
* Determine if this file is a brighterscript file
*/
public getParseMode() {
return this.pathAbsolute.toLowerCase().endsWith('.bs') ? ParseMode.BrighterScript : ParseMode.BrightScript;
}

public isPositionNextToTokenKind(position: Position, tokenKind: TokenKind) {
const closestToken = this.getClosestToken(position);
const previousToken = this.getPreviousToken(closestToken);
Expand Down Expand Up @@ -1435,7 +1427,7 @@ export class BrsFile {
}
}
const statementHandler = (statement: FunctionStatement) => {
if (statement.getName(this.getParseMode()).toLowerCase() === textToSearchFor) {
if (statement.getName(this.parseMode).toLowerCase() === textToSearchFor) {
const uri = util.pathToUri(file.pathAbsolute);
results.push(Location.create(uri, statement.range));
}
Expand All @@ -1455,7 +1447,7 @@ export class BrsFile {
let results: Location[] = [];
//get class fields and members
const statementHandler = (statement: ClassMethodStatement) => {
if (statement.getName(file.getParseMode()).toLowerCase() === textToSearchFor) {
if (statement.getName(file.parseMode).toLowerCase() === textToSearchFor) {
results.push(Location.create(util.pathToUri(file.pathAbsolute), statement.range));
}
};
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);
} else {
return func;
}
}

//template string
Expand Down

0 comments on commit 39ff28d

Please sign in to comment.