brighterscript 0.52.1 → 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 (94) hide show
  1. package/CHANGELOG.md +28 -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 +8 -3
  6. package/dist/DiagnosticMessages.js +8 -3
  7. package/dist/DiagnosticMessages.js.map +1 -1
  8. package/dist/LanguageServer.d.ts +2 -1
  9. package/dist/LanguageServer.js +49 -17
  10. package/dist/LanguageServer.js.map +1 -1
  11. package/dist/Program.d.ts +10 -5
  12. package/dist/Program.js +80 -21
  13. package/dist/Program.js.map +1 -1
  14. package/dist/Scope.d.ts +24 -9
  15. package/dist/Scope.js +96 -50
  16. package/dist/Scope.js.map +1 -1
  17. package/dist/SymbolTable.d.ts +62 -0
  18. package/dist/SymbolTable.js +101 -0
  19. package/dist/SymbolTable.js.map +1 -0
  20. package/dist/astUtils/reflection.d.ts +2 -1
  21. package/dist/astUtils/reflection.js +6 -2
  22. package/dist/astUtils/reflection.js.map +1 -1
  23. package/dist/astUtils/visitors.d.ts +2 -1
  24. package/dist/astUtils/visitors.js.map +1 -1
  25. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  26. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +10 -5
  27. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  28. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +23 -34
  29. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  30. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +3 -1
  31. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  32. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +7 -1
  33. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +77 -30
  34. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
  35. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +5 -1
  36. package/dist/bscPlugin/validation/BrsFileValidator.js +28 -2
  37. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  38. package/dist/bscPlugin/validation/ScopeValidator.d.ts +18 -3
  39. package/dist/bscPlugin/validation/ScopeValidator.js +137 -47
  40. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  41. package/dist/files/BrsFile.Class.spec.js +59 -11
  42. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  43. package/dist/files/BrsFile.d.ts +10 -4
  44. package/dist/files/BrsFile.js +68 -21
  45. package/dist/files/BrsFile.js.map +1 -1
  46. package/dist/files/BrsFile.spec.js +120 -91
  47. package/dist/files/BrsFile.spec.js.map +1 -1
  48. package/dist/files/tests/imports.spec.js +1 -1
  49. package/dist/files/tests/imports.spec.js.map +1 -1
  50. package/dist/files/tests/optionalChaning.spec.js +20 -16
  51. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  52. package/dist/globalCallables.js +3 -0
  53. package/dist/globalCallables.js.map +1 -1
  54. package/dist/lexer/Lexer.spec.js +7 -0
  55. package/dist/lexer/Lexer.spec.js.map +1 -1
  56. package/dist/lexer/TokenKind.d.ts +1 -0
  57. package/dist/lexer/TokenKind.js +7 -3
  58. package/dist/lexer/TokenKind.js.map +1 -1
  59. package/dist/parser/Expression.d.ts +4 -1
  60. package/dist/parser/Expression.js +8 -2
  61. package/dist/parser/Expression.js.map +1 -1
  62. package/dist/parser/Parser.Class.spec.js +1 -1
  63. package/dist/parser/Parser.d.ts +17 -2
  64. package/dist/parser/Parser.js +167 -60
  65. package/dist/parser/Parser.js.map +1 -1
  66. package/dist/parser/Parser.spec.js +51 -7
  67. package/dist/parser/Parser.spec.js.map +1 -1
  68. package/dist/parser/Statement.d.ts +29 -1
  69. package/dist/parser/Statement.js +72 -9
  70. package/dist/parser/Statement.js.map +1 -1
  71. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +73 -31
  72. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  73. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +148 -47
  74. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  75. package/dist/parser/tests/expression/TernaryExpression.spec.js +219 -37
  76. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  77. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  78. package/dist/parser/tests/statement/ConstStatement.spec.js +182 -0
  79. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  80. package/dist/parser/tests/statement/Enum.spec.js +50 -2
  81. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  82. package/dist/parser/tests/statement/InterfaceStatement.spec.js +16 -2
  83. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  84. package/dist/parser/tests/statement/PrintStatement.spec.js +72 -57
  85. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  86. package/dist/types/DynamicType.d.ts +1 -0
  87. package/dist/types/DynamicType.js +1 -0
  88. package/dist/types/DynamicType.js.map +1 -1
  89. package/dist/util.d.ts +15 -5
  90. package/dist/util.js +54 -7
  91. package/dist/util.js.map +1 -1
  92. package/dist/validators/ClassValidator.js +4 -6
  93. package/dist/validators/ClassValidator.js.map +1 -1
  94. 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,14 +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
