brighterscript 1.0.0-alpha.16 → 1.0.0-alpha.19

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 (158) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/README.md +30 -9
  3. package/dist/BsConfig.d.ts +4 -0
  4. package/dist/DiagnosticMessages.d.ts +16 -1
  5. package/dist/DiagnosticMessages.js +15 -0
  6. package/dist/DiagnosticMessages.js.map +1 -1
  7. package/dist/Logger.js +5 -5
  8. package/dist/Logger.js.map +1 -1
  9. package/dist/Program.d.ts +2 -2
  10. package/dist/Program.js +3 -3
  11. package/dist/Program.js.map +1 -1
  12. package/dist/ProgramBuilder.d.ts +4 -0
  13. package/dist/ProgramBuilder.js +14 -4
  14. package/dist/ProgramBuilder.js.map +1 -1
  15. package/dist/Scope.d.ts +58 -8
  16. package/dist/Scope.js +141 -25
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/XmlScope.js +1 -1
  19. package/dist/XmlScope.js.map +1 -1
  20. package/dist/astUtils/creators.d.ts +3 -3
  21. package/dist/astUtils/creators.js +8 -8
  22. package/dist/astUtils/creators.js.map +1 -1
  23. package/dist/astUtils/creators.spec.js +10 -0
  24. package/dist/astUtils/creators.spec.js.map +1 -1
  25. package/dist/astUtils/reflection.d.ts +8 -5
  26. package/dist/astUtils/reflection.js +18 -6
  27. package/dist/astUtils/reflection.js.map +1 -1
  28. package/dist/astUtils/reflection.spec.js +10 -0
  29. package/dist/astUtils/reflection.spec.js.map +1 -1
  30. package/dist/astUtils/visitors.d.ts +4 -1
  31. package/dist/astUtils/visitors.js.map +1 -1
  32. package/dist/astUtils/visitors.spec.js +2 -0
  33. package/dist/astUtils/visitors.spec.js.map +1 -1
  34. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +2 -2
  35. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  36. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +7 -3
  37. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -1
  38. package/dist/{types/FunctionType.spec.d.ts → bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.d.ts} +0 -0
  39. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +32 -0
  40. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +1 -0
  41. package/dist/cli.js +9 -2
  42. package/dist/cli.js.map +1 -1
  43. package/dist/examples/plugins/removePrint.js +12 -14
  44. package/dist/examples/plugins/removePrint.js.map +1 -1
  45. package/dist/files/BrsFile.Class.spec.js +3 -3
  46. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  47. package/dist/files/BrsFile.d.ts +2 -2
  48. package/dist/files/BrsFile.js +89 -59
  49. package/dist/files/BrsFile.js.map +1 -1
  50. package/dist/files/BrsFile.spec.js +187 -67
  51. package/dist/files/BrsFile.spec.js.map +1 -1
  52. package/dist/globalCallables.js +79 -79
  53. package/dist/globalCallables.js.map +1 -1
  54. package/dist/interfaces.d.ts +43 -4
  55. package/dist/parser/Expression.d.ts +75 -8
  56. package/dist/parser/Expression.js +147 -22
  57. package/dist/parser/Expression.js.map +1 -1
  58. package/dist/parser/Parser.Class.spec.js +6 -6
  59. package/dist/parser/Parser.Class.spec.js.map +1 -1
  60. package/dist/parser/Parser.d.ts +3 -6
  61. package/dist/parser/Parser.js +145 -142
  62. package/dist/parser/Parser.js.map +1 -1
  63. package/dist/parser/Parser.spec.js +61 -6
  64. package/dist/parser/Parser.spec.js.map +1 -1
  65. package/dist/parser/SGTypes.d.ts +2 -2
  66. package/dist/parser/SGTypes.js +2 -2
  67. package/dist/parser/SGTypes.js.map +1 -1
  68. package/dist/parser/Statement.d.ts +63 -43
  69. package/dist/parser/Statement.js +135 -92
  70. package/dist/parser/Statement.js.map +1 -1
  71. package/dist/parser/tests/statement/InterfaceStatement.spec.js +181 -0
  72. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  73. package/dist/parser/tests/statement/TryCatch.spec.js +7 -5
  74. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  75. package/dist/types/ArrayType.js +4 -1
  76. package/dist/types/ArrayType.js.map +1 -1
  77. package/dist/types/ArrayType.spec.js +3 -1
  78. package/dist/types/ArrayType.spec.js.map +1 -1
  79. package/dist/types/BooleanType.d.ts +4 -2
  80. package/dist/types/BooleanType.js +7 -2
  81. package/dist/types/BooleanType.js.map +1 -1
  82. package/dist/types/BooleanType.spec.js +3 -1
  83. package/dist/types/BooleanType.spec.js.map +1 -1
  84. package/dist/types/BscType.d.ts +1 -0
  85. package/dist/types/BscType.js +16 -1
  86. package/dist/types/BscType.js.map +1 -1
  87. package/dist/types/CustomType.js +10 -0
  88. package/dist/types/CustomType.js.map +1 -1
  89. package/dist/types/DoubleType.d.ts +2 -0
  90. package/dist/types/DoubleType.js +7 -2
  91. package/dist/types/DoubleType.js.map +1 -1
  92. package/dist/types/DoubleType.spec.js +3 -1
  93. package/dist/types/DoubleType.spec.js.map +1 -1
  94. package/dist/types/DynamicType.d.ts +2 -0
  95. package/dist/types/DynamicType.js +5 -1
  96. package/dist/types/DynamicType.js.map +1 -1
  97. package/dist/types/FloatType.d.ts +3 -1
  98. package/dist/types/FloatType.js +7 -2
  99. package/dist/types/FloatType.js.map +1 -1
  100. package/dist/types/FloatType.spec.js +2 -0
  101. package/dist/types/FloatType.spec.js.map +1 -1
  102. package/dist/types/FunctionType.d.ts +3 -22
  103. package/dist/types/FunctionType.js +8 -68
  104. package/dist/types/FunctionType.js.map +1 -1
  105. package/dist/types/IntegerType.d.ts +3 -1
  106. package/dist/types/IntegerType.js +7 -2
  107. package/dist/types/IntegerType.js.map +1 -1
  108. package/dist/types/IntegerType.spec.js +3 -1
  109. package/dist/types/IntegerType.spec.js.map +1 -1
  110. package/dist/types/InterfaceType.d.ts +13 -10
  111. package/dist/types/InterfaceType.js +33 -29
  112. package/dist/types/InterfaceType.js.map +1 -1
  113. package/dist/types/InterfaceType.spec.js +36 -16
  114. package/dist/types/InterfaceType.spec.js.map +1 -1
  115. package/dist/types/InvalidType.d.ts +4 -2
  116. package/dist/types/InvalidType.js +7 -2
  117. package/dist/types/InvalidType.js.map +1 -1
  118. package/dist/types/InvalidType.spec.js +2 -0
  119. package/dist/types/InvalidType.spec.js.map +1 -1
  120. package/dist/types/LazyType.js +4 -0
  121. package/dist/types/LazyType.js.map +1 -1
  122. package/dist/types/LongIntegerType.d.ts +3 -1
  123. package/dist/types/LongIntegerType.js +7 -2
  124. package/dist/types/LongIntegerType.js.map +1 -1
  125. package/dist/types/LongIntegerType.spec.js +2 -0
  126. package/dist/types/LongIntegerType.spec.js.map +1 -1
  127. package/dist/types/ObjectType.d.ts +2 -1
  128. package/dist/types/ObjectType.js +4 -2
  129. package/dist/types/ObjectType.js.map +1 -1
  130. package/dist/types/StringType.d.ts +4 -2
  131. package/dist/types/StringType.js +7 -2
  132. package/dist/types/StringType.js.map +1 -1
  133. package/dist/types/StringType.spec.js +2 -0
  134. package/dist/types/StringType.spec.js.map +1 -1
  135. package/dist/types/TypedFunctionType.d.ts +28 -0
  136. package/dist/types/TypedFunctionType.js +88 -0
  137. package/dist/types/TypedFunctionType.js.map +1 -0
  138. package/dist/types/TypedFunctionType.spec.d.ts +1 -0
  139. package/dist/types/TypedFunctionType.spec.js +37 -0
  140. package/dist/types/TypedFunctionType.spec.js.map +1 -0
  141. package/dist/types/UninitializedType.js.map +1 -1
  142. package/dist/types/VoidType.d.ts +4 -2
  143. package/dist/types/VoidType.js +5 -1
  144. package/dist/types/VoidType.js.map +1 -1
  145. package/dist/types/helpers.js +7 -2
  146. package/dist/types/helpers.js.map +1 -1
  147. package/dist/util.d.ts +6 -7
  148. package/dist/util.js +43 -55
  149. package/dist/util.js.map +1 -1
  150. package/dist/validators/ClassValidator.d.ts +14 -1
  151. package/dist/validators/ClassValidator.js +129 -82
  152. package/dist/validators/ClassValidator.js.map +1 -1
  153. package/package.json +3 -2
  154. package/dist/types/FunctionType.spec.js +0 -35
  155. package/dist/types/FunctionType.spec.js.map +0 -1
  156. package/dist/types/UniversalFunctionType.d.ts +0 -9
  157. package/dist/types/UniversalFunctionType.js +0 -25
  158. package/dist/types/UniversalFunctionType.js.map +0 -1
