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.
Files changed (132) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/dist/DiagnosticCollection.d.ts +3 -1
  3. package/dist/DiagnosticCollection.js +3 -5
  4. package/dist/DiagnosticCollection.js.map +1 -1
  5. package/dist/DiagnosticMessages.d.ts +24 -3
  6. package/dist/DiagnosticMessages.js +28 -7
  7. package/dist/DiagnosticMessages.js.map +1 -1
  8. package/dist/LanguageServer.d.ts +2 -1
  9. package/dist/LanguageServer.js +96 -31
  10. package/dist/LanguageServer.js.map +1 -1
  11. package/dist/Program.d.ts +14 -8
  12. package/dist/Program.js +125 -71
  13. package/dist/Program.js.map +1 -1
  14. package/dist/ProgramBuilder.js +2 -1
  15. package/dist/ProgramBuilder.js.map +1 -1
  16. package/dist/Scope.d.ts +23 -15
  17. package/dist/Scope.js +124 -122
  18. package/dist/Scope.js.map +1 -1
  19. package/dist/SymbolTable.d.ts +17 -6
  20. package/dist/SymbolTable.js +38 -9
  21. package/dist/SymbolTable.js.map +1 -1
  22. package/dist/XmlScope.js +3 -2
  23. package/dist/XmlScope.js.map +1 -1
  24. package/dist/astUtils/reflection.d.ts +5 -1
  25. package/dist/astUtils/reflection.js +15 -2
  26. package/dist/astUtils/reflection.js.map +1 -1
  27. package/dist/astUtils/visitors.d.ts +2 -1
  28. package/dist/astUtils/visitors.js.map +1 -1
  29. package/dist/bscPlugin/BscPlugin.d.ts +3 -1
  30. package/dist/bscPlugin/BscPlugin.js +8 -0
  31. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  32. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  33. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +11 -5
  34. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  35. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +75 -1
  36. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  37. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +6 -0
  38. package/dist/bscPlugin/completions/CompletionsProcessor.js +53 -0
  39. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  40. package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
  41. package/dist/bscPlugin/hover/HoverProcessor.js +190 -0
  42. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  43. package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
  44. package/dist/bscPlugin/hover/HoverProcessor.spec.js +195 -0
  45. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  46. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +8 -1
  47. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +64 -63
  48. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  49. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +238 -23
  50. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  51. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +7 -1
  52. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +77 -30
  53. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
  54. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +14 -1
  55. package/dist/bscPlugin/validation/BrsFileValidator.js +104 -27
  56. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  57. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  58. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +48 -0
  59. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  60. package/dist/bscPlugin/validation/ScopeValidator.d.ts +24 -3
  61. package/dist/bscPlugin/validation/ScopeValidator.js +251 -44
  62. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  63. package/dist/cli.js +18 -10
  64. package/dist/cli.js.map +1 -1
  65. package/dist/files/BrsFile.Class.spec.js +135 -38
  66. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  67. package/dist/files/BrsFile.d.ts +21 -10
  68. package/dist/files/BrsFile.js +158 -179
  69. package/dist/files/BrsFile.js.map +1 -1
  70. package/dist/files/BrsFile.spec.js +222 -126
  71. package/dist/files/BrsFile.spec.js.map +1 -1
  72. package/dist/files/XmlFile.d.ts +2 -2
  73. package/dist/files/XmlFile.js +1 -0
  74. package/dist/files/XmlFile.js.map +1 -1
  75. package/dist/files/tests/imports.spec.js +1 -1
  76. package/dist/files/tests/imports.spec.js.map +1 -1
  77. package/dist/files/tests/optionalChaning.spec.js +20 -16
  78. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  79. package/dist/globalCallables.js +3 -0
  80. package/dist/globalCallables.js.map +1 -1
  81. package/dist/index.d.ts +1 -1
  82. package/dist/index.js +3 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/interfaces.d.ts +77 -3
  85. package/dist/lexer/Lexer.spec.js +7 -0
  86. package/dist/lexer/Lexer.spec.js.map +1 -1
  87. package/dist/lexer/TokenKind.d.ts +1 -0
  88. package/dist/lexer/TokenKind.js +8 -3
  89. package/dist/lexer/TokenKind.js.map +1 -1
  90. package/dist/parser/Expression.d.ts +12 -3
  91. package/dist/parser/Expression.js +16 -4
  92. package/dist/parser/Expression.js.map +1 -1
  93. package/dist/parser/Parser.Class.spec.js +1 -1
  94. package/dist/parser/Parser.d.ts +14 -3
  95. package/dist/parser/Parser.js +138 -48
  96. package/dist/parser/Parser.js.map +1 -1
  97. package/dist/parser/Parser.spec.js +232 -115
  98. package/dist/parser/Parser.spec.js.map +1 -1
  99. package/dist/parser/Statement.d.ts +41 -7
  100. package/dist/parser/Statement.js +85 -12
  101. package/dist/parser/Statement.js.map +1 -1
  102. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +73 -31
  103. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  104. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +148 -47
  105. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  106. package/dist/parser/tests/expression/TernaryExpression.spec.js +219 -37
  107. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  108. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  109. package/dist/parser/tests/statement/ConstStatement.spec.js +213 -0
  110. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  111. package/dist/parser/tests/statement/Enum.spec.js +56 -8
  112. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  113. package/dist/parser/tests/statement/InterfaceStatement.spec.js +16 -2
  114. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  115. package/dist/parser/tests/statement/PrintStatement.spec.js +72 -57
  116. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  117. package/dist/preprocessor/Manifest.js +2 -2
  118. package/dist/preprocessor/Manifest.js.map +1 -1
  119. package/dist/preprocessor/Preprocessor.js +10 -6
  120. package/dist/preprocessor/Preprocessor.js.map +1 -1
  121. package/dist/roku-types/data.json +1002 -788
  122. package/dist/roku-types/index.d.ts +64 -239
  123. package/dist/types/DynamicType.d.ts +1 -0
  124. package/dist/types/DynamicType.js +1 -0
  125. package/dist/types/DynamicType.js.map +1 -1
  126. package/dist/util.d.ts +57 -16
  127. package/dist/util.js +139 -30
  128. package/dist/util.js.map +1 -1
  129. package/dist/validators/ClassValidator.d.ts +4 -1
  130. package/dist/validators/ClassValidator.js +34 -25
  131. package/dist/validators/ClassValidator.js.map +1 -1
  132. 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
