brighterscript 0.52.3 → 0.53.0

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 (82) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/DiagnosticMessages.d.ts +8 -3
  3. package/dist/DiagnosticMessages.js +8 -3
  4. package/dist/DiagnosticMessages.js.map +1 -1
  5. package/dist/LanguageServer.js +27 -6
  6. package/dist/LanguageServer.js.map +1 -1
  7. package/dist/Program.d.ts +4 -3
  8. package/dist/Program.js +36 -5
  9. package/dist/Program.js.map +1 -1
  10. package/dist/Scope.d.ts +24 -9
  11. package/dist/Scope.js +96 -50
  12. package/dist/Scope.js.map +1 -1
  13. package/dist/SymbolTable.d.ts +62 -0
  14. package/dist/SymbolTable.js +101 -0
  15. package/dist/SymbolTable.js.map +1 -0
  16. package/dist/astUtils/reflection.d.ts +2 -1
  17. package/dist/astUtils/reflection.js +6 -2
  18. package/dist/astUtils/reflection.js.map +1 -1
  19. package/dist/astUtils/visitors.d.ts +2 -1
  20. package/dist/astUtils/visitors.js.map +1 -1
  21. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  22. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +10 -5
  23. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  24. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +7 -1
  25. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +81 -22
  26. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
  27. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +5 -1
  28. package/dist/bscPlugin/validation/BrsFileValidator.js +28 -2
  29. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  30. package/dist/bscPlugin/validation/ScopeValidator.d.ts +18 -3
  31. package/dist/bscPlugin/validation/ScopeValidator.js +137 -47
  32. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  33. package/dist/files/BrsFile.Class.spec.js +10 -10
  34. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  35. package/dist/files/BrsFile.d.ts +10 -4
  36. package/dist/files/BrsFile.js +68 -21
  37. package/dist/files/BrsFile.js.map +1 -1
  38. package/dist/files/BrsFile.spec.js +120 -91
  39. package/dist/files/BrsFile.spec.js.map +1 -1
  40. package/dist/files/tests/imports.spec.js +1 -1
  41. package/dist/files/tests/imports.spec.js.map +1 -1
  42. package/dist/files/tests/optionalChaning.spec.js +20 -16
  43. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  44. package/dist/globalCallables.js +3 -0
  45. package/dist/globalCallables.js.map +1 -1
  46. package/dist/lexer/Lexer.spec.js +7 -0
  47. package/dist/lexer/Lexer.spec.js.map +1 -1
  48. package/dist/lexer/TokenKind.d.ts +1 -0
  49. package/dist/lexer/TokenKind.js +7 -3
  50. package/dist/lexer/TokenKind.js.map +1 -1
  51. package/dist/parser/Expression.d.ts +4 -1
  52. package/dist/parser/Expression.js +8 -2
  53. package/dist/parser/Expression.js.map +1 -1
  54. package/dist/parser/Parser.Class.spec.js +1 -1
  55. package/dist/parser/Parser.d.ts +13 -2
  56. package/dist/parser/Parser.js +137 -60
  57. package/dist/parser/Parser.js.map +1 -1
  58. package/dist/parser/Statement.d.ts +29 -1
  59. package/dist/parser/Statement.js +66 -4
  60. package/dist/parser/Statement.js.map +1 -1
  61. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +73 -31
  62. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  63. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +148 -47
  64. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  65. package/dist/parser/tests/expression/TernaryExpression.spec.js +219 -37
  66. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  67. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  68. package/dist/parser/tests/statement/ConstStatement.spec.js +182 -0
  69. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  70. package/dist/parser/tests/statement/Enum.spec.js +17 -2
  71. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  72. package/dist/parser/tests/statement/PrintStatement.spec.js +72 -57
  73. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  74. package/dist/types/DynamicType.d.ts +1 -0
  75. package/dist/types/DynamicType.js +1 -0
  76. package/dist/types/DynamicType.js.map +1 -1
  77. package/dist/util.d.ts +15 -5
  78. package/dist/util.js +51 -5
  79. package/dist/util.js.map +1 -1
  80. package/dist/validators/ClassValidator.js +4 -6
  81. package/dist/validators/ClassValidator.js.map +1 -1
  82. package/package.json +1 -1