@@ -187,7 +187,7 @@ class Parser {
187
187
  declaration() {
188
188
  try {
189
189
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
190
- return this.functionDeclaration(false);
190
+ return this.functionStatement({ hasName: true, hasBody: true, hasEnd: true });
191
191
  }
192
192
  if (this.checkLibrary()) {
193
193
  return this.libraryStatement();
@@ -241,46 +241,29 @@ class Parser {
241
241
  return new Statement_1.EnumMemberStatement(tokens, value);
242
242
  }
243
243
  /**
244
- * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration`
244
+ * Create a new InterfaceFieldStatement. This should only be called from within `interfaceDeclaration`
245
245
  */
246
246
  interfaceFieldStatement() {
247
247
  const name = this.identifier(...TokenKind_1.AllowedProperties);
248
- let asToken = this.consumeToken(TokenKind_1.TokenKind.As);
249
- let typeToken = this.typeToken();
250
- const type = util_1.util.tokenToBscType(typeToken);
251
- if (!type) {
252
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text)), { range: typeToken.range }));
253
- throw this.lastDiagnosticAsError();
254
- }
255
- return new Statement_1.InterfaceFieldStatement(name, asToken, typeToken, type);
256
- }
257
- /**
258
- * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration()`
259
- */
260
- interfaceMethodStatement() {
261
- const functionType = this.advance();
262
- const name = this.identifier(...TokenKind_1.AllowedProperties);
263
- const leftParen = this.consumeToken(TokenKind_1.TokenKind.LeftParen);
264
- const params = [];
265
- const rightParen = this.consumeToken(TokenKind_1.TokenKind.RightParen);
266
- let asToken = null;
267
- let returnTypeToken = null;
248
+ let asToken;
249
+ let typeExpr;
250
+ //look for `as SOME_TYPE`
268
251
  if (this.check(TokenKind_1.TokenKind.As)) {
269
- asToken = this.advance();
270
- returnTypeToken = this.typeToken();
271
- const returnType = util_1.util.tokenToBscType(returnTypeToken);
272
- if (!returnType) {
273
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, returnTypeToken.text)), { range: returnTypeToken.range }));
274
- throw this.lastDiagnosticAsError();
252
+ asToken = this.consumeToken(TokenKind_1.TokenKind.As);
253
+ typeExpr = this.typeExpression();
254
+ //no field type specified
255
+ if (!typeExpr.isValidType()) {
256
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
275
257
  }
