brighterscript 0.42.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/LanguageServer.js +0 -9
  3. package/dist/LanguageServer.js.map +1 -1
  4. package/dist/Program.d.ts +1 -1
  5. package/dist/Program.js +35 -9
  6. package/dist/Program.js.map +1 -1
  7. package/dist/ProgramBuilder.js +3 -3
  8. package/dist/ProgramBuilder.js.map +1 -1
  9. package/dist/Scope.d.ts +3 -2
  10. package/dist/Scope.js +13 -13
  11. package/dist/Scope.js.map +1 -1
  12. package/dist/astUtils/reflection.d.ts +2 -1
  13. package/dist/astUtils/reflection.js +6 -2
  14. package/dist/astUtils/reflection.js.map +1 -1
  15. package/dist/astUtils/reflection.spec.js +6 -6
  16. package/dist/astUtils/reflection.spec.js.map +1 -1
  17. package/dist/astUtils/visitors.spec.js +13 -16
  18. package/dist/astUtils/visitors.spec.js.map +1 -1
  19. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +3 -3
  20. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  21. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +4 -4
  22. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +1 -1
  23. package/dist/files/BrsFile.Class.spec.js +182 -78
  24. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  25. package/dist/files/BrsFile.d.ts +11 -5
  26. package/dist/files/BrsFile.js +106 -67
  27. package/dist/files/BrsFile.js.map +1 -1
  28. package/dist/files/BrsFile.spec.js +150 -101
  29. package/dist/files/BrsFile.spec.js.map +1 -1
  30. package/dist/files/XmlFile.d.ts +1 -0
  31. package/dist/files/XmlFile.js +9 -8
  32. package/dist/files/XmlFile.js.map +1 -1
  33. package/dist/files/XmlFile.spec.js +41 -39
  34. package/dist/files/XmlFile.spec.js.map +1 -1
  35. package/dist/files/tests/imports.spec.js +6 -4
  36. package/dist/files/tests/imports.spec.js.map +1 -1
  37. package/dist/index.d.ts +12 -3
  38. package/dist/index.js +21 -4
  39. package/dist/index.js.map +1 -1
  40. package/dist/interfaces.d.ts +21 -1
  41. package/dist/lexer/Lexer.js +1 -2
  42. package/dist/lexer/Lexer.js.map +1 -1
  43. package/dist/lexer/Lexer.spec.js +462 -462
  44. package/dist/lexer/Lexer.spec.js.map +1 -1
  45. package/dist/parser/Expression.d.ts +1 -1
  46. package/dist/parser/Expression.js +10 -10
  47. package/dist/parser/Expression.js.map +1 -1
  48. package/dist/parser/Parser.Class.spec.js +32 -31
  49. package/dist/parser/Parser.Class.spec.js.map +1 -1
  50. package/dist/parser/Parser.d.ts +13 -1
  51. package/dist/parser/Parser.js +355 -253
  52. package/dist/parser/Parser.js.map +1 -1
  53. package/dist/parser/Parser.spec.js +86 -24
  54. package/dist/parser/Parser.spec.js.map +1 -1
  55. package/dist/parser/Statement.d.ts +2 -2
  56. package/dist/parser/Statement.js +8 -8
  57. package/dist/parser/Statement.js.map +1 -1
  58. package/dist/parser/Statement.spec.js +4 -4
  59. package/dist/parser/Statement.spec.js.map +1 -1
  60. package/dist/parser/tests/Parser.spec.d.ts +3 -3
  61. package/dist/parser/tests/Parser.spec.js +4 -4
  62. package/dist/parser/tests/Parser.spec.js.map +1 -1
  63. package/dist/parser/tests/controlFlow/For.spec.js +40 -40
  64. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  65. package/dist/parser/tests/controlFlow/ForEach.spec.js +22 -21
  66. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  67. package/dist/parser/tests/controlFlow/If.spec.js +100 -99
  68. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  69. package/dist/parser/tests/controlFlow/While.spec.js +25 -25
  70. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  71. package/dist/parser/tests/expression/Additive.spec.js +21 -21
  72. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  73. package/dist/parser/tests/expression/ArrayLiterals.spec.js +91 -91
  74. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  75. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +102 -102
  76. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  77. package/dist/parser/tests/expression/Boolean.spec.js +15 -15
  78. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  79. package/dist/parser/tests/expression/Call.spec.js +22 -21
  80. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  81. package/dist/parser/tests/expression/Exponential.spec.js +11 -11
  82. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  83. package/dist/parser/tests/expression/Function.spec.js +171 -171
  84. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  85. package/dist/parser/tests/expression/Indexing.spec.js +50 -50
  86. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  87. package/dist/parser/tests/expression/Multiplicative.spec.js +25 -25
  88. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  89. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
  90. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  91. package/dist/parser/tests/expression/PrefixUnary.spec.js +26 -26
  92. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  93. package/dist/parser/tests/expression/Primary.spec.js +27 -27
  94. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  95. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +3 -2
  96. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  97. package/dist/parser/tests/expression/Relational.spec.js +25 -25
  98. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  99. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +7 -7
  100. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  101. package/dist/parser/tests/expression/TernaryExpression.spec.js +6 -6
  102. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  103. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  104. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  105. package/dist/parser/tests/statement/Declaration.spec.js +20 -20
  106. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  107. package/dist/parser/tests/statement/Function.spec.js +121 -120
  108. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  109. package/dist/parser/tests/statement/Goto.spec.js +9 -8
  110. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  111. package/dist/parser/tests/statement/Increment.spec.js +22 -22
  112. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  113. package/dist/parser/tests/statement/InterfaceStatement.spec.js +12 -0
  114. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  115. package/dist/parser/tests/statement/LibraryStatement.spec.js +7 -7
  116. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  117. package/dist/parser/tests/statement/Misc.spec.js +71 -70
  118. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  119. package/dist/parser/tests/statement/PrintStatement.spec.js +17 -17
  120. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  121. package/dist/parser/tests/statement/ReturnStatement.spec.js +33 -33
  122. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  123. package/dist/parser/tests/statement/Set.spec.js +53 -53
  124. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  125. package/dist/parser/tests/statement/Stop.spec.js +7 -6
  126. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  127. package/dist/preprocessor/Chunk.d.ts +1 -1
  128. package/dist/preprocessor/Preprocessor.d.ts +1 -1
  129. package/dist/preprocessor/Preprocessor.js +7 -7
  130. package/dist/preprocessor/Preprocessor.js.map +1 -1
  131. package/dist/util.d.ts +5 -1
  132. package/dist/util.js +36 -29
  133. package/dist/util.js.map +1 -1
  134. package/dist/validators/ClassValidator.js +20 -27
  135. package/dist/validators/ClassValidator.js.map +1 -1
  136. package/package.json +2 -1
  137. package/dist/astUtils/index.d.ts +0 -7
  138. package/dist/astUtils/index.js +0 -26
  139. package/dist/astUtils/index.js.map +0 -1
  140. package/dist/lexer/index.d.ts +0 -3
  141. package/dist/lexer/index.js +0 -18
  142. package/dist/lexer/index.js.map +0 -1
  143. package/dist/parser/index.d.ts +0 -3
  144. package/dist/parser/index.js +0 -16
  145. package/dist/parser/index.js.map +0 -1
  146. package/dist/preprocessor/index.d.ts +0 -3
  147. package/dist/preprocessor/index.js +0 -16
  148. package/dist/preprocessor/index.js.map +0 -1