- result = new Statement_1.AssignmentStatement(operator, name, new Expression_1.BinaryExpression(new Expression_1.VariableExpression(name, this.currentNamespaceName), operator, value), this.currentFunctionExpression);
670
+ const nameExpression = new Expression_1.VariableExpression(name, this.currentNamespaceName);
671
+ result = new Statement_2.AssignmentStatement(operator, name, new Expression_1.BinaryExpression(nameExpression, operator, value), this.currentFunctionExpression);
672
+ this.addExpressionsToReferences(nameExpression);
635
673
  //remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
636
674
  this._references.expressions.delete(value);
637
675
  this._references.expressions.add(result);
638
676
  }
677
+ this.currentSymbolTable.addSymbol(name.text, name.range, DynamicType_1.DynamicType.instance);
639
678
  this._references.assignmentStatements.push(result);
640
679
  return result;
641
680
  }
@@ -755,11 +794,11 @@ class Parser {
755
794
  else {
756
795
  endWhile = this.advance();
757
796
  }
758
- return new Statement_1.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
797
+ return new Statement_2.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
759
798
  }
760
799
  exitWhile() {
761
800
  let keyword = this.advance();
762
- return new Statement_1.ExitWhileStatement({ exitWhile: keyword });
801
+ return new Statement_2.ExitWhileStatement({ exitWhile: keyword });
763
802
  }
764
803
  forStatement() {
765
804
  const forToken = this.advance();
@@ -790,7 +829,7 @@ class Parser {
790
829
  }
791
830
  // WARNING: BrightScript doesn't delete the loop initial value after a for/to loop! It just
792
831
  // stays around in scope with whatever value it was when the loop exited.
793
- 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);
794
833
  }