276
258
  }
277
- return new Statement_1.InterfaceMethodStatement(functionType, name, leftParen, params, rightParen, asToken, returnTypeToken, util_1.util.tokenToBscType(returnTypeToken));
259
+ return new Statement_1.InterfaceFieldStatement(name, asToken, typeExpr, this.currentNamespaceName);
278
260
  }
279
261
  interfaceDeclaration() {
280
262
  this.warnIfNotBrighterScriptMode('interface declarations');
281
263
  const parentAnnotations = this.enterAnnotationBlock();
282
264
  const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
283
- const nameToken = this.identifier(...this.allowedLocalIdentifiers);
265
+ //get the interface name
266
+ let nameToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('interface'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
284
267
  let extendsToken;
285
268
  let parentInterfaceName;
286
269
  if (this.peek().text.toLowerCase() === 'extends') {
@@ -292,6 +275,10 @@ class Parser {
292
275
  let body = [];
293
276
  while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
294
277
  try {
278
+ //break out of this loop if we encountered the `EndInterface` token not followed by `as`
279
+ if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
280
+ break;
281
+ }
295
282
  let decl;
296
283
  //collect leading annotations
297
284
  if (this.check(TokenKind_1.TokenKind.At)) {
@@ -303,7 +290,15 @@ class Parser {
303
290
  //methods (function/sub keyword followed by opening paren)
304
291
  }
305
292
  else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
306
- decl = this.interfaceMethodStatement();
293
+ const functionStatement = this.functionStatement({
294
+ hasName: true,
295
+ hasBody: false,
296
+ hasEnd: false,
297
+ onlyCallableAsMember: true
298
+ });
299
+ decl = new Statement_1.InterfaceMethodStatement(functionStatement.name, functionStatement.func);
300
+ //refer to this statement as parent of the expression
301
+ functionStatement.func.functionStatement = decl;
307
302
  //comments
308
303
  }
309
304
  else if (this.check(TokenKind_1.TokenKind.Comment)) {
@@ -313,10 +308,6 @@ class Parser {
313
308
  this.consumePendingAnnotations(decl);
314
309
  body.push(decl);
315
310
  }
316
- else {
317
- //we didn't find a declaration...flag tokens until next line
318
- this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
319
- }
320
311
  }
321
312
  catch (e) {
322
313
  //throw out any failed members and move on to the next line
@@ -324,14 +315,13 @@ class Parser {
324
315
  }
325
316
  //ensure statement separator
326
317
  this.consumeStatementSeparators();
327
- //break out of this loop if we encountered the `EndInterface` token not followed by `as`
328
- if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
329
- break;
330
- }
331
318
  }
332
319
  //consume the final `end interface` token
333
- const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
334
- const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endInterfaceToken, this.currentNamespaceName);
320
+ let endingKeyword = this.advance();
321
+ if (endingKeyword.kind !== TokenKind_1.TokenKind.EndInterface) {
322
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('interface')), { range: endingKeyword.range }));
323
+ }
324
+ const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endingKeyword, this.currentNamespaceName);
335
325
  this._references.interfaceStatements.push(statement);
