brighterscript 1.0.0-alpha.13 → 1.0.0-alpha.16

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 (229) hide show
  1. package/CHANGELOG.md +87 -2
  2. package/dist/Cache.d.ts +3 -8
  3. package/dist/Cache.js +9 -14
  4. package/dist/Cache.js.map +1 -1
  5. package/dist/DependencyGraph.js +5 -4
  6. package/dist/DependencyGraph.js.map +1 -1
  7. package/dist/DiagnosticMessages.d.ts +21 -1
  8. package/dist/DiagnosticMessages.js +21 -1
  9. package/dist/DiagnosticMessages.js.map +1 -1
  10. package/dist/LanguageServer.d.ts +1 -6
  11. package/dist/LanguageServer.js +0 -9
  12. package/dist/LanguageServer.js.map +1 -1
  13. package/dist/PluginInterface.d.ts +3 -3
  14. package/dist/PluginInterface.js +3 -0
  15. package/dist/PluginInterface.js.map +1 -1
  16. package/dist/Program.d.ts +30 -16
  17. package/dist/Program.js +108 -43
  18. package/dist/Program.js.map +1 -1
  19. package/dist/ProgramBuilder.js +3 -3
  20. package/dist/ProgramBuilder.js.map +1 -1
  21. package/dist/Scope.d.ts +29 -15
  22. package/dist/Scope.js +68 -28
  23. package/dist/Scope.js.map +1 -1
  24. package/dist/SymbolTable.d.ts +1 -1
  25. package/dist/XmlScope.d.ts +3 -3
  26. package/dist/astUtils/AstEditor.d.ts +6 -0
  27. package/dist/astUtils/AstEditor.js +10 -0
  28. package/dist/astUtils/AstEditor.js.map +1 -1
  29. package/dist/astUtils/AstEditor.spec.js +37 -0
  30. package/dist/astUtils/AstEditor.spec.js.map +1 -1
  31. package/dist/astUtils/creators.d.ts +8 -4
  32. package/dist/astUtils/creators.js +87 -6
  33. package/dist/astUtils/creators.js.map +1 -1
  34. package/dist/astUtils/reflection.d.ts +5 -1
  35. package/dist/astUtils/reflection.js +15 -3
  36. package/dist/astUtils/reflection.js.map +1 -1
  37. package/dist/astUtils/reflection.spec.js +11 -10
  38. package/dist/astUtils/reflection.spec.js.map +1 -1
  39. package/dist/astUtils/visitors.d.ts +3 -1
  40. package/dist/astUtils/visitors.js.map +1 -1
  41. package/dist/astUtils/visitors.spec.js +8 -8
  42. package/dist/astUtils/visitors.spec.js.map +1 -1
  43. package/dist/bscPlugin/BscPlugin.d.ts +4 -1
  44. package/dist/bscPlugin/BscPlugin.js +21 -2
  45. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  46. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +3 -3
  47. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  48. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  49. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +9 -0
  50. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +97 -0
  51. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  52. package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.d.ts → BrsFileSemanticTokensProcessor.spec.d.ts} +0 -0
  53. package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.js → BrsFileSemanticTokensProcessor.spec.js} +30 -2
  54. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
  55. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
  56. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +36 -0
  57. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
  58. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
  59. package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
  60. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  61. package/dist/bscPlugin/validation/ScopeValidator.d.ts +11 -0
  62. package/dist/bscPlugin/validation/ScopeValidator.js +94 -0
  63. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  64. package/dist/diagnosticUtils.js +3 -3
  65. package/dist/diagnosticUtils.js.map +1 -1
  66. package/dist/files/BrsFile.Class.spec.js +382 -232
  67. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  68. package/dist/files/BrsFile.d.ts +26 -12
  69. package/dist/files/BrsFile.js +268 -119
  70. package/dist/files/BrsFile.js.map +1 -1
  71. package/dist/files/BrsFile.spec.js +570 -168
  72. package/dist/files/BrsFile.spec.js.map +1 -1
  73. package/dist/files/XmlFile.d.ts +11 -10
  74. package/dist/files/XmlFile.js +16 -11
  75. package/dist/files/XmlFile.js.map +1 -1
  76. package/dist/files/XmlFile.spec.js +60 -58
  77. package/dist/files/XmlFile.spec.js.map +1 -1
  78. package/dist/files/tests/imports.spec.js +8 -6
  79. package/dist/files/tests/imports.spec.js.map +1 -1
  80. package/dist/index.d.ts +12 -3
  81. package/dist/index.js +21 -4
  82. package/dist/index.js.map +1 -1
  83. package/dist/interfaces.d.ts +63 -35
  84. package/dist/lexer/Lexer.js +1 -2
  85. package/dist/lexer/Lexer.js.map +1 -1
  86. package/dist/lexer/Lexer.spec.js +470 -462
  87. package/dist/lexer/Lexer.spec.js.map +1 -1
  88. package/dist/lexer/TokenKind.d.ts +2 -0
  89. package/dist/lexer/TokenKind.js +5 -0
  90. package/dist/lexer/TokenKind.js.map +1 -1
  91. package/dist/parser/Expression.d.ts +18 -16
  92. package/dist/parser/Expression.js +57 -48
  93. package/dist/parser/Expression.js.map +1 -1
  94. package/dist/parser/Parser.Class.spec.js +33 -32
  95. package/dist/parser/Parser.Class.spec.js.map +1 -1
  96. package/dist/parser/Parser.d.ts +28 -7
  97. package/dist/parser/Parser.js +508 -296
  98. package/dist/parser/Parser.js.map +1 -1
  99. package/dist/parser/Parser.spec.js +157 -35
  100. package/dist/parser/Parser.spec.js.map +1 -1
  101. package/dist/parser/SGTypes.spec.js +9 -9
  102. package/dist/parser/SGTypes.spec.js.map +1 -1
  103. package/dist/parser/Statement.d.ts +80 -20
  104. package/dist/parser/Statement.js +257 -92
  105. package/dist/parser/Statement.js.map +1 -1
  106. package/dist/parser/tests/Parser.spec.d.ts +3 -3
  107. package/dist/parser/tests/Parser.spec.js +4 -4
  108. package/dist/parser/tests/Parser.spec.js.map +1 -1
  109. package/dist/parser/tests/controlFlow/For.spec.js +40 -40
  110. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  111. package/dist/parser/tests/controlFlow/ForEach.spec.js +22 -21
  112. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  113. package/dist/parser/tests/controlFlow/If.spec.js +100 -99
  114. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  115. package/dist/parser/tests/controlFlow/While.spec.js +25 -25
  116. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  117. package/dist/parser/tests/expression/Additive.spec.js +21 -21
  118. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  119. package/dist/parser/tests/expression/ArrayLiterals.spec.js +91 -91
  120. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  121. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +102 -102
  122. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  123. package/dist/parser/tests/expression/Boolean.spec.js +15 -15
  124. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  125. package/dist/parser/tests/expression/Call.spec.js +22 -21
  126. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  127. package/dist/parser/tests/expression/Exponential.spec.js +11 -11
  128. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  129. package/dist/parser/tests/expression/Function.spec.js +171 -171
  130. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  131. package/dist/parser/tests/expression/Indexing.spec.js +50 -50
  132. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  133. package/dist/parser/tests/expression/Multiplicative.spec.js +25 -25
  134. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  135. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
  136. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  137. package/dist/parser/tests/expression/PrefixUnary.spec.js +26 -26
  138. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  139. package/dist/parser/tests/expression/Primary.spec.js +27 -27
  140. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  141. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +3 -2
  142. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  143. package/dist/parser/tests/expression/Relational.spec.js +25 -25
  144. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  145. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +7 -7
  146. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  147. package/dist/parser/tests/expression/TernaryExpression.spec.js +6 -6
  148. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  149. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  150. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  151. package/dist/parser/tests/statement/Declaration.spec.js +20 -20
  152. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  153. package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
  154. package/dist/parser/tests/statement/Enum.spec.js +774 -0
  155. package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
  156. package/dist/parser/tests/statement/For.spec.d.ts +1 -0
  157. package/dist/parser/tests/statement/For.spec.js +46 -0
  158. package/dist/parser/tests/statement/For.spec.js.map +1 -0
  159. package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
  160. package/dist/parser/tests/statement/ForEach.spec.js +37 -0
  161. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
  162. package/dist/parser/tests/statement/Function.spec.js +121 -120
  163. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  164. package/dist/parser/tests/statement/Goto.spec.js +9 -8
  165. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  166. package/dist/parser/tests/statement/Increment.spec.js +22 -22
  167. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  168. package/dist/parser/tests/statement/InterfaceStatement.spec.js +12 -0
  169. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  170. package/dist/parser/tests/statement/LibraryStatement.spec.js +7 -7
  171. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  172. package/dist/parser/tests/statement/Misc.spec.js +71 -70
  173. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  174. package/dist/parser/tests/statement/PrintStatement.spec.js +17 -17
  175. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  176. package/dist/parser/tests/statement/ReturnStatement.spec.js +33 -33
  177. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  178. package/dist/parser/tests/statement/Set.spec.js +53 -53
  179. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  180. package/dist/parser/tests/statement/Stop.spec.js +7 -6
  181. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  182. package/dist/preprocessor/Chunk.d.ts +1 -1
  183. package/dist/preprocessor/Preprocessor.d.ts +1 -1
  184. package/dist/preprocessor/Preprocessor.js +7 -7
  185. package/dist/preprocessor/Preprocessor.js.map +1 -1
  186. package/dist/types/ArrayType.d.ts +8 -5
  187. package/dist/types/ArrayType.js +45 -9
  188. package/dist/types/ArrayType.js.map +1 -1
  189. package/dist/types/ArrayType.spec.js +62 -3
  190. package/dist/types/ArrayType.spec.js.map +1 -1
  191. package/dist/types/BscType.d.ts +1 -1
  192. package/dist/types/CustomType.d.ts +1 -1
  193. package/dist/types/CustomType.js +4 -2
  194. package/dist/types/CustomType.js.map +1 -1
  195. package/dist/types/FunctionType.d.ts +7 -6
  196. package/dist/types/FunctionType.js +21 -18
  197. package/dist/types/FunctionType.js.map +1 -1
  198. package/dist/types/FunctionType.spec.js +6 -0
  199. package/dist/types/FunctionType.spec.js.map +1 -1
  200. package/dist/types/LazyType.d.ts +1 -2
  201. package/dist/types/LazyType.js +1 -5
  202. package/dist/types/LazyType.js.map +1 -1
  203. package/dist/types/UniversalFunctionType.d.ts +9 -0
  204. package/dist/types/UniversalFunctionType.js +25 -0
  205. package/dist/types/UniversalFunctionType.js.map +1 -0
  206. package/dist/types/helpers.js +1 -1
  207. package/dist/types/helpers.js.map +1 -1
  208. package/dist/util.d.ts +26 -10
  209. package/dist/util.js +145 -61
  210. package/dist/util.js.map +1 -1
  211. package/dist/validators/ClassValidator.js +17 -24
  212. package/dist/validators/ClassValidator.js.map +1 -1
  213. package/package.json +3 -3
  214. package/dist/astUtils/index.d.ts +0 -7
  215. package/dist/astUtils/index.js +0 -26
  216. package/dist/astUtils/index.js.map +0 -1
  217. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +0 -7
  218. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +0 -63
  219. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +0 -1
  220. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +0 -1
  221. package/dist/lexer/index.d.ts +0 -3
  222. package/dist/lexer/index.js +0 -18
  223. package/dist/lexer/index.js.map +0 -1
  224. package/dist/parser/index.d.ts +0 -3
  225. package/dist/parser/index.js +0 -16
  226. package/dist/parser/index.js.map +0 -1
  227. package/dist/preprocessor/index.d.ts +0 -3
  228. package/dist/preprocessor/index.js +0 -16
  229. package/dist/preprocessor/index.js.map +0 -1
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getBscTypeFromExpression = exports.TokenUsage = exports.References = exports.ParseMode = exports.Parser = void 0;
4
- const lexer_1 = require("../lexer");
4
+ const Token_1 = require("../lexer/Token");
5
+ const Lexer_1 = require("../lexer/Lexer");
6
+ const TokenKind_1 = require("../lexer/TokenKind");
5
7
  const Statement_1 = require("./Statement");
6
8
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
7
9
  const util_1 = require("../util");
@@ -10,12 +12,12 @@ const Logger_1 = require("../Logger");
10
12
  const reflection_1 = require("../astUtils/reflection");
11
13
  const visitors_1 = require("../astUtils/visitors");
12
14
  const creators_1 = require("../astUtils/creators");
15
+ const Cache_1 = require("../Cache");
13
16
  const DynamicType_1 = require("../types/DynamicType");
14
- const SymbolTable_1 = require("../SymbolTable");
15
- const ObjectType_1 = require("../types/ObjectType");
16
17
  const ArrayType_1 = require("../types/ArrayType");
17
18
  const helpers_1 = require("../types/helpers");