795
834
  forEachStatement() {
796
835
  let forEach = this.advance();
@@ -808,6 +847,7 @@ class Parser {
808
847
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
809
848
  throw this.lastDiagnosticAsError();
810
849
  }
850
+ this.currentSymbolTable.addSymbol(name.text, name.range, DynamicType_1.DynamicType.instance);
811
851
  this.consumeStatementSeparators();
812
852
  let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
813
853
  if (!body) {
@@ -815,7 +855,7 @@ class Parser {
815
855
  throw this.lastDiagnosticAsError();
816
856
  }
817
857
  let endFor = this.advance();
818
- return new Statement_1.ForEachStatement({
858
+ return new Statement_2.ForEachStatement({
819
859
  forEach: forEach,
820
860
  in: maybeIn,
821
861
  endFor: endFor
@@ -823,14 +863,14 @@ class Parser {
823
863
  }
824
864
  exitFor() {
825
865
  let keyword = this.advance();
826
- return new Statement_1.ExitForStatement({ exitFor: keyword });
866
+ return new Statement_2.ExitForStatement({ exitFor: keyword });
827
867
  }
828
868
  commentStatement() {
829
869
  //if this comment is on the same line as the previous statement,
830
870
  //then this comment should be treated as a single-line comment
831
871
  let prev = this.previous();
832
872
  if ((prev === null || prev === void 0 ? void 0 : prev.range.end.line) === this.peek().range.start.line) {
833
- return new Statement_1.CommentStatement([this.advance()]);
873
+ return new Statement_2.CommentStatement([this.advance()]);
834
874
  }
835
875
  else {
836
876
  let comments = [this.advance()];
@@ -838,7 +878,7 @@ class Parser {
838
878
  this.advance();
839
879
  comments.push(this.advance());
840
880
  }
841
- return new Statement_1.CommentStatement(comments);
881
+ return new Statement_2.CommentStatement(comments);
842
882
  }
843
883
  }
844
884
  namespaceStatement() {
@@ -850,12 +890,13 @@ class Parser {
850
890
  this.namespaceAndFunctionDepth++;
851
891
  let name = this.getNamespacedVariableNameExpression();
852
892
  //set the current namespace name
853
- this.currentNamespaceName = name;
893
+ let result = new Statement_2.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
894
+ this.currentNamespace = result;
854
895
  this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
855
896
  let body = this.body();
856
897
  this.globalTerminators.pop();
857
898
  //unset the current namespace name
858
- this.currentNamespaceName = undefined;
899
+ this.currentNamespace = undefined;
859
900
  let endKeyword;
860
901
  if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
861
902
  endKeyword = this.advance();
@@ -865,8 +906,14 @@ class Parser {
865
906
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('namespace')), { range: keyword.range }));
866
907
  }
867
908
  this.namespaceAndFunctionDepth--;
868
- let result = new Statement_1.NamespaceStatement(keyword, name, body, endKeyword);
909
+ result.body = body;
910
+ result.endKeyword = endKeyword;
869
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
+ }
870
917
  return result;
871
918
  }
872
919
  /**
@@ -919,8 +966,24 @@ class Parser {
919
966
  }
920
967
  return result;
921
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
+ }
922
985
  libraryStatement() {
923
- let libStatement = new Statement_1.LibraryStatement({
986
+ let libStatement = new Statement_2.LibraryStatement({
924
987
  library: this.advance(),
925
988
  //grab the next token only if it's a string
926
989
  filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
@@ -930,7 +993,7 @@ class Parser {
930
993
  }
931
994
  importStatement() {
932
995
  this.warnIfNotBrighterScriptMode('import statements');
933
- let importStatement = new Statement_1.ImportStatement(this.advance(),
996
+ let importStatement = new Statement_2.ImportStatement(this.advance(),
934
997
  //grab the next token only if it's a string
935
998
  this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
936
999
  this._references.importStatements.push(importStatement);
@@ -1057,7 +1120,7 @@ class Parser {
1057
1120
  }
1058
1121
  tryCatchStatement() {
1059
1122
  const tryToken = this.advance();
1060
- const statement = new Statement_1.TryCatchStatement({ try: tryToken });
1123
+ const statement = new Statement_2.TryCatchStatement({ try: tryToken });
1061
1124
  //ensure statement separator
1062
1125
  this.consumeStatementSeparators();
1063
1126
  statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
@@ -1070,7 +1133,7 @@ class Parser {
1070
1133
  }
1071
1134
  return statement;
1072
1135
  }
1073
- const catchStmt = new Statement_1.CatchStatement({ catch: this.advance() });
1136
+ const catchStmt = new Statement_2.CatchStatement({ catch: this.advance() });
1074
1137
  statement.catchStatement = catchStmt;
1075
1138
  const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1076
1139
  if (exceptionVarToken) {
@@ -1087,6 +1150,9 @@ class Parser {
1087
1150
  else {
1088
1151
  statement.tokens.endTry = this.advance();
1089
1152
  }
1153
+ if (exceptionVarToken) {
1154
+ this.currentSymbolTable.addSymbol(exceptionVarToken.text, exceptionVarToken.range, DynamicType_1.DynamicType.instance);
1155
+ }
1090
1156
  return statement;
1091
1157
  }
1092
1158
  throwStatement() {
@@ -1098,7 +1164,7 @@ class Parser {
1098
1164
  else {
1099
1165
  expression = this.expression();
1100
1166
  }
1101
- return new Statement_1.ThrowStatement(throwToken, expression);
1167
+ return new Statement_2.ThrowStatement(throwToken, expression);
1102
1168
  }
1103
1169
  dimStatement() {
1104
1170
  const dim = this.advance();
@@ -1129,7 +1195,7 @@ class Parser {
1129
1195
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
1130
1196
  }
1131
1197
  let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
1132
- return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1198
+ return new Statement_2.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1133
1199
  }
1134
1200
  ifStatement() {
1135
1201
  // colon before `if` is usually not allowed, unless it's after `then`
@@ -1235,7 +1301,7 @@ class Parser {
1235
1301
  }
1236
1302
  }
1237
1303
  }
1238
- return new Statement_1.IfStatement({
1304
+ return new Statement_2.IfStatement({
1239
1305
  if: ifToken,
1240
1306
  then: thenToken,
1241
1307
  endIf: endIfToken,
@@ -1311,7 +1377,7 @@ class Parser {
1311
1377
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(colon.text)), { range: colon.range }));
1312
1378
  }
1313
1379
  }
1314
- return new Statement_1.Block(statements, startingRange);
1380
+ return new Statement_2.Block(statements, startingRange);
1315
1381
  }
1316
1382
  expressionStatement(expr) {
1317
1383
  let expressionStart = this.peek();
@@ -1325,12 +1391,12 @@ class Parser {
1325
1391
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
1326
1392
  throw this.lastDiagnosticAsError();
1327
1393
  }
1328
- const result = new Statement_1.IncrementStatement(expr, operator);
1394
+ const result = new Statement_2.IncrementStatement(expr, operator);
1329
1395
  this._references.expressions.add(result);
1330
1396
  return result;
1331
1397
  }
1332
1398
  if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
1333
- return new Statement_1.ExpressionStatement(expr);
1399
+ return new Statement_2.ExpressionStatement(expr);
1334
1400
  }
1335
1401
  //at this point, it's probably an error. However, we recover a little more gracefully by creating an assignment
1336
1402
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementOrFunctionCallButReceivedExpression()), { range: expressionStart.range }));
@@ -1350,12 +1416,12 @@ class Parser {
1350
1416
  let right = this.expression();
1351
1417
  // Create a dotted or indexed "set" based on the left-hand side's type
1352
1418
  if ((0, reflection_1.isIndexedGetExpression)(left)) {
1353
- 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
1354
1420
  ? right
1355
1421
  : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
1356
1422
  }
1357
1423
  else if ((0, reflection_1.isDottedGetExpression)(left)) {
1358
- 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
1359
1425
  ? right
1360
1426
  : new Expression_1.BinaryExpression(left, operator, right));
1361
1427
  }
@@ -1388,7 +1454,7 @@ class Parser {
1388
1454
  if ((0, Token_1.isToken)(last)) {
1389
1455
  // TODO: error, expected value
1390
1456
  }
1391
- return new Statement_1.PrintStatement({ print: printKeyword }, values);
1457
+ return new Statement_2.PrintStatement({ print: printKeyword }, values);
1392
1458
  }
1393
1459
  /**
1394
1460
  * Parses a return statement with an optional return value.
@@ -1397,10 +1463,10 @@ class Parser {
1397
1463
  returnStatement() {
1398
1464
  let tokens = { return: this.previous() };
1399
1465
  if (this.checkEndOfStatement()) {
1400
- return new Statement_1.ReturnStatement(tokens);
1466
+ return new Statement_2.ReturnStatement(tokens);
1401
1467
  }
1402
1468
  let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
1403
- return new Statement_1.ReturnStatement(tokens, toReturn);
1469
+ return new Statement_2.ReturnStatement(tokens, toReturn);
1404
1470
  }
1405
1471
  /**
1406
1472
  * Parses a `label` statement
@@ -1417,7 +1483,7 @@ class Parser {
1417
1483
  this.current -= 2;
1418
1484
  throw new CancelStatementError();
1419
1485
  }
1420
- return new Statement_1.LabelStatement(tokens);
1486
+ return new Statement_2.LabelStatement(tokens);
1421
1487
  }
1422
1488
  /**
1423
1489
  * Parses a `goto` statement
@@ -1428,7 +1494,7 @@ class Parser {
1428
1494
  goto: this.advance(),
1429
1495
  label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
1430
1496
  };
1431
- return new Statement_1.GotoStatement(tokens);
1497
+ return new Statement_2.GotoStatement(tokens);
1432
1498
  }
1433
1499
  /**
1434
1500
  * Parses an `end` statement
@@ -1436,7 +1502,7 @@ class Parser {
1436
1502
  */
1437
1503
  endStatement() {
1438
1504
  let endTokens = { end: this.advance() };
1439
- return new Statement_1.EndStatement(endTokens);
1505
+ return new Statement_2.EndStatement(endTokens);
1440
1506
  }
1441
1507
  /**
1442
1508
  * Parses a `stop` statement
@@ -1444,7 +1510,7 @@ class Parser {
1444
1510
  */
1445
1511
  stopStatement() {
1446
1512
  let tokens = { stop: this.advance() };
1447
- return new Statement_1.StopStatement(tokens);
1513
+ return new Statement_2.StopStatement(tokens);
1448
1514
  }
1449
1515
  /**
1450
1516
  * Parses a block, looking for a specific terminating TokenKind to denote completion.
@@ -1496,7 +1562,7 @@ class Parser {
1496
1562
  }
1497
1563
  }
1498
1564
  this.exitAnnotationBlock(parentAnnotations);
1499
- return new Statement_1.Block(statements, startingToken.range);
1565
+ return new Statement_2.Block(statements, startingToken.range);
1500
1566
  }
1501
1567
  /**
1502
1568
  * Attach pending annotations to the provided statement,
@@ -1554,6 +1620,7 @@ class Parser {
1554
1620
  while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
1555
1621
  let operator = this.previous();
1556
1622
  let right = this.relational();
1623
+ this.addExpressionsToReferences(expr, right);
1557
1624
  expr = new Expression_1.BinaryExpression(expr, operator, right);
1558
1625
  }
1559
1626
  return expr;
@@ -1563,16 +1630,25 @@ class Parser {
1563
1630
  while (this.matchAny(TokenKind_1.TokenKind.Equal, TokenKind_1.TokenKind.LessGreater, TokenKind_1.TokenKind.Greater, TokenKind_1.TokenKind.GreaterEqual, TokenKind_1.TokenKind.Less, TokenKind_1.TokenKind.LessEqual)) {
1564
1631
  let operator = this.previous();
1565
1632
  let right = this.additive();
1633
+ this.addExpressionsToReferences(expr, right);
1566
1634
  expr = new Expression_1.BinaryExpression(expr, operator, right);
1567
1635
  }
1568
1636
  return expr;
1569
1637
  }
1638
+ addExpressionsToReferences(...expressions) {
1639
+ for (const expression of expressions) {
1640
+ if (!(0, reflection_1.isBinaryExpression)(expression)) {
1641
+ this.references.expressions.add(expression);
1642
+ }
1643
+ }
1644
+ }
1570
1645
  // TODO: bitshift
1571
1646
  additive() {
1572
1647
  let expr = this.multiplicative();
1573
1648
  while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
1574
1649
  let operator = this.previous();
1575
1650
  let right = this.multiplicative();
1651
+ this.addExpressionsToReferences(expr, right);
1576
1652
  expr = new Expression_1.BinaryExpression(expr, operator, right);
1577
1653
  }
1578
1654
  return expr;
@@ -1582,6 +1658,7 @@ class Parser {
1582
1658
  while (this.matchAny(TokenKind_1.TokenKind.Forwardslash, TokenKind_1.TokenKind.Backslash, TokenKind_1.TokenKind.Star, TokenKind_1.TokenKind.Mod, TokenKind_1.TokenKind.LeftShift, TokenKind_1.TokenKind.RightShift)) {
1583
1659
  let operator = this.previous();
1584
1660
  let right = this.exponential();
1661
+ this.addExpressionsToReferences(expr, right);
1585
1662
  expr = new Expression_1.BinaryExpression(expr, operator, right);
1586
1663
  }
1587
1664
  return expr;
@@ -1591,6 +1668,7 @@ class Parser {
1591
1668
  while (this.match(TokenKind_1.TokenKind.Caret)) {
1592
1669
  let operator = this.previous();
1593
1670
  let right = this.prefixUnary();
1671
+ this.addExpressionsToReferences(expr, right);
1594
1672
  expr = new Expression_1.BinaryExpression(expr, operator, right);
1595
1673
  }
1596
1674
  return expr;
@@ -1775,7 +1853,7 @@ class Parser {
1775
1853
  case this.check(TokenKind_1.TokenKind.RegexLiteral):
1776
1854
  return this.regexLiteralExpression();
1777
1855
  case this.check(TokenKind_1.TokenKind.Comment):
1778
- return new Statement_1.CommentStatement([this.advance()]);
1856
+ return new Statement_2.CommentStatement([this.advance()]);
1779
1857
  default:
1780
1858
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
1781
1859
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -1793,7 +1871,7 @@ class Parser {
1793
1871
  let openingSquare = this.previous();
1794
1872
  //add any comment found right after the opening square
1795
1873
  if (this.check(TokenKind_1.TokenKind.Comment)) {
1796
- elements.push(new Statement_1.CommentStatement([this.advance()]));
1874
+ elements.push(new Statement_2.CommentStatement([this.advance()]));
1797
1875
  }
1798
1876
  while (this.match(TokenKind_1.TokenKind.Newline)) {
1799
1877
  }
@@ -1802,7 +1880,7 @@ class Parser {
1802
1880
  while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1803
1881
  if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1804
1882
  let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1805
- elements.push(new Statement_1.CommentStatement([comment]));
1883
+ elements.push(new Statement_2.CommentStatement([comment]));
1806
1884
  }
1807
1885
  while (this.match(TokenKind_1.TokenKind.Newline)) {
1808
1886
  }
@@ -1845,7 +1923,7 @@ class Parser {
1845
1923
  let lastAAMember;
1846
1924
  if (this.check(TokenKind_1.TokenKind.Comment)) {
1847
1925
  lastAAMember = null;
1848
- members.push(new Statement_1.CommentStatement([this.advance()]));
1926
+ members.push(new Statement_2.CommentStatement([this.advance()]));
1849
1927
  }
1850
1928
  else {
1851
1929
  let k = key();
@@ -1861,7 +1939,7 @@ class Parser {
1861
1939
  //check for comment at the end of the current line
1862
1940
  if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1863
1941
  let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1864
- members.push(new Statement_1.CommentStatement([token]));
1942
+ members.push(new Statement_2.CommentStatement([token]));
1865
1943
  }
1866
1944
  else {
1867
1945
  this.consumeStatementSeparators(true);
@@ -1869,7 +1947,7 @@ class Parser {
1869
1947
  if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1870
1948
  let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1871
1949
  lastAAMember = null;
1872
- members.push(new Statement_1.CommentStatement([token]));
1950
+ members.push(new Statement_2.CommentStatement([token]));
1873
1951
  continue;
1874
1952
  }
1875
1953
  if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
@@ -2165,6 +2243,19 @@ class Parser {
2165
2243
  }
2166
2244
  }
2167
2245
  },
2246
+ BinaryExpression: (e, parent) => {
2247
+ //walk the chain of binary expressions and add each one to the list of expressions
2248
+ const expressions = [e];
2249
+ let expression;
2250
+ while ((expression = expressions.pop())) {
2251
+ if ((0, reflection_1.isBinaryExpression)(expression)) {
2252
+ expressions.push(expression.left, expression.right);
2253
+ }
2254
+ else {
2255
+ this._references.expressions.add(expression);
2256
+ }
2257
+ }
2258
+ },
2168
2259
  ArrayLiteralExpression: e => {
2169
2260
  for (const element of e.elements) {
2170
2261
  //keep everything except comments
@@ -2182,6 +2273,9 @@ class Parser {
2182
2273
  EnumStatement: e => {
2183
2274
  this._references.enumStatements.push(e);
2184
2275
  },
2276
+ ConstStatement: s => {
2277
+ this._references.constStatements.push(s);
2278
+ },
2185
2279
  UnaryExpression: e => {
2186
2280
  this._references.expressions.add(e);
2187
2281
  },
@@ -2210,6 +2304,7 @@ class References {
2210
2304
  this.functionStatements = [];
2211
2305
  this.interfaceStatements = [];
2212
2306
  this.enumStatements = [];
2307
+ this.constStatements = [];
2213
2308
  /**
2214
2309
  * A collection of full expressions. This excludes intermediary expressions.
2215
2310
  *
@@ -2219,6 +2314,9 @@ class References {
2219
2314
  *
2220
2315
  * Example 2:
2221
2316
  * `name.space.doSomething(a.b.c)` will result in 2 entries in this list. the `CallExpression` for `doSomething`, and the `.c` DottedGetExpression.
2317
+ *
2318
+ * Example 3:
2319
+ * `value = SomeEnum.value > 2 or SomeEnum.otherValue < 10` will result in 4 entries. `SomeEnum.value`, `2`, `SomeEnum.otherValue`, `10`
2222
2320
  */
2223
2321
  this.expressions = new Set();
2224
2322
  this.importStatements = [];
@@ -2266,6 +2364,15 @@ class References {
2266
2364
  return result;
2267
2365
  });
2268
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
+ }
2269
2376
  }
2270
2377
  exports.References = References;
2271
2378
  class CancelStatementError extends Error {