336
326
  this.exitAnnotationBlock(parentAnnotations);
337
327
  return statement;
@@ -424,14 +414,12 @@ class Parser {
424
414
  }
425
415
  //methods (function/sub keyword OR identifier followed by opening paren)
426
416
  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))) {
427
- const funcDeclaration = this.functionDeclaration(false, false, true);
428
- //remove this function from the lists because it's not a callable
429
- const functionStatement = this._references.functionStatements.pop();
417
+ const functionStatement = this.functionStatement({ hasName: true, hasBody: true, hasEnd: true, onlyCallableAsMember: true });
430
418
  //if we have an overrides keyword AND this method is called 'new', that's not allowed
431
- if (overrideKeyword && funcDeclaration.name.text.toLowerCase() === 'new') {
419
+ if (overrideKeyword && functionStatement.name.text.toLowerCase() === 'new') {
432
420
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { range: overrideKeyword.range }));
433
421
  }
434
- decl = new Statement_1.ClassMethodStatement(accessModifier, funcDeclaration.name, funcDeclaration.func, overrideKeyword);
422
+ decl = new Statement_1.ClassMethodStatement(accessModifier, functionStatement.name, functionStatement.func, overrideKeyword);
435
423
  //refer to this statement as parent of the expression
436
424
  functionStatement.func.functionStatement = decl;
437
425
  //cache the range property so that plugins can't affect it
@@ -476,13 +464,13 @@ class Parser {
476
464
  classFieldDeclaration(accessModifier) {
477
465
  let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
478
466
  let asToken;
479
- let fieldType;
467
+ let fieldTypeExpr;
480
468
  //look for `as SOME_TYPE`
481
469
  if (this.check(TokenKind_1.TokenKind.As)) {
482
470
  asToken = this.advance();
483
- fieldType = this.typeToken();
471
+ fieldTypeExpr = this.typeExpression();
484
472
  //no field type specified
485
- if (!util_1.util.tokenToBscType(fieldType, true, this.currentNamespaceName)) {
473
+ if (!fieldTypeExpr.isValidType(this.options.mode)) {
486
474
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedValidTypeToFollowAsKeyword()), { range: this.peek().range }));
487
475
  }
488
476
  }
@@ -493,22 +481,34 @@ class Parser {
493
481
  equal = this.advance();
494
482
  initialValue = this.expression();
495
483
  }
496
- return new Statement_1.ClassFieldStatement(accessModifier, name, asToken, fieldType, equal, initialValue, this.currentNamespaceName);
484
+ return new Statement_1.ClassFieldStatement(accessModifier, name, asToken, fieldTypeExpr, equal, initialValue, this.currentNamespaceName);
485
+ }
486
+ functionStatement(options) {
487
+ options.hasName = true;
488
+ const funcResult = this.functionDeclaration(options);
489
+ if (funcResult) {
490
+ let result = new Statement_1.FunctionStatement(funcResult.name, funcResult.functionExpression, this.currentNamespaceName);
491
+ funcResult.functionExpression.functionStatement = result;
492
+ if (!options.onlyCallableAsMember) {
493
+ this._references.functionStatements.push(result);
494
+ }
495
+ return result;
496
+ }
497
497
  }