@@ -5,6 +5,7 @@ const Token_1 = require("../lexer/Token");
5
5
  const Lexer_1 = require("../lexer/Lexer");
6
6
  const TokenKind_1 = require("../lexer/TokenKind");
7
7
  const Statement_1 = require("./Statement");
8
+ const Statement_2 = require("./Statement");
8
9
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
9
10
  const util_1 = require("../util");
10
11
  const Expression_1 = require("./Expression");
@@ -13,6 +14,8 @@ const reflection_1 = require("../astUtils/reflection");
13
14
  const visitors_1 = require("../astUtils/visitors");
14
15
  const creators_1 = require("../astUtils/creators");
15
16
  const Cache_1 = require("../Cache");
17
+ const SymbolTable_1 = require("../SymbolTable");
18
+ const DynamicType_1 = require("../types/DynamicType");
16
19
  class Parser {
17
20
  constructor() {
18
21
  /**
@@ -22,7 +25,11 @@ class Parser {
22
25
  /**
23
26
  * The list of statements for the parsed file
24
27
  */
25
- this.ast = new Statement_1.Body([]);
28
+ this.ast = new Statement_2.Body([]);
29
+ /**
30
+ * The top-level symbol table for this file. Things like top-level namespaces, non-namespaced classes, enums, interfaces, and functions beling here.
31
+ */
32
+ this.symbolTable = new SymbolTable_1.SymbolTable();
26
33
  this._references = new References();
27
34
  this.globalTerminators = [];
28
35
  /**
@@ -33,6 +40,10 @@ class Parser {
33
40
  get statements() {
34
41
  return this.ast.statements;
35
42
  }
43
+ get currentSymbolTable() {
44
+ var _a, _b, _c, _d;
45
+ return (_d = (_b = (_a = this.currentFunctionExpression) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : (_c = this.currentNamespace) === null || _c === void 0 ? void 0 : _c.symbolTable) !== null && _d !== void 0 ? _d : this.symbolTable;
46
+ }
36
47
  /**
37
48
  * References for significant statements/expressions in the parser.
38
49
  * These are initially extracted during parse-time to improve performance, but will also be dynamically regenerated if need be.
@@ -68,6 +79,10 @@ class Parser {
68
79
  }
69
80
  }
70
81
  }
82
+ get currentNamespaceName() {
83
+ var _a;
84
+ return (_a = this.currentNamespace) === null || _a === void 0 ? void 0 : _a.nameExpression;
85
+ }
71
86
  /**
72
87
  * Get the currently active global terminators
73
88
  */
@@ -79,22 +94,22 @@ class Parser {
79
94
  * Static wrapper around creating a new parser and parsing a list of tokens
80
95
  */
81
96
  static parse(toParse, options) {
82
- let tokens;
83
- if (typeof toParse === 'string') {
84
- tokens = Lexer_1.Lexer.scan(toParse).tokens;
85
- }
86
- else {
87
- tokens = toParse;
88
- }
89
- return new Parser().parse(tokens, options);
97
+ return new Parser().parse(toParse, options);
90
98
  }
91
99
  /**
92
100
  * Parses an array of `Token`s into an abstract syntax tree
93
101
  * @param toParse the array of tokens to parse. May not contain any whitespace tokens
94
102
  * @returns the same instance of the parser which contains the diagnostics and statements
95
103
  */
96
- parse(tokens, options) {
104
+ parse(toParse, options) {
97
105
  var _a;
106
+ let tokens;
107
+ if (typeof toParse === 'string') {
108
+ tokens = Lexer_1.Lexer.scan(toParse).tokens;
109
+ }
110
+ else {
111
+ tokens = toParse;
112
+ }
98
113
  this.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : new Logger_1.Logger();
99
114
  this.tokens = tokens;
100
115
  this.options = this.sanitizeParseOptions(options);
@@ -112,7 +127,7 @@ class Parser {
112
127
  }
113
128
  body() {
114
129
  const parentAnnotations = this.enterAnnotationBlock();
115
- let body = new Statement_1.Body([]);
130
+ let body = new Statement_2.Body([]);
116
131
  if (this.tokens.length > 0) {
117
132
  this.consumeStatementSeparators(true);
118
133
  try {
@@ -178,6 +193,9 @@ class Parser {
178
193
  if (this.checkLibrary()) {
179
194
  return this.libraryStatement();
180
195
  }
196
+ if (this.check(TokenKind_1.TokenKind.Const)) {
197
+ return this.constDeclaration();
198
+ }
181
199
  if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
182
200
  return this.annotationExpression();
183
201
  }
@@ -216,7 +234,7 @@ class Parser {
216
234
  return identifier;
217
235
  }
218
236
  enumMemberStatement() {
219
- const statement = new Statement_1.EnumMemberStatement({});
237
+ const statement = new Statement_2.EnumMemberStatement({});
220
238
  statement.tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
221
239
  //look for `= SOME_EXPRESSION`
222
240
  if (this.check(TokenKind_1.TokenKind.Equal)) {
@@ -237,7 +255,7 @@ class Parser {
237
255
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text)), { range: typeToken.range }));
238
256
  throw this.lastDiagnosticAsError();
239
257
  }
240
- return new Statement_1.InterfaceFieldStatement(name, asToken, typeToken, type);
258
+ return new Statement_2.InterfaceFieldStatement(name, asToken, typeToken, type);
241
259
  }
242
260
  /**
243
261
  * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration()`
@@ -259,7 +277,7 @@ class Parser {
259
277
  throw this.lastDiagnosticAsError();
260
278
  }
261
279
  }
262
- return new Statement_1.InterfaceMethodStatement(functionType, name, leftParen, params, rightParen, asToken, returnTypeToken, util_1.util.tokenToBscType(returnTypeToken));
280
+ return new Statement_2.InterfaceMethodStatement(functionType, name, leftParen, params, rightParen, asToken, returnTypeToken, util_1.util.tokenToBscType(returnTypeToken));
263
281
  }
264
282
  interfaceDeclaration() {
265
283
  this.warnIfNotBrighterScriptMode('interface declarations');
@@ -316,13 +334,13 @@ class Parser {
316
334
  }
317
335
  //consume the final `end interface` token
318
336
  const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
319
- const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endInterfaceToken, this.currentNamespaceName);
337
+ const statement = new Statement_2.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endInterfaceToken, this.currentNamespaceName);
320
338
  this._references.interfaceStatements.push(statement);
321
339
  this.exitAnnotationBlock(parentAnnotations);
322
340
  return statement;
323
341
  }
324
342
  enumDeclaration() {
325
- const result = new Statement_1.EnumStatement({}, [], this.currentNamespaceName);
343
+ const result = new Statement_2.EnumStatement({}, [], this.currentNamespaceName);
326
344
  this.warnIfNotBrighterScriptMode('enum declarations');
327
345
  const parentAnnotations = this.enterAnnotationBlock();
328
346
  result.tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
@@ -366,6 +384,9 @@ class Parser {
366
384
  }
367
385
  //consume the final `end interface` token
368
386
  result.tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
387
+ if (result.name) {
388
+ this.currentSymbolTable.addSymbol(result.tokens.name.text, result.tokens.name.range, DynamicType_1.DynamicType.instance);
389
+ }
369
390
  this._references.enumStatements.push(result);
370
391
  this.exitAnnotationBlock(parentAnnotations);
371
392
  return result;
@@ -414,9 +435,11 @@ class Parser {
414
435
  if (overrideKeyword && funcDeclaration.name.text.toLowerCase() === 'new') {
415
436
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { range: overrideKeyword.range }));
416
437
  }
417
- decl = new Statement_1.MethodStatement(accessModifier, funcDeclaration.name, funcDeclaration.func, overrideKeyword);
438
+ decl = new Statement_2.MethodStatement(accessModifier, funcDeclaration.name, funcDeclaration.func, overrideKeyword);
418
439
  //refer to this statement as parent of the expression
419
440
  functionStatement.func.functionStatement = decl;
441
+ //add the `super` symbol to class methods
442
+ funcDeclaration.func.symbolTable.addSymbol('super', undefined, DynamicType_1.DynamicType.instance);
420
443
  //fields
421
444
  }
422
445
  else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
@@ -446,7 +469,10 @@ class Parser {
446
469
  if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
447
470
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
448
471
  }
449
- const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName);
472
+ const result = new Statement_2.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName);
473
+ if (className) {
474
+ this.currentSymbolTable.addSymbol(className.text, className.range, DynamicType_1.DynamicType.instance);
475
+ }
450
476
  this._references.classStatements.push(result);
451
477
  this.exitAnnotationBlock(parentAnnotations);
452
478
  return result;
@@ -471,9 +497,9 @@ class Parser {
471
497
  equal = this.advance();
472
498
  initialValue = this.expression();
473
499
  }
474
- return new Statement_1.FieldStatement(accessModifier, name, asToken, fieldType, equal, initialValue);
500
+ return new Statement_2.FieldStatement(accessModifier, name, asToken, fieldType, equal, initialValue);
475
501
  }
476
- functionDeclaration(isAnonymous, checkIdentifier = true) {
502
+ functionDeclaration(isAnonymous, checkIdentifier = true, onlyCallableAsMember = false) {
477
503
  var _a;
478
504
  let previousCallExpressions = this.callExpressions;
479
505
  this.callExpressions = [];
@@ -547,11 +573,21 @@ class Parser {
547
573
  this.consumeStatementSeparators(true);
548
574
  let func = new Expression_1.FunctionExpression(params, undefined, //body
549
575
  functionType, undefined, //ending keyword
550
- leftParen, rightParen, asToken, typeToken, this.currentFunctionExpression, this.currentNamespaceName);
576
+ leftParen, rightParen, asToken, typeToken, this.currentFunctionExpression, this.currentNamespaceName, this.currentSymbolTable);
577
+ if (!func.symbolTable.hasSymbol('m')) {
578
+ func.symbolTable.addSymbol('m', undefined, DynamicType_1.DynamicType.instance);
579
+ }
551
580
  //if there is a parent function, register this function with the parent
552
581
  if (this.currentFunctionExpression) {
553
582
  this.currentFunctionExpression.childFunctionExpressions.push(func);
554
583
  }
584
+ // add the function to the relevant symbol tables
585
+ if (!onlyCallableAsMember && name) {
586
+ const funcType = func.getFunctionType();
587
+ funcType.setName(name.text);
588
+ // add the function as declared to the current symbol table
589
+ this.currentSymbolTable.addSymbol(name.text, name.range, funcType);
590
+ }
555
591
  this._references.functionExpressions.push(func);
556
592
  let previousFunctionExpression = this.currentFunctionExpression;
557
593
  this.currentFunctionExpression = func;
@@ -580,7 +616,7 @@ class Parser {
580
616
  return func;
581
617
  }
582
618
  else {
583
- let result = new Statement_1.FunctionStatement(name, func, this.currentNamespaceName);
619
+ let result = new Statement_2.FunctionStatement(name, func, this.currentNamespaceName);
584
620
  func.functionStatement = result;
585
621
  this._references.functionStatements.push(result);
586
622
  return result;
@@ -628,16 +664,17 @@ class Parser {
628
664
  let value = this.expression();
629
665
  let result;
630
666
  if (operator.kind === TokenKind_1.TokenKind.Equal) {
631
- result = new Statement_1.AssignmentStatement(operator, name, value, this.currentFunctionExpression);
667
+ result = new Statement_2.AssignmentStatement(operator, name, value, this.currentFunctionExpression);
632
668
  }
633
669
  else {
634
670
  const nameExpression = new Expression_1.VariableExpression(name, this.currentNamespaceName);
635
- result = new Statement_1.AssignmentStatement(operator, name, new Expression_1.BinaryExpression(nameExpression, operator, value), this.currentFunctionExpression);
671
+ result = new Statement_2.AssignmentStatement(operator, name, new Expression_1.BinaryExpression(nameExpression, operator, value), this.currentFunctionExpression);
636
672
  this.addExpressionsToReferences(nameExpression);
637
673
  //remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
638
674
  this._references.expressions.delete(value);
639
675
  this._references.expressions.add(result);
640
676
  }
677
+ this.currentSymbolTable.addSymbol(name.text, name.range, DynamicType_1.DynamicType.instance);
641
678
  this._references.assignmentStatements.push(result);
642
679
  return result;
643
680
  }
@@ -757,11 +794,11 @@ class Parser {
757
794
  else {
758
795
  endWhile = this.advance();
759
796
  }
760
- return new Statement_1.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
797
+ return new Statement_2.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
761
798
  }
762
799
  exitWhile() {
763
800
  let keyword = this.advance();
764
- return new Statement_1.ExitWhileStatement({ exitWhile: keyword });
801
+ return new Statement_2.ExitWhileStatement({ exitWhile: keyword });
765
802
  }
766
803
  forStatement() {
767
804
  const forToken = this.advance();
@@ -792,7 +829,7 @@ class Parser {
792
829
  }
793
830
  // WARNING: BrightScript doesn't delete the loop initial value after a for/to loop! It just
794
831
  // stays around in scope with whatever value it was when the loop exited.
795
- return new Statement_1.ForStatement(forToken, initializer, toToken, finalValue, body, endForToken, stepToken, incrementExpression);
832
+ return new Statement_2.ForStatement(forToken, initializer, toToken, finalValue, body, endForToken, stepToken, incrementExpression);
796
833
  }
797
834
  forEachStatement() {
798
835
  let forEach = this.advance();
@@ -810,6 +847,7 @@ class Parser {
810
847
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
811
848
  throw this.lastDiagnosticAsError();
812
849
  }
850
+ this.currentSymbolTable.addSymbol(name.text, name.range, DynamicType_1.DynamicType.instance);
813
851
  this.consumeStatementSeparators();
814
852
  let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
815
853
  if (!body) {
@@ -817,7 +855,7 @@ class Parser {
817
855
  throw this.lastDiagnosticAsError();
818
856
  }
819
857
  let endFor = this.advance();
820
- return new Statement_1.ForEachStatement({
858
+ return new Statement_2.ForEachStatement({
821
859
  forEach: forEach,
822
860
  in: maybeIn,
823
861
  endFor: endFor
@@ -825,14 +863,14 @@ class Parser {
825
863
  }
826
864
  exitFor() {
827
865
  let keyword = this.advance();
828
- return new Statement_1.ExitForStatement({ exitFor: keyword });
866
+ return new Statement_2.ExitForStatement({ exitFor: keyword });
829
867
  }
830
868
  commentStatement() {
831
869
  //if this comment is on the same line as the previous statement,
832
870
  //then this comment should be treated as a single-line comment
833
871
  let prev = this.previous();
834
872
  if ((prev === null || prev === void 0 ? void 0 : prev.range.end.line) === this.peek().range.start.line) {
835
- return new Statement_1.CommentStatement([this.advance()]);
873
+ return new Statement_2.CommentStatement([this.advance()]);
836
874
  }
837
875
  else {
838
876
  let comments = [this.advance()];
@@ -840,7 +878,7 @@ class Parser {
840
878
  this.advance();
841
879
  comments.push(this.advance());
842
880
  }
843
- return new Statement_1.CommentStatement(comments);
881
+ return new Statement_2.CommentStatement(comments);
844
882
  }
845
883
  }
846
884
  namespaceStatement() {
@@ -852,12 +890,13 @@ class Parser {
852
890
  this.namespaceAndFunctionDepth++;
853
891
  let name = this.getNamespacedVariableNameExpression();
854
892
  //set the current namespace name
855
- this.currentNamespaceName = name;
893
+ let result = new Statement_2.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
894
+ this.currentNamespace = result;
856
895
  this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
857
896
  let body = this.body();
858
897
  this.globalTerminators.pop();
859
898
  //unset the current namespace name
860
- this.currentNamespaceName = undefined;
899
+ this.currentNamespace = undefined;
861
900
  let endKeyword;
862
901
  if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
863
902
  endKeyword = this.advance();
@@ -867,8 +906,14 @@ class Parser {
867
906
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('namespace')), { range: keyword.range }));
868
907
  }
869
908
  this.namespaceAndFunctionDepth--;
870
- let result = new Statement_1.NamespaceStatement(keyword, name, body, endKeyword);
909
+ result.body = body;
910
+ result.endKeyword = endKeyword;
871
911
  this._references.namespaceStatements.push(result);
912
+ //cache the range property so that plugins can't affect it
913
+ result.cacheRange();
914
+ if (result.name) {
915
+ this.symbolTable.addSymbol(result.name.split('.')[0], result.nameExpression.range, DynamicType_1.DynamicType.instance);
916
+ }
872
917
  return result;
873
918
  }
874
919
  /**
@@ -921,8 +966,24 @@ class Parser {
921
966
  }
922
967
  return result;
923
968
  }
969
+ constDeclaration() {
970
+ const constToken = this.advance();
971
+ const nameToken = this.identifier();
972
+ const equalToken = this.consumeToken(TokenKind_1.TokenKind.Equal);
973
+ const expression = this.expression();
974
+ const statement = new Statement_1.ConstStatement({
975
+ const: constToken,
976
+ name: nameToken,
977
+ equals: equalToken
978
+ }, expression, this.currentNamespaceName);
979
+ if (nameToken) {
980
+ this.currentSymbolTable.addSymbol(nameToken.text, nameToken.range, DynamicType_1.DynamicType.instance);
981
+ }
982
+ this._references.constStatements.push(statement);
983
+ return statement;
984
+ }
924
985
  libraryStatement() {
925
- let libStatement = new Statement_1.LibraryStatement({
986
+ let libStatement = new Statement_2.LibraryStatement({
926
987
  library: this.advance(),
927
988
  //grab the next token only if it's a string
928
989
  filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
@@ -932,7 +993,7 @@ class Parser {
932
993
  }
933
994
  importStatement() {
934
995
  this.warnIfNotBrighterScriptMode('import statements');
935
- let importStatement = new Statement_1.ImportStatement(this.advance(),
996
+ let importStatement = new Statement_2.ImportStatement(this.advance(),
936
997
  //grab the next token only if it's a string
937
998
  this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
938
999
  this._references.importStatements.push(importStatement);
@@ -1059,7 +1120,7 @@ class Parser {
1059
1120
  }
1060
1121
  tryCatchStatement() {
1061
1122
  const tryToken = this.advance();
1062
- const statement = new Statement_1.TryCatchStatement({ try: tryToken });
1123
+ const statement = new Statement_2.TryCatchStatement({ try: tryToken });
1063
1124
  //ensure statement separator
1064
1125
  this.consumeStatementSeparators();
1065
1126
  statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
@@ -1072,7 +1133,7 @@ class Parser {
1072
1133
  }
1073
1134
  return statement;
1074
1135
  }
1075
- const catchStmt = new Statement_1.CatchStatement({ catch: this.advance() });
1136
+ const catchStmt = new Statement_2.CatchStatement({ catch: this.advance() });
1076
1137
  statement.catchStatement = catchStmt;
1077
1138
  const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1078
1139
  if (exceptionVarToken) {
@@ -1089,6 +1150,9 @@ class Parser {
1089
1150
  else {
1090
1151
  statement.tokens.endTry = this.advance();
1091
1152
  }
1153
+ if (exceptionVarToken) {
1154
+ this.currentSymbolTable.addSymbol(exceptionVarToken.text, exceptionVarToken.range, DynamicType_1.DynamicType.instance);
1155
+ }
1092
1156
  return statement;
1093
1157
  }
1094
1158
  throwStatement() {
@@ -1100,7 +1164,7 @@ class Parser {
1100
1164
  else {
1101
1165
  expression = this.expression();
1102
1166
  }
1103
- return new Statement_1.ThrowStatement(throwToken, expression);
1167
+ return new Statement_2.ThrowStatement(throwToken, expression);
1104
1168
  }
1105
1169
  dimStatement() {
1106
1170
  const dim = this.advance();
@@ -1131,7 +1195,7 @@ class Parser {
1131
1195
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
1132
1196
  }
1133
1197
  let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
1134
- return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1198
+ return new Statement_2.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1135
1199
  }
1136
1200
  ifStatement() {
1137
1201
  // colon before `if` is usually not allowed, unless it's after `then`
@@ -1237,7 +1301,7 @@ class Parser {
1237
1301
  }
1238
1302
  }
1239
1303
  }
1240
- return new Statement_1.IfStatement({
1304
+ return new Statement_2.IfStatement({
1241
1305
  if: ifToken,
1242
1306
  then: thenToken,
1243
1307
  endIf: endIfToken,
@@ -1313,7 +1377,7 @@ class Parser {
1313
1377
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(colon.text)), { range: colon.range }));
1314
1378
  }
1315
1379
  }
1316
- return new Statement_1.Block(statements, startingRange);
1380
+ return new Statement_2.Block(statements, startingRange);
1317
1381
  }
1318
1382
  expressionStatement(expr) {
1319
1383
  let expressionStart = this.peek();
@@ -1327,12 +1391,12 @@ class Parser {
1327
1391
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
1328
1392
  throw this.lastDiagnosticAsError();
1329
1393
  }
1330
- const result = new Statement_1.IncrementStatement(expr, operator);
1394
+ const result = new Statement_2.IncrementStatement(expr, operator);
1331
1395
  this._references.expressions.add(result);
1332
1396
  return result;
1333
1397
  }
1334
1398
  if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
1335
- return new Statement_1.ExpressionStatement(expr);
1399
+ return new Statement_2.ExpressionStatement(expr);
1336
1400
  }
1337
1401
  //at this point, it's probably an error. However, we recover a little more gracefully by creating an assignment
1338
1402
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementOrFunctionCallButReceivedExpression()), { range: expressionStart.range }));
@@ -1352,12 +1416,12 @@ class Parser {
1352
1416
  let right = this.expression();
1353
1417
  // Create a dotted or indexed "set" based on the left-hand side's type
1354
1418
  if ((0, reflection_1.isIndexedGetExpression)(left)) {
1355
- return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
1419
+ return new Statement_2.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
1356
1420
  ? right
1357
1421
  : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
1358
1422
  }
1359
1423
  else if ((0, reflection_1.isDottedGetExpression)(left)) {
1360
- return new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal
1424
+ return new Statement_2.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal
1361
1425
  ? right
1362
1426
  : new Expression_1.BinaryExpression(left, operator, right));
1363
1427
  }
@@ -1390,7 +1454,7 @@ class Parser {
1390
1454
  if ((0, Token_1.isToken)(last)) {
1391
1455
  // TODO: error, expected value
1392
1456
  }
1393
- return new Statement_1.PrintStatement({ print: printKeyword }, values);
1457
+ return new Statement_2.PrintStatement({ print: printKeyword }, values);
1394
1458
  }
1395
1459
  /**
1396
1460
  * Parses a return statement with an optional return value.
@@ -1399,10 +1463,10 @@ class Parser {
1399
1463
  returnStatement() {
1400
1464
  let tokens = { return: this.previous() };
1401
1465
  if (this.checkEndOfStatement()) {
1402
- return new Statement_1.ReturnStatement(tokens);
1466
+ return new Statement_2.ReturnStatement(tokens);
1403
1467
  }
1404
1468
  let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
1405
- return new Statement_1.ReturnStatement(tokens, toReturn);
1469
+ return new Statement_2.ReturnStatement(tokens, toReturn);
1406
1470
  }
1407
1471
  /**
1408
1472
  * Parses a `label` statement
@@ -1419,7 +1483,7 @@ class Parser {
1419
1483
  this.current -= 2;
1420
1484
  throw new CancelStatementError();
1421
1485
  }
1422
- return new Statement_1.LabelStatement(tokens);
1486
+ return new Statement_2.LabelStatement(tokens);
1423
1487
  }
1424
1488
  /**
1425
1489
  * Parses a `goto` statement
@@ -1430,7 +1494,7 @@ class Parser {
1430
1494
  goto: this.advance(),
1431
1495
  label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
1432
1496
  };
1433
- return new Statement_1.GotoStatement(tokens);
1497
+ return new Statement_2.GotoStatement(tokens);
1434
1498
  }
1435
1499
  /**
1436
1500
  * Parses an `end` statement
@@ -1438,7 +1502,7 @@ class Parser {
1438
1502
  */
1439
1503
  endStatement() {
1440
1504
  let endTokens = { end: this.advance() };
1441
- return new Statement_1.EndStatement(endTokens);
1505
+ return new Statement_2.EndStatement(endTokens);
1442
1506
  }
1443
1507
  /**
1444
1508
  * Parses a `stop` statement
@@ -1446,7 +1510,7 @@ class Parser {
1446
1510
  */
1447
1511
  stopStatement() {
1448
1512
  let tokens = { stop: this.advance() };
1449
- return new Statement_1.StopStatement(tokens);
1513
+ return new Statement_2.StopStatement(tokens);
1450
1514
  }
1451
1515
  /**
1452
1516
  * Parses a block, looking for a specific terminating TokenKind to denote completion.
@@ -1498,7 +1562,7 @@ class Parser {
1498
1562
  }
1499
1563
  }
1500
1564
  this.exitAnnotationBlock(parentAnnotations);
1501
- return new Statement_1.Block(statements, startingToken.range);
1565
+ return new Statement_2.Block(statements, startingToken.range);
1502
1566
  }
1503
1567
  /**
1504
1568
  * Attach pending annotations to the provided statement,
@@ -1789,7 +1853,7 @@ class Parser {
1789
1853
  case this.check(TokenKind_1.TokenKind.RegexLiteral):
1790
1854
  return this.regexLiteralExpression();
1791
1855
  case this.check(TokenKind_1.TokenKind.Comment):
1792
- return new Statement_1.CommentStatement([this.advance()]);
1856
+ return new Statement_2.CommentStatement([this.advance()]);
1793
1857
  default:
1794
1858
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
1795
1859
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -1807,7 +1871,7 @@ class Parser {
1807
1871
  let openingSquare = this.previous();
1808
1872
  //add any comment found right after the opening square
1809
1873
  if (this.check(TokenKind_1.TokenKind.Comment)) {
1810
- elements.push(new Statement_1.CommentStatement([this.advance()]));
1874
+ elements.push(new Statement_2.CommentStatement([this.advance()]));
1811
1875
  }
1812
1876
  while (this.match(TokenKind_1.TokenKind.Newline)) {
1813
1877
  }
@@ -1816,7 +1880,7 @@ class Parser {
1816
1880
  while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1817
1881
  if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1818
1882
  let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1819
- elements.push(new Statement_1.CommentStatement([comment]));
1883
+ elements.push(new Statement_2.CommentStatement([comment]));
1820
1884
  }
1821
1885
  while (this.match(TokenKind_1.TokenKind.Newline)) {
1822
1886
  }
@@ -1859,7 +1923,7 @@ class Parser {
1859
1923
  let lastAAMember;
1860
1924
  if (this.check(TokenKind_1.TokenKind.Comment)) {
1861
1925
  lastAAMember = null;
1862
- members.push(new Statement_1.CommentStatement([this.advance()]));
1926
+ members.push(new Statement_2.CommentStatement([this.advance()]));
1863
1927
  }
1864
1928
  else {
1865
1929
  let k = key();
@@ -1875,7 +1939,7 @@ class Parser {
1875
1939
  //check for comment at the end of the current line
1876
1940
  if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1877
1941
  let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1878
- members.push(new Statement_1.CommentStatement([token]));
1942
+ members.push(new Statement_2.CommentStatement([token]));
1879
1943
  }
1880
1944
  else {
1881
1945
  this.consumeStatementSeparators(true);
@@ -1883,7 +1947,7 @@ class Parser {
1883
1947
  if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1884
1948
  let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1885
1949
  lastAAMember = null;
1886
- members.push(new Statement_1.CommentStatement([token]));
1950
+ members.push(new Statement_2.CommentStatement([token]));
1887
1951
  continue;
1888
1952
  }
1889
1953
  if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
@@ -2209,6 +2273,9 @@ class Parser {
2209
2273
  EnumStatement: e => {
2210
2274
  this._references.enumStatements.push(e);
2211
2275
  },
2276
+ ConstStatement: s => {
2277
+ this._references.constStatements.push(s);
2278
+ },
2212
2279
  UnaryExpression: e => {
2213
2280
  this._references.expressions.add(e);
2214
2281
  },
@@ -2237,6 +2304,7 @@ class References {
2237
2304
  this.functionStatements = [];
2238
2305
  this.interfaceStatements = [];
2239
2306
  this.enumStatements = [];
2307
+ this.constStatements = [];
2240
2308
  /**
2241
2309
  * A collection of full expressions. This excludes intermediary expressions.
2242
2310
  *
@@ -2296,6 +2364,15 @@ class References {
2296
2364
  return result;
2297
2365
  });
2298
2366
  }
2367
+ get constStatementLookup() {
2368
+ return this.cache.getOrAdd('consts', () => {
2369
+ const result = new Map();
2370
+ for (const stmt of this.constStatements) {
2371
+ result.set(stmt.fullName.toLowerCase(), stmt);
2372
+ }
2373
+ return result;
2374
+ });
2375
+ }
2299
2376
  }
2300
2377
  exports.References = References;
2301
2378
  class CancelStatementError extends Error {