brighterscript 1.0.0-alpha.26 → 1.0.0-alpha.28

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 (200) hide show
  1. package/CHANGELOG.md +82 -5
  2. package/README.md +1 -1
  3. package/dist/AstValidationSegmenter.d.ts +1 -1
  4. package/dist/AstValidationSegmenter.js +4 -5
  5. package/dist/AstValidationSegmenter.js.map +1 -1
  6. package/dist/DiagnosticFilterer.d.ts +7 -4
  7. package/dist/DiagnosticFilterer.js +67 -37
  8. package/dist/DiagnosticFilterer.js.map +1 -1
  9. package/dist/DiagnosticMessages.d.ts +1 -3
  10. package/dist/DiagnosticMessages.js +5 -8
  11. package/dist/DiagnosticMessages.js.map +1 -1
  12. package/dist/PluginInterface.js +1 -1
  13. package/dist/PluginInterface.js.map +1 -1
  14. package/dist/Program.d.ts +1 -1
  15. package/dist/Program.js +34 -31
  16. package/dist/Program.js.map +1 -1
  17. package/dist/Scope.d.ts +7 -34
  18. package/dist/Scope.js +45 -305
  19. package/dist/Scope.js.map +1 -1
  20. package/dist/SymbolTable.d.ts +1 -8
  21. package/dist/SymbolTable.js +1 -10
  22. package/dist/SymbolTable.js.map +1 -1
  23. package/dist/SymbolTypeFlag.d.ts +8 -0
  24. package/dist/SymbolTypeFlag.js +13 -0
  25. package/dist/SymbolTypeFlag.js.map +1 -0
  26. package/dist/XmlScope.d.ts +0 -8
  27. package/dist/XmlScope.js +6 -84
  28. package/dist/XmlScope.js.map +1 -1
  29. package/dist/astUtils/CachedLookups.d.ts +1 -2
  30. package/dist/astUtils/CachedLookups.js +4 -19
  31. package/dist/astUtils/CachedLookups.js.map +1 -1
  32. package/dist/astUtils/creators.d.ts +1 -0
  33. package/dist/astUtils/creators.js +48 -8
  34. package/dist/astUtils/creators.js.map +1 -1
  35. package/dist/astUtils/creators.spec.js +0 -10
  36. package/dist/astUtils/creators.spec.js.map +1 -1
  37. package/dist/astUtils/reflection.d.ts +3 -2
  38. package/dist/astUtils/reflection.js +11 -7
  39. package/dist/astUtils/reflection.js.map +1 -1
  40. package/dist/astUtils/reflection.spec.js +11 -16
  41. package/dist/astUtils/reflection.spec.js.map +1 -1
  42. package/dist/astUtils/visitors.d.ts +1 -2
  43. package/dist/astUtils/visitors.js.map +1 -1
  44. package/dist/astUtils/visitors.spec.js +1 -5
  45. package/dist/astUtils/visitors.spec.js.map +1 -1
  46. package/dist/bscPlugin/BscPlugin.d.ts +2 -1
  47. package/dist/bscPlugin/BscPlugin.js +4 -0
  48. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  49. package/dist/bscPlugin/SignatureHelpUtil.js +4 -3
  50. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -1
  51. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -0
  52. package/dist/bscPlugin/completions/CompletionsProcessor.js +46 -29
  53. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  54. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +39 -0
  55. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  56. package/dist/bscPlugin/hover/HoverProcessor.d.ts +1 -0
  57. package/dist/bscPlugin/hover/HoverProcessor.js +30 -10
  58. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  59. package/dist/bscPlugin/hover/HoverProcessor.spec.js +125 -7
  60. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  61. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  62. package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
  63. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  64. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
  65. package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
  66. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
  67. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +2 -3
  68. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  69. package/dist/bscPlugin/validation/BrsFileValidator.js +25 -31
  70. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  71. package/dist/bscPlugin/validation/ScopeValidator.d.ts +34 -1
  72. package/dist/bscPlugin/validation/ScopeValidator.js +435 -27
  73. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  74. package/dist/bscPlugin/validation/ScopeValidator.spec.js +178 -10
  75. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  76. package/dist/diagnosticUtils.d.ts +1 -1
  77. package/dist/files/BrsFile.Class.spec.js +15 -7
  78. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  79. package/dist/files/BrsFile.d.ts +14 -5
  80. package/dist/files/BrsFile.js +83 -150
  81. package/dist/files/BrsFile.js.map +1 -1
  82. package/dist/files/BrsFile.spec.js +429 -162
  83. package/dist/files/BrsFile.spec.js.map +1 -1
  84. package/dist/files/XmlFile.d.ts +2 -3
  85. package/dist/files/XmlFile.js +1 -3
  86. package/dist/files/XmlFile.js.map +1 -1
  87. package/dist/index.d.ts +1 -0
  88. package/dist/index.js +1 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/interfaces.d.ts +117 -85
  91. package/dist/interfaces.js +9 -9
  92. package/dist/interfaces.js.map +1 -1
  93. package/dist/lexer/Lexer.d.ts +9 -3
  94. package/dist/lexer/Lexer.js +36 -15
  95. package/dist/lexer/Lexer.js.map +1 -1
  96. package/dist/lexer/Lexer.spec.js +76 -38
  97. package/dist/lexer/Lexer.spec.js.map +1 -1
  98. package/dist/lexer/Token.js +1 -1
  99. package/dist/lexer/Token.js.map +1 -1
  100. package/dist/lexer/TokenKind.d.ts +1 -0
  101. package/dist/lexer/TokenKind.js +4 -1
  102. package/dist/lexer/TokenKind.js.map +1 -1
  103. package/dist/parser/AstNode.d.ts +1 -2
  104. package/dist/parser/AstNode.js +0 -1
  105. package/dist/parser/AstNode.js.map +1 -1
  106. package/dist/parser/BrsTranspileState.d.ts +1 -1
  107. package/dist/parser/Expression.d.ts +153 -135
  108. package/dist/parser/Expression.js +204 -114
  109. package/dist/parser/Expression.js.map +1 -1
  110. package/dist/parser/Parser.Class.spec.js +15 -16
  111. package/dist/parser/Parser.Class.spec.js.map +1 -1
  112. package/dist/parser/Parser.d.ts +8 -4
  113. package/dist/parser/Parser.js +108 -149
  114. package/dist/parser/Parser.js.map +1 -1
  115. package/dist/parser/Parser.spec.js +48 -72
  116. package/dist/parser/Parser.spec.js.map +1 -1
  117. package/dist/parser/SGParser.js +49 -35
  118. package/dist/parser/SGParser.js.map +1 -1
  119. package/dist/parser/SGTypes.d.ts +36 -24
  120. package/dist/parser/SGTypes.js +31 -60
  121. package/dist/parser/SGTypes.js.map +1 -1
  122. package/dist/parser/Statement.d.ts +214 -207
  123. package/dist/parser/Statement.js +248 -169
  124. package/dist/parser/Statement.js.map +1 -1
  125. package/dist/parser/Statement.spec.js +0 -13
  126. package/dist/parser/Statement.spec.js.map +1 -1
  127. package/dist/parser/TranspileState.d.ts +17 -8
  128. package/dist/parser/TranspileState.js +64 -6
  129. package/dist/parser/TranspileState.js.map +1 -1
  130. package/dist/parser/tests/Parser.spec.d.ts +1 -1
  131. package/dist/parser/tests/Parser.spec.js +1 -2
  132. package/dist/parser/tests/Parser.spec.js.map +1 -1
  133. package/dist/parser/tests/controlFlow/If.spec.js +1 -1
  134. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  135. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +1 -3
  136. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  137. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +44 -0
  138. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  139. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +6 -6
  140. package/dist/parser/tests/expression/TernaryExpression.spec.js +47 -0
  141. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  142. package/dist/parser/tests/expression/TypeExpression.spec.js +8 -9
  143. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -1
  144. package/dist/parser/tests/statement/ConstStatement.spec.js +2 -2
  145. package/dist/parser/tests/statement/InterfaceStatement.spec.js +8 -1
  146. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  147. package/dist/parser/tests/statement/Misc.spec.js +25 -5
  148. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  149. package/dist/parser/tests/statement/TryCatch.spec.js +9 -2
  150. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  151. package/dist/preprocessor/Chunk.js +1 -2
  152. package/dist/preprocessor/Chunk.js.map +1 -1
  153. package/dist/preprocessor/PreprocessorParser.js +2 -1
  154. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  155. package/dist/roku-types/data.json +70 -52
  156. package/dist/roku-types/index.d.ts +43 -21
  157. package/dist/types/ArrayType.js +1 -2
  158. package/dist/types/ArrayType.js.map +1 -1
  159. package/dist/types/ArrayType.spec.js +7 -8
  160. package/dist/types/ArrayType.spec.js.map +1 -1
  161. package/dist/types/AssociativeArrayType.d.ts +3 -0
  162. package/dist/types/AssociativeArrayType.js +10 -2
  163. package/dist/types/AssociativeArrayType.js.map +1 -1
  164. package/dist/types/BscType.d.ts +1 -1
  165. package/dist/types/BscType.js +3 -3
  166. package/dist/types/BscType.js.map +1 -1
  167. package/dist/types/BuiltInInterfaceAdder.js +7 -8
  168. package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
  169. package/dist/types/BuiltInInterfaceAdder.spec.js +31 -32
  170. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -1
  171. package/dist/types/ClassType.spec.js +10 -11
  172. package/dist/types/ClassType.spec.js.map +1 -1
  173. package/dist/types/ComponentType.d.ts +2 -1
  174. package/dist/types/ComponentType.js.map +1 -1
  175. package/dist/types/EnumType.js +2 -3
  176. package/dist/types/EnumType.js.map +1 -1
  177. package/dist/types/InheritableType.js +3 -4
  178. package/dist/types/InheritableType.js.map +1 -1
  179. package/dist/types/InterfaceType.js +2 -3
  180. package/dist/types/InterfaceType.js.map +1 -1
  181. package/dist/types/InterfaceType.spec.js +3 -4
  182. package/dist/types/InterfaceType.spec.js.map +1 -1
  183. package/dist/types/ObjectType.js +1 -2
  184. package/dist/types/ObjectType.js.map +1 -1
  185. package/dist/types/ReferenceType.d.ts +1 -1
  186. package/dist/types/ReferenceType.spec.js +21 -22
  187. package/dist/types/ReferenceType.spec.js.map +1 -1
  188. package/dist/types/UnionType.js +3 -3
  189. package/dist/types/UnionType.js.map +1 -1
  190. package/dist/types/UnionType.spec.js +37 -38
  191. package/dist/types/UnionType.spec.js.map +1 -1
  192. package/dist/types/helper.spec.js +4 -5
  193. package/dist/types/helper.spec.js.map +1 -1
  194. package/dist/util.d.ts +21 -11
  195. package/dist/util.js +116 -37
  196. package/dist/util.js.map +1 -1
  197. package/dist/validators/ClassValidator.d.ts +0 -9
  198. package/dist/validators/ClassValidator.js +3 -46
  199. package/dist/validators/ClassValidator.js.map +1 -1
  200. package/package.json +6 -3