498
- functionDeclaration(isAnonymous, checkIdentifier = true, forClassMethod = false) {
498
+ functionDeclaration(options = {}) {
499
499
  var _a, _b, _c, _d;
500
500
  let previousCallExpressions = this.callExpressions;
501
501
  this.callExpressions = [];
502
502
  try {
503
503
  //track depth to help certain statements need to know if they are contained within a function body
504
504
  this.namespaceAndFunctionDepth++;
505
- let functionType;
505
+ let functionKeyword;
506
506
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
507
- functionType = this.advance();
507
+ functionKeyword = this.advance();
508
508
  }
509
509
  else {
510
510
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
511
- functionType = {
511
+ functionKeyword = {
512
512
  isReserved: true,
513
513
  kind: TokenKind_1.TokenKind.Function,
514
514
  text: 'function',
@@ -520,30 +520,30 @@ class Parser {
520
520
  leadingWhitespace: ''
521
521
  };
522
522
  }
523
- let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === TokenKind_1.TokenKind.Sub;
524
- let functionTypeText = isSub ? 'sub' : 'function';
523
+ let isSub = (functionKeyword === null || functionKeyword === void 0 ? void 0 : functionKeyword.kind) === TokenKind_1.TokenKind.Sub;
524
+ let functionKeywordText = isSub ? 'sub' : 'function';
525
525
  let name;
526
526
  let leftParen;
527
- if (isAnonymous) {
528
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), TokenKind_1.TokenKind.LeftParen);
527
+ if (!options.hasName) {
528
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
529
529
  }
530
530
  else {
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);
531
+ name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionKeywordText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
532
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
533
533
  //prevent functions from ending with type designators
534
534
  let lastChar = name.text[name.text.length - 1];
535
535
  if (['$', '%', '!', '#', '&'].includes(lastChar)) {
536
536
  //don't throw this error; let the parser continue
537
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { range: name.range }));
537
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionKeywordText, name.text, lastChar)), { range: name.range }));
538
538
  }
539
- //flag functions with keywords for names (only for standard functions)
540
- if (checkIdentifier && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
539
+ //flag functions with keywords for names (only for standard functions - not for class methods)
540
+ if (!options.onlyCallableAsMember && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
541
541
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
542
542
  }
543
543
  }
544
544
  let params = [];
545
545
  let asToken;
546
- let typeToken;
546
+ let typeExpr;
547
547
  if (!this.check(TokenKind_1.TokenKind.RightParen)) {
548
548
  do {
549
549
  if (params.length >= Expression_1.CallExpression.MaximumArguments) {
@@ -555,9 +555,9 @@ class Parser {
555
555
  let rightParen = this.advance();
556
556
  if (this.check(TokenKind_1.TokenKind.As)) {
557
557
  asToken = this.advance();
558
- typeToken = this.typeToken();
559
- if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
560
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a = typeToken.text) !== null && _a !== void 0 ? _a : '')), { range: typeToken.range }));
558
+ typeExpr = this.typeExpression();
559
+ if (!typeExpr.isValidType(this.options.mode)) {
560
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a = typeExpr.getText()) !== null && _a !== void 0 ? _a : '')), { range: typeExpr.range }));
561
561
  }
562
562
  }
563
563
  params.reduce((haveFoundOptional, param) => {
@@ -566,17 +566,20 @@ class Parser {
566
566
  }
567
567
  return haveFoundOptional || !!param.defaultValue;
568
568
  }, false);
569
- this.consumeStatementSeparators(true);
569
+ if (options.hasEnd && options.hasBody) {
570
+ // do not go to next statement - we don't care about any other statement
571
+ this.consumeStatementSeparators(true);
572
+ }
570
573
  let func = new Expression_1.FunctionExpression(params, undefined, //body
571
- functionType, undefined, //ending keyword
572
- leftParen, rightParen, asToken, typeToken, //return type
574
+ functionKeyword, undefined, //ending keyword
575
+ leftParen, rightParen, asToken, typeExpr, //return type
573
576
  this.currentFunctionExpression, this.currentNamespaceName, (_c = (_b = this.currentNamespace) === null || _b === void 0 ? void 0 : _b.symbolTable) !== null && _c !== void 0 ? _c : this.symbolTable);