- * Get a Named Type (e.g. Class, Interface, Enum) and its containing file by the name
85
- * @param name - The name of the type, including the namespace of the class/interface/enum, etc. if possible
86
- * @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
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(): 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
- * Get a Named Type (e.g. Class, Interface, Enum) and its containing file by the name
139
- * @param name - The name of the type, including the namespace of the class/interface/enum, etc. if possible
140
- * @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
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 namespace of file.parser.references.namespaceStatements) {
575
+ for (let namespaceStatement of file.parser.references.namespaceStatements) {
527
576
  //TODO should we handle non-brighterscript?
528
- let name = namespace.nameExpression.getName(Parser_1.ParseMode.BrighterScript);
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: namespace.nameExpression.range,
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(...namespace.body.statements);
553
- for (let statement of namespace.body.statements) {
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(namespace.symbolTable);
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 symbol table
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
- let callables = this.getAllCallables();
605
- //sort the callables by filepath and then method name, so the errors will be consistent
606
- callables = callables.sort((a, b) => {
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(callableContainerMap);
620
- // unlink the symbol table so it can't be accessed from the wrong scope
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
- var _a, _b;
652
- if (!this._symbolTable) {
653
- this._symbolTable = new SymbolTable_1.SymbolTable((_a = this.getParentScope()) === null || _a === void 0 ? void 0 : _a.symbolTable);
654
- this._symbolTable.addSymbol('m', null, new ObjectType_1.ObjectType('object', this.memberTable));
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
- this._symbolTable.mergeSymbolTable((_b = file.parser) === null || _b === void 0 ? void 0 : _b.symbolTable);
740
+ result.mergeSymbolTable((_b = file.parser) === null || _b === void 0 ? void 0 : _b.symbolTable);
658
741
  }
659
742
  }
660
- }
661
- return this._symbolTable;
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._symbolTable = null;
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.setParent(this.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.setParent(namespaceSymbolTable);
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.setParent(null);
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.setParent(null);
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: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
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: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
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) => {