@@ -11,7 +11,6 @@ const Expression_1 = require("./Expression");
11
11
  const Logger_1 = require("../Logger");
12
12
  const reflection_1 = require("../astUtils/reflection");
13
13
  const creators_1 = require("../astUtils/creators");
14
- const SymbolTable_1 = require("../SymbolTable");
15
14
  class Parser {
16
15
  constructor() {
17
16
  /**
@@ -28,6 +27,13 @@ class Parser {
28
27
  */
29
28
  this.callExpressions = [];
30
29
  }
30
+ get eofToken() {
31
+ var _a;
32
+ const lastToken = (_a = this.tokens) === null || _a === void 0 ? void 0 : _a[this.tokens.length - 1];
33
+ if ((lastToken === null || lastToken === void 0 ? void 0 : lastToken.kind) === TokenKind_1.TokenKind.Eof) {
34
+ return lastToken;
35
+ }
36
+ }
31
37
  get statements() {
32
38
  return this.ast.statements;
33
39
  }
@@ -57,16 +63,17 @@ class Parser {
57
63
  */
58
64
  parse(toParse, options) {
59
65
  var _a;
66
+ this.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : new Logger_1.Logger();
67
+ options = this.sanitizeParseOptions(options);
68
+ this.options = options;
60
69
  let tokens;
61
70
  if (typeof toParse === 'string') {
62
- tokens = Lexer_1.Lexer.scan(toParse).tokens;
71
+ tokens = Lexer_1.Lexer.scan(toParse, { trackLocations: options.trackLocations }).tokens;
63
72
  }
64
73
  else {
65
74
  tokens = toParse;
66
75
  }
67
- this.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : new Logger_1.Logger();
68
76
  this.tokens = tokens;
69
- this.options = this.sanitizeParseOptions(options);
70
77
  this.allowedLocalIdentifiers = [
71
78
  ...TokenKind_1.AllowedLocalIdentifiers,
72
79
  //when in plain brightscript mode, the BrighterScript source literals can be used as regular variables
@@ -115,7 +122,11 @@ class Parser {
115
122
  return body;
116
123
  }
117
124
  sanitizeParseOptions(options) {
118
- return Object.assign({ mode: 'brightscript' }, (options || {}));
125
+ var _a, _b;
126
+ options !== null && options !== void 0 ? options : (options = {});
127
+ (_a = options.mode) !== null && _a !== void 0 ? _a : (options.mode = ParseMode.BrightScript);
128
+ (_b = options.trackLocations) !== null && _b !== void 0 ? _b : (options.trackLocations = true);
129
+ return options;
119
130
  }
120
131
  /**
121
132
  * Determine if the parser is currently parsing tokens at the root level.
@@ -155,9 +166,6 @@ class Parser {
155
166
  if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
156
167
  return this.annotationExpression();
157
168
  }
158
- if (this.check(TokenKind_1.TokenKind.Comment)) {
159
- return this.commentStatement();
160
- }
161
169
  //catch certain global terminators to prevent unnecessary lookahead (i.e. like `end namespace`, no need to continue)
162
170
  if (this.checkAny(...this.peekGlobalTerminators())) {
163
171
  return;
@@ -190,13 +198,15 @@ class Parser {
190
198
  return identifier;
191
199
  }
192
200
  enumMemberStatement() {
193
- const statement = new Statement_1.EnumMemberStatement({});
194
- statement.tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
201
+ const name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
202
+ let equalsToken;
203
+ let value;
195
204
  //look for `= SOME_EXPRESSION`
196
205
  if (this.check(TokenKind_1.TokenKind.Equal)) {
197
- statement.tokens.equals = this.advance();
198
- statement.value = this.expression();
206
+ equalsToken = this.advance();
207
+ value = this.expression();
199
208
  }
209
+ const statement = new Statement_1.EnumMemberStatement({ name: name, equals: equalsToken, value: value });
200
210
  return statement;
201
211
  }
202
212
  /**
@@ -290,6 +300,10 @@ class Parser {
290
300
  let body = [];
291
301
  while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
292
302
  try {
303
+ //break out of this loop if we encountered the `EndInterface` token not followed by `as`
304
+ if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
305
+ break;
306
+ }
293
307
  let decl;
294
308
  //collect leading annotations
295
309
  if (this.check(TokenKind_1.TokenKind.At)) {
@@ -309,10 +323,6 @@ class Parser {
309
323
  }
310
324
  else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
311
325
  decl = this.interfaceMethodStatement(optionalKeyword);
312
- //comments
313
- }
314
- else if (this.check(TokenKind_1.TokenKind.Comment)) {
315
- decl = this.commentStatement();
316
326
  }
317
327
  if (decl) {
318
328
  this.consumePendingAnnotations(decl);
@@ -329,10 +339,6 @@ class Parser {
329
339
  }
330
340
  //ensure statement separator
331
341
  this.consumeStatementSeparators();
332
- //break out of this loop if we encountered the `EndInterface` token not followed by `as`
333
- if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
334
- break;
335
- }
336
342
  }
337
343
  //consume the final `end interface` token
338
344
  const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
@@ -348,12 +354,12 @@ class Parser {
348
354
  return statement;
349
355
  }
350
356
  enumDeclaration() {
351
- const result = new Statement_1.EnumStatement({ name: {}, body: [] });
357
+ const enumToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
358
+ const nameToken = this.tryIdentifier(...this.allowedLocalIdentifiers);
352
359
  this.warnIfNotBrighterScriptMode('enum declarations');
353
360
  const parentAnnotations = this.enterAnnotationBlock();
354
- result.tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
355
- result.tokens.name = this.tryIdentifier(...this.allowedLocalIdentifiers);
356
361
  this.consumeStatementSeparators();
362
+ const body = [];
357
363
  //gather up all members
358
364
  while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
359
365
  try {
@@ -365,14 +371,10 @@ class Parser {
365
371
  //members
366
372
  if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
367
373
  decl = this.enumMemberStatement();
368
- //comments
369
- }
370
- else if (this.check(TokenKind_1.TokenKind.Comment)) {
371
- decl = this.commentStatement();
372
374
  }
373
375
  if (decl) {
374
376
  this.consumePendingAnnotations(decl);
375
- result.body.push(decl);
377
+ body.push(decl);
376
378
  }
377
379
  else {
378
380
  //we didn't find a declaration...flag tokens until next line
@@ -391,7 +393,13 @@ class Parser {
391
393
  }
392
394
  }
393
395
  //consume the final `end interface` token
394
- result.tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
396
+ const endEnumToken = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
397
+ const result = new Statement_1.EnumStatement({
398
+ enum: enumToken,
399
+ name: nameToken,
400
+ body: body,
401
+ endEnum: endEnumToken
402
+ });
395
403
  this.exitAnnotationBlock(parentAnnotations);
396
404
  return result;
397
405
  }
@@ -448,8 +456,6 @@ class Parser {
448
456
  func: funcDeclaration.func,
449
457
  override: overrideKeyword
450
458
  });
451
- //refer to this statement as parent of the expression
452
- funcDeclaration.func.functionStatement = decl;
453
459
  //fields
454
460
  }
455
461
  else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
@@ -458,10 +464,6 @@ class Parser {
458
464
  if (overrideKeyword) {
459
465
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classFieldCannotBeOverridden()), { range: overrideKeyword.range }));
460
466
  }
461
- //comments
462
- }
463
- else if (this.check(TokenKind_1.TokenKind.Comment)) {
464
- decl = this.commentStatement();
465
467
  }
466
468
  if (decl) {
467
469
  this.consumePendingAnnotations(decl);
@@ -542,7 +544,6 @@ class Parser {
542
544
  });
543
545
  }
544
546
  functionDeclaration(isAnonymous, checkIdentifier = true, onlyCallableAsMember = false) {
545
- var _a;
546
547
  let previousCallExpressions = this.callExpressions;
547
548
  this.callExpressions = [];
548
549
  try {
@@ -610,46 +611,38 @@ class Parser {
610
611
  return haveFoundOptional || !!param.defaultValue;
611
612
  }, false);
612
613
  this.consumeStatementSeparators(true);
614
+ //support ending the function with `end sub` OR `end function`
615
+ let body = this.block();
616
+ //if the parser was unable to produce a block, make an empty one so the AST makes some sense...
617
+ // consume 'end sub' or 'end function'
618
+ const endFunctionType = this.advance();
619
+ let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
620
+ //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
621
+ //add an error but don't hard-fail so the AST can continue more gracefully
622
+ if (endFunctionType.kind !== expectedEndKind) {
623
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, endFunctionType.text)), { range: endFunctionType.range }));
624
+ }
625
+ if (!body) {
626
+ body = new Statement_1.Block({
627
+ statements: [],
628
+ startingRange: util_1.util.createBoundingRange(functionType, name, leftParen, ...params, rightParen, asToken, typeExpression, endFunctionType)
629
+ });
630
+ }
613
631
  let func = new Expression_1.FunctionExpression({
614
632
  parameters: params,
615
- body: undefined,
633
+ body: body,
616
634
  functionType: functionType,
617
- endFunctionType: undefined,
635
+ endFunctionType: endFunctionType,
618
636
  leftParen: leftParen,
619
637
  rightParen: rightParen,
620
638
  as: asToken,
621
639
  returnTypeExpression: typeExpression
622
640
  });
623
- //support ending the function with `end sub` OR `end function`
624
- func.body = this.block();
625
- //if the parser was unable to produce a block, make an empty one so the AST makes some sense...
626
- if (!func.body) {
627
- func.body = new Statement_1.Block({
628
- statements: [],
629
- startingRange: util_1.util.createRangeFromPositions(func.range.start, func.range.start)
630
- });
631
- }
632
- func.body.symbolTable = new SymbolTable_1.SymbolTable(`Block: Function '${(_a = name === null || name === void 0 ? void 0 : name.text) !== null && _a !== void 0 ? _a : ''}'`, () => func.getSymbolTable());
633
- if (!func.body) {
634
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionTypeText)), { range: this.peek().range }));
635
- throw this.lastDiagnosticAsError();
636
- }
637
- // consume 'end sub' or 'end function'
638
- func.tokens.endFunctionType = this.advance();
639
- let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
640
- //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
641
- //add an error but don't hard-fail so the AST can continue more gracefully
642
- if (func.tokens.endFunctionType.kind !== expectedEndKind) {
643
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, func.tokens.endFunctionType.text)), { range: func.tokens.endFunctionType.range }));
644
- }
645
- func.callExpressions = this.callExpressions;
646
641
  if (isAnonymous) {
647
642
  return func;
648
643
  }
649
644
  else {
650
645
  let result = new Statement_1.FunctionStatement({ name: name, func: func });
651
- func.symbolTable.name += `: '${name === null || name === void 0 ? void 0 : name.text}'`;
652
- func.functionStatement = result;
653
646
  return result;
654
647
  }
655
648
  }
@@ -926,6 +919,7 @@ class Parser {
926
919
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInAfterForEach(name.text)), { range: this.peek().range }));
927
920
  throw this.lastDiagnosticAsError();
928
921
  }
922
+ maybeIn.kind = TokenKind_1.TokenKind.In;
929
923
  let target = this.expression();
930
924
  if (!target) {
931
925
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
@@ -951,29 +945,12 @@ class Parser {
951
945
  let keyword = this.advance();
952
946
  return new Statement_1.ExitForStatement({ exitFor: keyword });
953
947
  }
954
- commentStatement() {
955
- //if this comment is on the same line as the previous statement,
956
- //then this comment should be treated as a single-line comment
957
- let prev = this.previous();
958
- if ((prev === null || prev === void 0 ? void 0 : prev.range.end.line) === this.peek().range.start.line) {
959
- return new Statement_1.CommentStatement({ comments: [this.advance()] });
960
- }
961
- else {
962
- let comments = [this.advance()];
963
- while (this.check(TokenKind_1.TokenKind.Newline) && this.checkNext(TokenKind_1.TokenKind.Comment)) {
964
- this.advance();
965
- comments.push(this.advance());
966
- }
967
- return new Statement_1.CommentStatement({ comments: comments });
968
- }
969
- }
970
948
  namespaceStatement() {
971
949
  this.warnIfNotBrighterScriptMode('namespace');
972
950
  let keyword = this.advance();
973
951
  this.namespaceAndFunctionDepth++;
974
952
  let name = this.identifyingExpression();
975
953
  //set the current namespace name
976
- let result = new Statement_1.NamespaceStatement({ namespace: keyword, nameExpression: name, body: null });
977
954
  this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
978
955
  let body = this.body();
979
956
  this.globalTerminators.pop();
@@ -986,8 +963,12 @@ class Parser {
986
963
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('namespace')), { range: keyword.range }));
987
964
  }
988
965
  this.namespaceAndFunctionDepth--;
989
- result.body = body;
990
- result.tokens.endNamespace = endKeyword;
966
+ let result = new Statement_1.NamespaceStatement({
967
+ namespace: keyword,
968
+ nameExpression: name,
969
+ body: body,
970
+ endNamespace: endKeyword
971
+ });
991
972
  //cache the range property so that plugins can't affect it
992
973
  result.cacheRange();
993
974
  result.body.symbolTable.name += `: namespace '${result.name}'`;
@@ -1071,7 +1052,7 @@ class Parser {
1071
1052
  let importStatement = new Statement_1.ImportStatement({
1072
1053
  import: this.advance(),
1073
1054
  //grab the next token only if it's a string
1074
- filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral)
1055
+ path: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral)
1075
1056
  });
1076
1057
  return importStatement;
1077
1058
  }
@@ -1217,36 +1198,43 @@ class Parser {
1217
1198
  }
1218
1199
  tryCatchStatement() {
1219
1200
  const tryToken = this.advance();
1220
- const statement = new Statement_1.TryCatchStatement({ try: tryToken });
1201
+ let endTryToken;
1202
+ let catchStmt;
1221
1203
  //ensure statement separator
1222
1204
  this.consumeStatementSeparators();
1223
- statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
1205
+ let tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
1224
1206
  const peek = this.peek();
1225
1207
  if (peek.kind !== TokenKind_1.TokenKind.Catch) {
1226
1208
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
1227
- //gracefully handle end-try
1228
- if (peek.kind === TokenKind_1.TokenKind.EndTry) {
1229
- statement.tokens.endTry = this.advance();
1230
- }
1231
- return statement;
1232
1209
  }
1233
- const catchStmt = new Statement_1.CatchStatement({ catch: this.advance() });
1234
- statement.catchStatement = catchStmt;
1235
- const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1236
- if (exceptionVarToken) {
1237
- // force it into an identifier so the AST makes some sense
1238
- exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
1239
- catchStmt.tokens.exceptionVariable = exceptionVarToken;
1210
+ else {
1211
+ const catchToken = this.advance();
1212
+ const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1213
+ if (exceptionVarToken) {
1214
+ // force it into an identifier so the AST makes some sense
1215
+ exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
1216
+ }
1217
+ //ensure statement sepatator
1218
+ this.consumeStatementSeparators();
1219
+ const catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1220
+ catchStmt = new Statement_1.CatchStatement({
1221
+ catch: catchToken,
1222
+ exceptionVariable: exceptionVarToken,
1223
+ catchBranch: catchBranch
1224
+ });
1240
1225
  }
1241
- //ensure statement sepatator
1242
- this.consumeStatementSeparators();
1243
- catchStmt.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1244
1226
  if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
1245
1227
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
1246
1228
  }
1247
1229
  else {
1248
- statement.tokens.endTry = this.advance();
1230
+ endTryToken = this.advance();
1249
1231
  }
1232
+ const statement = new Statement_1.TryCatchStatement({
1233
+ try: tryToken,
1234
+ tryBranch: tryBranch,
1235
+ catchStatement: catchStmt,
1236
+ endTry: endTryToken
1237
+ });
1250
1238
  return statement;
1251
1239
  }
1252
1240
  throwStatement() {
@@ -2077,8 +2065,6 @@ class Parser {
2077
2065
  return this.anonymousFunction();
2078
2066
  case this.check(TokenKind_1.TokenKind.RegexLiteral):
2079
2067
  return this.regexLiteralExpression();
2080
- case this.check(TokenKind_1.TokenKind.Comment):
2081
- return new Statement_1.CommentStatement({ comments: [this.advance()] });
2082
2068
  default:
2083
2069
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
2084
2070
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -2094,10 +2080,6 @@ class Parser {
2094
2080
  arrayLiteral() {
2095
2081
  let elements = [];
2096
2082
  let openingSquare = this.previous();
2097
- //add any comment found right after the opening square
2098
- if (this.check(TokenKind_1.TokenKind.Comment)) {
2099
- elements.push(new Statement_1.CommentStatement({ comments: [this.advance()] }));
2100
- }
2101
2083
  while (this.match(TokenKind_1.TokenKind.Newline)) {
2102
2084
  }
2103
2085
  let closingSquare;
@@ -2105,10 +2087,6 @@ class Parser {
2105
2087
  try {
2106
2088
  elements.push(this.expression());
2107
2089
  while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
2108
- if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
2109
- let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
2110
- elements.push(new Statement_1.CommentStatement({ comments: [comment] }));
2111
- }
2112
2090
  while (this.match(TokenKind_1.TokenKind.Newline)) {
2113
2091
  }
2114
2092
  if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
@@ -2156,11 +2134,23 @@ class Parser {
2156
2134
  if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
2157
2135
  let lastAAMember;
2158
2136
  try {
2159
- if (this.check(TokenKind_1.TokenKind.Comment)) {
2160
- lastAAMember = null;
2161
- members.push(new Statement_1.CommentStatement({ comments: [this.advance()] }));
2162
- }
2163
- else {
2137
+ let k = key();
2138
+ let expr = this.expression();
2139
+ lastAAMember = new Expression_1.AAMemberExpression({
2140
+ key: k.keyToken,
2141
+ colon: k.colonToken,
2142
+ value: expr
2143
+ });
2144
+ members.push(lastAAMember);
2145
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
2146
+ // collect comma at end of expression
2147
+ if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
2148
+ lastAAMember.tokens.comma = this.previous();
2149
+ }
2150
+ this.consumeStatementSeparators(true);
2151
+ if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
2152
+ break;
2153
+ }
2164
2154
  let k = key();
2165
2155
  let expr = this.expression();
2166
2156
  lastAAMember = new Expression_1.AAMemberExpression({
@@ -2170,38 +2160,6 @@ class Parser {
2170
2160
  });
2171
2161
  members.push(lastAAMember);
2172
2162
  }
2173
- while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
2174
- // collect comma at end of expression
2175
- if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
2176
- lastAAMember.tokens.comma = this.previous();
2177
- }
2178
- //check for comment at the end of the current line
2179
- if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
2180
- let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
2181
- members.push(new Statement_1.CommentStatement({ comments: [token] }));
2182
- }
2183
- else {
2184
- this.consumeStatementSeparators(true);
2185
- //check for a comment on its own line
2186
- if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
2187
- let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
2188
- lastAAMember = null;
2189
- members.push(new Statement_1.CommentStatement({ comments: [token] }));
2190
- continue;
2191
- }
2192
- if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
2193
- break;
2194
- }
2195
- let k = key();
2196
- let expr = this.expression();
2197
- lastAAMember = new Expression_1.AAMemberExpression({
2198
- key: k.keyToken,
2199
- colon: k.colonToken,
2200
- value: expr
2201
- });
2202
- members.push(lastAAMember);
2203
- }
2204
- }
2205
2163
  }
2206
2164
  catch (error) {
2207
2165
  this.rethrowNonDiagnosticError(error);
@@ -2353,7 +2311,8 @@ class Parser {
2353
2311
  return tokenKinds.includes(nextKind);
2354
2312
  }
2355
2313
  isAtEnd() {
2356
- return this.peek().kind === TokenKind_1.TokenKind.Eof;
2314
+ const peekToken = this.peek();
2315
+ return !peekToken || peekToken.kind === TokenKind_1.TokenKind.Eof;
2357
2316
  }
2358
2317
  peekNext() {
2359
2318
  if (this.isAtEnd()) {