574
577
  //if there is a parent function, register this function with the parent
575
578
  if (this.currentFunctionExpression) {
576
579
  this.currentFunctionExpression.childFunctionExpressions.push(func);
577
580
  }
578
581
  // add the function to the relevant symbol tables
579
- if (!isAnonymous && !forClassMethod) {
582
+ if (!options.onlyCallableAsMember && name) {
580
583
  const funcType = func.getFunctionType();
581
584
  funcType.setName(name.text);
582
585
  // add the function as declared to the current namespace's table
@@ -589,42 +592,35 @@ class Parser {
589
592
  this.currentSymbolTable.addSymbol(fullyQualifiedName, name.range, funcType);
590
593
  }
591
594
  this._references.functionExpressions.push(func);
592
- let previousFunctionExpression = this.currentFunctionExpression;
593
- this.currentFunctionExpression = func;
594
- //make sure to restore the currentFunctionExpression even if the body block fails to parse
595
- try {
596
- //support ending the function with `end sub` OR `end function`
597
- func.body = this.block();
598
- }
599
- finally {
600
- this.currentFunctionExpression = previousFunctionExpression;
601
- }
602
- if (!func.body) {
603
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionTypeText)), { range: this.peek().range }));
604
- throw this.lastDiagnosticAsError();
595
+ if (options.hasBody) {
596
+ let previousFunctionExpression = this.currentFunctionExpression;
597
+ this.currentFunctionExpression = func;
598
+ //make sure to restore the currentFunctionExpression even if the body block fails to parse
599
+ try {
600
+ //support ending the function with `end sub` OR `end function`
601
+ func.body = this.block();
602
+ }
603
+ finally {
604
+ this.currentFunctionExpression = previousFunctionExpression;
605
+ }
606
+ if (!func.body) {
607
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionKeywordText)), { range: this.peek().range }));
608
+ throw this.lastDiagnosticAsError();
609
+ }
605
610
  }
606
- // consume 'end sub' or 'end function'
607
- func.end = this.advance();
608
- let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
609
- //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
610
- //add an error but don't hard-fail so the AST can continue more gracefully
611
- if (func.end.kind !== expectedEndKind) {
612
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, func.end.text)), { range: this.peek().range }));
611
+ if (options.hasEnd) {
612
+ // consume 'end sub' or 'end function'
613
+ func.end = this.advance();
614
+ let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
615
+ //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
616
+ //add an error but don't hard-fail so the AST can continue more gracefully
617
+ if (func.end.kind !== expectedEndKind) {
618
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionKeywordText, func.end.text)), { range: this.peek().range }));
619
+ }
613
620
  }
614
621
  func.callExpressions = this.callExpressions;
615
- if (isAnonymous) {
616
- //cache the range property so that plugins can't affect it
617
- func.cacheRange();
618
- return func;
619
- }
620
- else {
621
- let result = new Statement_1.FunctionStatement(name, func, this.currentNamespaceName);
622
- func.functionStatement = result;
623
- this._references.functionStatements.push(result);
624
- //cache the range property so that plugins can't affect it
625
- result.cacheRange();
626
- return result;
627
- }
622
+ func.cacheRange();
623
+ return { name: name, functionExpression: func };
628
624
  }
629
625
  finally {
630
626
  this.namespaceAndFunctionDepth--;
@@ -638,7 +634,7 @@ class Parser {
638
634
  throw this.lastDiagnosticAsError();
639
635
  }
640
636
  const name = this.identifier(...TokenKind_1.AllowedLocalIdentifiers);
641
- let typeToken;
637
+ let typeExpr;
642
638
  let defaultValue;
643
639
  let equalsToken;
644
640
  // parse argument default value
@@ -650,26 +646,26 @@ class Parser {
650
646
  let asToken = null;
651
647
  if (this.check(TokenKind_1.TokenKind.As)) {
652
648
  asToken = this.advance();
653
- typeToken = this.typeToken();
654
- if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
655
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text)), { range: typeToken.range }));
649
+ typeExpr = this.typeExpression();
650
+ if (!typeExpr.isValidType(this.options.mode)) {
651
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
656
652
  throw this.lastDiagnosticAsError();
657
653
  }
658
654
  }