@@ -7,8 +7,9 @@ const chalk_1 = require("chalk");
7
7
  const path = require("path");
8
8
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
9
9
  const FunctionScope_1 = require("../FunctionScope");
10
- const lexer_1 = require("../lexer");
11
- const parser_1 = require("../parser");
10
+ const Lexer_1 = require("../lexer/Lexer");
11
+ const TokenKind_1 = require("../lexer/TokenKind");
12
+ const Parser_1 = require("../parser/Parser");
12
13
  const DynamicType_1 = require("../types/DynamicType");
13
14
  const FunctionType_1 = require("../types/FunctionType");
14
15
  const VoidType_1 = require("../types/VoidType");
@@ -36,7 +37,7 @@ class BrsFile {
36
37
  /**
37
38
  * The parseMode used for the parser for this file
38
39
  */
39
- this.parseMode = parser_1.ParseMode.BrightScript;
40
+ this.parseMode = Parser_1.ParseMode.BrightScript;
40
41
  this.diagnostics = [];
41
42
  this.commentFlags = [];
42
43
  this.callables = [];
@@ -57,7 +58,7 @@ class BrsFile {
57
58
  //all BrighterScript files need to be transpiled
58
59
  if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
59
60
  this.needsTranspiled = true;
60
- this.parseMode = parser_1.ParseMode.BrighterScript;
61
+ this.parseMode = Parser_1.ParseMode.BrighterScript;
61
62
  }
62
63
  this.isTypedef = this.extension === '.d.bs';
63
64
  if (!this.isTypedef) {
@@ -149,7 +150,7 @@ class BrsFile {
149
150
  }
150
151
  //tokenize the input file
151
152
  let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.pathAbsolute)], () => {
152
- return lexer_1.Lexer.scan(fileContents, {
153
+ return Lexer_1.Lexer.scan(fileContents, {
153
154
  includeWhitespace: false
154
155
  });
155
156
  });
@@ -172,32 +173,50 @@ class BrsFile {
172
173
  //if the preprocessor generated tokens, use them.
173
174
  let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
174
175
  this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.pathAbsolute)], () => {
175
- this._parser = parser_1.Parser.parse(tokens, {
176
+ this._parser = Parser_1.Parser.parse(tokens, {
176
177
  mode: this.parseMode,
177
178
  logger: this.program.logger
178
179
  });
179
180
  });
180
181
  //absorb all lexing/preprocessing/parsing diagnostics
181
182
  this.diagnostics.push(...lexer.diagnostics, ...preprocessor.diagnostics, ...this._parser.diagnostics);
182
- //notify AST ready
183
- this.program.plugins.emit('afterFileParse', this);
184
183
  //extract all callables from this file
185
184
  this.findCallables();
186
185
  //find all places where a sub/function is being called
187
186
  this.findFunctionCalls();
188
- this.findAndValidateImportAndImportStatements();
187
+ //register all import statements for use in the rest of the program
188
+ this.registerImports();
189
189
  //attach this file to every diagnostic
190
190
  for (let diagnostic of this.diagnostics) {
191
191
  diagnostic.file = this;
192
192
  }
193
193
  }
