From c8048ec699e6e27844e748026f1a1bda75a7ed6b Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 19 Oct 2022 09:52:20 -0400 Subject: [PATCH 1/3] better parse recover for unkonwn func params --- src/bscPlugin/validation/ScopeValidator.ts | 2 +- src/parser/Parser.spec.ts | 15 ++++++++++++++- src/parser/Parser.ts | 3 +-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bscPlugin/validation/ScopeValidator.ts b/src/bscPlugin/validation/ScopeValidator.ts index 33d9199fb..87df3dc9b 100644 --- a/src/bscPlugin/validation/ScopeValidator.ts +++ b/src/bscPlugin/validation/ScopeValidator.ts @@ -89,7 +89,7 @@ export class ScopeValidator { const symbolTable = info.expression.getSymbolTable(); const firstPart = info.parts[0]; //flag all unknown left-most variables - if (!symbolTable.hasSymbol(firstPart.name?.text)) { + if (!symbolTable?.hasSymbol(firstPart.name?.text)) { this.addMultiScopeDiagnostic({ file: file as BscFile, ...DiagnosticMessages.cannotFindName(firstPart.name?.text), diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts index ef1d50f8b..16b66a1ca 100644 --- a/src/parser/Parser.spec.ts +++ b/src/parser/Parser.spec.ts @@ -9,7 +9,7 @@ import { PrintStatement, FunctionStatement, NamespaceStatement, ImportStatement import { Range } from 'vscode-languageserver'; import { DiagnosticMessages } from '../DiagnosticMessages'; import { isBlock, isCommentStatement, isFunctionStatement, isIfStatement, isIndexedGetExpression } from '../astUtils/reflection'; -import { expectZeroDiagnostics } from '../testHelpers.spec'; +import { expectDiagnostics, expectZeroDiagnostics } from '../testHelpers.spec'; import { BrsTranspileState } from './BrsTranspileState'; import { SourceNode } from 'source-map'; import { BrsFile } from '../files/BrsFile'; @@ -366,6 +366,19 @@ describe('parser', () => { `, ParseMode.BrighterScript).diagnostics[0]?.message).not.to.exist; }); + it('does not scrap the entire function when encountering unknown parameter type', () => { + const parser = parse(` + sub test(param1 as unknownType) + end sub + `); + expectDiagnostics(parser, [{ + ...DiagnosticMessages.functionParameterTypeIsInvalid('param1', 'unknownType') + }]); + expect( + isFunctionStatement(parser.ast.statements[0]) + ).to.be.true; + }); + describe('namespace', () => { it('allows namespaces declared inside other namespaces', () => { const parser = parse(` diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index 80bf0f7b1..c7e29bb71 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -981,7 +981,6 @@ export class Parser { ...DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text), range: typeToken.range }); - throw this.lastDiagnosticAsError(); } } return new FunctionParameterExpression( @@ -2536,7 +2535,7 @@ export class Parser { /** * Tries to get the next token as a type * Allows for built-in types (double, string, etc.) or namespaced custom types in Brighterscript mode - * Will return a token of whatever is next to be parsed (unless `advanceIfUnknown` is false, in which case undefined will be returned instead + * Will return a token of whatever is next to be parsed */ private typeToken(): Token { let typeToken: Token; From 449e0eaab672ec16e0c6c3b18090711bcc51bf52 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 19 Oct 2022 10:19:35 -0400 Subject: [PATCH 2/3] Some small crash fixes --- src/bscPlugin/hover/HoverProcessor.ts | 2 +- .../semanticTokens/BrsFileSemanticTokensProcessor.ts | 5 +++++ src/files/BrsFile.ts | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bscPlugin/hover/HoverProcessor.ts b/src/bscPlugin/hover/HoverProcessor.ts index 7c51fe7a2..951d6d9d1 100644 --- a/src/bscPlugin/hover/HoverProcessor.ts +++ b/src/bscPlugin/hover/HoverProcessor.ts @@ -65,7 +65,7 @@ export class HoverProcessor { const fullName = util.getAllDottedGetParts(expression)?.map(x => x.text).join('.'); //find a constant with this name - const constant = scope.getConstFileLink(fullName, containingNamespace); + const constant = scope?.getConstFileLink(fullName, containingNamespace); if (constant) { const constantValue = new SourceNode(null, null, null, constant.item.value.transpile(new BrsTranspileState(file))).toString(); return { diff --git a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts index 86df2b3b0..14a3c2bfa 100644 --- a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts +++ b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.ts @@ -87,6 +87,11 @@ export class BrsFileSemanticTokensProcessor { private iterateExpressions() { const scope = this.event.scopes[0]; + //if this file has no scopes, there's nothing else we can do about this + if (!scope) { + return; + } + for (let expression of this.event.file.parser.references.expressions) { //lift the callee from call expressions to handle namespaced function calls if (isCallExpression(expression)) { diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 0a26ba0d5..695690214 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -1440,7 +1440,7 @@ export class BrsFile { const fullName = util.getAllDottedGetParts(expression)?.map(x => x.text).join('.'); //find a constant with this name - const constant = scope.getConstFileLink(fullName, containingNamespace); + const constant = scope?.getConstFileLink(fullName, containingNamespace); if (constant) { results.push( util.createLocation( From a0e8331a23f5fb5e164c7814e2016361b3c36d8b Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 19 Oct 2022 10:25:16 -0400 Subject: [PATCH 3/3] Another small crash fix --- src/files/BrsFile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 695690214..9edef7fd8 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -1432,10 +1432,10 @@ export class BrsFile { const scopesForFile = this.program.getScopesForFile(this); const [scope] = scopesForFile; - scope.linkSymbolTable(); const expression = this.getClosestExpression(position); - if (expression) { + if (scope && expression) { + scope.linkSymbolTable(); let containingNamespace = expression.findAncestor(isNamespaceStatement)?.getName(ParseMode.BrighterScript); const fullName = util.getAllDottedGetParts(expression)?.map(x => x.text).join('.');