659
- let type;
660
- if (typeToken) {
661
- type = util_1.util.tokenToBscType(typeToken, true, this.currentNamespaceName);
655
+ let typeInContext;
656
+ if (typeExpr) {
657
+ typeInContext = typeExpr.type;
662
658
  }
663
659
  else if (defaultValue) {
664
- type = getBscTypeFromExpression(defaultValue, this.currentFunctionExpression);
665
- if ((0, reflection_1.isInvalidType)(type)) {
666
- type = new DynamicType_1.DynamicType();
660
+ typeInContext = getBscTypeFromExpression(defaultValue, this.currentFunctionExpression);
661
+ if ((0, reflection_1.isInvalidType)(typeInContext)) {
662
+ typeInContext = new DynamicType_1.DynamicType();
667
663
  }
668
664
  }
669
665
  else {
670
- type = new DynamicType_1.DynamicType();
666
+ typeInContext = new DynamicType_1.DynamicType();
671
667
  }
672
- return new Expression_1.FunctionParameterExpression(name, type, equalsToken, defaultValue, asToken, typeToken, this.currentNamespaceName);
668
+ return new Expression_1.FunctionParameterExpression(name, typeInContext, equalsToken, defaultValue, asToken, typeExpr, this.currentNamespaceName);
673
669
  }
674
670
  assignment() {
675
671
  let name = this.identifier(...this.allowedLocalIdentifiers);
@@ -863,6 +859,12 @@ class Parser {
863
859
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
864
860
  throw this.lastDiagnosticAsError();
865
861
  }
862
+ let itemType = new DynamicType_1.DynamicType();
863
+ const targetType = getBscTypeFromExpression(target, this.currentFunctionExpression);
864
+ if ((0, reflection_1.isArrayType)(targetType)) {
865
+ itemType = targetType.getDefaultType();
866
+ }
867
+ this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
866
868
  this.consumeStatementSeparators();
867
869
  let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
868
870
  if (!body) {
@@ -870,12 +872,6 @@ class Parser {
870
872
  throw this.lastDiagnosticAsError();
871
873
  }
872
874
  let endFor = this.advance();
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
- }
878
- this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
879
875
  return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
880
876
  }
881
877
  exitFor() {
@@ -1120,7 +1116,7 @@ class Parser {
1120
1116
  }
1121
1117
  tryCatchStatement() {
1122
1118
  const tryToken = this.advance();
1123
- const statement = new Statement_1.TryCatchStatement(tryToken);
1119
+ const statement = new Statement_1.TryCatchStatement({ try: tryToken });
1124
1120
  //ensure statement separator
1125
1121
  this.consumeStatementSeparators();
1126
1122
  statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
@@ -1129,27 +1125,26 @@ class Parser {
1129
1125
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
1130
1126
  //gracefully handle end-try
1131
1127
  if (peek.kind === TokenKind_1.TokenKind.EndTry) {
1132
- statement.endTryToken = this.advance();
1128
+ statement.tokens.endTry = this.advance();
1133
1129
  }
1134
1130
  return statement;
1135
1131
  }
1136
- else {
1137
- statement.catchToken = this.advance();
1138
- }
1132
+ const catchStmt = new Statement_1.CatchStatement({ catch: this.advance() });
1133
+ statement.catchStatement = catchStmt;
1139
1134
  const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1140
1135
  if (exceptionVarToken) {
1141
1136
  // force it into an identifier so the AST makes some sense
1142
1137
  exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
1143
- statement.exceptionVariable = exceptionVarToken;
1138
+ catchStmt.exceptionVariable = exceptionVarToken;
1144
1139
  }
1145
1140
  //ensure statement sepatator
1146
1141
  this.consumeStatementSeparators();
1147
- statement.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1142
+ catchStmt.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1148
1143
  if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
1149
1144
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
1150
1145
  }
1151
1146
  else {
1152
- statement.endTryToken = this.advance();
1147
+ statement.tokens.endTry = this.advance();
1153
1148
  }
1154
1149
  return statement;
1155
1150
  }
@@ -1595,7 +1590,7 @@ class Parser {
1595
1590
  }
1596
1591
  anonymousFunction() {
1597
1592
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
1598
- const func = this.functionDeclaration(true);
1593
+ const func = this.functionDeclaration({ hasName: false, hasBody: true, hasEnd: true }).functionExpression;
1599
1594
  //if there's an open paren after this, this is an IIFE
1600
1595
  if (this.check(TokenKind_1.TokenKind.LeftParen)) {
1601
1596
  return this.finishCall(this.advance(), func);
@@ -1784,7 +1779,7 @@ class Parser {
1784
1779
  * Allows for built-in types (double, string, etc.) or namespaced custom types in Brighterscript mode
1785
1780
  * Will return a token of whatever is next to be parsed (unless `advanceIfUnknown` is false, in which case undefined will be returned instead
1786
1781
  */
1787
- typeToken() {
1782
+ typeExpression() {
1788
1783
  let typeToken;
1789
1784
  if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
1790
1785
  // Token is a built in type
@@ -1805,18 +1800,23 @@ class Parser {
1805
1800
  // just get whatever's next
1806
1801
  typeToken = this.advance();
1807
1802
  }
1808
- if (typeToken && this.options.mode === ParseMode.BrighterScript) {
1803
+ //TODO: to support InterfaceTypeLiterals - (eg. `{name as string; age as integer}`), check if "typeToken" is a curly bracket, and do something else
1804
+ let typeExpr = new Expression_1.TypeExpression({ type: typeToken }, this.currentNamespaceName);
1805
+ if (this.options.mode === ParseMode.BrighterScript) {
1809
1806
  // 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();
1807
+ // eg. `string[]` or `SomeKlass[]` or `float[][][]`
1808
+ while (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
1809
+ const leftBracket = this.advance();
1813
1810
  if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1814
1811
  const rightBracket = this.advance();
1815
- typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, typeToken.text + '[]', util_1.util.getRange(typeToken, rightBracket));
1812
+ typeExpr = new Expression_1.ArrayTypeExpression([typeExpr], { leftBracket: leftBracket, rightBracket: rightBracket }, this.currentNamespaceName);
1813
+ }
1814
+ else {
1815
+ break;
1816
1816
  }
1817
1817
  }
1818
1818
  }
1819
- return typeToken;
1819
+ return typeExpr;
1820
1820
  }
1821
1821
  primary() {
1822
1822
  switch (true) {
@@ -2397,6 +2397,9 @@ class Parser {
2397
2397
  this._references.expressions.add(s.initialValue);
2398
2398
  }
2399
2399
  },
2400
+ InterfaceStatement: s => {
2401
+ this._references.interfaceStatements.push(s);
2402
+ },
2400
2403
  NamespaceStatement: s => {
2401
2404
  this._references.namespaceStatements.push(s);
2402
2405
  },
@@ -2410,7 +2413,7 @@ class Parser {
2410
2413
  this._references.libraryStatements.push(s);
2411
2414
  },
2412
2415
  FunctionExpression: (expression, parent) => {
2413
- if (!(0, reflection_1.isClassMethodStatement)(parent)) {
2416
+ if (!(0, reflection_1.isClassMethodStatement)(parent) && !(0, reflection_1.isInterfaceMethodStatement)(parent)) {
2414
2417
  this._references.functionExpressions.push(expression);
2415
2418
  }
2416
2419
  },
@@ -2542,7 +2545,7 @@ class References {
2542
2545
  if (!this._interfaceStatementLookup) {
2543
2546
  this._interfaceStatementLookup = new Map();
2544
2547
  for (const stmt of this.interfaceStatements) {
2545
- this._interfaceStatementLookup.set(stmt.fullName.toLowerCase(), stmt);
2548
+ this._interfaceStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2546
2549
  }
2547
2550
  }
2548
2551
  return this._interfaceStatementLookup;
@@ -2587,7 +2590,7 @@ function getBscTypeFromExpression(expression, functionExpression) {
2587
2590
  //Associative array literal
2588
2591
  }
2589
2592
  else if ((0, reflection_1.isAALiteralExpression)(expression)) {
2590
- return new ObjectType_1.ObjectType(expression.memberTable);
2593
+ return new ObjectType_1.ObjectType('object', expression.memberTable);
2591
2594
  //Array literal
2592
2595
  }
2593
2596
  else if ((0, reflection_1.isArrayLiteralExpression)(expression)) {
@@ -2598,7 +2601,7 @@ function getBscTypeFromExpression(expression, functionExpression) {
2598
2601
  //function call
2599
2602
  }
2600
2603
  else if ((0, reflection_1.isNewExpression)(expression)) {
2601
- return (0, helpers_1.getTypeFromNewExpression)(expression, functionExpression); // new CustomType(expression.className.getName(ParseMode.BrighterScript));
2604
+ return (0, helpers_1.getTypeFromNewExpression)(expression, functionExpression);
2602
2605
  //Function call
2603
2606
  }
2604
2607
  else if ((0, reflection_1.isCallExpression)(expression)) {