brighterscript 1.0.0-alpha.22 → 1.0.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +140 -0
- package/dist/DiagnosticCollection.d.ts +3 -1
- package/dist/DiagnosticCollection.js +3 -5
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +24 -3
- package/dist/DiagnosticMessages.js +28 -7
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.d.ts +2 -1
- package/dist/LanguageServer.js +96 -31
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Program.d.ts +14 -8
- package/dist/Program.js +125 -71
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.js +2 -1
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +23 -15
- package/dist/Scope.js +124 -122
- package/dist/Scope.js.map +1 -1
- package/dist/SymbolTable.d.ts +17 -6
- package/dist/SymbolTable.js +38 -9
- package/dist/SymbolTable.js.map +1 -1
- package/dist/XmlScope.js +3 -2
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +5 -1
- package/dist/astUtils/reflection.js +15 -2
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +2 -1
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +3 -1
- package/dist/bscPlugin/BscPlugin.js +8 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +11 -5
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +75 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +6 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +53 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
- package/dist/bscPlugin/hover/HoverProcessor.js +190 -0
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +195 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +8 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +64 -63
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +238 -23
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +7 -1
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +77 -30
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +14 -1
- package/dist/bscPlugin/validation/BrsFileValidator.js +104 -27
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +48 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +24 -3
- package/dist/bscPlugin/validation/ScopeValidator.js +251 -44
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/cli.js +18 -10
- package/dist/cli.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +135 -38
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +21 -10
- package/dist/files/BrsFile.js +158 -179
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +222 -126
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +2 -2
- package/dist/files/XmlFile.js +1 -0
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/tests/imports.spec.js +1 -1
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.js +20 -16
- package/dist/files/tests/optionalChaning.spec.js.map +1 -1
- package/dist/globalCallables.js +3 -0
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +77 -3
- package/dist/lexer/Lexer.spec.js +7 -0
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +1 -0
- package/dist/lexer/TokenKind.js +8 -3
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/Expression.d.ts +12 -3
- package/dist/parser/Expression.js +16 -4
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +1 -1
- package/dist/parser/Parser.d.ts +14 -3
- package/dist/parser/Parser.js +138 -48
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +232 -115
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/Statement.d.ts +41 -7
- package/dist/parser/Statement.js +85 -12
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +73 -31
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +148 -47
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +219 -37
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js +213 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/Enum.spec.js +56 -8
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +16 -2
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +72 -57
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/preprocessor/Manifest.js +2 -2
- package/dist/preprocessor/Manifest.js.map +1 -1
- package/dist/preprocessor/Preprocessor.js +10 -6
- package/dist/preprocessor/Preprocessor.js.map +1 -1
- package/dist/roku-types/data.json +1002 -788
- package/dist/roku-types/index.d.ts +64 -239
- package/dist/types/DynamicType.d.ts +1 -0
- package/dist/types/DynamicType.js +1 -0
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/util.d.ts +57 -16
- package/dist/util.js +139 -30
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +4 -1
- package/dist/validators/ClassValidator.js +34 -25
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +5 -2
package/dist/Scope.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import type { CompletionItem, Position, Range } from 'vscode-languageserver';
|
|
2
|
-
import { Location } from 'vscode-languageserver';
|
|
1
|
+
import type { CompletionItem, Position, Range, Location } from 'vscode-languageserver';
|
|
3
2
|
import type { CallableContainer, BsDiagnostic, BscFile, CallableContainerMap, FileLink, InheritableStatement, InheritableType, NamedTypeStatement } from './interfaces';
|
|
4
3
|
import type { Program } from './Program';
|
|
5
|
-
import type { NamespaceStatement, Statement, FunctionStatement, ClassStatement, EnumStatement, InterfaceStatement } from './parser/Statement';
|
|
4
|
+
import type { NamespaceStatement, Statement, FunctionStatement, ClassStatement, EnumStatement, InterfaceStatement, EnumMemberStatement, ConstStatement } from './parser/Statement';
|
|
6
5
|
import type { FunctionExpression, NewExpression } from './parser/Expression';
|
|
7
6
|
import { ParseMode } from './parser/Parser';
|
|
8
7
|
import { Cache } from './Cache';
|
|
9
8
|
import type { BrsFile, TokenSymbolLookup } from './files/BrsFile';
|
|
10
9
|
import type { DependencyGraph, DependencyChangedEvent } from './DependencyGraph';
|
|
11
10
|
import { SymbolTable } from './SymbolTable';
|
|
12
|
-
import type { BscType, TypeContext } from './types/BscType';
|
|
13
11
|
import type { Token } from './lexer/Token';
|
|
12
|
+
import type { BscType, TypeContext } from './types/BscType';
|
|
14
13
|
/**
|
|
15
14
|
* A class to keep track of all declarations within a given scope (like source scope, component scope)
|
|
16
15
|
*/
|
|
@@ -81,10 +80,10 @@ export declare class Scope {
|
|
|
81
80
|
*/
|
|
82
81
|
getEnumFileLink(enumName: string, containingNamespace?: string): FileLink<EnumStatement>;
|
|
83
82
|
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
* Get a Named Type (e.g. Class, Interface, Enum) and its containing file by the name
|
|
84
|
+
* @param name - The name of the type, including the namespace of the class/interface/enum, etc. if possible
|
|
85
|
+
* @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
|
|
86
|
+
*/
|
|
88
87
|
getNamedTypeFileLink(name: string, containingNamespace?: string): FileLink<NamedTypeStatement>;
|
|
89
88
|
/**
|
|
90
89
|
* Get a InheritableStatement and its containing file by the name of the interface or class
|
|
@@ -97,6 +96,12 @@ export declare class Scope {
|
|
|
97
96
|
* @param klass - The class to get the parent of, if possible
|
|
98
97
|
*/
|
|
99
98
|
getParentClass(klass: ClassStatement): ClassStatement;
|
|
99
|
+
/**
|
|
100
|
+
* Get a constant and its containing file by the constant name
|
|
101
|
+
* @param constName - The constant name, including the namespace of the constant if possible
|
|
102
|
+
* @param containingNamespace - The namespace used to resolve relative constant names. (i.e. the namespace around the current statement trying to find a constant)
|
|
103
|
+
*/
|
|
104
|
+
getConstFileLink(constName: string, containingNamespace?: string): FileLink<ConstStatement>;
|
|
100
105
|
/**
|
|
101
106
|
* Gets the parent interface of the given interface
|
|
102
107
|
* @param iface - The interface to get the parent of, if possible
|
|
@@ -107,6 +112,7 @@ export declare class Scope {
|
|
|
107
112
|
* @param stmt - The class or interface to get the parent of, if possible
|
|
108
113
|
*/
|
|
109
114
|
getParentStatement(stmt: InheritableStatement): InheritableStatement;
|
|
115
|
+
getEnumMemberMap(): Map<string, EnumMemberStatement>;
|
|
110
116
|
/**
|
|
111
117
|
* Tests if a class exists with the specified name
|
|
112
118
|
* @param className - the all-lower-case namespace-included class name
|
|
@@ -148,6 +154,11 @@ export declare class Scope {
|
|
|
148
154
|
* The key is stored in lower case
|
|
149
155
|
*/
|
|
150
156
|
getEnumMap(): Map<string, FileLink<EnumStatement>>;
|
|
157
|
+
/**
|
|
158
|
+
* A dictionary of all constants in this scope. This includes namespaced constants always with their full name.
|
|
159
|
+
* The key is stored in lower case
|
|
160
|
+
*/
|
|
161
|
+
getConstMap(): Map<string, FileLink<ConstStatement>>;
|
|
151
162
|
/**
|
|
152
163
|
* The list of diagnostics found specifically for this scope. Individual file diagnostics are stored on the files themselves.
|
|
153
164
|
*/
|
|
@@ -233,13 +244,13 @@ export declare class Scope {
|
|
|
233
244
|
protected logDebug(...args: any[]): void;
|
|
234
245
|
private _debugLogComponentName;
|
|
235
246
|
validate(): void;
|
|
247
|
+
getCallableContainerMap(): CallableContainerMap;
|
|
236
248
|
protected _validate(callableContainerMap: CallableContainerMap): void;
|
|
237
249
|
/**
|
|
238
250
|
* Mark this scope as invalid, which means its `validate()` function needs to be called again before use.
|
|
239
251
|
*/
|
|
240
252
|
invalidate(): void;
|
|
241
|
-
get symbolTable():
|
|
242
|
-
private _symbolTable;
|
|
253
|
+
get symbolTable(): any;
|
|
243
254
|
protected _memberTable: SymbolTable;
|
|
244
255
|
get memberTable(): SymbolTable;
|
|
245
256
|
protected clearSymbolTable(): void;
|
|
@@ -259,11 +270,6 @@ export declare class Scope {
|
|
|
259
270
|
* Find function parameters and function return types that are neither built-in types or known Class references
|
|
260
271
|
*/
|
|
261
272
|
private diagnosticDetectInvalidFunctionExpressionTypes;
|
|
262
|
-
/**
|
|
263
|
-
* Find functions with either the wrong type of parameters, or the wrong number of parameters
|
|
264
|
-
*/
|
|
265
|
-
private diagnosticDetectInvalidFunctionCalls;
|
|
266
|
-
private addMismatchParamCountDiagnostic;
|
|
267
273
|
getNewExpressions(): AugmentedNewExpression[];
|
|
268
274
|
private validateClasses;
|
|
269
275
|
/**
|
|
@@ -324,8 +330,10 @@ export interface NamespaceContainer {
|
|
|
324
330
|
lastPartName: string;
|
|
325
331
|
statements: Statement[];
|
|
326
332
|
classStatements: Record<string, ClassStatement>;
|
|
333
|
+
interfaceStatements: Record<string, InterfaceStatement>;
|
|
327
334
|
functionStatements: Record<string, FunctionStatement>;
|
|
328
335
|
enumStatements: Map<string, EnumStatement>;
|
|
336
|
+
constStatements: Map<string, ConstStatement>;
|
|
329
337
|
namespaces: Map<string, NamespaceContainer>;
|
|
330
338
|
symbolTable: SymbolTable;
|
|
331
339
|
}
|
package/dist/Scope.js
CHANGED
|
@@ -16,7 +16,6 @@ const SymbolTable_1 = require("./SymbolTable");
|
|
|
16
16
|
const BscType_1 = require("./types/BscType");
|
|
17
17
|
const DynamicType_1 = require("./types/DynamicType");
|
|
18
18
|
const ObjectType_1 = require("./types/ObjectType");
|
|
19
|
-
const UninitializedType_1 = require("./types/UninitializedType");
|
|
20
19
|
/**
|
|
21
20
|
* A class to keep track of all declarations within a given scope (like source scope, component scope)
|
|
22
21
|
*/
|
|
@@ -135,10 +134,10 @@ class Scope {
|
|
|
135
134
|
return enumeration;
|
|
136
135
|
}
|
|
137
136
|
/**
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
* Get a Named Type (e.g. Class, Interface, Enum) and its containing file by the name
|
|
138
|
+
* @param name - The name of the type, including the namespace of the class/interface/enum, etc. if possible
|
|
139
|
+
* @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
|
|
140
|
+
*/
|
|
142
141
|
getNamedTypeFileLink(name, containingNamespace) {
|
|
143
142
|
return this.getInheritableFileLink(name, containingNamespace) || this.getEnumFileLink(name, containingNamespace);
|
|
144
143
|
}
|
|
@@ -165,6 +164,21 @@ class Scope {
|
|
|
165
164
|
}
|
|
166
165
|
}
|
|
167
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Get a constant and its containing file by the constant name
|
|
169
|
+
* @param constName - The constant name, including the namespace of the constant if possible
|
|
170
|
+
* @param containingNamespace - The namespace used to resolve relative constant names. (i.e. the namespace around the current statement trying to find a constant)
|
|
171
|
+
*/
|
|
172
|
+
getConstFileLink(constName, containingNamespace) {
|
|
173
|
+
const lowerName = constName === null || constName === void 0 ? void 0 : constName.toLowerCase();
|
|
174
|
+
const constMap = this.getConstMap();
|
|
175
|
+
let result = constMap.get(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
|
|
176
|
+
//if we couldn't find the constant by its full namespaced name, look for a global constant with that name
|
|
177
|
+
if (!result) {
|
|
178
|
+
result = constMap.get(lowerName);
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
168
182
|
/**
|
|
169
183
|
* Gets the parent interface of the given interface
|
|
170
184
|
* @param iface - The interface to get the parent of, if possible
|
|
@@ -192,6 +206,22 @@ class Scope {
|
|
|
192
206
|
return this.getParentClass(stmt);
|
|
193
207
|
}
|
|
194
208
|
}
|
|
209
|
+
/*
|
|
210
|
+
* Get a map of all enums by their member name.
|
|
211
|
+
* The keys are lower-case fully-qualified paths to the enum and its member. For example:
|
|
212
|
+
* namespace.enum.value
|
|
213
|
+
*/
|
|
214
|
+
getEnumMemberMap() {
|
|
215
|
+
return this.cache.getOrAdd('enumMemberMap', () => {
|
|
216
|
+
const result = new Map();
|
|
217
|
+
for (const [key, eenum] of this.getEnumMap()) {
|
|
218
|
+
for (const member of eenum.item.getMembers()) {
|
|
219
|
+
result.set(`${key}.${member.name.toLowerCase()}`, member);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
195
225
|
/**
|
|
196
226
|
* Tests if a class exists with the specified name
|
|
197
227
|
* @param className - the all-lower-case namespace-included class name
|
|
@@ -310,6 +340,25 @@ class Scope {
|
|
|
310
340
|
return map;
|
|
311
341
|
});
|
|
312
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* A dictionary of all constants in this scope. This includes namespaced constants always with their full name.
|
|
345
|
+
* The key is stored in lower case
|
|
346
|
+
*/
|
|
347
|
+
getConstMap() {
|
|
348
|
+
return this.cache.getOrAdd('constMap', () => {
|
|
349
|
+
const map = new Map();
|
|
350
|
+
this.enumerateBrsFiles((file) => {
|
|
351
|
+
for (let stmt of file.parser.references.constStatements) {
|
|
352
|
+
const lowerEnumName = stmt.fullName.toLowerCase();
|
|
353
|
+
//only track enums with a defined name (i.e. exclude nameless malformed enums)
|
|
354
|
+
if (lowerEnumName) {
|
|
355
|
+
map.set(lowerEnumName, { item: stmt, file: file });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
return map;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
313
362
|
onDependenciesChanged(event) {
|
|
314
363
|
this.logDebug('invalidated because dependency graph said [', event.sourceKey, '] changed');
|
|
315
364
|
this.invalidate();
|
|
@@ -523,9 +572,9 @@ class Scope {
|
|
|
523
572
|
buildNamespaceLookup() {
|
|
524
573
|
let namespaceLookup = new Map();
|
|
525
574
|
this.enumerateBrsFiles((file) => {
|
|
526
|
-
for (let
|
|
575
|
+
for (let namespaceStatement of file.parser.references.namespaceStatements) {
|
|
527
576
|
//TODO should we handle non-brighterscript?
|
|
528
|
-
let name =
|
|
577
|
+
let name = namespaceStatement.nameExpression.getName(Parser_1.ParseMode.BrighterScript);
|
|
529
578
|
let nameParts = name.split('.');
|
|
530
579
|
let loopName = null;
|
|
531
580
|
//ensure each namespace section is represented in the results
|
|
@@ -537,33 +586,41 @@ class Scope {
|
|
|
537
586
|
namespaceLookup.set(lowerLoopName, {
|
|
538
587
|
file: file,
|
|
539
588
|
fullName: loopName,
|
|
540
|
-
nameRange:
|
|
589
|
+
nameRange: namespaceStatement.nameExpression.range,
|
|
541
590
|
lastPartName: part,
|
|
542
591
|
namespaces: new Map(),
|
|
543
592
|
classStatements: {},
|
|
544
593
|
functionStatements: {},
|
|
594
|
+
interfaceStatements: {},
|
|
545
595
|
enumStatements: new Map(),
|
|
596
|
+
constStatements: new Map(),
|
|
546
597
|
statements: [],
|
|
547
|
-
symbolTable: new SymbolTable_1.SymbolTable(this.symbolTable)
|
|
598
|
+
symbolTable: new SymbolTable_1.SymbolTable(this.symbolTable, `Namespace ${loopName}`)
|
|
548
599
|
});
|
|
549
600
|
}
|
|
550
601
|
}
|
|
551
602
|
let ns = namespaceLookup.get(name.toLowerCase());
|
|
552
|
-
ns.statements.push(...
|
|
553
|
-
for (let statement of
|
|
603
|
+
ns.statements.push(...namespaceStatement.body.statements);
|
|
604
|
+
for (let statement of namespaceStatement.body.statements) {
|
|
554
605
|
if ((0, reflection_1.isClassStatement)(statement) && statement.name) {
|
|
555
606
|
ns.classStatements[statement.name.text.toLowerCase()] = statement;
|
|
556
607
|
}
|
|
608
|
+
else if ((0, reflection_1.isInterfaceStatement)(statement) && statement.name) {
|
|
609
|
+
ns.interfaceStatements[statement.name.text.toLowerCase()] = statement;
|
|
610
|
+
}
|
|
557
611
|
else if ((0, reflection_1.isFunctionStatement)(statement) && statement.name) {
|
|
558
612
|
ns.functionStatements[statement.name.text.toLowerCase()] = statement;
|
|
559
613
|
}
|
|
560
614
|
else if ((0, reflection_1.isEnumStatement)(statement) && statement.fullName) {
|
|
561
615
|
ns.enumStatements.set(statement.fullName.toLowerCase(), statement);
|
|
562
616
|
}
|
|
617
|
+
else if ((0, reflection_1.isConstStatement)(statement) && statement.fullName) {
|
|
618
|
+
ns.constStatements.set(statement.fullName.toLowerCase(), statement);
|
|
619
|
+
}
|
|
563
620
|
}
|
|
564
621
|
// Merges all the symbol tables of the namespace statements into the new symbol table created above.
|
|
565
622
|
// Set those symbol tables to have this new merged table as a parent
|
|
566
|
-
ns.symbolTable.mergeSymbolTable(
|
|
623
|
+
ns.symbolTable.mergeSymbolTable(namespaceStatement.symbolTable);
|
|
567
624
|
}
|
|
568
625
|
//associate child namespaces with their parents
|
|
569
626
|
for (let [, ns] of namespaceLookup) {
|
|
@@ -599,27 +656,54 @@ class Scope {
|
|
|
599
656
|
}
|
|
600
657
|
//clear the scope's errors list (we will populate them from this method)
|
|
601
658
|
this.diagnostics = [];
|
|
602
|
-
// link the
|
|
659
|
+
//Since statements from files are shared across multiple scopes, we need to link those statements to the current scope
|
|
603
660
|
this.linkSymbolTable();
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
return (
|
|
608
|
-
//sort by path
|
|
609
|
-
a.callable.file.srcPath.localeCompare(b.callable.file.srcPath) ||
|
|
610
|
-
//then sort by method name
|
|
611
|
-
a.callable.name.localeCompare(b.callable.name));
|
|
661
|
+
this.program.plugins.emit('beforeScopeValidate', {
|
|
662
|
+
program: this.program,
|
|
663
|
+
scope: this
|
|
612
664
|
});
|
|
613
|
-
//get a list of all callables, indexed by their lower case names
|
|
614
|
-
let callableContainerMap = util_1.util.getCallableContainersByLowerName(callables);
|
|
615
665
|
this.program.plugins.emit('onScopeValidate', {
|
|
616
666
|
program: this.program,
|
|
617
667
|
scope: this
|
|
618
668
|
});
|
|
619
|
-
this._validate(
|
|
620
|
-
|
|
669
|
+
this._validate(this.getCallableContainerMap());
|
|
670
|
+
this.program.plugins.emit('afterScopeValidate', {
|
|
671
|
+
program: this.program,
|
|
672
|
+
scope: this
|
|
673
|
+
});
|
|
674
|
+
//unlink all symbol tables from this scope (so they don't accidentally stick around)
|
|
621
675
|
this.unlinkSymbolTable();
|
|
676
|
+
this.isValidated = true;
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
//Get a list of all callables, indexed by their lower case name
|
|
680
|
+
getCallableContainerMap() {
|
|
681
|
+
let callables = this.getAllCallables();
|
|
682
|
+
//sort the callables by filepath and then method name, so the errors will be consistent
|
|
683
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
684
|
+
callables = callables.sort((a, b) => {
|
|
685
|
+
const pathA = a.callable.file.srcPath;
|
|
686
|
+
const pathB = b.callable.file.srcPath;
|
|
687
|
+
//sort by path
|
|
688
|
+
if (pathA < pathB) {
|
|
689
|
+
return -1;
|
|
690
|
+
}
|
|
691
|
+
else if (pathA > pathB) {
|
|
692
|
+
return 1;
|
|
693
|
+
}
|
|
694
|
+
//sort by function name
|
|
695
|
+
const funcA = b.callable.name;
|
|
696
|
+
const funcB = b.callable.name;
|
|
697
|
+
if (funcA < funcB) {
|
|
698
|
+
return -1;
|
|
699
|
+
}
|
|
700
|
+
else if (funcA > funcB) {
|
|
701
|
+
return 1;
|
|
702
|
+
}
|
|
703
|
+
return 0;
|
|
622
704
|
});
|
|
705
|
+
//get a list of all callables, indexed by their lower case names
|
|
706
|
+
return util_1.util.getCallableContainersByLowerName(callables);
|
|
623
707
|
}
|
|
624
708
|
_validate(callableContainerMap) {
|
|
625
709
|
//find all duplicate function declarations
|
|
@@ -634,7 +718,6 @@ class Scope {
|
|
|
634
718
|
this.diagnosticDetectFunctionCollisions(file);
|
|
635
719
|
this.detectVariableNamespaceCollisions(file);
|
|
636
720
|
this.diagnosticDetectInvalidFunctionExpressionTypes(file);
|
|
637
|
-
this.diagnosticDetectInvalidFunctionCalls(file, callableContainerMap);
|
|
638
721
|
});
|
|
639
722
|
}
|
|
640
723
|
/**
|
|
@@ -648,17 +731,17 @@ class Scope {
|
|
|
648
731
|
this.symbolCache.clear();
|
|
649
732
|
}
|
|
650
733
|
get symbolTable() {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
734
|
+
return this.cache.getOrAdd('symbolTable', () => {
|
|
735
|
+
var _a, _b;
|
|
736
|
+
const result = new SymbolTable_1.SymbolTable((_a = this.getParentScope()) === null || _a === void 0 ? void 0 : _a.symbolTable, `Scope ${this.name}`);
|
|
737
|
+
result.addSymbol('m', null, new ObjectType_1.ObjectType('object', this.memberTable));
|
|
655
738
|
for (let file of this.getOwnFiles()) {
|
|
656
739
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
657
|
-
|
|
740
|
+
result.mergeSymbolTable((_b = file.parser) === null || _b === void 0 ? void 0 : _b.symbolTable);
|
|
658
741
|
}
|
|
659
742
|
}
|
|
660
|
-
|
|
661
|
-
|
|
743
|
+
return result;
|
|
744
|
+
});
|
|
662
745
|
}
|
|
663
746
|
get memberTable() {
|
|
664
747
|
var _a;
|
|
@@ -671,7 +754,7 @@ class Scope {
|
|
|
671
754
|
return this._memberTable;
|
|
672
755
|
}
|
|
673
756
|
clearSymbolTable() {
|
|
674
|
-
this.
|
|
757
|
+
this.cache.delete('symbolTable');
|
|
675
758
|
this._memberTable = null;
|
|
676
759
|
}
|
|
677
760
|
/**
|
|
@@ -683,11 +766,12 @@ class Scope {
|
|
|
683
766
|
var _a, _b, _c;
|
|
684
767
|
for (const file of this.getAllFiles()) {
|
|
685
768
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
686
|
-
file.parser.symbolTable.
|
|
769
|
+
file.parser.symbolTable.pushParent(this.symbolTable);
|
|
770
|
+
//link each NamespaceStatement's SymbolTable with the aggregate NamespaceLookup SymbolTable
|
|
687
771
|
for (const namespace of file.parser.references.namespaceStatements) {
|
|
688
772
|
const namespaceNameLower = namespace.nameExpression.getName(Parser_1.ParseMode.BrighterScript).toLowerCase();
|
|
689
773
|
const namespaceSymbolTable = this.namespaceLookup.get(namespaceNameLower).symbolTable;
|
|
690
|
-
namespace.symbolTable.
|
|
774
|
+
namespace.symbolTable.pushParent(namespaceSymbolTable);
|
|
691
775
|
}
|
|
692
776
|
//TODO TYPES: build symbol tables for dotted set assignments using actual values
|
|
693
777
|
// Currently this is prone to call-stack issues.
|
|
@@ -728,9 +812,9 @@ class Scope {
|
|
|
728
812
|
var _a;
|
|
729
813
|
for (let file of this.getOwnFiles()) {
|
|
730
814
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
731
|
-
(_a = file.parser) === null || _a === void 0 ? void 0 : _a.symbolTable.
|
|
815
|
+
(_a = file.parser) === null || _a === void 0 ? void 0 : _a.symbolTable.popParent();
|
|
732
816
|
for (const namespace of file.parser.references.namespaceStatements) {
|
|
733
|
-
namespace.symbolTable.
|
|
817
|
+
namespace.symbolTable.popParent();
|
|
734
818
|
}
|
|
735
819
|
}
|
|
736
820
|
}
|
|
@@ -745,7 +829,7 @@ class Scope {
|
|
|
745
829
|
if (namespace) {
|
|
746
830
|
this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.parameterMayNotHaveSameNameAsNamespace(param.name.text)), { range: param.name.range, relatedInformation: [{
|
|
747
831
|
message: 'Namespace declared here',
|
|
748
|
-
location:
|
|
832
|
+
location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
|
|
749
833
|
}] }));
|
|
750
834
|
}
|
|
751
835
|
}
|
|
@@ -757,7 +841,7 @@ class Scope {
|
|
|
757
841
|
if (namespace) {
|
|
758
842
|
this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.variableMayNotHaveSameNameAsNamespace(assignment.name.text)), { range: assignment.name.range, relatedInformation: [{
|
|
759
843
|
message: 'Namespace declared here',
|
|
760
|
-
location:
|
|
844
|
+
location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
|
|
761
845
|
}] }));
|
|
762
846
|
}
|
|
763
847
|
}
|
|
@@ -812,88 +896,6 @@ class Scope {
|
|
|
812
896
|
}
|
|
813
897
|
}
|
|
814
898
|
}
|
|
815
|
-
/**
|
|
816
|
-
* Find functions with either the wrong type of parameters, or the wrong number of parameters
|
|
817
|
-
*/
|
|
818
|
-
diagnosticDetectInvalidFunctionCalls(file, callableContainersByLowerName) {
|
|
819
|
-
var _a, _b, _c, _d;
|
|
820
|
-
if ((0, reflection_1.isBrsFile)(file)) {
|
|
821
|
-
for (let expCall of file.functionCalls) {
|
|
822
|
-
const symbolTypeInfo = file.getSymbolTypeFromToken(expCall.name, expCall.functionExpression, this);
|
|
823
|
-
let funcType = symbolTypeInfo.type;
|
|
824
|
-
if (!(0, reflection_1.isTypedFunctionType)(funcType) && !(0, reflection_1.isDynamicType)(funcType)) {
|
|
825
|
-
// We don't know if this is a function. Try seeing if it is a global
|
|
826
|
-
const callableContainer = util_1.util.getCallableContainerByFunctionCall(callableContainersByLowerName, expCall);
|
|
827
|
-
if (callableContainer) {
|
|
828
|
-
// We found a global callable with correct number of params - use that
|
|
829
|
-
funcType = (_a = callableContainer.callable) === null || _a === void 0 ? void 0 : _a.type;
|
|
830
|
-
}
|
|
831
|
-
else {
|
|
832
|
-
const allowedParamCount = util_1.util.getMinMaxParamCountByFunctionCall(callableContainersByLowerName, expCall);
|
|
833
|
-
if (allowedParamCount) {
|
|
834
|
-
// We found a global callable, but it needs a different number of args
|
|
835
|
-
this.addMismatchParamCountDiagnostic(allowedParamCount, expCall, file);
|
|
836
|
-
continue;
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
if ((0, reflection_1.isFunctionType)(funcType)) {
|
|
841
|
-
// This is a generic function, and it is callable
|
|
842
|
-
}
|
|
843
|
-
else if ((0, reflection_1.isTypedFunctionType)(funcType)) {
|
|
844
|
-
// Check for Argument count mismatch.
|
|
845
|
-
//get min/max parameter count for callable
|
|
846
|
-
let paramCount = util_1.util.getMinMaxParamCount(funcType.params);
|
|
847
|
-
if (expCall.args.length > paramCount.max || expCall.args.length < paramCount.min) {
|
|
848
|
-
this.addMismatchParamCountDiagnostic(paramCount, expCall, file);
|
|
849
|
-
}
|
|
850
|
-
// Check for Argument type mismatch.
|
|
851
|
-
const paramTypeContext = { file: file, scope: this, position: (_b = expCall.functionExpression.range) === null || _b === void 0 ? void 0 : _b.start };
|
|
852
|
-
const argTypeContext = { file: file, scope: this, position: (_c = expCall.range) === null || _c === void 0 ? void 0 : _c.start };
|
|
853
|
-
for (let index = 0; index < funcType.params.length; index++) {
|
|
854
|
-
const param = funcType.params[index];
|
|
855
|
-
const arg = expCall.args[index];
|
|
856
|
-
if (!arg) {
|
|
857
|
-
// not enough args
|
|
858
|
-
break;
|
|
859
|
-
}
|
|
860
|
-
let argType = (_d = arg.type) !== null && _d !== void 0 ? _d : new UninitializedType_1.UninitializedType();
|
|
861
|
-
const paramType = (0, BscType_1.getTypeFromContext)(param.type, paramTypeContext);
|
|
862
|
-
if (!paramType) {
|
|
863
|
-
// other error - can not determine what type this parameter should be
|
|
864
|
-
continue;
|
|
865
|
-
}
|
|
866
|
-
argType = (0, BscType_1.getTypeFromContext)(argType, argTypeContext);
|
|
867
|
-
let assignable = argType === null || argType === void 0 ? void 0 : argType.isAssignableTo(paramType, argTypeContext);
|
|
868
|
-
if (!assignable) {
|
|
869
|
-
// TODO TYPES: perhaps this should be a strict mode setting?
|
|
870
|
-
assignable = argType === null || argType === void 0 ? void 0 : argType.isConvertibleTo(paramType, argTypeContext);
|
|
871
|
-
}
|
|
872
|
-
if (!assignable) {
|
|
873
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch(argType === null || argType === void 0 ? void 0 : argType.toString(argTypeContext), paramType.toString(paramTypeContext))), { range: arg === null || arg === void 0 ? void 0 : arg.range, file: file }));
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
else if ((0, reflection_1.isInvalidType)(symbolTypeInfo.type)) {
|
|
878
|
-
// TODO TYPES: standard member functions like integer.ToStr() are not detectable yet.
|
|
879
|
-
}
|
|
880
|
-
else if ((0, reflection_1.isDynamicType)(symbolTypeInfo.type)) {
|
|
881
|
-
// maybe this is a function? who knows
|
|
882
|
-
}
|
|
883
|
-
else {
|
|
884
|
-
const functionNameText = symbolTypeInfo.expandedTokenText;
|
|
885
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callToUnknownFunction(functionNameText, this.name)), { range: expCall.nameRange,
|
|
886
|
-
//TODO detect end of expression call
|
|
887
|
-
file: file }));
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
addMismatchParamCountDiagnostic(paramCount, expCall, file) {
|
|
893
|
-
const minMaxParamsText = paramCount.min === paramCount.max ? paramCount.max : `${paramCount.min}-${paramCount.max}`;
|
|
894
|
-
const expCallArgCount = expCall.args.length;
|
|
895
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expCall.nameRange, file: file }));
|
|
896
|
-
}
|
|
897
899
|
getNewExpressions() {
|
|
898
900
|
let result = [];
|
|
899
901
|
this.enumerateBrsFiles((file) => {
|