18
- const _1 = require(".");
19
+ const SymbolTable_1 = require("../SymbolTable");
20
+ const ObjectType_1 = require("../types/ObjectType");
19
21
  class Parser {
20
22
  constructor() {
21
23
  /**
@@ -61,7 +63,7 @@ class Parser {
61
63
  this._references = undefined;
62
64
  }
63
65
  addPropertyHints(item) {
64
- if ((0, lexer_1.isToken)(item)) {
66
+ if ((0, Token_1.isToken)(item)) {
65
67
  const name = item.text;
66
68
  this._references.propertyHints[name.toLowerCase()] = name;
67
69
  }
@@ -93,7 +95,7 @@ class Parser {
93
95
  static parse(toParse, options) {
94
96
  let tokens;
95
97
  if (typeof toParse === 'string') {
96
- tokens = lexer_1.Lexer.scan(toParse).tokens;
98
+ tokens = Lexer_1.Lexer.scan(toParse).tokens;
97
99
  }
98
100
  else {
99
101
  tokens = toParse;
@@ -111,9 +113,9 @@ class Parser {
111
113
  this.tokens = tokens;
112
114
  this.options = this.sanitizeParseOptions(options);
113
115
  this.allowedLocalIdentifiers = [
114
- ...lexer_1.AllowedLocalIdentifiers,
116
+ ...TokenKind_1.AllowedLocalIdentifiers,
115
117
  //when in plain brightscript mode, the BrighterScript source literals can be used as regular variables
116
- ...(this.options.mode === ParseMode.BrightScript ? lexer_1.BrighterScriptSourceLiterals : [])
118
+ ...(this.options.mode === ParseMode.BrightScript ? TokenKind_1.BrighterScriptSourceLiterals : [])
117
119
  ];
118
120
  this.current = 0;
119
121
  this.diagnostics = [];
@@ -184,16 +186,16 @@ class Parser {
184
186
  }
185
187
  declaration() {
186
188
  try {
187
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
189
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
188
190
  return this.functionDeclaration(false);
189
191
  }
190
192
  if (this.checkLibrary()) {
191
193
  return this.libraryStatement();
192
194
  }
193
- if (this.check(lexer_1.TokenKind.At) && this.checkNext(lexer_1.TokenKind.Identifier)) {
195
+ if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
194
196
  return this.annotationExpression();
195
197
  }
196
- if (this.check(lexer_1.TokenKind.Comment)) {
198
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
197
199
  return this.commentStatement();
198
200
  }
199
201
  //catch certain global terminators to prevent unnecessary lookahead (i.e. like `end namespace`, no need to continue)
@@ -210,18 +212,40 @@ class Parser {
210
212
  this.synchronize();
211
213
  }
212
214
  }
215
+ /**
216
+ * Try to get an identifier. If not found, add diagnostic and return undefined
217
+ */
218
+ tryIdentifier(...additionalTokenKinds) {
219
+ const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
220
+ if (identifier) {
221
+ // force the name into an identifier so the AST makes some sense
222
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
223
+ return identifier;
224
+ }
225
+ }
213
226
  identifier(...additionalTokenKinds) {
214
- const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...additionalTokenKinds);
227
+ const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
215
228
  // force the name into an identifier so the AST makes some sense
216
- identifier.kind = lexer_1.TokenKind.Identifier;
229
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
217
230
  return identifier;
218
231
  }
232
+ enumMemberStatement() {
233
+ const tokens = {};
234
+ let value;
235
+ tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
236
+ //look for `= SOME_EXPRESSION`
237
+ if (this.check(TokenKind_1.TokenKind.Equal)) {
238
+ tokens.equal = this.advance();
239
+ value = this.expression();
240
+ }
241
+ return new Statement_1.EnumMemberStatement(tokens, value);
242
+ }
219
243
  /**
220
244
  * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration`
221
245
  */
222
246
  interfaceFieldStatement() {
223
- const name = this.identifier(...lexer_1.AllowedProperties);
224
- let asToken = this.consumeToken(lexer_1.TokenKind.As);
247
+ const name = this.identifier(...TokenKind_1.AllowedProperties);
248
+ let asToken = this.consumeToken(TokenKind_1.TokenKind.As);
225
249
  let typeToken = this.typeToken();
226
250
  const type = util_1.util.tokenToBscType(typeToken);
227
251
  if (!type) {
@@ -235,13 +259,13 @@ class Parser {
235
259
  */
236
260
  interfaceMethodStatement() {
237
261
  const functionType = this.advance();
238
- const name = this.identifier(...lexer_1.AllowedProperties);
239
- const leftParen = this.consumeToken(lexer_1.TokenKind.LeftParen);
262
+ const name = this.identifier(...TokenKind_1.AllowedProperties);
263
+ const leftParen = this.consumeToken(TokenKind_1.TokenKind.LeftParen);
240
264
  const params = [];
241
- const rightParen = this.consumeToken(lexer_1.TokenKind.RightParen);
265
+ const rightParen = this.consumeToken(TokenKind_1.TokenKind.RightParen);
242
266
  let asToken = null;
243
267
  let returnTypeToken = null;
244
- if (this.check(lexer_1.TokenKind.As)) {
268
+ if (this.check(TokenKind_1.TokenKind.As)) {
245
269
  asToken = this.advance();
246
270
  returnTypeToken = this.typeToken();
247
271
  const returnType = util_1.util.tokenToBscType(returnTypeToken);
@@ -255,7 +279,7 @@ class Parser {
255
279
  interfaceDeclaration() {
256
280
  this.warnIfNotBrighterScriptMode('interface declarations');
257
281
  const parentAnnotations = this.enterAnnotationBlock();
258
- const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(lexer_1.TokenKind.Interface), lexer_1.TokenKind.Interface);
282
+ const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
259
283
  const nameToken = this.identifier(...this.allowedLocalIdentifiers);
260
284
  let extendsToken;
261
285
  let parentInterfaceName;
@@ -266,23 +290,23 @@ class Parser {
266
290
  this.consumeStatementSeparators();
267
291
  //gather up all interface members (Fields, Methods)
268
292
  let body = [];
269
- while (this.checkAny(lexer_1.TokenKind.Comment, lexer_1.TokenKind.Identifier, lexer_1.TokenKind.At, ...lexer_1.AllowedProperties)) {
293
+ while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
270
294
  try {
271
295
  let decl;
272
296
  //collect leading annotations
273
- if (this.check(lexer_1.TokenKind.At)) {
297
+ if (this.check(TokenKind_1.TokenKind.At)) {
274
298
  this.annotationExpression();
275
299
  }
276
300
  //fields
277
- if (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties) && this.checkNext(lexer_1.TokenKind.As)) {
301
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.As)) {
278
302
  decl = this.interfaceFieldStatement();
279
303
  //methods (function/sub keyword followed by opening paren)
280
304
  }
281
- else if (this.checkAny(lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub) && this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties)) {
305
+ else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
282
306
  decl = this.interfaceMethodStatement();
283
307
  //comments
284
308
  }
285
- else if (this.check(lexer_1.TokenKind.Comment)) {
309
+ else if (this.check(TokenKind_1.TokenKind.Comment)) {
286
310
  decl = this.commentStatement();
287
311
  }
288
312
  if (decl) {
@@ -291,39 +315,89 @@ class Parser {
291
315
  }
292
316
  else {
293
317
  //we didn't find a declaration...flag tokens until next line
294
- this.flagUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
318
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
295
319
  }
296
320
  }
297
321
  catch (e) {
298
322
  //throw out any failed members and move on to the next line
299
- this.flagUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
323
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
300
324
  }
301
325
  //ensure statement separator
302
326
  this.consumeStatementSeparators();
303
327
  //break out of this loop if we encountered the `EndInterface` token not followed by `as`
304
- if (this.check(lexer_1.TokenKind.EndInterface) && !this.checkNext(lexer_1.TokenKind.As)) {
328
+ if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
305
329
  break;
306
330
  }
307
331
  }
308
332
  //consume the final `end interface` token
309
- const endInterfaceToken = this.consumeToken(lexer_1.TokenKind.EndInterface);
310
- this.consumeStatementSeparators();
333
+ const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
311
334
  const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endInterfaceToken, this.currentNamespaceName);
312
335
  this._references.interfaceStatements.push(statement);
313
336
  this.exitAnnotationBlock(parentAnnotations);
314
337
  return statement;
315
338
  }
339
+ enumDeclaration() {
340
+ this.warnIfNotBrighterScriptMode('enum declarations');
341
+ const parentAnnotations = this.enterAnnotationBlock();
342
+ const tokens = {};
343
+ const body = [];
344
+ tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
345
+ tokens.name = this.tryIdentifier();
346
+ this.consumeStatementSeparators();
347
+ //gather up all members
348
+ while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
349
+ try {
350
+ let decl;
351
+ //collect leading annotations
352
+ if (this.check(TokenKind_1.TokenKind.At)) {
353
+ this.annotationExpression();
354
+ }
355
+ //members
356
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
357
+ decl = this.enumMemberStatement();
358
+ //comments
359
+ }
360
+ else if (this.check(TokenKind_1.TokenKind.Comment)) {
361
+ decl = this.commentStatement();
362
+ }
363
+ if (decl) {
364
+ this.consumePendingAnnotations(decl);
365
+ body.push(decl);
366
+ }
367
+ else {
368
+ //we didn't find a declaration...flag tokens until next line
369
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
370
+ }
371
+ }
372
+ catch (e) {
373
+ //throw out any failed members and move on to the next line
374
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
375
+ }
376
+ //ensure statement separator
377
+ this.consumeStatementSeparators();
378
+ //break out of this loop if we encountered the `EndEnum` token
379
+ if (this.check(TokenKind_1.TokenKind.EndEnum)) {
380
+ break;
381
+ }
382
+ }
383
+ //consume the final `end interface` token
384
+ tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
385
+ const result = new Statement_1.EnumStatement(tokens, body, this.currentNamespaceName);
386
+ this._references.enumStatements.push(result);
387
+ this.exitAnnotationBlock(parentAnnotations);
388
+ return result;
389
+ }
316
390
  /**
317
391
  * A BrighterScript class declaration
318
392
  */
319
393
  classDeclaration() {
320
394
  this.warnIfNotBrighterScriptMode('class declarations');
321
395
  const parentAnnotations = this.enterAnnotationBlock();
322
- let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(lexer_1.TokenKind.Class), lexer_1.TokenKind.Class);
396
+ let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Class), TokenKind_1.TokenKind.Class);
323
397
  let extendsKeyword;
324
398
  let parentClassName;
325
399
  //get the class name
326
- let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
400
+ let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
327
401
  //see if the class inherits from parent
328
402
  if (this.peek().text.toLowerCase() === 'extends') {
329
403
  extendsKeyword = this.advance();
@@ -333,14 +407,14 @@ class Parser {
333
407
  this.consumeStatementSeparators();
334
408
  //gather up all class members (Fields, Methods)
335
409
  let body = [];
336
- while (this.checkAny(lexer_1.TokenKind.Public, lexer_1.TokenKind.Protected, lexer_1.TokenKind.Private, lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub, lexer_1.TokenKind.Comment, lexer_1.TokenKind.Identifier, lexer_1.TokenKind.At, ...lexer_1.AllowedProperties)) {
410
+ while (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private, TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
337
411
  try {
338
412
  let decl;
339
413
  let accessModifier;
340
- if (this.check(lexer_1.TokenKind.At)) {
414
+ if (this.check(TokenKind_1.TokenKind.At)) {
341
415
  this.annotationExpression();
342
416
  }
343
- if (this.checkAny(lexer_1.TokenKind.Public, lexer_1.TokenKind.Protected, lexer_1.TokenKind.Private)) {
417
+ if (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private)) {
344
418
  //use actual access modifier
345
419
  accessModifier = this.advance();
346
420
  }
@@ -349,7 +423,7 @@ class Parser {
349
423
  overrideKeyword = this.advance();
350
424
  }
351
425
  //methods (function/sub keyword OR identifier followed by opening paren)
352
- if (this.checkAny(lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub) || (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties) && this.checkNext(lexer_1.TokenKind.LeftParen))) {
426
+ if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) || (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.LeftParen))) {
353
427
  const funcDeclaration = this.functionDeclaration(false, false, true);
354
428
  //remove this function from the lists because it's not a callable
355
429
  const functionStatement = this._references.functionStatements.pop();
@@ -360,9 +434,11 @@ class Parser {
360
434
  decl = new Statement_1.ClassMethodStatement(accessModifier, funcDeclaration.name, funcDeclaration.func, overrideKeyword);
361
435
  //refer to this statement as parent of the expression
362
436
  functionStatement.func.functionStatement = decl;
437
+ //cache the range property so that plugins can't affect it
438
+ decl.cacheRange();
363
439
  //fields
364
440
  }
365
- else if (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties)) {
441
+ else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
366
442
  decl = this.classFieldDeclaration(accessModifier);
367
443
  //class fields cannot be overridden
368
444
  if (overrideKeyword) {
@@ -370,7 +446,7 @@ class Parser {
370
446
  }
371
447
  //comments
372
448
  }
373
- else if (this.check(lexer_1.TokenKind.Comment)) {
449
+ else if (this.check(TokenKind_1.TokenKind.Comment)) {
374
450
  decl = this.commentStatement();
375
451
  }
376
452
  if (decl) {
@@ -380,13 +456,13 @@ class Parser {
380
456
  }
381
457
  catch (e) {
382
458
  //throw out any failed members and move on to the next line
383
- this.flagUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
459
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
384
460
  }
385
461
  //ensure statement separator
386
462
  this.consumeStatementSeparators();
387
463
  }
388
464
  let endingKeyword = this.advance();
389
- if (endingKeyword.kind !== lexer_1.TokenKind.EndClass) {
465
+ if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
390
466
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
391
467
  }
392
468
  const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName, this.currentSymbolTable);
@@ -398,11 +474,11 @@ class Parser {
398
474
  return result;
399
475
  }
400
476
  classFieldDeclaration(accessModifier) {
401
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
477
+ let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
402
478
  let asToken;
403
479
  let fieldType;
404
480
  //look for `as SOME_TYPE`
405
- if (this.check(lexer_1.TokenKind.As)) {
481
+ if (this.check(TokenKind_1.TokenKind.As)) {
406
482
  asToken = this.advance();
407
483
  fieldType = this.typeToken();
408
484
  //no field type specified
@@ -413,7 +489,7 @@ class Parser {
413
489
  let initialValue;
414
490
  let equal;
415
491
  //if there is a field initializer
416
- if (this.check(lexer_1.TokenKind.Equal)) {
492
+ if (this.check(TokenKind_1.TokenKind.Equal)) {
417
493
  equal = this.advance();
418
494
  initialValue = this.expression();
419
495
  }
@@ -427,14 +503,14 @@ class Parser {
427
503
  //track depth to help certain statements need to know if they are contained within a function body
428
504
  this.namespaceAndFunctionDepth++;
429
505
  let functionType;
430
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
506
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
431
507
  functionType = this.advance();
432
508
  }
433
509
  else {
434
510
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
435
511
  functionType = {
436
512
  isReserved: true,
437
- kind: lexer_1.TokenKind.Function,
513
+ kind: TokenKind_1.TokenKind.Function,
438
514
  text: 'function',
439
515
  //zero-length location means derived
440
516
  range: {
@@ -444,16 +520,16 @@ class Parser {
444
520
  leadingWhitespace: ''
445
521
  };
446
522
  }
447
- let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === lexer_1.TokenKind.Sub;
523
+ let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === TokenKind_1.TokenKind.Sub;
448
524
  let functionTypeText = isSub ? 'sub' : 'function';
449
525
  let name;
450
526
  let leftParen;
451
527
  if (isAnonymous) {
452
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), lexer_1.TokenKind.LeftParen);
528
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), TokenKind_1.TokenKind.LeftParen);
453
529
  }
454
530
  else {
455
- name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
456
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), lexer_1.TokenKind.LeftParen);
531
+ name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
532
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), TokenKind_1.TokenKind.LeftParen);
457
533
  //prevent functions from ending with type designators
458
534
  let lastChar = name.text[name.text.length - 1];
459
535
  if (['$', '%', '!', '#', '&'].includes(lastChar)) {
@@ -461,23 +537,23 @@ class Parser {
461
537
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { range: name.range }));
462
538
  }
463
539
  //flag functions with keywords for names (only for standard functions)
464
- if (checkIdentifier && lexer_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
540
+ if (checkIdentifier && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
465
541
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
466
542
  }
467
543
  }
468
544
  let params = [];
469
545
  let asToken;
470
546
  let typeToken;
471
- if (!this.check(lexer_1.TokenKind.RightParen)) {
547
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
472
548
  do {
473
549
  if (params.length >= Expression_1.CallExpression.MaximumArguments) {
474
550
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
475
551
  }
476
552
  params.push(this.functionParameter());
477
- } while (this.match(lexer_1.TokenKind.Comma));
553
+ } while (this.match(TokenKind_1.TokenKind.Comma));
478
554
  }
479
555
  let rightParen = this.advance();
480
- if (this.check(lexer_1.TokenKind.As)) {
556
+ if (this.check(TokenKind_1.TokenKind.As)) {
481
557
  asToken = this.advance();
482
558
  typeToken = this.typeToken();
483
559
  if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
@@ -529,7 +605,7 @@ class Parser {
529
605
  }
530
606
  // consume 'end sub' or 'end function'
531
607
  func.end = this.advance();
532
- let expectedEndKind = isSub ? lexer_1.TokenKind.EndSub : lexer_1.TokenKind.EndFunction;
608
+ let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
533
609
  //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
534
610
  //add an error but don't hard-fail so the AST can continue more gracefully
535
611
  if (func.end.kind !== expectedEndKind) {
@@ -537,12 +613,16 @@ class Parser {
537
613
  }
538
614
  func.callExpressions = this.callExpressions;
539
615
  if (isAnonymous) {
616
+ //cache the range property so that plugins can't affect it
617
+ func.cacheRange();
540
618
  return func;
541
619
  }
542
620
  else {
543
621
  let result = new Statement_1.FunctionStatement(name, func, this.currentNamespaceName);
544
622
  func.functionStatement = result;
545
623
  this._references.functionStatements.push(result);
624
+ //cache the range property so that plugins can't affect it
625
+ result.cacheRange();
546
626
  return result;
547
627
  }
548
628
  }
@@ -553,22 +633,22 @@ class Parser {
553
633
  }
554
634
  }
555
635
  functionParameter() {
556
- if (!this.checkAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
636
+ if (!this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
557
637
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { range: this.peek().range }));
558
638
  throw this.lastDiagnosticAsError();
559
639
  }
560
- const name = this.identifier(...lexer_1.AllowedLocalIdentifiers);
640
+ const name = this.identifier(...TokenKind_1.AllowedLocalIdentifiers);
561
641
  let typeToken;
562
642
  let defaultValue;
563
643
  let equalsToken;
564
644
  // parse argument default value
565
- if (this.match(lexer_1.TokenKind.Equal)) {
645
+ if (this.match(TokenKind_1.TokenKind.Equal)) {
566
646
  equalsToken = this.previous();
567
647
  // it seems any expression is allowed here -- including ones that operate on other arguments!
568
648
  defaultValue = this.expression();
569
649
  }
570
650
  let asToken = null;
571
- if (this.check(lexer_1.TokenKind.As)) {
651
+ if (this.check(TokenKind_1.TokenKind.As)) {
572
652
  asToken = this.advance();
573
653
  typeToken = this.typeToken();
574
654
  if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
@@ -594,17 +674,20 @@ class Parser {
594
674
  assignment() {
595
675
  let name = this.identifier(...this.allowedLocalIdentifiers);
596
676
  //add diagnostic if name is a reserved word that cannot be used as an identifier
597
- if (lexer_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
677
+ if (TokenKind_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
598
678
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
599
679
  }
600
- let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(lexer_1.AssignmentOperators, name.text), ...lexer_1.AssignmentOperators);
680
+ let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(TokenKind_1.AssignmentOperators, name.text), ...TokenKind_1.AssignmentOperators);
601
681
  let value = this.expression();
602
682
  let result;
603
- if (operator.kind === lexer_1.TokenKind.Equal) {
683
+ if (operator.kind === TokenKind_1.TokenKind.Equal) {
604
684
  result = new Statement_1.AssignmentStatement(name, operator, value, this.currentFunctionExpression);
605
685
  }
606
686
  else {
607
687
  result = new Statement_1.AssignmentStatement(name, operator, new Expression_1.BinaryExpression(new Expression_1.VariableExpression(name, this.currentNamespaceName), operator, value), this.currentFunctionExpression);
688
+ //remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
689
+ this._references.expressions.delete(value);
690
+ this._references.expressions.add(result);
608
691
  }
609
692
  this._references.assignmentStatements.push(result);
610
693
  const assignmentType = getBscTypeFromExpression(result.value, this.currentFunctionExpression);
@@ -612,14 +695,14 @@ class Parser {
612
695
  return result;
613
696
  }
614
697
  checkLibrary() {
615
- let isLibraryToken = this.check(lexer_1.TokenKind.Library);
698
+ let isLibraryToken = this.check(TokenKind_1.TokenKind.Library);
616
699
  //if we are at the top level, any line that starts with "library" should be considered a library statement
617
700
  if (this.isAtRootLevel() && isLibraryToken) {
618
701
  return true;
619
702
  //not at root level, library statements are all invalid here, but try to detect if the tokens look
620
703
  //like a library statement (and let the libraryStatement function handle emitting the diagnostics)
621
704
  }
622
- else if (isLibraryToken && this.checkNext(lexer_1.TokenKind.StringLiteral)) {
705
+ else if (isLibraryToken && this.checkNext(TokenKind_1.TokenKind.StringLiteral)) {
623
706
  return true;
624
707
  //definitely not a library statement
625
708
  }
@@ -631,54 +714,54 @@ class Parser {
631
714
  if (this.checkLibrary()) {
632
715
  return this.libraryStatement();
633
716
  }
634
- if (this.check(lexer_1.TokenKind.Import)) {
717
+ if (this.check(TokenKind_1.TokenKind.Import)) {
635
718
  return this.importStatement();
636
719
  }
637
- if (this.check(lexer_1.TokenKind.Stop)) {
720
+ if (this.check(TokenKind_1.TokenKind.Stop)) {
638
721
  return this.stopStatement();
639
722
  }
640
- if (this.check(lexer_1.TokenKind.If)) {
723
+ if (this.check(TokenKind_1.TokenKind.If)) {
641
724
  return this.ifStatement();
642
725
  }
643
726
  //`try` must be followed by a block, otherwise it could be a local variable
644
- if (this.check(lexer_1.TokenKind.Try) && this.checkAnyNext(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment)) {
727
+ if (this.check(TokenKind_1.TokenKind.Try) && this.checkAnyNext(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
645
728
  return this.tryCatchStatement();
646
729
  }
647
- if (this.check(lexer_1.TokenKind.Throw)) {
730
+ if (this.check(TokenKind_1.TokenKind.Throw)) {
648
731
  return this.throwStatement();
649
732
  }
650
- if (this.checkAny(lexer_1.TokenKind.Print, lexer_1.TokenKind.Question)) {
733
+ if (this.checkAny(TokenKind_1.TokenKind.Print, TokenKind_1.TokenKind.Question)) {
651
734
  return this.printStatement();
652
735
  }
653
- if (this.check(lexer_1.TokenKind.Dim)) {
736
+ if (this.check(TokenKind_1.TokenKind.Dim)) {
654
737
  return this.dimStatement();
655
738
  }
656
- if (this.check(lexer_1.TokenKind.While)) {
739
+ if (this.check(TokenKind_1.TokenKind.While)) {
657
740
  return this.whileStatement();
658
741
  }
659
- if (this.check(lexer_1.TokenKind.ExitWhile)) {
742
+ if (this.check(TokenKind_1.TokenKind.ExitWhile)) {
660
743
  return this.exitWhile();
661
744
  }
662
- if (this.check(lexer_1.TokenKind.For)) {
745
+ if (this.check(TokenKind_1.TokenKind.For)) {
663
746
  return this.forStatement();
664
747
  }
665
- if (this.check(lexer_1.TokenKind.ForEach)) {
748
+ if (this.check(TokenKind_1.TokenKind.ForEach)) {
666
749
  return this.forEachStatement();
667
750
  }
668
- if (this.check(lexer_1.TokenKind.ExitFor)) {
751
+ if (this.check(TokenKind_1.TokenKind.ExitFor)) {
669
752
  return this.exitFor();
670
753
  }
671
- if (this.check(lexer_1.TokenKind.End)) {
754
+ if (this.check(TokenKind_1.TokenKind.End)) {
672
755
  return this.endStatement();
673
756
  }
674
- if (this.match(lexer_1.TokenKind.Return)) {
757
+ if (this.match(TokenKind_1.TokenKind.Return)) {
675
758
  return this.returnStatement();
676
759
  }
677
- if (this.check(lexer_1.TokenKind.Goto)) {
760
+ if (this.check(TokenKind_1.TokenKind.Goto)) {
678
761
  return this.gotoStatement();
679
762
  }
680
763
  //does this line look like a label? (i.e. `someIdentifier:` )
681
- if (this.check(lexer_1.TokenKind.Identifier) && this.checkNext(lexer_1.TokenKind.Colon) && this.checkPrevious(lexer_1.TokenKind.Newline)) {
764
+ if (this.check(TokenKind_1.TokenKind.Identifier) && this.checkNext(TokenKind_1.TokenKind.Colon) && this.checkPrevious(TokenKind_1.TokenKind.Newline)) {
682
765
  try {
683
766
  return this.labelStatement();
684
767
  }
@@ -692,20 +775,23 @@ class Parser {
692
775
  // BrightScript is like python, in that variables can be declared without a `var`,
693
776
  // `let`, (...) keyword. As such, we must check the token *after* an identifier to figure
694
777
  // out what to do with it.
695
- if (this.checkAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
696
- this.checkAnyNext(...lexer_1.AssignmentOperators)) {
778
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
779
+ this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
697
780
  return this.assignment();
698
781
  }
699
782
  //some BrighterScript keywords are allowed as a local identifiers, so we need to check for them AFTER the assignment check
700
- if (this.check(lexer_1.TokenKind.Interface)) {
783
+ if (this.check(TokenKind_1.TokenKind.Interface)) {
701
784
  return this.interfaceDeclaration();
702
785
  }
703
- if (this.check(lexer_1.TokenKind.Class)) {
786
+ if (this.check(TokenKind_1.TokenKind.Class)) {
704
787
  return this.classDeclaration();
705
788
  }
706
- if (this.check(lexer_1.TokenKind.Namespace)) {
789
+ if (this.check(TokenKind_1.TokenKind.Namespace)) {
707
790
  return this.namespaceStatement();
708
791
  }
792
+ if (this.check(TokenKind_1.TokenKind.Enum)) {
793
+ return this.enumDeclaration();
794
+ }
709
795
  // TODO: support multi-statements
710
796
  return this.setStatement();
711
797
  }
@@ -713,9 +799,9 @@ class Parser {
713
799
  const whileKeyword = this.advance();
714
800
  const condition = this.expression();
715
801
  this.consumeStatementSeparators();
716
- const whileBlock = this.block(lexer_1.TokenKind.EndWhile);
802
+ const whileBlock = this.block(TokenKind_1.TokenKind.EndWhile);
717
803
  let endWhile;
718
- if (!whileBlock || this.peek().kind !== lexer_1.TokenKind.EndWhile) {
804
+ if (!whileBlock || this.peek().kind !== TokenKind_1.TokenKind.EndWhile) {
719
805
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('while')), { range: this.peek().range }));
720
806
  if (!whileBlock) {
721
807
  throw this.lastDiagnosticAsError();
@@ -738,7 +824,7 @@ class Parser {
738
824
  const finalValue = this.expression();
739
825
  let incrementExpression;
740
826
  let stepToken;
741
- if (this.check(lexer_1.TokenKind.Step)) {
827
+ if (this.check(TokenKind_1.TokenKind.Step)) {
742
828
  stepToken = this.advance();
743
829
  incrementExpression = this.expression();
744
830
  }
@@ -746,9 +832,9 @@ class Parser {
746
832
  // BrightScript for/to/step loops default to a step of 1 if no `step` is provided
747
833
  }
748
834
  this.consumeStatementSeparators();
749
- let body = this.block(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next);
835
+ let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
750
836
  let endForToken;
751
- if (!body || !this.checkAny(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next)) {
837
+ if (!body || !this.checkAny(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next)) {
752
838
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
753
839
  if (!body) {
754
840
  throw this.lastDiagnosticAsError();
@@ -765,7 +851,7 @@ class Parser {
765
851
  let forEach = this.advance();
766
852
  let name = this.identifier(...this.allowedLocalIdentifiers);
767
853
  let maybeIn = this.peek();
768
- if (this.check(lexer_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
854
+ if (this.check(TokenKind_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
769
855
  this.advance();
770
856
  }
771
857
  else {
@@ -778,14 +864,17 @@ class Parser {
778
864
  throw this.lastDiagnosticAsError();
779
865
  }
780
866
  this.consumeStatementSeparators();
781
- let body = this.block(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next);
867
+ let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
782
868
  if (!body) {
783
869
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
784
870
  throw this.lastDiagnosticAsError();
785
871
  }
786
872
  let endFor = this.advance();
787
- //TODO TYPES infer type from `target`
788
- const itemType = new DynamicType_1.DynamicType();
873
+ let itemType = new DynamicType_1.DynamicType();
874
+ const targetType = getBscTypeFromExpression(target, this.currentFunctionExpression);
875
+ if ((0, reflection_1.isArrayType)(targetType)) {
876
+ itemType = targetType.getDefaultType();
877
+ }
789
878
  this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
790
879
  return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
791
880
  }
@@ -802,7 +891,7 @@ class Parser {
802
891
  }
803
892
  else {
804
893
  let comments = [this.advance()];
805
- while (this.check(lexer_1.TokenKind.Newline) && this.checkNext(lexer_1.TokenKind.Comment)) {
894
+ while (this.check(TokenKind_1.TokenKind.Newline) && this.checkNext(TokenKind_1.TokenKind.Comment)) {
806
895
  this.advance();
807
896
  comments.push(this.advance());
808
897
  }
@@ -820,13 +909,13 @@ class Parser {
820
909
  //set the current namespace name
821
910
  let result = new Statement_1.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
822
911
  this.currentNamespace = result;
823
- this.globalTerminators.push([lexer_1.TokenKind.EndNamespace]);
912
+ this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
824
913
  let body = this.body();
825
914
  this.globalTerminators.pop();
826
915
  //unset the current namespace name
827
916
  this.currentNamespace = undefined;
828
917
  let endKeyword;
829
- if (this.check(lexer_1.TokenKind.EndNamespace)) {
918
+ if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
830
919
  endKeyword = this.advance();
831
920
  }
832
921
  else {
@@ -837,30 +926,33 @@ class Parser {
837
926
  result.body = body;
838
927
  result.endKeyword = endKeyword;
839
928
  this._references.namespaceStatements.push(result);
929
+ //cache the range property so that plugins can't affect it
930
+ result.cacheRange();
840
931
  return result;
841
932
  }
842
933
  /**
843
934
  * Get an expression with identifiers separated by periods. Useful for namespaces and class extends
844
935
  */
845
936
  getNamespacedVariableNameExpression() {
846
- let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
937
+ let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
847
938
  let expr;
848
939
  if (firstIdentifier) {
849
940
  // force it into an identifier so the AST makes some sense
850
- firstIdentifier.kind = lexer_1.TokenKind.Identifier;
851
- expr = new Expression_1.VariableExpression(firstIdentifier, null);
941
+ firstIdentifier.kind = TokenKind_1.TokenKind.Identifier;
942
+ const varExpr = new Expression_1.VariableExpression(firstIdentifier, null);
943
+ expr = varExpr;
852
944
  //consume multiple dot identifiers (i.e. `Name.Space.Can.Have.Many.Parts`)
853
- while (this.check(lexer_1.TokenKind.Dot)) {
854
- let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), lexer_1.TokenKind.Dot);
945
+ while (this.check(TokenKind_1.TokenKind.Dot)) {
946
+ let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.Dot);
855
947
  if (!dot) {
856
948
  break;
857
949
  }
858
- let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...lexer_1.AllowedProperties);
950
+ let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...TokenKind_1.AllowedProperties);
859
951
  if (!identifier) {
860
952
  break;
861
953
  }
862
954
  // force it into an identifier so the AST makes some sense
863
- identifier.kind = lexer_1.TokenKind.Identifier;
955
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
864
956
  expr = new Expression_1.DottedGetExpression(expr, identifier, dot);
865
957
  }
866
958
  }
@@ -892,7 +984,7 @@ class Parser {
892
984
  let libStatement = new Statement_1.LibraryStatement({
893
985
  library: this.advance(),
894
986
  //grab the next token only if it's a string
895
- filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), lexer_1.TokenKind.StringLiteral)
987
+ filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
896
988
  });
897
989
  this._references.libraryStatements.push(libStatement);
898
990
  return libStatement;
@@ -901,23 +993,25 @@ class Parser {
901
993
  this.warnIfNotBrighterScriptMode('import statements');
902
994
  let importStatement = new Statement_1.ImportStatement(this.advance(),
903
995
  //grab the next token only if it's a string
904
- this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), lexer_1.TokenKind.StringLiteral));
996
+ this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
905
997
  this._references.importStatements.push(importStatement);
906
998
  return importStatement;
907
999
  }
908
1000
  annotationExpression() {
909
1001
  const atToken = this.advance();
910
- const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1002
+ const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
911
1003
  if (identifier) {
912
- identifier.kind = lexer_1.TokenKind.Identifier;
1004
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
913
1005
  }
914
1006
  let annotation = new Expression_1.AnnotationExpression(atToken, identifier);
915
1007
  this.pendingAnnotations.push(annotation);
916
1008
  //optional arguments
917
- if (this.check(lexer_1.TokenKind.LeftParen)) {
1009
+ if (this.check(TokenKind_1.TokenKind.LeftParen)) {
918
1010
  let leftParen = this.advance();
919
1011
  annotation.call = this.finishCall(leftParen, annotation, false);
920
1012
  }
1013
+ //cache the range property so that plugins can't affect it
1014
+ annotation.cacheRange();
921
1015
  return annotation;
922
1016
  }
923
1017
  ternaryExpression(test) {
@@ -927,7 +1021,7 @@ class Parser {
927
1021
  }
928
1022
  const questionMarkToken = this.advance();
929
1023
  //consume newlines or comments
930
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1024
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
931
1025
  this.advance();
932
1026
  }
933
1027
  let consequent;
@@ -936,12 +1030,12 @@ class Parser {
936
1030
  }
937
1031
  catch (_a) { }
938
1032
  //consume newlines or comments
939
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1033
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
940
1034
  this.advance();
941
1035
  }
942
- const colonToken = this.tryConsumeToken(lexer_1.TokenKind.Colon);
1036
+ const colonToken = this.tryConsumeToken(TokenKind_1.TokenKind.Colon);
943
1037
  //consume newlines
944
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1038
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
945
1039
  this.advance();
946
1040
  }
947
1041
  let alternate;
@@ -959,7 +1053,7 @@ class Parser {
959
1053
  }
960
1054
  regexLiteralExpression() {
961
1055
  this.warnIfNotBrighterScriptMode('regular expression literal');
962
- return new _1.RegexLiteralExpression({
1056
+ return new Expression_1.RegexLiteralExpression({
963
1057
  regexLiteral: this.advance()
964
1058
  });
965
1059
  }
@@ -968,23 +1062,23 @@ class Parser {
968
1062
  //get the tag name
969
1063
  let tagName;
970
1064
  if (isTagged) {
971
- tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1065
+ tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
972
1066
  // force it into an identifier so the AST makes some sense
973
- tagName.kind = lexer_1.TokenKind.Identifier;
1067
+ tagName.kind = TokenKind_1.TokenKind.Identifier;
974
1068
  }
975
1069
  let quasis = [];
976
1070
  let expressions = [];
977
1071
  let openingBacktick = this.peek();
978
1072
  this.advance();
979
1073
  let currentQuasiExpressionParts = [];
980
- while (!this.isAtEnd() && !this.check(lexer_1.TokenKind.BackTick)) {
1074
+ while (!this.isAtEnd() && !this.check(TokenKind_1.TokenKind.BackTick)) {
981
1075
  let next = this.peek();
982
- if (next.kind === lexer_1.TokenKind.TemplateStringQuasi) {
1076
+ if (next.kind === TokenKind_1.TokenKind.TemplateStringQuasi) {
983
1077
  //a quasi can actually be made up of multiple quasis when it includes char literals
984
1078
  currentQuasiExpressionParts.push(new Expression_1.LiteralExpression(next));
985
1079
  this.advance();
986
1080
  }
987
- else if (next.kind === lexer_1.TokenKind.EscapedCharCodeLiteral) {
1081
+ else if (next.kind === TokenKind_1.TokenKind.EscapedCharCodeLiteral) {
988
1082
  currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression(next));
989
1083
  this.advance();
990
1084
  }
@@ -992,12 +1086,12 @@ class Parser {
992
1086
  //finish up the current quasi
993
1087
  quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
994
1088
  currentQuasiExpressionParts = [];
995
- if (next.kind === lexer_1.TokenKind.TemplateStringExpressionBegin) {
1089
+ if (next.kind === TokenKind_1.TokenKind.TemplateStringExpressionBegin) {
996
1090
  this.advance();
997
1091
  }
998
1092
  //now keep this expression
999
1093
  expressions.push(this.expression());
1000
- if (!this.isAtEnd() && this.check(lexer_1.TokenKind.TemplateStringExpressionEnd)) {
1094
+ if (!this.isAtEnd() && this.check(TokenKind_1.TokenKind.TemplateStringExpressionEnd)) {
1001
1095
  //TODO is it an error if this is not present?
1002
1096
  this.advance();
1003
1097
  }
@@ -1029,12 +1123,12 @@ class Parser {
1029
1123
  const statement = new Statement_1.TryCatchStatement(tryToken);
1030
1124
  //ensure statement separator
1031
1125
  this.consumeStatementSeparators();
1032
- statement.tryBranch = this.block(lexer_1.TokenKind.Catch, lexer_1.TokenKind.EndTry);
1126
+ statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
1033
1127
  const peek = this.peek();
1034
- if (peek.kind !== lexer_1.TokenKind.Catch) {
1128
+ if (peek.kind !== TokenKind_1.TokenKind.Catch) {
1035
1129
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
1036
1130
  //gracefully handle end-try
1037
- if (peek.kind === lexer_1.TokenKind.EndTry) {
1131
+ if (peek.kind === TokenKind_1.TokenKind.EndTry) {
1038
1132
  statement.endTryToken = this.advance();
1039
1133
  }
1040
1134
  return statement;
@@ -1042,16 +1136,16 @@ class Parser {
1042
1136
  else {
1043
1137
  statement.catchToken = this.advance();
1044
1138
  }
1045
- const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1139
+ const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1046
1140
  if (exceptionVarToken) {
1047
1141
  // force it into an identifier so the AST makes some sense
1048
- exceptionVarToken.kind = lexer_1.TokenKind.Identifier;
1142
+ exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
1049
1143
  statement.exceptionVariable = exceptionVarToken;
1050
1144
  }
1051
1145
  //ensure statement sepatator
1052
1146
  this.consumeStatementSeparators();
1053
- statement.catchBranch = this.block(lexer_1.TokenKind.EndTry);
1054
- if (this.peek().kind !== lexer_1.TokenKind.EndTry) {
1147
+ statement.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1148
+ if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
1055
1149
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
1056
1150
  }
1057
1151
  else {
@@ -1062,7 +1156,7 @@ class Parser {
1062
1156
  throwStatement() {
1063
1157
  const throwToken = this.advance();
1064
1158
  let expression;
1065
- if (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
1159
+ if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1066
1160
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword()), { range: throwToken.range }));
1067
1161
  }
1068
1162
  else {
@@ -1072,19 +1166,19 @@ class Parser {
1072
1166
  }
1073
1167
  dimStatement() {
1074
1168
  const dim = this.advance();
1075
- let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1169
+ let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1076
1170
  // force to an identifier so the AST makes some sense
1077
1171
  if (identifier) {
1078
- identifier.kind = lexer_1.TokenKind.Identifier;
1172
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
1079
1173
  }
1080
- let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), lexer_1.TokenKind.LeftSquareBracket);
1174
+ let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.LeftSquareBracket);
1081
1175
  let expressions = [];
1082
1176
  let expression;
1083
1177
  do {
1084
1178
  try {
1085
1179
  expression = this.expression();
1086
1180
  expressions.push(expression);
1087
- if (this.check(lexer_1.TokenKind.Comma)) {
1181
+ if (this.check(TokenKind_1.TokenKind.Comma)) {
1088
1182
  this.advance();
1089
1183
  }
1090
1184
  else {
@@ -1098,15 +1192,15 @@ class Parser {
1098
1192
  if (expressions.length === 0) {
1099
1193
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
1100
1194
  }
1101
- let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), lexer_1.TokenKind.RightSquareBracket);
1195
+ let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
1102
1196
  return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1103
1197
  }
1104
1198
  ifStatement() {
1105
1199
  // colon before `if` is usually not allowed, unless it's after `then`
1106
1200
  if (this.current > 0) {
1107
1201
  const prev = this.previous();
1108
- if (prev.kind === lexer_1.TokenKind.Colon) {
1109
- if (this.current > 1 && this.tokens[this.current - 2].kind !== lexer_1.TokenKind.Then) {
1202
+ if (prev.kind === TokenKind_1.TokenKind.Colon) {
1203
+ if (this.current > 1 && this.tokens[this.current - 2].kind !== TokenKind_1.TokenKind.Then) {
1110
1204
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedColonBeforeIfStatement()), { range: prev.range }));
1111
1205
  }
1112
1206
  }
@@ -1120,14 +1214,14 @@ class Parser {
1120
1214
  let endIfToken;
1121
1215
  let elseToken;
1122
1216
  //optional `then`
1123
- if (this.check(lexer_1.TokenKind.Then)) {
1217
+ if (this.check(TokenKind_1.TokenKind.Then)) {
1124
1218
  thenToken = this.advance();
1125
1219
  }
1126
1220
  //is it inline or multi-line if?
1127
- const isInlineIfThen = !this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment);
1221
+ const isInlineIfThen = !this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment);
1128
1222
  if (isInlineIfThen) {
1129
1223
  /*** PARSE INLINE IF STATEMENT ***/
1130
- thenBranch = this.inlineConditionalBranch(lexer_1.TokenKind.Else, lexer_1.TokenKind.EndIf);
1224
+ thenBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
1131
1225
  if (!thenBranch) {
1132
1226
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowConditionalCondition(ifToken.text)), { range: this.peek().range }));
1133
1227
  throw this.lastDiagnosticAsError();
@@ -1136,9 +1230,9 @@ class Parser {
1136
1230
  this.ensureInline(thenBranch.statements);
1137
1231
  }
1138
1232
  //else branch
1139
- if (this.check(lexer_1.TokenKind.Else)) {
1233
+ if (this.check(TokenKind_1.TokenKind.Else)) {
1140
1234
  elseToken = this.advance();
1141
- if (this.check(lexer_1.TokenKind.If)) {
1235
+ if (this.check(TokenKind_1.TokenKind.If)) {
1142
1236
  // recurse-read `else if`
1143
1237
  elseBranch = this.ifStatement();
1144
1238
  //no multi-line if chained with an inline if
@@ -1146,13 +1240,13 @@ class Parser {
1146
1240
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: elseBranch.range }));
1147
1241
  }
1148
1242
  }
1149
- else if (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
1243
+ else if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1150
1244
  //expecting inline else branch
1151
1245
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: this.peek().range }));
1152
1246
  throw this.lastDiagnosticAsError();
1153
1247
  }
1154
1248
  else {
1155
- elseBranch = this.inlineConditionalBranch(lexer_1.TokenKind.Else, lexer_1.TokenKind.EndIf);
1249
+ elseBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
1156
1250
  if (elseBranch) {
1157
1251
  this.ensureInline(elseBranch.statements);
1158
1252
  }
@@ -1166,9 +1260,9 @@ class Parser {
1166
1260
  if (!elseBranch || !(0, reflection_1.isIfStatement)(elseBranch)) {
1167
1261
  //enforce newline at the end of the inline if statement
1168
1262
  const peek = this.peek();
1169
- if (peek.kind !== lexer_1.TokenKind.Newline && peek.kind !== lexer_1.TokenKind.Comment && !this.isAtEnd()) {
1263
+ if (peek.kind !== TokenKind_1.TokenKind.Newline && peek.kind !== TokenKind_1.TokenKind.Comment && !this.isAtEnd()) {
1170
1264
  //ignore last error if it was about a colon
1171
- if (this.previous().kind === lexer_1.TokenKind.Colon) {
1265
+ if (this.previous().kind === TokenKind_1.TokenKind.Colon) {
1172
1266
  this.diagnostics.pop();
1173
1267
  this.current--;
1174
1268
  }
@@ -1183,9 +1277,9 @@ class Parser {
1183
1277
  //ensure newline/colon before next keyword
1184
1278
  this.ensureNewLineOrColon();
1185
1279
  //else branch
1186
- if (this.check(lexer_1.TokenKind.Else)) {
1280
+ if (this.check(TokenKind_1.TokenKind.Else)) {
1187
1281
  elseToken = this.advance();
1188
- if (this.check(lexer_1.TokenKind.If)) {
1282
+ if (this.check(TokenKind_1.TokenKind.If)) {
1189
1283
  // recurse-read `else if`
1190
1284
  elseBranch = this.ifStatement();
1191
1285
  }
@@ -1196,7 +1290,7 @@ class Parser {
1196
1290
  }
1197
1291
  }
1198
1292
  if (!(0, reflection_1.isIfStatement)(elseBranch)) {
1199
- if (this.check(lexer_1.TokenKind.EndIf)) {
1293
+ if (this.check(TokenKind_1.TokenKind.EndIf)) {
1200
1294
  endIfToken = this.advance();
1201
1295
  }
1202
1296
  else {
@@ -1219,7 +1313,7 @@ class Parser {
1219
1313
  let diagnosticsLengthBeforeBlock = this.diagnostics.length;
1220
1314
  // we're parsing a multi-line ("block") form of the BrightScript if/then and must find
1221
1315
  // a trailing "end if" or "else if"
1222
- let branch = this.block(lexer_1.TokenKind.EndIf, lexer_1.TokenKind.Else);
1316
+ let branch = this.block(TokenKind_1.TokenKind.EndIf, TokenKind_1.TokenKind.Else);
1223
1317
  if (!branch) {
1224
1318
  //throw out any new diagnostics created as a result of a `then` block parse failure.
1225
1319
  //the block() function will discard the current line, so any discarded diagnostics will
@@ -1233,7 +1327,7 @@ class Parser {
1233
1327
  }
1234
1328
  ensureNewLineOrColon(silent = false) {
1235
1329
  const prev = this.previous().kind;
1236
- if (prev !== lexer_1.TokenKind.Newline && prev !== lexer_1.TokenKind.Colon) {
1330
+ if (prev !== TokenKind_1.TokenKind.Newline && prev !== TokenKind_1.TokenKind.Colon) {
1237
1331
  if (!silent) {
1238
1332
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { range: this.peek().range }));
1239
1333
  }
@@ -1262,12 +1356,12 @@ class Parser {
1262
1356
  const startingRange = statement.range;
1263
1357
  //look for colon statement separator
1264
1358
  let foundColon = false;
1265
- while (this.match(lexer_1.TokenKind.Colon)) {
1359
+ while (this.match(TokenKind_1.TokenKind.Colon)) {
1266
1360
  foundColon = true;
1267
1361
  }
1268
1362
  //if a colon was found, add the next statement or err if unexpected
1269
1363
  if (foundColon) {
1270
- if (!this.checkAny(lexer_1.TokenKind.Newline, ...additionalTerminators)) {
1364
+ if (!this.checkAny(TokenKind_1.TokenKind.Newline, ...additionalTerminators)) {
1271
1365
  //if not an ending keyword, add next statement
1272
1366
  let extra = this.inlineConditionalBranch(...additionalTerminators);
1273
1367
  if (!extra) {
@@ -1285,9 +1379,9 @@ class Parser {
1285
1379
  }
1286
1380
  expressionStatement(expr) {
1287
1381
  let expressionStart = this.peek();
1288
- if (this.checkAny(lexer_1.TokenKind.PlusPlus, lexer_1.TokenKind.MinusMinus)) {
1382
+ if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
1289
1383
  let operator = this.advance();
1290
- if (this.checkAny(lexer_1.TokenKind.PlusPlus, lexer_1.TokenKind.MinusMinus)) {
1384
+ if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
1291
1385
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.consecutiveIncrementDecrementOperatorsAreNotAllowed()), { range: this.peek().range }));
1292
1386
  throw this.lastDiagnosticAsError();
1293
1387
  }
@@ -1295,7 +1389,9 @@ class Parser {
1295
1389
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
1296
1390
  throw this.lastDiagnosticAsError();
1297
1391
  }
1298
- return new Statement_1.IncrementStatement(expr, operator);
1392
+ const result = new Statement_1.IncrementStatement(expr, operator);
1393
+ this._references.expressions.add(result);
1394
+ return result;
1299
1395
  }
1300
1396
  if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
1301
1397
  return new Statement_1.ExpressionStatement(expr);
@@ -1312,20 +1408,18 @@ class Parser {
1312
1408
  * priority as standalone function calls though, so we can parse them in the same way.
1313
1409
  */
1314
1410
  let expr = this.call();
1315
- if (this.checkAny(...lexer_1.AssignmentOperators) && !((0, reflection_1.isCallExpression)(expr))) {
1411
+ if (this.checkAny(...TokenKind_1.AssignmentOperators) && !((0, reflection_1.isCallExpression)(expr))) {
1316
1412
  let left = expr;
1317
1413
  let operator = this.advance();
1318
1414
  let right = this.expression();
1319
1415
  // Create a dotted or indexed "set" based on the left-hand side's type
1320
1416
  if ((0, reflection_1.isIndexedGetExpression)(left)) {
1321
- return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === lexer_1.TokenKind.Equal
1417
+ return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
1322
1418
  ? right
1323
- : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
1419
+ : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare, operator);
1324
1420
  }
1325
1421
  else if ((0, reflection_1.isDottedGetExpression)(left)) {
1326
- const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === lexer_1.TokenKind.Equal
1327
- ? right
1328
- : new Expression_1.BinaryExpression(left, operator, right));
1422
+ const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal ? right : new Expression_1.BinaryExpression(left, operator, right), left.dot, operator);
1329
1423
  this._references.dottedSetStatements.push(dottedSetStmt);
1330
1424
  return dottedSetStmt;
1331
1425
  }
@@ -1336,13 +1430,13 @@ class Parser {
1336
1430
  let printKeyword = this.advance();
1337
1431
  let values = [];
1338
1432
  while (!this.checkEndOfStatement()) {
1339
- if (this.check(lexer_1.TokenKind.Semicolon)) {
1433
+ if (this.check(TokenKind_1.TokenKind.Semicolon)) {
1340
1434
  values.push(this.advance());
1341
1435
  }
1342
- else if (this.check(lexer_1.TokenKind.Comma)) {
1436
+ else if (this.check(TokenKind_1.TokenKind.Comma)) {
1343
1437
  values.push(this.advance());
1344
1438
  }
1345
- else if (this.check(lexer_1.TokenKind.Else)) {
1439
+ else if (this.check(TokenKind_1.TokenKind.Else)) {
1346
1440
  break; // inline branch
1347
1441
  }
1348
1442
  else {
@@ -1355,7 +1449,7 @@ class Parser {
1355
1449
  values.push(emptyStringLiteral);
1356
1450
  }
1357
1451
  let last = values[values.length - 1];
1358
- if ((0, lexer_1.isToken)(last)) {
1452
+ if ((0, Token_1.isToken)(last)) {
1359
1453
  // TODO: error, expected value
1360
1454
  }
1361
1455
  return new Statement_1.PrintStatement({ print: printKeyword }, values);
@@ -1369,7 +1463,7 @@ class Parser {
1369
1463
  if (this.checkEndOfStatement()) {
1370
1464
  return new Statement_1.ReturnStatement(tokens);
1371
1465
  }
1372
- let toReturn = this.check(lexer_1.TokenKind.Else) ? undefined : this.expression();
1466
+ let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
1373
1467
  return new Statement_1.ReturnStatement(tokens, toReturn);
1374
1468
  }
1375
1469
  /**
@@ -1382,7 +1476,7 @@ class Parser {
1382
1476
  colon: this.advance()
1383
1477
  };
1384
1478
  //label must be alone on its line, this is probably not a label
1385
- if (!this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1479
+ if (!this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1386
1480
  //rewind and cancel
1387
1481
  this.current -= 2;
1388
1482
  throw new CancelStatementError();
@@ -1398,7 +1492,7 @@ class Parser {
1398
1492
  gotoStatement() {
1399
1493
  let tokens = {
1400
1494
  goto: this.advance(),
1401
- label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), lexer_1.TokenKind.Identifier)
1495
+ label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
1402
1496
  };
1403
1497
  return new Statement_1.GotoStatement(tokens);
1404
1498
  }
@@ -1429,7 +1523,7 @@ class Parser {
1429
1523
  this.consumeStatementSeparators(true);
1430
1524
  let startingToken = this.peek();
1431
1525
  const statements = [];
1432
- while (!this.isAtEnd() && !this.checkAny(lexer_1.TokenKind.EndSub, lexer_1.TokenKind.EndFunction, ...terminators)) {
1526
+ while (!this.isAtEnd() && !this.checkAny(TokenKind_1.TokenKind.EndSub, TokenKind_1.TokenKind.EndFunction, ...terminators)) {
1433
1527
  //grab the location of the current token
1434
1528
  let loopCurrent = this.current;
1435
1529
  let dec = this.declaration();
@@ -1445,7 +1539,7 @@ class Parser {
1445
1539
  //something went wrong. reset to the top of the loop
1446
1540
  this.current = loopCurrent;
1447
1541
  //scrap the entire line (hopefully whatever failed has added a diagnostic)
1448
- this.consumeUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
1542
+ this.consumeUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
1449
1543
  //trash the next token. this prevents an infinite loop. not exactly sure why we need this,
1450
1544
  //but there's already an error in the file being parsed, so just leave this line here
1451
1545
  this.advance();
@@ -1462,8 +1556,8 @@ class Parser {
1462
1556
  //if so, we need to restore the statement separator
1463
1557
  let prev = this.previous().kind;
1464
1558
  let peek = this.peek().kind;
1465
- if ((peek === lexer_1.TokenKind.EndSub || peek === lexer_1.TokenKind.EndFunction) &&
1466
- (prev === lexer_1.TokenKind.Newline || prev === lexer_1.TokenKind.Colon)) {
1559
+ if ((peek === TokenKind_1.TokenKind.EndSub || peek === TokenKind_1.TokenKind.EndFunction) &&
1560
+ (prev === TokenKind_1.TokenKind.Newline || prev === TokenKind_1.TokenKind.Colon)) {
1467
1561
  this.current--;
1468
1562
  }
1469
1563
  }
@@ -1495,13 +1589,15 @@ class Parser {
1495
1589
  this.pendingAnnotations = parentAnnotations;
1496
1590
  }
1497
1591
  expression() {
1498
- return this.anonymousFunction();
1592
+ const expression = this.anonymousFunction();
1593
+ this._references.expressions.add(expression);
1594
+ return expression;
1499
1595
  }
1500
1596
  anonymousFunction() {
1501
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
1597
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
1502
1598
  const func = this.functionDeclaration(true);
1503
1599
  //if there's an open paren after this, this is an IIFE
1504
- if (this.check(lexer_1.TokenKind.LeftParen)) {
1600
+ if (this.check(TokenKind_1.TokenKind.LeftParen)) {
1505
1601
  return this.finishCall(this.advance(), func);
1506
1602
  }
1507
1603
  else {
@@ -1509,10 +1605,10 @@ class Parser {
1509
1605
  }
1510
1606
  }
1511
1607
  let expr = this.boolean();
1512
- if (this.check(lexer_1.TokenKind.Question)) {
1608
+ if (this.check(TokenKind_1.TokenKind.Question)) {
1513
1609
  return this.ternaryExpression(expr);
1514
1610
  }
1515
- else if (this.check(lexer_1.TokenKind.QuestionQuestion)) {
1611
+ else if (this.check(TokenKind_1.TokenKind.QuestionQuestion)) {
1516
1612
  return this.nullCoalescingExpression(expr);
1517
1613
  }
1518
1614
  else {
@@ -1521,7 +1617,7 @@ class Parser {
1521
1617
  }
1522
1618
  boolean() {
1523
1619
  let expr = this.relational();
1524
- while (this.matchAny(lexer_1.TokenKind.And, lexer_1.TokenKind.Or)) {
1620
+ while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
1525
1621
  let operator = this.previous();
1526
1622
  let right = this.relational();
1527
1623
  expr = new Expression_1.BinaryExpression(expr, operator, right);
@@ -1530,7 +1626,7 @@ class Parser {
1530
1626
  }
1531
1627
  relational() {
1532
1628
  let expr = this.additive();
1533
- while (this.matchAny(lexer_1.TokenKind.Equal, lexer_1.TokenKind.LessGreater, lexer_1.TokenKind.Greater, lexer_1.TokenKind.GreaterEqual, lexer_1.TokenKind.Less, lexer_1.TokenKind.LessEqual)) {
1629
+ 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)) {
1534
1630
  let operator = this.previous();
1535
1631
  let right = this.additive();
1536
1632
  expr = new Expression_1.BinaryExpression(expr, operator, right);
@@ -1540,7 +1636,7 @@ class Parser {
1540
1636
  // TODO: bitshift
1541
1637
  additive() {
1542
1638
  let expr = this.multiplicative();
1543
- while (this.matchAny(lexer_1.TokenKind.Plus, lexer_1.TokenKind.Minus)) {
1639
+ while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
1544
1640
  let operator = this.previous();
1545
1641
  let right = this.multiplicative();
1546
1642
  expr = new Expression_1.BinaryExpression(expr, operator, right);
@@ -1549,7 +1645,7 @@ class Parser {
1549
1645
  }
1550
1646
  multiplicative() {
1551
1647
  let expr = this.exponential();
1552
- while (this.matchAny(lexer_1.TokenKind.Forwardslash, lexer_1.TokenKind.Backslash, lexer_1.TokenKind.Star, lexer_1.TokenKind.Mod, lexer_1.TokenKind.LeftShift, lexer_1.TokenKind.RightShift)) {
1648
+ 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)) {
1553
1649
  let operator = this.previous();
1554
1650
  let right = this.exponential();
1555
1651
  expr = new Expression_1.BinaryExpression(expr, operator, right);
@@ -1558,7 +1654,7 @@ class Parser {
1558
1654
  }
1559
1655
  exponential() {
1560
1656
  let expr = this.prefixUnary();
1561
- while (this.match(lexer_1.TokenKind.Caret)) {
1657
+ while (this.match(TokenKind_1.TokenKind.Caret)) {
1562
1658
  let operator = this.previous();
1563
1659
  let right = this.prefixUnary();
1564
1660
  expr = new Expression_1.BinaryExpression(expr, operator, right);
@@ -1567,7 +1663,7 @@ class Parser {
1567
1663
  }
1568
1664
  prefixUnary() {
1569
1665
  const nextKind = this.peek().kind;
1570
- if (nextKind === lexer_1.TokenKind.Not || nextKind === lexer_1.TokenKind.Minus) {
1666
+ if (nextKind === TokenKind_1.TokenKind.Not || nextKind === TokenKind_1.TokenKind.Minus) {
1571
1667
  this.current++; //advance
1572
1668
  let operator = this.previous();
1573
1669
  let right = this.prefixUnary();
@@ -1577,17 +1673,17 @@ class Parser {
1577
1673
  }
1578
1674
  indexedGet(expr) {
1579
1675
  let openingSquare = this.previous();
1580
- while (this.match(lexer_1.TokenKind.Newline)) { }
1676
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1581
1677
  let index = this.expression();
1582
- while (this.match(lexer_1.TokenKind.Newline)) { }
1583
- let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), lexer_1.TokenKind.RightSquareBracket);
1678
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1679
+ let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
1584
1680
  return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare);
1585
1681
  }
1586
1682
  newExpression() {
1587
1683
  this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
1588
1684
  let newToken = this.advance();
1589
1685
  let nameExpr = this.getNamespacedVariableNameExpression();
1590
- let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), lexer_1.TokenKind.LeftParen);
1686
+ let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen);
1591
1687
  let call = this.finishCall(leftParen, nameExpr);
1592
1688
  //pop the call from the callExpressions list because this is technically something else
1593
1689
  this.callExpressions.pop();
@@ -1601,46 +1697,52 @@ class Parser {
1601
1697
  callfunc(callee) {
1602
1698
  this.warnIfNotBrighterScriptMode('callfunc operator');
1603
1699
  let operator = this.previous();
1604
- let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1700
+ let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1605
1701
  // force it into an identifier so the AST makes some sense
1606
- methodName.kind = lexer_1.TokenKind.Identifier;
1607
- let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), lexer_1.TokenKind.LeftParen);
1702
+ methodName.kind = TokenKind_1.TokenKind.Identifier;
1703
+ let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), TokenKind_1.TokenKind.LeftParen);
1608
1704
  let call = this.finishCall(openParen, callee, false);
1609
1705
  return new Expression_1.CallfuncExpression(callee, operator, methodName, openParen, call.args, call.closingParen);
1610
1706
  }
1611
1707
  call() {
1612
- if (this.check(lexer_1.TokenKind.New) && this.checkAnyNext(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
1708
+ if (this.check(TokenKind_1.TokenKind.New) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
1613
1709
  return this.newExpression();
1614
1710
  }
1615
1711
  let expr = this.primary();
1712
+ //an expression to keep for _references
1713
+ let referenceCallExpression;
1616
1714
  while (true) {
1617
- if (this.match(lexer_1.TokenKind.LeftParen)) {
1715
+ if (this.match(TokenKind_1.TokenKind.LeftParen)) {
1618
1716
  expr = this.finishCall(this.previous(), expr);
1717
+ //store this call expression in references
1718
+ referenceCallExpression = expr;
1619
1719
  }
1620
- else if (this.match(lexer_1.TokenKind.LeftSquareBracket)) {
1720
+ else if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
1621
1721
  expr = this.indexedGet(expr);
1622
1722
  }
1623
- else if (this.match(lexer_1.TokenKind.Callfunc)) {
1723
+ else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
1624
1724
  expr = this.callfunc(expr);
1725
+ //store this callfunc expression in references
1726
+ referenceCallExpression = expr;
1625
1727
  }
1626
- else if (this.match(lexer_1.TokenKind.Dot)) {
1627
- if (this.match(lexer_1.TokenKind.LeftSquareBracket)) {
1728
+ else if (this.match(TokenKind_1.TokenKind.Dot)) {
1729
+ if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
1628
1730
  expr = this.indexedGet(expr);
1629
1731
  }
1630
1732
  else {
1631
1733
  let dot = this.previous();
1632
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1734
+ let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1633
1735
  // force it into an identifier so the AST makes some sense
1634
- name.kind = lexer_1.TokenKind.Identifier;
1736
+ name.kind = TokenKind_1.TokenKind.Identifier;
1635
1737
  expr = new Expression_1.DottedGetExpression(expr, name, dot);
1636
1738
  this.addPropertyHints(name);
1637
1739
  }
1638
1740
  }
1639
- else if (this.check(lexer_1.TokenKind.At)) {
1741
+ else if (this.check(TokenKind_1.TokenKind.At)) {
1640
1742
  let dot = this.advance();
1641
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1743
+ let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1642
1744
  // force it into an identifier so the AST makes some sense
1643
- name.kind = lexer_1.TokenKind.Identifier;
1745
+ name.kind = TokenKind_1.TokenKind.Identifier;
1644
1746
  expr = new Expression_1.XmlAttributeGetExpression(expr, name, dot);
1645
1747
  //only allow a single `@` expression
1646
1748
  break;
@@ -1649,27 +1751,28 @@ class Parser {
1649
1751
  break;
1650
1752
  }
1651
1753
  }
1754
+ //if we found a callExpression, add it to `expressions` in references
1755
+ if (referenceCallExpression) {
1756
+ this._references.expressions.add(referenceCallExpression);
1757
+ }
1652
1758
  return expr;
1653
1759
  }
1654
1760
  finishCall(openingParen, callee, addToCallExpressionList = true) {
1655
1761
  let args = [];
1656
- while (this.match(lexer_1.TokenKind.Newline)) {
1762
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1657
1763
  }
1658
- if (!this.check(lexer_1.TokenKind.RightParen)) {
1764
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
1659
1765
  do {
1660
- while (this.match(lexer_1.TokenKind.Newline)) { }
1766
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1661
1767
  if (args.length >= Expression_1.CallExpression.MaximumArguments) {
1662
1768
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
1663
1769
  throw this.lastDiagnosticAsError();
1664
1770
  }
1665
1771
  args.push(this.expression());
1666
- } while (this.match(lexer_1.TokenKind.Comma));
1667
- }
1668
- while (this.match(lexer_1.TokenKind.Newline)) { }
1669
- const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), lexer_1.TokenKind.RightParen);
1670
- if ((0, reflection_1.isVariableExpression)(callee)) {
1671
- callee.isCalled = true;
1772
+ } while (this.match(TokenKind_1.TokenKind.Comma));
1672
1773
  }
1774
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1775
+ const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
1673
1776
  let expression = new Expression_1.CallExpression(callee, openingParen, closingParen, args, this.currentNamespaceName);
1674
1777
  if (addToCallExpressionList) {
1675
1778
  this.callExpressions.push(expression);
@@ -1683,15 +1786,15 @@ class Parser {
1683
1786
  */
1684
1787
  typeToken() {
1685
1788
  let typeToken;
1686
- if (this.checkAny(...lexer_1.DeclarableTypes)) {
1789
+ if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
1687
1790
  // Token is a built in type
1688
1791
  typeToken = this.advance();
1689
1792
  }
1690
1793
  else if (this.options.mode === ParseMode.BrighterScript) {
1691
1794
  try {
1692
- // see if we can get a namespaced identifer
1795
+ // see if we can get a namespaced identifier
1693
1796
  const qualifiedType = this.getNamespacedVariableNameExpression();
1694
- typeToken = (0, creators_1.createToken)(lexer_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
1797
+ typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
1695
1798
  }
1696
1799
  catch (_a) {
1697
1800
  //could not get an identifier - just get whatever's next
@@ -1702,57 +1805,68 @@ class Parser {
1702
1805
  // just get whatever's next
1703
1806
  typeToken = this.advance();
1704
1807
  }
1808
+ if (typeToken && this.options.mode === ParseMode.BrighterScript) {
1809
+ // Check if it is an array - that is, if it has `[]` after the type
1810
+ // eg. `string[]` or `SomeKlass[]`
1811
+ if (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
1812
+ this.advance();
1813
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1814
+ const rightBracket = this.advance();
1815
+ typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, typeToken.text + '[]', util_1.util.getRange(typeToken, rightBracket));
1816
+ }
1817
+ }
1818
+ }
1705
1819
  return typeToken;
1706
1820
  }
1707
1821
  primary() {
1708
1822
  switch (true) {
1709
- case this.matchAny(lexer_1.TokenKind.False, lexer_1.TokenKind.True, lexer_1.TokenKind.Invalid, lexer_1.TokenKind.IntegerLiteral, lexer_1.TokenKind.LongIntegerLiteral, lexer_1.TokenKind.FloatLiteral, lexer_1.TokenKind.DoubleLiteral, lexer_1.TokenKind.StringLiteral):
1823
+ case this.matchAny(TokenKind_1.TokenKind.False, TokenKind_1.TokenKind.True, TokenKind_1.TokenKind.Invalid, TokenKind_1.TokenKind.IntegerLiteral, TokenKind_1.TokenKind.LongIntegerLiteral, TokenKind_1.TokenKind.FloatLiteral, TokenKind_1.TokenKind.DoubleLiteral, TokenKind_1.TokenKind.StringLiteral):
1710
1824
  return new Expression_1.LiteralExpression(this.previous());
1711
1825
  //capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript)
1712
- case this.matchAny(lexer_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : lexer_1.BrighterScriptSourceLiterals)):
1826
+ case this.matchAny(TokenKind_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : TokenKind_1.BrighterScriptSourceLiterals)):
1713
1827
  return new Expression_1.SourceLiteralExpression(this.previous());
1714
1828
  //template string
1715
- case this.check(lexer_1.TokenKind.BackTick):
1829
+ case this.check(TokenKind_1.TokenKind.BackTick):
1716
1830
  return this.templateString(false);
1717
1831
  //tagged template string (currently we do not support spaces between the identifier and the backtick)
1718
- case this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedLocalIdentifiers) && this.checkNext(lexer_1.TokenKind.BackTick):
1832
+ case this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers) && this.checkNext(TokenKind_1.TokenKind.BackTick):
1719
1833
  return this.templateString(true);
1720
- case this.matchAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
1834
+ case this.matchAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
1721
1835
  return new Expression_1.VariableExpression(this.previous(), this.currentNamespaceName);
1722
- case this.match(lexer_1.TokenKind.LeftParen):
1836
+ case this.match(TokenKind_1.TokenKind.LeftParen):
1723
1837
  let left = this.previous();
1724
1838
  let expr = this.expression();
1725
- let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), lexer_1.TokenKind.RightParen);
1839
+ let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
1726
1840
  return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
1727
- case this.match(lexer_1.TokenKind.LeftSquareBracket):
1841
+ case this.match(TokenKind_1.TokenKind.LeftSquareBracket):
1728
1842
  let elements = [];
1729
1843
  let openingSquare = this.previous();
1730
1844
  //add any comment found right after the opening square
1731
- if (this.check(lexer_1.TokenKind.Comment)) {
1845
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
1732
1846
  elements.push(new Statement_1.CommentStatement([this.advance()]));
1733
1847
  }
1734
- while (this.match(lexer_1.TokenKind.Newline)) {
1848
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1735
1849
  }
1736
- if (!this.match(lexer_1.TokenKind.RightSquareBracket)) {
1850
+ if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
1737
1851
  elements.push(this.expression());
1738
- while (this.matchAny(lexer_1.TokenKind.Comma, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1739
- if (this.checkPrevious(lexer_1.TokenKind.Comment) || this.check(lexer_1.TokenKind.Comment)) {
1740
- let comment = this.check(lexer_1.TokenKind.Comment) ? this.advance() : this.previous();
1852
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1853
+ if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1854
+ let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1741
1855
  elements.push(new Statement_1.CommentStatement([comment]));
1742
1856
  }
1743
- while (this.match(lexer_1.TokenKind.Newline)) {
1857
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1744
1858
  }
1745
- if (this.check(lexer_1.TokenKind.RightSquareBracket)) {
1859
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1746
1860
  break;
1747
1861
  }
1748
1862
  elements.push(this.expression());
1749
1863
  }
1750
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), lexer_1.TokenKind.RightSquareBracket);
1864
+ this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
1751
1865
  }
1752
1866
  let closingSquare = this.previous();
1753
1867
  //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
1754
1868
  return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
1755
- case this.match(lexer_1.TokenKind.LeftCurlyBrace):
1869
+ case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
1756
1870
  let openingBrace = this.previous();
1757
1871
  let members = [];
1758
1872
  let key = () => {
@@ -1761,25 +1875,25 @@ class Parser {
1761
1875
  keyToken: null,
1762
1876
  range: null
1763
1877
  };
1764
- if (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties)) {
1878
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
1765
1879
  result.keyToken = this.advance();
1766
1880
  }
1767
- else if (this.check(lexer_1.TokenKind.StringLiteral)) {
1881
+ else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
1768
1882
  result.keyToken = this.advance();
1769
1883
  }
1770
1884
  else {
1771
1885
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
1772
1886
  throw this.lastDiagnosticAsError();
1773
1887
  }
1774
- result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), lexer_1.TokenKind.Colon);
1888
+ result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
1775
1889
  result.range = util_1.util.getRange(result.keyToken, result.colonToken);
1776
1890
  return result;
1777
1891
  };
1778
- while (this.match(lexer_1.TokenKind.Newline)) {
1892
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
1779
1893
  }
1780
- if (!this.match(lexer_1.TokenKind.RightCurlyBrace)) {
1894
+ if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
1781
1895
  let lastAAMember;
1782
- if (this.check(lexer_1.TokenKind.Comment)) {
1896
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
1783
1897
  lastAAMember = null;
1784
1898
  members.push(new Statement_1.CommentStatement([this.advance()]));
1785
1899
  }
@@ -1789,26 +1903,26 @@ class Parser {
1789
1903
  lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1790
1904
  members.push(lastAAMember);
1791
1905
  }
1792
- while (this.matchAny(lexer_1.TokenKind.Comma, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment)) {
1906
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
1793
1907
  // collect comma at end of expression
1794
- if (lastAAMember && this.checkPrevious(lexer_1.TokenKind.Comma)) {
1908
+ if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
1795
1909
  lastAAMember.commaToken = this.previous();
1796
1910
  }
1797
1911
  //check for comment at the end of the current line
1798
- if (this.check(lexer_1.TokenKind.Comment) || this.checkPrevious(lexer_1.TokenKind.Comment)) {
1799
- let token = this.checkPrevious(lexer_1.TokenKind.Comment) ? this.previous() : this.advance();
1912
+ if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1913
+ let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1800
1914
  members.push(new Statement_1.CommentStatement([token]));
1801
1915
  }
1802
1916
  else {
1803
1917
  this.consumeStatementSeparators(true);
1804
1918
  //check for a comment on its own line
1805
- if (this.check(lexer_1.TokenKind.Comment) || this.checkPrevious(lexer_1.TokenKind.Comment)) {
1806
- let token = this.checkPrevious(lexer_1.TokenKind.Comment) ? this.previous() : this.advance();
1919
+ if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1920
+ let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1807
1921
  lastAAMember = null;
1808
1922
  members.push(new Statement_1.CommentStatement([token]));
1809
1923
  continue;
1810
1924
  }
1811
- if (this.check(lexer_1.TokenKind.RightCurlyBrace)) {
1925
+ if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
1812
1926
  break;
1813
1927
  }
1814
1928
  let k = key();
@@ -1817,23 +1931,23 @@ class Parser {
1817
1931
  members.push(lastAAMember);
1818
1932
  }
1819
1933
  }
1820
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), lexer_1.TokenKind.RightCurlyBrace);
1934
+ this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
1821
1935
  }
1822
1936
  let closingBrace = this.previous();
1823
1937
  const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
1824
1938
  this._references.aaLiterals.push(aaExpr);
1825
1939
  this.addPropertyHints(aaExpr);
1826
1940
  return aaExpr;
1827
- case this.matchAny(lexer_1.TokenKind.Pos, lexer_1.TokenKind.Tab):
1941
+ case this.matchAny(TokenKind_1.TokenKind.Pos, TokenKind_1.TokenKind.Tab):
1828
1942
  let token = Object.assign(this.previous(), {
1829
- kind: lexer_1.TokenKind.Identifier
1943
+ kind: TokenKind_1.TokenKind.Identifier
1830
1944
  });
1831
1945
  return new Expression_1.VariableExpression(token, this.currentNamespaceName);
1832
- case this.checkAny(lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub):
1946
+ case this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub):
1833
1947
  return this.anonymousFunction();
1834
- case this.check(lexer_1.TokenKind.RegexLiteral):
1948
+ case this.check(TokenKind_1.TokenKind.RegexLiteral):
1835
1949
  return this.regexLiteralExpression();
1836
- case this.check(lexer_1.TokenKind.Comment):
1950
+ case this.check(TokenKind_1.TokenKind.Comment):
1837
1951
  return new Statement_1.CommentStatement([this.advance()]);
1838
1952
  default:
1839
1953
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
@@ -1903,12 +2017,12 @@ class Parser {
1903
2017
  }
1904
2018
  consumeStatementSeparators(optional = false) {
1905
2019
  //a comment or EOF mark the end of the statement
1906
- if (this.isAtEnd() || this.check(lexer_1.TokenKind.Comment)) {
2020
+ if (this.isAtEnd() || this.check(TokenKind_1.TokenKind.Comment)) {
1907
2021
  return true;
1908
2022
  }
1909
2023
  let consumed = false;
1910
2024
  //consume any newlines and colons
1911
- while (this.matchAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
2025
+ while (this.matchAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1912
2026
  consumed = true;
1913
2027
  }
1914
2028
  if (!optional && !consumed) {
@@ -1924,7 +2038,7 @@ class Parser {
1924
2038
  }
1925
2039
  checkEndOfStatement() {
1926
2040
  const nextKind = this.peek().kind;
1927
- return [lexer_1.TokenKind.Colon, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment, lexer_1.TokenKind.Eof].includes(nextKind);
2041
+ return [TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Eof].includes(nextKind);
1928
2042
  }
1929
2043
  checkPrevious(tokenKind) {
1930
2044
  var _a;
@@ -1932,14 +2046,14 @@ class Parser {
1932
2046
  }
1933
2047
  check(tokenKind) {
1934
2048
  const nextKind = this.peek().kind;
1935
- if (nextKind === lexer_1.TokenKind.Eof) {
2049
+ if (nextKind === TokenKind_1.TokenKind.Eof) {
1936
2050
  return false;
1937
2051
  }
1938
2052
  return nextKind === tokenKind;
1939
2053
  }
1940
2054
  checkAny(...tokenKinds) {
1941
2055
  const nextKind = this.peek().kind;
1942
- if (nextKind === lexer_1.TokenKind.Eof) {
2056
+ if (nextKind === TokenKind_1.TokenKind.Eof) {
1943
2057
  return false;
1944
2058
  }
1945
2059
  return tokenKinds.includes(nextKind);
@@ -1958,7 +2072,7 @@ class Parser {
1958
2072
  return tokenKinds.includes(nextKind);
1959
2073
  }
1960
2074
  isAtEnd() {
1961
- return this.peek().kind === lexer_1.TokenKind.Eof;
2075
+ return this.peek().kind === TokenKind_1.TokenKind.Eof;
1962
2076
  }
1963
2077
  peekNext() {
1964
2078
  if (this.isAtEnd()) {
@@ -1980,16 +2094,16 @@ class Parser {
1980
2094
  return;
1981
2095
  }
1982
2096
  switch (this.peek().kind) { //eslint-disable-line @typescript-eslint/switch-exhaustiveness-check
1983
- case lexer_1.TokenKind.Namespace:
1984
- case lexer_1.TokenKind.Class:
1985
- case lexer_1.TokenKind.Function:
1986
- case lexer_1.TokenKind.Sub:
1987
- case lexer_1.TokenKind.If:
1988
- case lexer_1.TokenKind.For:
1989
- case lexer_1.TokenKind.ForEach:
1990
- case lexer_1.TokenKind.While:
1991
- case lexer_1.TokenKind.Print:
1992
- case lexer_1.TokenKind.Return:
2097
+ case TokenKind_1.TokenKind.Namespace:
2098
+ case TokenKind_1.TokenKind.Class:
2099
+ case TokenKind_1.TokenKind.Function:
2100
+ case TokenKind_1.TokenKind.Sub:
2101
+ case TokenKind_1.TokenKind.If:
2102
+ case TokenKind_1.TokenKind.For:
2103
+ case TokenKind_1.TokenKind.ForEach:
2104
+ case TokenKind_1.TokenKind.While:
2105
+ case TokenKind_1.TokenKind.Print:
2106
+ case TokenKind_1.TokenKind.Return:
1993
2107
  // start parsing again from the next block starter or obvious
1994
2108
  // expression start
1995
2109
  return;
@@ -2035,17 +2149,17 @@ class Parser {
2035
2149
  const previousToken = this.getPreviousToken(closestToken);
2036
2150
  const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
2037
2151
  //next to matched token
2038
- if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
2152
+ if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
2039
2153
  return false;
2040
2154
  }
2041
2155
  else if (closestToken.kind === tokenKind) {
2042
2156
  return true;
2043
2157
  }
2044
- else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
2158
+ else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
2045
2159
  return false;
2046
2160
  //next to an identifier, which is next to token kind
2047
2161
  }
2048
- else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
2162
+ else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
2049
2163
  return true;
2050
2164
  }
2051
2165
  else {
@@ -2056,7 +2170,7 @@ class Parser {
2056
2170
  const index = this.tokens.indexOf(currentToken);
2057
2171
  for (let i = index - 1; i >= 0; i--) {
2058
2172
  currentToken = this.tokens[i];
2059
- if (currentToken.kind === lexer_1.TokenKind.Newline) {
2173
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
2060
2174
  break;
2061
2175
  }
2062
2176
  else if (currentToken.kind === tokenKind) {
@@ -2076,7 +2190,7 @@ class Parser {
2076
2190
  let tokens = [];
2077
2191
  for (let i = this.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.tokens.length; i += direction) {
2078
2192
  currentToken = this.tokens[i];
2079
- if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
2193
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
2080
2194
  break;
2081
2195
  }
2082
2196
  tokens.push(currentToken);
@@ -2147,12 +2261,12 @@ class Parser {
2147
2261
  currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2148
2262
  currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2149
2263
  }
2150
- if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === lexer_1.TokenKind.Dot) {
2264
+ if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.Dot) {
2151
2265
  previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
2152
2266
  currentToken = previousTokenResult.token;
2153
2267
  currentTokenIndex = previousTokenResult.index;
2154
2268
  }
2155
- previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, lexer_1.TokenKind.LeftParen, lexer_1.TokenKind.RightParen);
2269
+ previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.RightParen);
2156
2270
  currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2157
2271
  currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2158
2272
  if (previousTokenResult.hasBrackets) {
@@ -2160,7 +2274,7 @@ class Parser {
2160
2274
  }
2161
2275
  let tokenTypeIsNotKnowable = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable;
2162
2276
  if (currentTokenIndex) {
2163
- previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, lexer_1.TokenKind.LeftSquareBracket, lexer_1.TokenKind.RightSquareBracket);
2277
+ previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.RightSquareBracket);
2164
2278
  currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2165
2279
  currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2166
2280
  if (previousTokenResult.hasBrackets) {
@@ -2178,15 +2292,15 @@ class Parser {
2178
2292
  if (!currentToken || lastTokenHasWhitespace) {
2179
2293
  return false;
2180
2294
  }
2181
- if (currentToken.kind === lexer_1.TokenKind.Identifier) {
2295
+ if (currentToken.kind === TokenKind_1.TokenKind.Identifier) {
2182
2296
  return true;
2183
2297
  }
2184
2298
  if (currentToken.leadingWhitespace.length === 0) {
2185
2299
  // start of the chain
2186
- return lexer_1.AllowedLocalIdentifiers.includes(currentToken.kind);
2300
+ return TokenKind_1.AllowedLocalIdentifiers.includes(currentToken.kind);
2187
2301
  }
2188
2302
  // not the start of the chain
2189
- return lexer_1.AllowedProperties.includes(currentToken.kind);
2303
+ return TokenKind_1.AllowedProperties.includes(currentToken.kind);
2190
2304
  }
2191
2305
  /**
2192
2306
  * Builds up a chain of tokens, starting with the first in the chain, and ending with currentToken
@@ -2233,32 +2347,67 @@ class Parser {
2233
2347
  */
2234
2348
  findReferences() {
2235
2349
  this._references = new References();
2350
+ const excludedExpressions = new Set();
2351
+ const visitCallExpression = (e) => {
2352
+ for (const p of e.args) {
2353
+ this._references.expressions.add(p);
2354
+ }
2355
+ //add calls that were not excluded (from loop below)
2356
+ if (!excludedExpressions.has(e)) {
2357
+ this._references.expressions.add(e);
2358
+ }
2359
+ //if this call is part of a longer expression that includes a call higher up, find that higher one and remove it
2360
+ if (e.callee) {
2361
+ let node = e.callee;
2362
+ while (node) {
2363
+ //the primary goal for this loop. If we found a parent call expression, remove it from `references`
2364
+ if ((0, reflection_1.isCallExpression)(node)) {
2365
+ this.references.expressions.delete(node);
2366
+ excludedExpressions.add(node);
2367
+ //stop here. even if there are multiple calls in the chain, each child will find and remove its closest parent, so that reduces excess walking.
2368
+ break;
2369
+ //when we hit a variable expression, we're definitely at the leftmost expression so stop
2370
+ }
2371
+ else if ((0, reflection_1.isVariableExpression)(node)) {
2372
+ break;
2373
+ //if
2374
+ }
2375
+ else if ((0, reflection_1.isDottedGetExpression)(node) || (0, reflection_1.isIndexedGetExpression)(node)) {
2376
+ node = node.obj;
2377
+ }
2378
+ else {
2379
+ //some expression we don't understand. log it and quit the loop
2380
+ this.logger.info('Encountered unknown expression while calculating function expression chain', node);
2381
+ break;
2382
+ }
2383
+ }
2384
+ }
2385
+ };
2236
2386
  //gather up all the top-level statements
2237
2387
  this.ast.walk((0, visitors_1.createVisitor)({
2388
+ AssignmentStatement: s => {
2389
+ this._references.assignmentStatements.push(s);
2390
+ this.references.expressions.add(s.value);
2391
+ },
2238
2392
  ClassStatement: s => {
2239
2393
  this._references.classStatements.push(s);
2240
2394
  },
2395
+ ClassFieldStatement: s => {
2396
+ if (s.initialValue) {
2397
+ this._references.expressions.add(s.initialValue);
2398
+ }
2399
+ },
2241
2400
  NamespaceStatement: s => {
2242
2401
  this._references.namespaceStatements.push(s);
2243
2402
  },
2244
2403
  FunctionStatement: s => {
2245
2404
  this._references.functionStatements.push(s);
2246
- //add the initial set of function expressions for function statements
2247
- this._references.functionExpressions.push(s.func);
2248
2405
  },
2249
2406
  ImportStatement: s => {
2250
2407
  this._references.importStatements.push(s);
2251
2408
  },
2252
2409
  LibraryStatement: s => {
2253
2410
  this._references.libraryStatements.push(s);
2254
- }
2255
- }), {
2256
- walkMode: visitors_1.WalkMode.visitStatements
2257
- });
2258
- let func;
2259
- let visitor = (0, visitors_1.createVisitor)({
2260
- AssignmentStatement: s => {
2261
- this._references.assignmentStatements.push(s);
2262
2411
  },
2263
2412
  FunctionExpression: (expression, parent) => {
2264
2413
  if (!(0, reflection_1.isClassMethodStatement)(parent)) {
@@ -2267,25 +2416,54 @@ class Parser {
2267
2416
  },
2268
2417
  NewExpression: e => {
2269
2418
  this._references.newExpressions.push(e);
2419
+ for (const p of e.call.args) {
2420
+ this._references.expressions.add(p);
2421
+ }
2422
+ },
2423
+ ExpressionStatement: s => {
2424
+ this._references.expressions.add(s.expression);
2425
+ },
2426
+ CallfuncExpression: e => {
2427
+ visitCallExpression(e);
2428
+ },
2429
+ CallExpression: e => {
2430
+ visitCallExpression(e);
2270
2431
  },
2271
2432
  AALiteralExpression: e => {
2272
2433
  this.addPropertyHints(e);
2434
+ this._references.expressions.add(e);
2435
+ for (const member of e.elements) {
2436
+ if ((0, reflection_1.isAAMemberExpression)(member)) {
2437
+ this._references.expressions.add(member.value);
2438
+ }
2439
+ }
2440
+ },
2441
+ ArrayLiteralExpression: e => {
2442
+ for (const element of e.elements) {
2443
+ //keep everything except comments
2444
+ if (!(0, reflection_1.isCommentStatement)(element)) {
2445
+ this._references.expressions.add(element);
2446
+ }
2447
+ }
2273
2448
  },
2274
2449
  DottedGetExpression: e => {
2275
2450
  this.addPropertyHints(e.name);
2276
2451
  },
2277
2452
  DottedSetStatement: e => {
2278
2453
  this.addPropertyHints(e.name);
2454
+ },
2455
+ EnumStatement: e => {
2456
+ this._references.enumStatements.push(e);
2457
+ },
2458
+ UnaryExpression: e => {
2459
+ this._references.expressions.add(e);
2460
+ },
2461
+ IncrementStatement: e => {
2462
+ this._references.expressions.add(e);
2279
2463
  }
2464
+ }), {
2465
+ walkMode: visitors_1.WalkMode.visitAllRecursive
2280
2466
  });
2281
- //walk all function expressions (we'll add new ones as we move along too)
2282
- for (let i = 0; i < this._references.functionExpressions.length; i++) {
2283
- func = this._references.functionExpressions[i];
2284
- //walk this function expression
2285
- func.body.walk(visitor, {
2286
- walkMode: visitors_1.WalkMode.visitAll
2287
- });
2288
- }
2289
2467
  }
2290
2468
  getContainingClass(currentToken) {
2291
2469
  return this.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
@@ -2297,7 +2475,10 @@ class Parser {
2297
2475
  return this.references.namespaceStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
2298
2476
  }
2299
2477
  getContainingFunctionExpression(currentToken) {
2300
- return this.references.functionExpressions.find((fe) => util_1.util.rangeContains(fe.range, currentToken.range.start));
2478
+ return this.getContainingFunctionExpressionByPosition(currentToken.range.start);
2479
+ }
2480
+ getContainingFunctionExpressionByPosition(position) {
2481
+ return this.references.functionExpressions.find((fe) => util_1.util.rangeContains(fe.range, position));
2301
2482
  }
2302
2483
  dispose() {
2303
2484
  }
@@ -2310,6 +2491,7 @@ var ParseMode;
2310
2491
  })(ParseMode = exports.ParseMode || (exports.ParseMode = {}));
2311
2492
  class References {
2312
2493
  constructor() {
2494
+ this.cache = new Cache_1.Cache();
2313
2495
  this.assignmentStatements = [];
2314
2496
  this.classStatements = [];
2315
2497
  this.dottedSetStatements = [];
@@ -2317,6 +2499,18 @@ class References {
2317
2499
  this.functionExpressions = [];
2318
2500
  this.functionStatements = [];
2319
2501
  this.interfaceStatements = [];
2502
+ this.enumStatements = [];
2503
+ /**
2504
+ * A collection of full expressions. This excludes intermediary expressions.
2505
+ *
2506
+ * Example 1:
2507
+ * `a.b.c` is composed of `a` (variableExpression) `.b` (DottedGetExpression) `.c` (DottedGetExpression)
2508
+ * This will only contain the final `.c` DottedGetExpression because `.b` and `a` can both be derived by walking back from the `.c` DottedGetExpression.
2509
+ *
2510
+ * Example 2:
2511
+ * `name.space.doSomething(a.b.c)` will result in 2 entries in this list. the `CallExpression` for `doSomething`, and the `.c` DottedGetExpression.
2512
+ */
2513
+ this.expressions = new Set();
2320
2514
  this.importStatements = [];
2321
2515
  this.libraryStatements = [];
2322
2516
  this.namespaceStatements = [];
@@ -2353,6 +2547,15 @@ class References {
2353
2547
  }
2354
2548
  return this._interfaceStatementLookup;
2355
2549
  }
2550
+ get enumStatementLookup() {
2551
+ return this.cache.getOrAdd('enums', () => {
2552
+ const result = new Map();
2553
+ for (const stmt of this.enumStatements) {
2554
+ result.set(stmt.fullName.toLowerCase(), stmt);
2555
+ }
2556
+ return result;
2557
+ });
2558
+ }
2356
2559
  }
2357
2560
  exports.References = References;
2358
2561
  var TokenUsage;
@@ -2388,7 +2591,10 @@ function getBscTypeFromExpression(expression, functionExpression) {
2388
2591
  //Array literal
2389
2592
  }
2390
2593
  else if ((0, reflection_1.isArrayLiteralExpression)(expression)) {
2391
- return new ArrayType_1.ArrayType();
2594
+ const innerTypes = expression.elements.filter((element) => !(0, reflection_1.isCommentStatement)(element)).map((element) => {
2595
+ return getBscTypeFromExpression(element, functionExpression);
2596
+ });
2597
+ return new ArrayType_1.ArrayType(...innerTypes);
2392
2598
  //function call
2393
2599
  }
2394
2600
  else if ((0, reflection_1.isNewExpression)(expression)) {
@@ -2404,6 +2610,12 @@ function getBscTypeFromExpression(expression, functionExpression) {
2404
2610
  else if ((0, reflection_1.isDottedGetExpression)(expression)) {
2405
2611
  return (0, helpers_1.getTypeFromDottedGetExpression)(expression, functionExpression);
2406
2612
  }
2613
+ else if ((0, reflection_1.isIndexedGetExpression)(expression)) {
2614
+ const source = getBscTypeFromExpression(expression.obj, functionExpression);
2615
+ if ((0, reflection_1.isArrayType)(source)) {
2616
+ return source.getDefaultType();
2617
+ }
2618
+ }
2407
2619
  }
2408
2620
  catch (e) {
2409
2621
  //do nothing. Just return dynamic