194
194
  catch (e) {
195
- this._parser = new parser_1.Parser();
195
+ this._parser = new Parser_1.Parser();
196
196
  this.diagnostics.push(Object.assign({ file: this, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }, DiagnosticMessages_1.DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify((0, serialize_error_1.serializeError)(e)))));
197
197
  }
198
198
  }
199
- findAndValidateImportAndImportStatements() {
200
- var _a;
199
+ registerImports() {
200
+ var _a, _b, _c, _d;
201
+ for (const statement of (_c = (_b = (_a = this.parser) === null || _a === void 0 ? void 0 : _a.references) === null || _b === void 0 ? void 0 : _b.importStatements) !== null && _c !== void 0 ? _c : []) {
202
+ //register import statements
203
+ if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
204
+ this.ownScriptImports.push({
205
+ filePathRange: statement.filePathToken.range,
206
+ pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
207
+ sourceFile: this,
208
+ text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
209
+ });
210
+ }
211
+ }
212
+ }
213
+ validate() {
214
+ //only validate the file if it was actually parsed (skip files containing typedefs)
215
+ if (!this.hasTypedef) {
216
+ this.validateImportStatements();
217
+ }
218
+ }
219
+ validateImportStatements() {
201
220
  let topOfFileIncludeStatements = [];
202
221
  for (let stmt of this.ast.statements) {
203
222
  //skip comments
@@ -218,15 +237,6 @@ class BrsFile {
218
237
  ...this._parser.references.importStatements
219
238
  ];
220
239
  for (let result of statements) {
221
- //register import statements
222
- if ((0, reflection_1.isImportStatement)(result) && result.filePathToken) {
223
- this.ownScriptImports.push({
224
- filePathRange: result.filePathToken.range,
225
- pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, result.filePath),
226
- sourceFile: this,
227
- text: (_a = result.filePathToken) === null || _a === void 0 ? void 0 : _a.text
228
- });
229
- }
230
240
  //if this statement is not one of the top-of-file statements,
231
241
  //then add a diagnostic explaining that it is invalid
232
242
  if (!topOfFileIncludeStatements.includes(result)) {
@@ -284,7 +294,7 @@ class BrsFile {
284
294
  const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
285
295
  this.commentFlags = [];
286
296
  for (let token of tokens) {
287
- if (token.kind === lexer_1.TokenKind.Comment) {
297
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
288
298
  processor.tryAdd(token.text, token.range);
289
299
  }
290
300
  }
@@ -570,10 +580,10 @@ class BrsFile {
570
580
  //if cursor is within a comment, disable completions
571
581
  let currentToken = this.getTokenAt(position);
572
582
  const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
573
- if (tokenKind === lexer_1.TokenKind.Comment) {
583
+ if (tokenKind === TokenKind_1.TokenKind.Comment) {
574
584
  return [];
575
585
  }
576
- else if (tokenKind === lexer_1.TokenKind.StringLiteral || tokenKind === lexer_1.TokenKind.TemplateStringQuasi) {
586
+ else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
577
587
  const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
578
588
  if (match) {
579
589
  const [, openingQuote, fileProtocol] = match;
@@ -605,7 +615,7 @@ class BrsFile {
605
615
  let functionScope = this.getFunctionScopeAtPosition(position);
606
616
  if (!functionScope) {
607
617
  //we aren't in any function scope, so return the keyword completions and namespaces
608
- if (this.getTokenBefore(currentToken, lexer_1.TokenKind.New)) {
618
+ if (this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
609
619
  // there's a new keyword, so only class types are viable here
610
620
  return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
611
621
  }
@@ -614,17 +624,17 @@ class BrsFile {
614
624
  }
615
625
  }
616
626
  const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
617
- const newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
627
+ const newToken = this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
618
628
  if (newToken) {
619
629
  //we are after a new keyword; so we can only be namespaces or classes at this point
620
630
  result.push(...classNameCompletions);
621
631
  result.push(...namespaceCompletions);
622
632
  return result;
623
633
  }
624
- if (this.tokenFollows(currentToken, lexer_1.TokenKind.Goto)) {
634
+ if (this.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
625
635
  return this.getLabelCompletion(functionScope);
626
636
  }
627
- if (this.isPositionNextToTokenKind(position, lexer_1.TokenKind.Dot)) {
637
+ if (this.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
628
638
  if (namespaceCompletions.length > 0) {
629
639
  //if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
630
640
  return namespaceCompletions;
@@ -670,7 +680,7 @@ class BrsFile {
670
680
  kind: (0, reflection_1.isFunctionType)(variable.type) ? vscode_languageserver_1.CompletionItemKind.Function : vscode_languageserver_1.CompletionItemKind.Variable
671
681
  });
672
682
  }
673
- if (this.parseMode === parser_1.ParseMode.BrighterScript) {
683
+ if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
674
684
  //include the first part of namespaces
675
685
  let namespaces = scope.getAllNamespaceStatements();
676
686
  for (let stmt of namespaces) {
@@ -700,7 +710,7 @@ class BrsFile {
700
710
  let classStatement = this.getClassFromMReference(position, currentToken, functionScope);
701
711
  let results = new Map();
702
712
  if (classStatement) {
703
- let classes = scope.getClassHierarchy(classStatement.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
713
+ let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
704
714
  for (let cs of classes) {
705
715
  for (let member of [...(_b = (_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : [], ...(_d = (_c = cs === null || cs === void 0 ? void 0 : cs.item) === null || _c === void 0 ? void 0 : _c.methods) !== null && _d !== void 0 ? _d : []]) {
706
716
  if (!results.has(member.name.text.toLowerCase())) {
@@ -716,21 +726,21 @@ class BrsFile {
716
726
  }
717
727
  getClassFromMReference(position, currentToken, functionScope) {
718
728
  let previousToken = this.getPreviousToken(currentToken);
719
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot) {
729
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot) {
720
730
  previousToken = this.getPreviousToken(previousToken);
721
731
  }
722
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Identifier && (previousToken === null || previousToken === void 0 ? void 0 : previousToken.text.toLowerCase()) === 'm' && (0, reflection_1.isClassMethodStatement)(functionScope.func.functionStatement)) {
732
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Identifier && (previousToken === null || previousToken === void 0 ? void 0 : previousToken.text.toLowerCase()) === 'm' && (0, reflection_1.isClassMethodStatement)(functionScope.func.functionStatement)) {
723
733
  return { item: this.parser.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, position)), file: this };
724
734
  }
725
735
  return undefined;
726
736
  }
727
737
  getGlobalClassStatementCompletions(currentToken, parseMode) {
728
738
  var _a;
729
- if (parseMode === parser_1.ParseMode.BrightScript) {
739
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
730
740
  return [];
731
741
  }
732
742
  let results = new Map();
733
- let completionName = (_a = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
743
+ let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
734
744
  if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
735
745
  return [];
736
746
  }
@@ -752,17 +762,17 @@ class BrsFile {
752
762
  }
753
763
  getNamespaceCompletions(currentToken, parseMode, scope) {
754
764
  //BrightScript does not support namespaces, so return an empty list in that case
755
- if (parseMode === parser_1.ParseMode.BrightScript) {
765
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
756
766
  return [];
757
767
  }
758
- let completionName = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
768
+ let completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
759
769
  if (!completionName) {
760
770
  return [];
761
771
  }
762
772
  //remove any trailing identifer and then any trailing dot, to give us the
763
773
  //name of its immediate parent namespace
764
774
  let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
765
- let newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
775
+ let newToken = this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
766
776
  let result = new Map();
767
777
  for (let [, namespace] of scope.namespaceLookup) {
768
778
  //completionName = "NameA."
@@ -811,11 +821,11 @@ class BrsFile {
811
821
  return undefined;
812
822
  }
813
823
  let location;
814
- const nameParts = this.getPartialVariableName(token, [lexer_1.TokenKind.New]).split('.');
824
+ const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
815
825
  const endName = nameParts[nameParts.length - 1].toLowerCase();
816
826
  const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
817
827
  const statementHandler = (statement) => {
818
- if (!location && statement.getName(parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
828
+ if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
819
829
  const namespaceItemStatementHandler = (statement) => {
820
830
  if (!location && statement.name.text.toLowerCase() === endName) {
821
831
  const uri = util_1.util.pathToUri(file.pathAbsolute);
@@ -841,7 +851,7 @@ class BrsFile {
841
851
  * Given a current token, walk
842
852
  */
843
853
  getPartialVariableName(currentToken, excludeTokens = null) {
844
- let identifierAndDotKinds = [lexer_1.TokenKind.Identifier, ...lexer_1.AllowedLocalIdentifiers, lexer_1.TokenKind.Dot];
854
+ let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
845
855
  //consume tokens backwards until we find something other than a dot or an identifier
846
856
  let tokens = [];
847
857
  const parser = this.parser;
@@ -867,17 +877,17 @@ class BrsFile {
867
877
  const previousToken = this.getPreviousToken(closestToken);
868
878
  const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
869
879
  //next to matched token
870
- if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
880
+ if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
871
881
  return false;
872
882
  }
873
883
  else if (closestToken.kind === tokenKind) {
874
884
  return true;
875
885
  }
876
- else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
886
+ else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
877
887
  return false;
878
888
  //next to an identifier, which is next to token kind
879
889
  }
880
- else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
890
+ else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
881
891
  return true;
882
892
  }
883
893
  else {
@@ -888,7 +898,7 @@ class BrsFile {
888
898
  const index = this.parser.tokens.indexOf(currentToken);
889
899
  for (let i = index - 1; i >= 0; i--) {
890
900
  currentToken = this.parser.tokens[i];
891
- if (currentToken.kind === lexer_1.TokenKind.Newline) {
901
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
892
902
  break;
893
903
  }
894
904
  else if (currentToken.kind === tokenKind) {
@@ -908,7 +918,7 @@ class BrsFile {
908
918
  let tokens = [];
909
919
  for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
910
920
  currentToken = this.parser.tokens[i];
911
- if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
921
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
912
922
  break;
913
923
  }
914
924
  tokens.push(currentToken);
@@ -1052,7 +1062,7 @@ class BrsFile {
1052
1062
  else {
1053
1063
  return;
1054
1064
  }
1055
- const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(parser_1.ParseMode.BrighterScript);
1065
+ const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
1056
1066
  return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
1057
1067
  }
1058
1068
  /**
@@ -1086,9 +1096,9 @@ class BrsFile {
1086
1096
  else {
1087
1097
  return symbols;
1088
1098
  }
1089
- const name = statement.getName(parser_1.ParseMode.BrighterScript);
1099
+ const name = statement.getName(Parser_1.ParseMode.BrighterScript);
1090
1100
  const uri = util_1.util.pathToUri(this.pathAbsolute);
1091
- const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(parser_1.ParseMode.BrighterScript));
1101
+ const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(Parser_1.ParseMode.BrighterScript));
1092
1102
  symbols.push(symbol);
1093
1103
  return symbols;
1094
1104
  }
@@ -1102,8 +1112,8 @@ class BrsFile {
1102
1112
  const token = this.getTokenAt(position);
1103
1113
  // While certain other tokens are allowed as local variables (AllowedLocalIdentifiers: https://github.com/rokucommunity/brighterscript/blob/master/src/lexer/TokenKind.ts#L418), these are converted by the parser to TokenKind.Identifier by the time we retrieve the token using getTokenAt
1104
1114
  let definitionTokenTypes = [
1105
- lexer_1.TokenKind.Identifier,
1106
- lexer_1.TokenKind.StringLiteral
1115
+ TokenKind_1.TokenKind.Identifier,
1116
+ TokenKind_1.TokenKind.StringLiteral
1107
1117
  ];
1108
1118
  //throw out invalid tokens and the wrong kind of tokens
1109
1119
  if (!token || !definitionTokenTypes.includes(token.kind)) {
@@ -1111,7 +1121,7 @@ class BrsFile {
1111
1121
  }
1112
1122
  let textToSearchFor = token.text.toLowerCase();
1113
1123
  const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
1114
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Callfunc) {
1124
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
1115
1125
  for (const scope of this.program.getScopes()) {
1116
1126
  //to only get functions defined in interface methods
1117
1127
  const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
@@ -1121,7 +1131,7 @@ class BrsFile {
1121
1131
  }
1122
1132
  return results;
1123
1133
  }
1124
- let classToken = this.getTokenBefore(token, lexer_1.TokenKind.Class);
1134
+ let classToken = this.getTokenBefore(token, TokenKind_1.TokenKind.Class);
1125
1135
  if (classToken) {
1126
1136
  let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
1127
1137
  if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
@@ -1133,7 +1143,7 @@ class BrsFile {
1133
1143
  }
1134
1144
  return results;
1135
1145
  }
1136
- if (token.kind === lexer_1.TokenKind.StringLiteral) {
1146
+ if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
1137
1147
  // We need to strip off the quotes but only if present
1138
1148
  const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
1139
1149
  let endIndex = textToSearchFor.length;
@@ -1153,7 +1163,7 @@ class BrsFile {
1153
1163
  results.push(vscode_languageserver_1.Location.create(uri, varDeclaration.nameRange));
1154
1164
  }
1155
1165
  }
1156
- if (this.tokenFollows(token, lexer_1.TokenKind.Goto)) {
1166
+ if (this.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
1157
1167
  for (const label of functionScope.labelStatements) {
1158
1168
  if (label.name.toLocaleLowerCase() === textToSearchFor) {
1159
1169
  const uri = util_1.util.pathToUri(this.pathAbsolute);
@@ -1170,7 +1180,7 @@ class BrsFile {
1170
1180
  continue;
1171
1181
  }
1172
1182
  filesSearched.add(file);
1173
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot && file.parseMode === parser_1.ParseMode.BrighterScript) {
1183
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1174
1184
  results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1175
1185
  const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1176
1186
  if (namespaceDefinition) {
@@ -1214,14 +1224,15 @@ class BrsFile {
1214
1224
  return results;
1215
1225
  }
1216
1226
  getHover(position) {
1227
+ const fence = (code) => util_1.util.mdFence(code, 'brightscript');
1217
1228
  //get the token at the position
1218
1229
  let token = this.getTokenAt(position);
1219
1230
  let hoverTokenTypes = [
1220
- lexer_1.TokenKind.Identifier,
1221
- lexer_1.TokenKind.Function,
1222
- lexer_1.TokenKind.EndFunction,
1223
- lexer_1.TokenKind.Sub,
1224
- lexer_1.TokenKind.EndSub
1231
+ TokenKind_1.TokenKind.Identifier,
1232
+ TokenKind_1.TokenKind.Function,
1233
+ TokenKind_1.TokenKind.EndFunction,
1234
+ TokenKind_1.TokenKind.Sub,
1235
+ TokenKind_1.TokenKind.EndSub
1225
1236
  ];
1226
1237
  //throw out invalid tokens and the wrong kind of tokens
1227
1238
  if (!token || !hoverTokenTypes.includes(token.kind)) {
@@ -1247,7 +1258,7 @@ class BrsFile {
1247
1258
  return {
1248
1259
  range: token.range,
1249
1260
  //append the variable name to the front for scope
1250
- contents: typeText
1261
+ contents: fence(typeText)
1251
1262
  };
1252
1263
  }
1253
1264
  }
@@ -1255,7 +1266,7 @@ class BrsFile {
1255
1266
  if (labelStatement.name.toLocaleLowerCase() === lowerTokenText) {
1256
1267
  return {
1257
1268
  range: token.range,
1258
- contents: `${labelStatement.name}: label`
1269
+ contents: fence(`${labelStatement.name}: label`)
1259
1270
  };
1260
1271
  }
1261
1272
  }
@@ -1269,12 +1280,40 @@ class BrsFile {
1269
1280
  if (callable) {
1270
1281
  return {
1271
1282
  range: token.range,
1272
- contents: callable.type.toString()
1283
+ contents: this.getCallableDocumentation(callable)
1273
1284
  };
1274
1285
  }
1275
1286
  }
1276
1287
  }
1277
1288
  }
1289
+ /**
1290
+ * Build a hover documentation for a callable.
1291
+ */
1292
+ getCallableDocumentation(callable) {
1293
+ const comments = [];
1294
+ const tokens = callable.file.parser.tokens;
1295
+ const idx = tokens.indexOf(callable.functionStatement.func.functionType);
1296
+ for (let i = idx - 1; i >= 0; i--) {
1297
+ const token = tokens[i];
1298
+ //skip whitespace and newline chars
1299
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
1300
+ comments.push(token);
1301
+ }
1302
+ else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
1303
+ //skip these tokens
1304
+ continue;
1305
+ //any other token means there are no more comments
1306
+ }
1307
+ else {
1308
+ break;
1309
+ }
1310
+ }
1311
+ let result = util_1.util.mdFence(callable.type.toString(), 'brightscript');
1312
+ if (comments.length > 0) {
1313
+ result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
1314
+ }
1315
+ return result;
1316
+ }
1278
1317
  getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
1279
1318
  var _a;
1280
1319
  if (!dottedGetText) {
@@ -1321,12 +1360,12 @@ class BrsFile {
1321
1360
  }
1322
1361
  }
1323
1362
  const kind = currentToken.kind;
1324
- if (kind === lexer_1.TokenKind.Comment) {
1363
+ if (kind === TokenKind_1.TokenKind.Comment) {
1325
1364
  // Strip off common leading characters to make it easier to read
1326
1365
  const commentText = currentToken.text.replace(/^[' *\/]+/, '');
1327
1366
  functionComments.unshift(commentText);
1328
1367
  }
1329
- else if (kind === lexer_1.TokenKind.Newline) {
1368
+ else if (kind === TokenKind_1.TokenKind.Newline) {
1330
1369
  if (functionComments.length === 0) {
1331
1370
  continue;
1332
1371
  }
@@ -1385,7 +1424,7 @@ class BrsFile {
1385
1424
  const classConstructor = this.getClassMethod(classStatement, 'new');
1386
1425
  let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
1387
1426
  if (sigHelp) {
1388
- sigHelp.key = classStatement.getName(parser_1.ParseMode.BrighterScript);
1427
+ sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
1389
1428
  sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
1390
1429
  }
1391
1430
  return sigHelp;
@@ -1462,7 +1501,7 @@ exports.BrsFile = BrsFile;
1462
1501
  * List of completions for all valid keywords/reserved words.
1463
1502
  * Build this list once because it won't change for the lifetime of this process
1464
1503
  */
1465
- exports.KeywordCompletions = Object.keys(lexer_1.Keywords)
1504
+ exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
1466
1505
  //remove any keywords with whitespace
1467
1506
  .filter(x => !x.includes(' '))
1468
1507
  //create completions