brighterscript 1.0.0-alpha.2 → 1.0.0-alpha.20

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 (381) hide show
  1. package/CHANGELOG.md +542 -253
  2. package/README.md +30 -9
  3. package/bsconfig.schema.json +13 -1
  4. package/dist/BsConfig.d.ts +4 -0
  5. package/dist/Cache.d.ts +3 -8
  6. package/dist/Cache.js +9 -14
  7. package/dist/Cache.js.map +1 -1
  8. package/dist/CodeActionUtil.d.ts +11 -2
  9. package/dist/CodeActionUtil.js +17 -3
  10. package/dist/CodeActionUtil.js.map +1 -1
  11. package/dist/CommentFlagProcessor.d.ts +4 -4
  12. package/dist/CommentFlagProcessor.js +5 -3
  13. package/dist/CommentFlagProcessor.js.map +1 -1
  14. package/dist/DependencyGraph.js +5 -4
  15. package/dist/DependencyGraph.js.map +1 -1
  16. package/dist/DiagnosticFilterer.js +1 -1
  17. package/dist/DiagnosticFilterer.js.map +1 -1
  18. package/dist/DiagnosticMessages.d.ts +59 -4
  19. package/dist/DiagnosticMessages.js +65 -7
  20. package/dist/DiagnosticMessages.js.map +1 -1
  21. package/dist/LanguageServer.d.ts +4 -14
  22. package/dist/LanguageServer.js +40 -26
  23. package/dist/LanguageServer.js.map +1 -1
  24. package/dist/Logger.d.ts +2 -0
  25. package/dist/Logger.js +10 -8
  26. package/dist/Logger.js.map +1 -1
  27. package/dist/PluginInterface.d.ts +7 -3
  28. package/dist/PluginInterface.js +9 -0
  29. package/dist/PluginInterface.js.map +1 -1
  30. package/dist/Program.d.ts +43 -25
  31. package/dist/Program.js +180 -82
  32. package/dist/Program.js.map +1 -1
  33. package/dist/ProgramBuilder.d.ts +4 -0
  34. package/dist/ProgramBuilder.js +30 -14
  35. package/dist/ProgramBuilder.js.map +1 -1
  36. package/dist/Scope.d.ts +100 -28
  37. package/dist/Scope.js +382 -154
  38. package/dist/Scope.js.map +1 -1
  39. package/dist/SemanticTokenUtils.d.ts +14 -0
  40. package/dist/SemanticTokenUtils.js +81 -0
  41. package/dist/SemanticTokenUtils.js.map +1 -0
  42. package/dist/SymbolTable.d.ts +10 -4
  43. package/dist/SymbolTable.js +40 -13
  44. package/dist/SymbolTable.js.map +1 -1
  45. package/dist/XmlScope.d.ts +8 -3
  46. package/dist/XmlScope.js +65 -27
  47. package/dist/XmlScope.js.map +1 -1
  48. package/dist/astUtils/AstEditor.d.ts +33 -0
  49. package/dist/astUtils/AstEditor.js +107 -0
  50. package/dist/astUtils/AstEditor.js.map +1 -0
  51. package/dist/{types/FunctionType.spec.d.ts → astUtils/AstEditor.spec.d.ts} +0 -0
  52. package/dist/astUtils/AstEditor.spec.js +170 -0
  53. package/dist/astUtils/AstEditor.spec.js.map +1 -0
  54. package/dist/astUtils/creators.d.ts +24 -6
  55. package/dist/astUtils/creators.js +130 -19
  56. package/dist/astUtils/creators.js.map +1 -1
  57. package/dist/astUtils/creators.spec.js +14 -4
  58. package/dist/astUtils/creators.spec.js.map +1 -1
  59. package/dist/astUtils/reflection.d.ts +27 -8
  60. package/dist/astUtils/reflection.js +66 -1
  61. package/dist/astUtils/reflection.js.map +1 -1
  62. package/dist/astUtils/reflection.spec.js +130 -119
  63. package/dist/astUtils/reflection.spec.js.map +1 -1
  64. package/dist/astUtils/stackedVisitor.js.map +1 -1
  65. package/dist/astUtils/stackedVisitor.spec.js +13 -13
  66. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  67. package/dist/astUtils/visitors.d.ts +17 -2
  68. package/dist/astUtils/visitors.js +2 -2
  69. package/dist/astUtils/visitors.js.map +1 -1
  70. package/dist/astUtils/visitors.spec.js +31 -29
  71. package/dist/astUtils/visitors.spec.js.map +1 -1
  72. package/dist/astUtils/xml.d.ts +4 -3
  73. package/dist/astUtils/xml.js +8 -3
  74. package/dist/astUtils/xml.js.map +1 -1
  75. package/dist/bscPlugin/BscPlugin.d.ts +7 -1
  76. package/dist/bscPlugin/BscPlugin.js +28 -0
  77. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  78. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +4 -4
  79. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  80. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +26 -26
  81. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  82. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +9 -0
  83. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +97 -0
  84. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  85. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
  86. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +73 -0
  87. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
  88. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
  89. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +52 -0
  90. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
  91. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.d.ts +1 -0
  92. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +32 -0
  93. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +1 -0
  94. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
  95. package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
  96. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  97. package/dist/bscPlugin/validation/ScopeValidator.d.ts +29 -0
  98. package/dist/bscPlugin/validation/ScopeValidator.js +183 -0
  99. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  100. package/dist/cli.js +9 -3
  101. package/dist/cli.js.map +1 -1
  102. package/dist/diagnosticUtils.d.ts +1 -0
  103. package/dist/diagnosticUtils.js +15 -8
  104. package/dist/diagnosticUtils.js.map +1 -1
  105. package/dist/examples/plugins/removePrint.js +12 -14
  106. package/dist/examples/plugins/removePrint.js.map +1 -1
  107. package/dist/files/BrsFile.Class.spec.js +634 -145
  108. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  109. package/dist/files/BrsFile.d.ts +62 -30
  110. package/dist/files/BrsFile.js +683 -335
  111. package/dist/files/BrsFile.js.map +1 -1
  112. package/dist/files/BrsFile.spec.js +1055 -449
  113. package/dist/files/BrsFile.spec.js.map +1 -1
  114. package/dist/files/XmlFile.d.ts +11 -10
  115. package/dist/files/XmlFile.js +33 -26
  116. package/dist/files/XmlFile.js.map +1 -1
  117. package/dist/files/XmlFile.spec.js +302 -237
  118. package/dist/files/XmlFile.spec.js.map +1 -1
  119. package/dist/files/tests/imports.spec.js +44 -42
  120. package/dist/files/tests/imports.spec.js.map +1 -1
  121. package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
  122. package/dist/files/tests/optionalChaning.spec.js +88 -0
  123. package/dist/files/tests/optionalChaning.spec.js.map +1 -0
  124. package/dist/globalCallables.d.ts +3 -1
  125. package/dist/globalCallables.js +424 -152
  126. package/dist/globalCallables.js.map +1 -1
  127. package/dist/index.d.ts +13 -3
  128. package/dist/index.js +23 -4
  129. package/dist/index.js.map +1 -1
  130. package/dist/interfaces.d.ts +129 -16
  131. package/dist/lexer/Lexer.d.ts +19 -1
  132. package/dist/lexer/Lexer.js +127 -21
  133. package/dist/lexer/Lexer.js.map +1 -1
  134. package/dist/lexer/Lexer.spec.js +657 -536
  135. package/dist/lexer/Lexer.spec.js.map +1 -1
  136. package/dist/lexer/Token.d.ts +2 -2
  137. package/dist/lexer/TokenKind.d.ts +13 -1
  138. package/dist/lexer/TokenKind.js +60 -3
  139. package/dist/lexer/TokenKind.js.map +1 -1
  140. package/dist/parser/BrsTranspileState.d.ts +7 -0
  141. package/dist/parser/BrsTranspileState.js +9 -0
  142. package/dist/parser/BrsTranspileState.js.map +1 -1
  143. package/dist/parser/Expression.d.ts +150 -34
  144. package/dist/parser/Expression.js +337 -150
  145. package/dist/parser/Expression.js.map +1 -1
  146. package/dist/parser/Parser.Class.spec.js +189 -89
  147. package/dist/parser/Parser.Class.spec.js.map +1 -1
  148. package/dist/parser/Parser.d.ts +152 -29
  149. package/dist/parser/Parser.js +1095 -501
  150. package/dist/parser/Parser.js.map +1 -1
  151. package/dist/parser/Parser.spec.js +687 -266
  152. package/dist/parser/Parser.spec.js.map +1 -1
  153. package/dist/parser/SGParser.d.ts +41 -4
  154. package/dist/parser/SGParser.js +186 -175
  155. package/dist/parser/SGParser.js.map +1 -1
  156. package/dist/parser/SGParser.spec.js +35 -22
  157. package/dist/parser/SGParser.spec.js.map +1 -1
  158. package/dist/parser/SGTypes.d.ts +206 -38
  159. package/dist/parser/SGTypes.js +470 -161
  160. package/dist/parser/SGTypes.js.map +1 -1
  161. package/dist/parser/SGTypes.spec.d.ts +1 -0
  162. package/dist/parser/SGTypes.spec.js +351 -0
  163. package/dist/parser/SGTypes.spec.js.map +1 -0
  164. package/dist/parser/Statement.d.ts +194 -40
  165. package/dist/parser/Statement.js +597 -160
  166. package/dist/parser/Statement.js.map +1 -1
  167. package/dist/parser/Statement.spec.js +11 -11
  168. package/dist/parser/Statement.spec.js.map +1 -1
  169. package/dist/parser/TranspileState.d.ts +1 -1
  170. package/dist/parser/TranspileState.js +15 -7
  171. package/dist/parser/TranspileState.js.map +1 -1
  172. package/dist/parser/tests/Parser.spec.d.ts +10 -9
  173. package/dist/parser/tests/Parser.spec.js +15 -11
  174. package/dist/parser/tests/Parser.spec.js.map +1 -1
  175. package/dist/parser/tests/controlFlow/For.spec.js +60 -60
  176. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  177. package/dist/parser/tests/controlFlow/ForEach.spec.js +40 -39
  178. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  179. package/dist/parser/tests/controlFlow/If.spec.js +213 -194
  180. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  181. package/dist/parser/tests/controlFlow/While.spec.js +37 -37
  182. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  183. package/dist/parser/tests/expression/Additive.spec.js +30 -30
  184. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  185. package/dist/parser/tests/expression/ArrayLiterals.spec.js +119 -119
  186. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  187. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +162 -138
  188. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  189. package/dist/parser/tests/expression/Boolean.spec.js +24 -24
  190. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  191. package/dist/parser/tests/expression/Call.spec.js +41 -40
  192. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  193. package/dist/parser/tests/expression/Exponential.spec.js +17 -17
  194. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  195. package/dist/parser/tests/expression/Function.spec.js +256 -256
  196. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  197. package/dist/parser/tests/expression/Indexing.spec.js +87 -87
  198. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  199. package/dist/parser/tests/expression/Multiplicative.spec.js +37 -37
  200. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  201. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +75 -63
  202. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  203. package/dist/parser/tests/expression/PrefixUnary.spec.js +41 -41
  204. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  205. package/dist/parser/tests/expression/Primary.spec.js +41 -41
  206. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  207. package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
  208. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
  209. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
  210. package/dist/parser/tests/expression/Relational.spec.js +43 -43
  211. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  212. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +9 -9
  213. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  214. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +28 -28
  215. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  216. package/dist/parser/tests/expression/TernaryExpression.spec.js +102 -102
  217. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  218. package/dist/parser/tests/statement/AssignmentOperators.spec.js +36 -36
  219. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  220. package/dist/parser/tests/statement/Declaration.spec.js +44 -44
  221. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  222. package/dist/parser/tests/statement/Dim.spec.js +21 -21
  223. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  224. package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
  225. package/dist/parser/tests/statement/Enum.spec.js +840 -0
  226. package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
  227. package/dist/parser/tests/statement/For.spec.d.ts +1 -0
  228. package/dist/parser/tests/statement/For.spec.js +46 -0
  229. package/dist/parser/tests/statement/For.spec.js.map +1 -0
  230. package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
  231. package/dist/parser/tests/statement/ForEach.spec.js +37 -0
  232. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
  233. package/dist/parser/tests/statement/Function.spec.js +198 -197
  234. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  235. package/dist/parser/tests/statement/Goto.spec.js +15 -14
  236. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  237. package/dist/parser/tests/statement/Increment.spec.js +50 -50
  238. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  239. package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
  240. package/dist/parser/tests/statement/InterfaceStatement.spec.js +254 -0
  241. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
  242. package/dist/parser/tests/statement/LibraryStatement.spec.js +17 -17
  243. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  244. package/dist/parser/tests/statement/Misc.spec.js +108 -106
  245. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  246. package/dist/parser/tests/statement/PrintStatement.spec.js +40 -40
  247. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  248. package/dist/parser/tests/statement/ReturnStatement.spec.js +46 -46
  249. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  250. package/dist/parser/tests/statement/Set.spec.js +83 -83
  251. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  252. package/dist/parser/tests/statement/Stop.spec.js +12 -11
  253. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  254. package/dist/parser/tests/statement/Throw.spec.js +5 -5
  255. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  256. package/dist/parser/tests/statement/TryCatch.spec.js +15 -13
  257. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  258. package/dist/preprocessor/Chunk.d.ts +1 -1
  259. package/dist/preprocessor/Chunk.js.map +1 -1
  260. package/dist/preprocessor/Manifest.d.ts +5 -5
  261. package/dist/preprocessor/Manifest.js +14 -35
  262. package/dist/preprocessor/Manifest.js.map +1 -1
  263. package/dist/preprocessor/Manifest.spec.d.ts +1 -0
  264. package/dist/preprocessor/Manifest.spec.js +78 -103
  265. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  266. package/dist/preprocessor/Preprocessor.d.ts +1 -1
  267. package/dist/preprocessor/Preprocessor.js +8 -8
  268. package/dist/preprocessor/Preprocessor.js.map +1 -1
  269. package/dist/preprocessor/Preprocessor.spec.js +49 -49
  270. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  271. package/dist/preprocessor/PreprocessorParser.spec.js +72 -72
  272. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  273. package/dist/roku-types/data.json +21891 -0
  274. package/dist/roku-types/index.d.ts +6776 -0
  275. package/dist/roku-types/index.js +11 -0
  276. package/dist/roku-types/index.js.map +1 -0
  277. package/dist/types/ArrayType.d.ts +8 -5
  278. package/dist/types/ArrayType.js +52 -12
  279. package/dist/types/ArrayType.js.map +1 -1
  280. package/dist/types/ArrayType.spec.js +72 -11
  281. package/dist/types/ArrayType.spec.js.map +1 -1
  282. package/dist/types/BooleanType.d.ts +4 -2
  283. package/dist/types/BooleanType.js +9 -4
  284. package/dist/types/BooleanType.js.map +1 -1
  285. package/dist/types/BooleanType.spec.js +5 -3
  286. package/dist/types/BooleanType.spec.js.map +1 -1
  287. package/dist/types/BscType.d.ts +20 -5
  288. package/dist/types/BscType.js +24 -0
  289. package/dist/types/BscType.js.map +1 -1
  290. package/dist/types/CustomType.d.ts +8 -6
  291. package/dist/types/CustomType.js +20 -11
  292. package/dist/types/CustomType.js.map +1 -1
  293. package/dist/types/DoubleType.d.ts +2 -0
  294. package/dist/types/DoubleType.js +14 -9
  295. package/dist/types/DoubleType.js.map +1 -1
  296. package/dist/types/DoubleType.spec.js +5 -3
  297. package/dist/types/DoubleType.spec.js.map +1 -1
  298. package/dist/types/DynamicType.d.ts +2 -0
  299. package/dist/types/DynamicType.js +6 -2
  300. package/dist/types/DynamicType.js.map +1 -1
  301. package/dist/types/DynamicType.spec.js +2 -2
  302. package/dist/types/DynamicType.spec.js.map +1 -1
  303. package/dist/types/FloatType.d.ts +2 -0
  304. package/dist/types/FloatType.js +14 -9
  305. package/dist/types/FloatType.js.map +1 -1
  306. package/dist/types/FloatType.spec.js +4 -2
  307. package/dist/types/FloatType.spec.js.map +1 -1
  308. package/dist/types/FunctionType.d.ts +7 -31
  309. package/dist/types/FunctionType.js +11 -57
  310. package/dist/types/FunctionType.js.map +1 -1
  311. package/dist/types/IntegerType.d.ts +2 -0
  312. package/dist/types/IntegerType.js +14 -9
  313. package/dist/types/IntegerType.js.map +1 -1
  314. package/dist/types/IntegerType.spec.js +5 -3
  315. package/dist/types/IntegerType.spec.js.map +1 -1
  316. package/dist/types/InterfaceType.d.ts +13 -4
  317. package/dist/types/InterfaceType.js +48 -8
  318. package/dist/types/InterfaceType.js.map +1 -1
  319. package/dist/types/InterfaceType.spec.d.ts +1 -0
  320. package/dist/types/InterfaceType.spec.js +194 -0
  321. package/dist/types/InterfaceType.spec.js.map +1 -0
  322. package/dist/types/InvalidType.d.ts +4 -2
  323. package/dist/types/InvalidType.js +10 -5
  324. package/dist/types/InvalidType.js.map +1 -1
  325. package/dist/types/InvalidType.spec.js +4 -2
  326. package/dist/types/InvalidType.spec.js.map +1 -1
  327. package/dist/types/LazyType.d.ts +8 -7
  328. package/dist/types/LazyType.js +22 -10
  329. package/dist/types/LazyType.js.map +1 -1
  330. package/dist/types/LongIntegerType.d.ts +2 -0
  331. package/dist/types/LongIntegerType.js +14 -9
  332. package/dist/types/LongIntegerType.js.map +1 -1
  333. package/dist/types/LongIntegerType.spec.js +4 -2
  334. package/dist/types/LongIntegerType.spec.js.map +1 -1
  335. package/dist/types/ObjectType.d.ts +8 -4
  336. package/dist/types/ObjectType.js +9 -4
  337. package/dist/types/ObjectType.js.map +1 -1
  338. package/dist/types/ObjectType.spec.js +2 -2
  339. package/dist/types/ObjectType.spec.js.map +1 -1
  340. package/dist/types/StringType.d.ts +4 -2
  341. package/dist/types/StringType.js +9 -4
  342. package/dist/types/StringType.js.map +1 -1
  343. package/dist/types/StringType.spec.js +4 -2
  344. package/dist/types/StringType.spec.js.map +1 -1
  345. package/dist/types/TypedFunctionType.d.ts +28 -0
  346. package/dist/types/TypedFunctionType.js +88 -0
  347. package/dist/types/TypedFunctionType.js.map +1 -0
  348. package/dist/types/TypedFunctionType.spec.d.ts +1 -0
  349. package/dist/types/TypedFunctionType.spec.js +37 -0
  350. package/dist/types/TypedFunctionType.spec.js.map +1 -0
  351. package/dist/types/UninitializedType.js +3 -3
  352. package/dist/types/UninitializedType.js.map +1 -1
  353. package/dist/types/VoidType.d.ts +4 -2
  354. package/dist/types/VoidType.js +8 -4
  355. package/dist/types/VoidType.js.map +1 -1
  356. package/dist/types/VoidType.spec.js +2 -2
  357. package/dist/types/VoidType.spec.js.map +1 -1
  358. package/dist/types/helpers.d.ts +42 -0
  359. package/dist/types/helpers.js +118 -0
  360. package/dist/types/helpers.js.map +1 -0
  361. package/dist/util.d.ts +87 -16
  362. package/dist/util.js +339 -94
  363. package/dist/util.js.map +1 -1
  364. package/dist/validators/ClassValidator.d.ts +19 -2
  365. package/dist/validators/ClassValidator.js +163 -102
  366. package/dist/validators/ClassValidator.js.map +1 -1
  367. package/package.json +26 -15
  368. package/dist/astUtils/index.d.ts +0 -7
  369. package/dist/astUtils/index.js +0 -26
  370. package/dist/astUtils/index.js.map +0 -1
  371. package/dist/lexer/index.d.ts +0 -3
  372. package/dist/lexer/index.js +0 -17
  373. package/dist/lexer/index.js.map +0 -1
  374. package/dist/parser/index.d.ts +0 -3
  375. package/dist/parser/index.js +0 -16
  376. package/dist/parser/index.js.map +0 -1
  377. package/dist/preprocessor/index.d.ts +0 -3
  378. package/dist/preprocessor/index.js +0 -16
  379. package/dist/preprocessor/index.js.map +0 -1
  380. package/dist/types/FunctionType.spec.js +0 -23
  381. package/dist/types/FunctionType.spec.js.map +0 -1
@@ -6,10 +6,11 @@ const vscode_languageserver_1 = require("vscode-languageserver");
6
6
  const chalk_1 = require("chalk");
7
7
  const path = require("path");
8
8
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
9
- const lexer_1 = require("../lexer");
10
- const parser_1 = require("../parser");
11
- const FunctionType_1 = require("../types/FunctionType");
12
- const VoidType_1 = require("../types/VoidType");
9
+ const Token_1 = require("../lexer/Token");
10
+ const Lexer_1 = require("../lexer/Lexer");
11
+ const TokenKind_1 = require("../lexer/TokenKind");
12
+ const Parser_1 = require("../parser/Parser");
13
+ const DynamicType_1 = require("../types/DynamicType");
13
14
  const util_1 = require("../util");
14
15
  const BrsTranspileState_1 = require("../parser/BrsTranspileState");
15
16
  const Preprocessor_1 = require("../preprocessor/Preprocessor");
@@ -18,6 +19,9 @@ const serialize_error_1 = require("serialize-error");
18
19
  const reflection_1 = require("../astUtils/reflection");
19
20
  const visitors_1 = require("../astUtils/visitors");
20
21
  const CommentFlagProcessor_1 = require("../CommentFlagProcessor");
22
+ const BscType_1 = require("../types/BscType");
23
+ const UninitializedType_1 = require("../types/UninitializedType");
24
+ const InvalidType_1 = require("../types/InvalidType");
21
25
  /**
22
26
  * Holds all details about this file within the scope of the whole program
23
27
  */
@@ -38,30 +42,27 @@ class BrsFile {
38
42
  /**
39
43
  * The parseMode used for the parser for this file
40
44
  */
41
- this.parseMode = parser_1.ParseMode.BrightScript;
45
+ this.parseMode = Parser_1.ParseMode.BrightScript;
42
46
  /**
43
47
  * Indicates whether this file needs to be validated.
48
+ * Files are only ever validated a single time
44
49
  */
45
50
  this.isValidated = false;
46
51
  this.diagnostics = [];
47
52
  this.commentFlags = [];
48
53
  this.callables = [];
49
54
  this.functionCalls = [];
50
- /**
51
- * files referenced by import statements
52
- */
53
- this.ownScriptImports = [];
54
55
  /**
55
56
  * Does this file need to be transpiled?
56
57
  */
57
58
  this.needsTranspiled = false;
58
- this.srcPath = util_1.standardizePath `${this.srcPath}`;
59
+ this.srcPath = (0, util_1.standardizePath) `${this.srcPath}`;
59
60
  this.dependencyGraphKey = this.pkgPath.toLowerCase();
60
61
  this.extension = util_1.util.getExtension(this.srcPath);
61
62
  //all BrighterScript files need to be transpiled
62
63
  if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
63
64
  this.needsTranspiled = true;
64
- this.parseMode = parser_1.ParseMode.BrighterScript;
65
+ this.parseMode = Parser_1.ParseMode.BrighterScript;
65
66
  }
66
67
  this.isTypedef = this.extension === '.d.bs';
67
68
  if (!this.isTypedef) {
@@ -79,21 +80,34 @@ class BrsFile {
79
80
  this.diagnostics.push(...diagnostics);
80
81
  }
81
82
  /**
82
- * The AST for this file
83
+ * files referenced by import statements
83
84
  */
84
- get ast() {
85
- return this.parser.ast;
85
+ get ownScriptImports() {
86
+ var _a, _b;
87
+ // eslint-disable-next-line @typescript-eslint/dot-notation
88
+ const result = (_b = (_a = this._parser) === null || _a === void 0 ? void 0 : _a.references['cache'].getOrAdd('BrsFile_ownScriptImports', () => {
89
+ var _a, _b, _c, _d;
90
+ const result = [];
91
+ 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 : []) {
92
+ //register import statements
93
+ if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
94
+ result.push({
95
+ filePathRange: statement.filePathToken.range,
96
+ pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
97
+ sourceFile: this,
98
+ text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
99
+ });
100
+ }
101
+ }
102
+ return result;
103
+ })) !== null && _b !== void 0 ? _b : [];
104
+ return result;
86
105
  }
87
106
  /**
88
- * Get the token at the specified position
89
- * @param position
107
+ * The AST for this file
90
108
  */
91
- getTokenAt(position) {
92
- for (let token of this.parser.tokens) {
93
- if (util_1.util.rangeContains(token.range, position)) {
94
- return token;
95
- }
96
- }
109
+ get ast() {
110
+ return this.parser.ast;
97
111
  }
98
112
  get parser() {
99
113
  if (!this._parser) {
@@ -119,9 +133,8 @@ class BrsFile {
119
133
  * Also notify the dependency graph of our current dependencies so other dependents can be notified.
120
134
  */
121
135
  attachDependencyGraph(dependencyGraph) {
122
- if (this.unsubscribeFromDependencyGraph) {
123
- this.unsubscribeFromDependencyGraph();
124
- }
136
+ var _a;
137
+ (_a = this.unsubscribeFromDependencyGraph) === null || _a === void 0 ? void 0 : _a.call(this);
125
138
  //event that fires anytime a dependency changes
126
139
  this.unsubscribeFromDependencyGraph = dependencyGraph.onchange(this.dependencyGraphKey, () => {
127
140
  this.resolveTypedef();
@@ -143,11 +156,13 @@ class BrsFile {
143
156
  this.diagnostics = [];
144
157
  //if we have a typedef file, skip parsing this file
145
158
  if (this.hasTypedef) {
159
+ //skip validation since the typedef is shadowing this file
160
+ this.isValidated = true;
146
161
  return;
147
162
  }
148
163
  //tokenize the input file
149
164
  let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
150
- return lexer_1.Lexer.scan(fileContents, {
165
+ return Lexer_1.Lexer.scan(fileContents, {
151
166
  includeWhitespace: false
152
167
  });
153
168
  });
@@ -170,7 +185,7 @@ class BrsFile {
170
185
  //if the preprocessor generated tokens, use them.
171
186
  let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
172
187
  this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
173
- this._parser = parser_1.Parser.parse(tokens, {
188
+ this._parser = Parser_1.Parser.parse(tokens, {
174
189
  mode: this.parseMode,
175
190
  logger: this.program.logger
176
191
  });
@@ -181,28 +196,31 @@ class BrsFile {
181
196
  this.findCallables();
182
197
  //find all places where a sub/function is being called
183
198
  this.findFunctionCalls();
184
- this.findAndValidateImportAndImportStatements();
185
199
  //attach this file to every diagnostic
186
200
  for (let diagnostic of this.diagnostics) {
187
201
  diagnostic.file = this;
188
202
  }
189
203
  }
190
204
  catch (e) {
191
- this._parser = new parser_1.Parser();
192
- 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(serialize_error_1.serializeError(e)))));
205
+ this._parser = new Parser_1.Parser();
206
+ 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)))));
193
207
  }
194
208
  }
195
- validate() { }
196
- findAndValidateImportAndImportStatements() {
197
- var _a;
209
+ validate() {
210
+ //only validate the file if it was actually parsed (skip files containing typedefs)
211
+ if (!this.hasTypedef) {
212
+ this.validateImportStatements();
213
+ }
214
+ }
215
+ validateImportStatements() {
198
216
  let topOfFileIncludeStatements = [];
199
217
  for (let stmt of this.ast.statements) {
200
218
  //skip comments
201
- if (reflection_1.isCommentStatement(stmt)) {
219
+ if ((0, reflection_1.isCommentStatement)(stmt)) {
202
220
  continue;
203
221
  }
204
222
  //if we found a non-library statement, this statement is not at the top of the file
205
- if (reflection_1.isLibraryStatement(stmt) || reflection_1.isImportStatement(stmt)) {
223
+ if ((0, reflection_1.isLibraryStatement)(stmt) || (0, reflection_1.isImportStatement)(stmt)) {
206
224
  topOfFileIncludeStatements.push(stmt);
207
225
  }
208
226
  else {
@@ -215,22 +233,13 @@ class BrsFile {
215
233
  ...this._parser.references.importStatements
216
234
  ];
217
235
  for (let result of statements) {
218
- //register import statements
219
- if (reflection_1.isImportStatement(result) && result.filePathToken) {
220
- this.ownScriptImports.push({
221
- filePathRange: result.filePathToken.range,
222
- pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, result.filePath),
223
- sourceFile: this,
224
- text: (_a = result.filePathToken) === null || _a === void 0 ? void 0 : _a.text
225
- });
226
- }
227
236
  //if this statement is not one of the top-of-file statements,
228
237
  //then add a diagnostic explaining that it is invalid
229
238
  if (!topOfFileIncludeStatements.includes(result)) {
230
- if (reflection_1.isLibraryStatement(result)) {
239
+ if ((0, reflection_1.isLibraryStatement)(result)) {
231
240
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.libraryStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
232
241
  }
233
- else if (reflection_1.isImportStatement(result)) {
242
+ else if ((0, reflection_1.isImportStatement)(result)) {
234
243
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
235
244
  }
236
245
  }
@@ -281,7 +290,7 @@ class BrsFile {
281
290
  const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
282
291
  this.commentFlags = [];
283
292
  for (let token of tokens) {
284
- if (token.kind === lexer_1.TokenKind.Comment) {
293
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
285
294
  processor.tryAdd(token.text, token.range);
286
295
  }
287
296
  }
@@ -291,31 +300,14 @@ class BrsFile {
291
300
  findCallables() {
292
301
  var _a;
293
302
  for (let statement of (_a = this.parser.references.functionStatements) !== null && _a !== void 0 ? _a : []) {
294
- let functionType = new FunctionType_1.FunctionType(statement.func.returnType);
303
+ let functionType = statement.func.getFunctionType();
295
304
  functionType.setName(statement.name.text);
296
- functionType.isSub = statement.func.functionType.text.toLowerCase() === 'sub';
297
- if (functionType.isSub) {
298
- functionType.returnType = new VoidType_1.VoidType();
299
- }
300
- //extract the parameters
301
- let params = [];
302
- for (let param of statement.func.parameters) {
303
- let callableParam = {
304
- name: param.name.text,
305
- type: param.type,
306
- isOptional: !!param.defaultValue,
307
- isRestArgument: false
308
- };
309
- params.push(callableParam);
310
- let isRequired = !param.defaultValue;
311
- functionType.addParameter(callableParam.name, callableParam.type, isRequired);
312
- }
313
305
  this.callables.push({
314
306
  isSub: statement.func.functionType.text.toLowerCase() === 'sub',
315
307
  name: statement.name.text,
316
308
  nameRange: statement.name.range,
317
309
  file: this,
318
- params: params,
310
+ params: functionType.params,
319
311
  range: statement.func.range,
320
312
  type: functionType,
321
313
  getName: statement.getName.bind(statement),
@@ -325,21 +317,24 @@ class BrsFile {
325
317
  }
326
318
  }
327
319
  findFunctionCalls() {
320
+ var _a;
328
321
  this.functionCalls = [];
329
322
  //for every function in the file
330
323
  for (let func of this._parser.references.functionExpressions) {
331
324
  //for all function calls in this function
332
325
  for (let expression of func.callExpressions) {
333
326
  if (
334
- //filter out dotted function invocations (i.e. object.doSomething()) (not currently supported. TODO support it)
335
- expression.callee.obj ||
336
- //filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
337
- expression.callee.callee ||
327
+ //filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
328
+ expression.callee.callee ||
329
+ //filter out method calls on regexp literals for now
330
+ (0, reflection_1.isRegexLiteralExpression)((_a = expression.callee) === null || _a === void 0 ? void 0 : _a.obj) ||
338
331
  //filter out callees without a name (immediately-invoked function expressions)
339
332
  !expression.callee.name) {
340
333
  continue;
341
334
  }
342
- let functionName = expression.callee.name.text;
335
+ //Flag dotted function invocations (i.e. object.doSomething())
336
+ const dottedInvocation = expression.callee.obj;
337
+ let functionName = expression.callee.name;
343
338
  //callee is the name of the function being called
344
339
  let callee = expression.callee;
345
340
  let columnIndexBegin = callee.range.start.character;
@@ -347,7 +342,7 @@ class BrsFile {
347
342
  let args = [];
348
343
  //TODO convert if stmts to use instanceof instead
349
344
  for (let arg of expression.args) {
350
- let impliedType = parser_1.getBscTypeFromExpression(arg, func);
345
+ let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
351
346
  let argText = '';
352
347
  // Get the text to display for the arg
353
348
  if (arg.token) {
@@ -355,24 +350,28 @@ class BrsFile {
355
350
  //is a function call being passed into argument
356
351
  }
357
352
  else if (arg.name) {
358
- if (lexer_1.isToken(arg.name)) {
353
+ if ((0, Token_1.isToken)(arg.name)) {
359
354
  argText = arg.name.text;
360
355
  }
361
356
  }
362
357
  else if (arg.value) {
363
358
  /* istanbul ignore next: TODO figure out why value is undefined sometimes */
364
359
  if (arg.value.value) {
365
- argText = arg.value.value.toString();
360
+ if (arg.value.value.toString) {
361
+ argText = arg.value.value.toString();
362
+ }
366
363
  }
367
364
  //wrap the value in quotes because that's how it appears in the code
368
- if (reflection_1.isStringType(impliedType)) {
365
+ if (argText && (0, reflection_1.isStringType)(inferredType)) {
369
366
  argText = '"' + argText + '"';
370
367
  }
371
368
  }
372
369
  args.push({
373
370
  range: arg.range,
374
- type: impliedType,
375
- text: argText
371
+ type: inferredType,
372
+ text: argText,
373
+ expression: arg,
374
+ typeToken: undefined
376
375
  });
377
376
  }
378
377
  let functionCall = {
@@ -381,8 +380,8 @@ class BrsFile {
381
380
  file: this,
382
381
  name: functionName,
383
382
  nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
384
- //TODO keep track of parameters
385
- args: args
383
+ args: args,
384
+ isDottedInvocation: dottedInvocation
386
385
  };
387
386
  this.functionCalls.push(functionCall);
388
387
  }
@@ -408,10 +407,25 @@ class BrsFile {
408
407
  }
409
408
  }
410
409
  }
410
+ /**
411
+ * Find the NamespaceStatement enclosing the given position
412
+ * @param position
413
+ * @param functionScopes
414
+ */
415
+ getNamespaceStatementForPosition(position) {
416
+ if (position) {
417
+ for (const statement of this.parser.references.namespaceStatements) {
418
+ if (util_1.util.rangeContains(statement.range, position)) {
419
+ return statement;
420
+ }
421
+ }
422
+ }
423
+ }
411
424
  /**
412
425
  * Get completions available at the given cursor. This aggregates all values from this file and the current scope.
413
426
  */
414
427
  getCompletions(position, scope) {
428
+ var _a;
415
429
  let result = [];
416
430
  //a map of lower-case names of all added options
417
431
  let names = {};
@@ -421,12 +435,12 @@ class BrsFile {
421
435
  return this.program.getScriptImportCompletions(this.pkgPath, scriptImport);
422
436
  }
423
437
  //if cursor is within a comment, disable completions
424
- let currentToken = this.getTokenAt(position);
438
+ let currentToken = this.parser.getTokenAt(position);
425
439
  const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
426
- if (tokenKind === lexer_1.TokenKind.Comment) {
440
+ if (tokenKind === TokenKind_1.TokenKind.Comment) {
427
441
  return [];
428
442
  }
429
- else if (tokenKind === lexer_1.TokenKind.StringLiteral || tokenKind === lexer_1.TokenKind.TemplateStringQuasi) {
443
+ else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
430
444
  const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
431
445
  if (match) {
432
446
  const [, openingQuote, fileProtocol] = match;
@@ -450,43 +464,56 @@ class BrsFile {
450
464
  return [];
451
465
  }
452
466
  }
453
- let namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
467
+ const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
454
468
  if (namespaceCompletions.length > 0) {
455
- return namespaceCompletions;
469
+ return [...namespaceCompletions];
470
+ }
471
+ const enumMemberCompletions = this.getEnumMemberStatementCompletions(currentToken, this.parseMode, scope);
472
+ if (enumMemberCompletions.length > 0) {
473
+ // no other completion is valid in this case
474
+ return enumMemberCompletions;
456
475
  }
457
476
  //determine if cursor is inside a function
458
477
  let functionExpression = this.getFunctionExpressionAtPosition(position);
459
478
  if (!functionExpression) {
460
479
  //we aren't in any function scope, so return the keyword completions and namespaces
461
- if (this.getTokenBefore(currentToken, lexer_1.TokenKind.New)) {
480
+ if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
462
481
  // there's a new keyword, so only class types are viable here
463
- return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
482
+ return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope)];
464
483
  }
465
484
  else {
466
- return [...exports.KeywordCompletions, ...this.getGlobalClassStatementCompletions(currentToken, this.parseMode), ...namespaceCompletions];
467
- }
468
- }
469
- const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
470
- const newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
485
+ return [
486
+ ...exports.KeywordCompletions,
487
+ ...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope),
488
+ ...namespaceCompletions,
489
+ ...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope),
490
+ ...this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope)
491
+ ];
492
+ }
493
+ }
494
+ const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope);
495
+ const interfaceNameCompletions = this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope);
496
+ const newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
471
497
  if (newToken) {
472
- //we are after a new keyword; so we can only be namespaces or classes at this point
498
+ //we are after a new keyword; so we can only be top-level namespaces or classes at this point
473
499
  result.push(...classNameCompletions);
474
500
  result.push(...namespaceCompletions);
475
501
  return result;
476
502
  }
477
- if (this.tokenFollows(currentToken, lexer_1.TokenKind.Goto)) {
503
+ if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
478
504
  return this.getLabelCompletion(functionExpression);
479
505
  }
480
- if (this.isPositionNextToTokenKind(position, lexer_1.TokenKind.Dot)) {
481
- if (namespaceCompletions.length > 0) {
482
- //if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
483
- return namespaceCompletions;
484
- }
506
+ if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
485
507
  const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
486
508
  if (selfClassMemberCompletions.size > 0) {
487
509
  return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
488
510
  }
489
- if (!this.getClassFromMReference(position, currentToken, functionExpression)) {
511
+ const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
512
+ if ((_a = tokenLookup.symbolContainer) === null || _a === void 0 ? void 0 : _a.memberTable) {
513
+ return this.getCompletionsFromSymbolTable(tokenLookup.symbolContainer.memberTable);
514
+ }
515
+ const foundClassLink = this.getClassFromTokenLookup(tokenLookup, scope);
516
+ if (!foundClassLink) {
490
517
  //and anything from any class in scope to a non m class
491
518
  let classMemberCompletions = scope.getAllClassMemberCompletions();
492
519
  result.push(...classMemberCompletions.values());
@@ -501,6 +528,10 @@ class BrsFile {
501
528
  result.push(...namespaceCompletions);
502
529
  //include class names
503
530
  result.push(...classNameCompletions);
531
+ //include interfaces
532
+ result.push(...interfaceNameCompletions);
533
+ //include enums
534
+ result.push(...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope));
504
535
  //include the global callables
505
536
  result.push(...scope.getCallablesAsCompletions(this.parseMode));
506
537
  //add `m` because that's always valid within a function
@@ -511,22 +542,24 @@ class BrsFile {
511
542
  names.m = true;
512
543
  result.push(...exports.KeywordCompletions);
513
544
  //include local variables
514
- for (let symbol of functionExpression.symbolTable.ownSymbols) {
545
+ for (let symbol of functionExpression.symbolTable.getOwnSymbols()) {
515
546
  const symbolNameLower = symbol.name.toLowerCase();
516
547
  //skip duplicate variable names
517
548
  if (names[symbolNameLower]) {
518
549
  continue;
519
550
  }
520
551
  names[symbolNameLower] = true;
552
+ // TODO TYPES (This may be a performance hit?)
553
+ // const foundType = getTypeFromContext(symbol.type, { scope: scope, file: this });
521
554
  result.push({
522
555
  //TODO does this work?
523
556
  label: symbol.name,
524
- //TODO find type for local vars
557
+ //TODO TYPES find type for local vars - SEE above
525
558
  kind: vscode_languageserver_1.CompletionItemKind.Variable
526
- // kind: isFunctionType(variable.type) ? CompletionItemKind.Function : CompletionItemKind.Variable
559
+ // kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
527
560
  });
528
561
  }
529
- if (this.parseMode === parser_1.ParseMode.BrighterScript) {
562
+ if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
530
563
  //include the first part of namespaces
531
564
  let namespaces = scope.getAllNamespaceStatements();
532
565
  for (let stmt of namespaces) {
@@ -545,6 +578,14 @@ class BrsFile {
545
578
  }
546
579
  return result;
547
580
  }
581
+ getCompletionsFromSymbolTable(symbolTable) {
582
+ return symbolTable.getAllSymbols().map(bscType => {
583
+ return {
584
+ label: bscType.name,
585
+ kind: (0, reflection_1.isTypedFunctionType)(bscType.type) ? vscode_languageserver_1.CompletionItemKind.Method : vscode_languageserver_1.CompletionItemKind.Field
586
+ };
587
+ });
588
+ }
548
589
  getLabelCompletion(func) {
549
590
  return func.labelStatements.map(label => ({
550
591
  label: label.tokens.identifier.text,
@@ -552,17 +593,17 @@ class BrsFile {
552
593
  }));
553
594
  }
554
595
  getClassMemberCompletions(position, currentToken, functionExpression, scope) {
555
- var _a, _b;
556
- let classStatement = this.getClassFromMReference(position, currentToken, functionExpression);
596
+ var _a, _b, _c, _d;
597
+ let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
557
598
  let results = new Map();
558
599
  if (classStatement) {
559
- let classes = scope.getClassHierarchy(classStatement.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
600
+ let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
560
601
  for (let cs of classes) {
561
- for (let member of [...(_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields, ...(_b = cs === null || cs === void 0 ? void 0 : cs.item) === null || _b === void 0 ? void 0 : _b.methods]) {
602
+ 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 : []]) {
562
603
  if (!results.has(member.name.text.toLowerCase())) {
563
604
  results.set(member.name.text.toLowerCase(), {
564
605
  label: member.name.text,
565
- kind: reflection_1.isClassFieldStatement(member) ? vscode_languageserver_1.CompletionItemKind.Field : vscode_languageserver_1.CompletionItemKind.Function
606
+ kind: (0, reflection_1.isClassFieldStatement)(member) ? vscode_languageserver_1.CompletionItemKind.Field : vscode_languageserver_1.CompletionItemKind.Method
566
607
  });
567
608
  }
568
609
  }
@@ -570,69 +611,392 @@ class BrsFile {
570
611
  }
571
612
  return results;
572
613
  }
573
- getClassFromMReference(position, currentToken, functionExpression) {
574
- let previousToken = this.getPreviousToken(currentToken);
575
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot) {
576
- previousToken = this.getPreviousToken(previousToken);
614
+ /**
615
+ * Gets the class (if any) of a given token based on the scope
616
+ * @param currentToken token in question
617
+ * @param functionExpression current functionExpression
618
+ * @param scope the current scope
619
+ * @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
620
+ */
621
+ getClassFromToken(currentToken, functionExpression, scope) {
622
+ const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
623
+ return this.getClassFromTokenLookup(tokenLookup, scope);
624
+ }
625
+ /**
626
+ * Gets the class (if any) of a given token based on the scope
627
+ * @param currentToken token in question
628
+ * @param functionExpression current functionExpression
629
+ * @param scope the current scope
630
+ * @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
631
+ */
632
+ getClassFromTokenLookup(tokenLookup, scope) {
633
+ const currentClass = tokenLookup === null || tokenLookup === void 0 ? void 0 : tokenLookup.symbolContainer;
634
+ if ((0, reflection_1.isClassStatement)(currentClass)) {
635
+ return { item: currentClass, file: this };
577
636
  }
578
- 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' && reflection_1.isClassMethodStatement(functionExpression.functionStatement)) {
579
- return { item: this.parser.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, position)), file: this };
637
+ else if ((0, reflection_1.isCustomType)(currentClass)) {
638
+ const foundClass = scope.getClass(currentClass.name);
639
+ if (foundClass) {
640
+ return { item: foundClass, file: this };
641
+ }
580
642
  }
581
643
  return undefined;
582
644
  }
583
- getGlobalClassStatementCompletions(currentToken, parseMode) {
645
+ findNamespaceFromTokenChain(originalTokenChain, scope) {
646
+ let namespaceTokens = [];
647
+ let startsWithNamespace = '';
648
+ let namespaceContainer;
649
+ let tokenChain = [...originalTokenChain];
650
+ while (tokenChain[0] && tokenChain[0].usage === Parser_1.TokenUsage.Direct) {
651
+ const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
652
+ const foundNamespace = scope.namespaceLookup.get(namespaceNameToCheck);
653
+ if (foundNamespace) {
654
+ namespaceContainer = foundNamespace;
655
+ namespaceTokens.push(tokenChain[0].token);
656
+ startsWithNamespace = namespaceTokens.map(token => token.text).join('.');
657
+ tokenChain.shift();
658
+ }
659
+ else {
660
+ break;
661
+ }
662
+ }
663
+ if (namespaceTokens.length > 0) {
664
+ namespaceContainer = scope.namespaceLookup.get(startsWithNamespace.toLowerCase());
665
+ }
666
+ return { namespaceContainer: namespaceContainer, tokenChain: tokenChain };
667
+ }
668
+ checkForSpecialClassSymbol(currentToken, scope, func) {
669
+ var _a;
670
+ const containingClass = this.parser.getContainingClass(currentToken);
671
+ let symbolType;
672
+ let currentClassRef;
673
+ const currentTokenLower = currentToken.text.toLowerCase();
674
+ const typeContext = { file: this, scope: scope, position: currentToken.range.start };
675
+ if (containingClass) {
676
+ // Special cases for a single token inside a class
677
+ let expandedText = '';
678
+ let useExpandedTextOnly = false;
679
+ if (containingClass.name === currentToken) {
680
+ symbolType = containingClass.getThisBscType();
681
+ expandedText = `class ${containingClass.getName(Parser_1.ParseMode.BrighterScript)}`;
682
+ useExpandedTextOnly = true;
683
+ currentClassRef = containingClass;
684
+ }
685
+ else if (currentTokenLower === 'm') {
686
+ symbolType = containingClass.getThisBscType();
687
+ expandedText = currentToken.text;
688
+ currentClassRef = containingClass;
689
+ }
690
+ else if (currentTokenLower === 'super') {
691
+ symbolType = (0, BscType_1.getTypeFromContext)(containingClass.symbolTable.getSymbolType(currentTokenLower, true, typeContext), typeContext);
692
+ if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
693
+ currentClassRef = scope.getParentClass(containingClass);
694
+ }
695
+ }
696
+ else if (((_a = func === null || func === void 0 ? void 0 : func.functionStatement) === null || _a === void 0 ? void 0 : _a.name) === currentToken) {
697
+ // check if this is a method declaration
698
+ currentClassRef = containingClass;
699
+ symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
700
+ expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
701
+ }
702
+ else if (!func) {
703
+ // check if this is a field declaration
704
+ currentClassRef = containingClass;
705
+ symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
706
+ expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
707
+ }
708
+ if (symbolType) {
709
+ return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
710
+ }
711
+ }
712
+ }
713
+ checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope) {
714
+ var _a;
715
+ const tokenChain = (_a = nameSpacedTokenChain.tokenChain) !== null && _a !== void 0 ? _a : [];
716
+ if (nameSpacedTokenChain.namespaceContainer && tokenChain.length === 0) {
717
+ //currentToken was part of a namespace
718
+ return {
719
+ type: null,
720
+ expandedTokenText: `namespace ${nameSpacedTokenChain.namespaceContainer.fullName}`,
721
+ useExpandedTextOnly: true
722
+ };
723
+ }
724
+ const specialCase = tokenChain.length === 1 ? this.checkForSpecialClassSymbol(tokenChain[0].token, scope, functionExpression) : null;
725
+ if (specialCase) {
726
+ return specialCase;
727
+ }
728
+ }
729
+ /**
730
+ * Checks previous tokens for the start of a symbol chain (eg. m.property.subProperty.method())
731
+ * @param currentToken The token to check
732
+ * @param functionExpression The current function context
733
+ * @param scope use this scope for finding class maps
734
+ * @returns the BscType, expanded text (e.g <Class.field>) and classStatement (if available) for the token
735
+ */
736
+ getSymbolTypeFromToken(currentToken, functionExpression, scope) {
737
+ var _a, _b, _c, _d, _e;
738
+ if (!scope || !currentToken) {
739
+ return undefined;
740
+ }
741
+ const cachedSymbolData = scope.symbolCache.get(currentToken);
742
+ if (cachedSymbolData) {
743
+ return cachedSymbolData;
744
+ }
745
+ const tokenChainResponse = this.parser.getTokenChain(currentToken);
746
+ if (tokenChainResponse.includesUnknowableTokenType) {
747
+ const symbolData = { type: new DynamicType_1.DynamicType(), expandedTokenText: currentToken.text };
748
+ scope.symbolCache.set(currentToken, symbolData);
749
+ return symbolData;
750
+ }
751
+ const nameSpacedTokenChain = this.findNamespaceFromTokenChain(tokenChainResponse.chain, scope);
752
+ const specialCase = this.checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope);
753
+ if (specialCase) {
754
+ scope.symbolCache.set(currentToken, specialCase);
755
+ return specialCase;
756
+ }
757
+ const tokenChain = nameSpacedTokenChain.tokenChain;
758
+ let symbolContainer = this.parser.getContainingAA(currentToken) || this.parser.getContainingClass(currentToken);
759
+ let currentSymbolTable = (_b = (_a = nameSpacedTokenChain.namespaceContainer) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : functionExpression === null || functionExpression === void 0 ? void 0 : functionExpression.symbolTable;
760
+ let tokenFoundCount = 0;
761
+ let symbolTypeBeforeReference;
762
+ let symbolType;
763
+ let tokenText = [];
764
+ let justReturnDynamic = false;
765
+ const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
766
+ for (const tokenChainMember of tokenChain) {
767
+ const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
768
+ const tokenUsage = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.usage;
769
+ const tokenLowerText = token.text.toLowerCase();
770
+ if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
771
+ /// Special cases for first item in chain inside a class
772
+ symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
773
+ currentSymbolTable = (_d = symbolContainer) === null || _d === void 0 ? void 0 : _d.memberTable;
774
+ if (symbolContainer && currentSymbolTable) {
775
+ tokenText.push(symbolContainer.getName(Parser_1.ParseMode.BrighterScript));
776
+ tokenFoundCount++;
777
+ continue;
778
+ }
779
+ }
780
+ if (!currentSymbolTable) {
781
+ // uh oh... no symbol table to continue to check
782
+ break;
783
+ }
784
+ symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
785
+ if (tokenFoundCount === 0 && !symbolType) {
786
+ //check for global callable
787
+ symbolType = (_e = scope.getGlobalCallableByName(tokenLowerText)) === null || _e === void 0 ? void 0 : _e.type;
788
+ }
789
+ if (symbolType) {
790
+ // found this symbol, and it's valid. increase found counter
791
+ tokenFoundCount++;
792
+ }
793
+ symbolTypeBeforeReference = symbolType;
794
+ if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
795
+ // this is a function, and it is in the start or middle of the chain
796
+ // the next symbol to check will be the return value of this function
797
+ symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
798
+ if (tokenFoundCount < tokenChain.length) {
799
+ // We still have more tokens, but remember the last known reference
800
+ symbolTypeBeforeReference = symbolType;
801
+ }
802
+ }
803
+ if ((0, reflection_1.isArrayType)(symbolType) && tokenUsage === Parser_1.TokenUsage.ArrayReference) {
804
+ symbolType = (0, BscType_1.getTypeFromContext)(symbolType.getDefaultType(typeContext), typeContext);
805
+ }
806
+ if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
807
+ if ((0, reflection_1.isCustomType)(symbolType) || (0, reflection_1.isInterfaceType)(symbolType)) {
808
+ // we're currently looking at a customType or interface, that has it's own symbol table
809
+ // use the name of the custom type
810
+ // TODO TYPES: get proper parent name for methods/fields defined in super classes
811
+ tokenText.push(tokenChain.length === 1 ? token.text : symbolType.name);
812
+ }
813
+ else {
814
+ justReturnDynamic = true;
815
+ tokenText.push(token.text);
816
+ }
817
+ symbolContainer = symbolType;
818
+ currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
819
+ }
820
+ else if ((0, reflection_1.isObjectType)(symbolType) || (0, reflection_1.isArrayType)(symbolType) || (0, reflection_1.isDynamicType)(symbolType)) {
821
+ // this is an object that has no member table
822
+ // this could happen if a parameter is marked as object
823
+ // assume all fields are dynamic
824
+ symbolContainer = undefined;
825
+ tokenText.push(token.text);
826
+ justReturnDynamic = true;
827
+ break;
828
+ }
829
+ else {
830
+ // No further symbol tables were found
831
+ symbolContainer = undefined;
832
+ tokenText.push(token.text);
833
+ break;
834
+ }
835
+ }
836
+ if (tokenText.length > 2) {
837
+ // TokenText is used for hovers. We only need the last two tokens for a hover
838
+ // So in a long chain (e.g. klass.getData()[0].anotherKlass.property), the hover
839
+ // for the last token should just be "AnotherKlass.property", not the whole chain
840
+ tokenText = tokenText.slice(-2);
841
+ }
842
+ let expandedTokenText = tokenText.join('.');
843
+ let backUpReturnType;
844
+ if (tokenFoundCount === tokenChain.length) {
845
+ // did we complete the chain? if so, we have a valid token at the end
846
+ const symbolData = { type: symbolTypeBeforeReference, expandedTokenText: tokenText.join('.'), symbolContainer: symbolContainer };
847
+ scope.symbolCache.set(currentToken, symbolData);
848
+ return symbolData;
849
+ }
850
+ if ((0, reflection_1.isDynamicType)(symbolTypeBeforeReference) || (0, reflection_1.isArrayType)(symbolTypeBeforeReference) || justReturnDynamic) {
851
+ // last type in chain is dynamic... so currentToken could be anything.
852
+ backUpReturnType = new DynamicType_1.DynamicType();
853
+ expandedTokenText = currentToken.text;
854
+ }
855
+ else if ((0, reflection_1.isPrimitiveType)(symbolTypeBeforeReference)) {
856
+ // last type in chain is dynamic... so currentToken could be anything.
857
+ backUpReturnType = new DynamicType_1.DynamicType();
858
+ expandedTokenText = currentToken.text;
859
+ }
860
+ else if (tokenChain.length === 1) {
861
+ // variable that has not been assigned
862
+ expandedTokenText = currentToken.text;
863
+ backUpReturnType = new UninitializedType_1.UninitializedType();
864
+ }
865
+ else if (tokenFoundCount === tokenChain.length - 1) {
866
+ // member field that is not known
867
+ if (symbolContainer) {
868
+ backUpReturnType = new InvalidType_1.InvalidType();
869
+ }
870
+ else {
871
+ // TODO TYPES: once we have stricter object/node member type checking, we could say this is invalid, but until then, call it dynamic
872
+ backUpReturnType = new DynamicType_1.DynamicType();
873
+ expandedTokenText = currentToken.text;
874
+ }
875
+ }
876
+ const symbolData = { type: backUpReturnType, expandedTokenText: expandedTokenText };
877
+ scope.symbolCache.set(currentToken, symbolData);
878
+ return symbolData;
879
+ }
880
+ getGlobalClassStatementCompletions(currentToken, parseMode, scope) {
584
881
  var _a;
585
- if (parseMode === parser_1.ParseMode.BrightScript) {
882
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
586
883
  return [];
587
884
  }
588
885
  let results = new Map();
589
- let completionName = (_a = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
886
+ let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
590
887
  if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
591
888
  return [];
592
889
  }
593
- let scopes = this.program.getScopesForFile(this);
594
- for (let scope of scopes) {
595
- let classMap = scope.getClassMap();
596
- // let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
597
- for (const key of [...classMap.keys()]) {
598
- let cs = classMap.get(key).item;
599
- if (!results.has(cs.name.text)) {
600
- results.set(cs.name.text, {
601
- label: cs.name.text,
602
- kind: vscode_languageserver_1.CompletionItemKind.Class
603
- });
604
- }
890
+ let classMap = scope.getClassMap();
891
+ // let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
892
+ for (const key of [...classMap.keys()]) {
893
+ let cs = classMap.get(key).item;
894
+ if (!results.has(cs.name.text)) {
895
+ results.set(cs.name.text, {
896
+ label: cs.name.text,
897
+ kind: vscode_languageserver_1.CompletionItemKind.Class
898
+ });
899
+ }
900
+ }
901
+ return [...results.values()];
902
+ }
903
+ getNonNamespacedEnumStatementCompletions(currentToken, parseMode, scope) {
904
+ var _a, _b;
905
+ if (parseMode !== Parser_1.ParseMode.BrighterScript) {
906
+ return [];
907
+ }
908
+ const containingNamespaceName = ((_b = this.getNamespaceStatementForPosition((_a = currentToken === null || currentToken === void 0 ? void 0 : currentToken.range) === null || _a === void 0 ? void 0 : _a.start)) === null || _b === void 0 ? void 0 : _b.name) + '.';
909
+ const results = new Map();
910
+ const enumMap = scope.getEnumMap();
911
+ for (const key of [...enumMap.keys()]) {
912
+ const enumStatement = enumMap.get(key).item;
913
+ const fullName = enumStatement.fullName;
914
+ //if the enum is contained within our own namespace, or if it's a non-namespaced enum
915
+ if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
916
+ results.set(fullName, {
917
+ label: enumStatement.name,
918
+ kind: vscode_languageserver_1.CompletionItemKind.Enum
919
+ });
920
+ }
921
+ }
922
+ return [...results.values()];
923
+ }
924
+ getEnumMemberStatementCompletions(currentToken, parseMode, scope) {
925
+ var _a, _b, _c, _d, _e;
926
+ if (parseMode === Parser_1.ParseMode.BrightScript || !currentToken) {
927
+ return [];
928
+ }
929
+ const results = new Map();
930
+ const completionName = (_a = this.getPartialVariableName(currentToken)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
931
+ //if we don't have a completion name, or if there's no period in the name, then this is not to the right of an enum name
932
+ if (!completionName || !completionName.includes('.')) {
933
+ return [];
934
+ }
935
+ const enumNameLower = (_b = completionName === null || completionName === void 0 ? void 0 : completionName.split(/\.(\w+)?$/)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
936
+ const namespaceNameLower = (_c = this.getNamespaceStatementForPosition(currentToken.range.end)) === null || _c === void 0 ? void 0 : _c.name.toLowerCase();
937
+ const enumMap = scope.getEnumMap();
938
+ //get the enum statement with this name (check without namespace prefix first, then with inferred namespace prefix next)
939
+ const enumStatement = (_e = ((_d = enumMap.get(enumNameLower)) !== null && _d !== void 0 ? _d : enumMap.get(namespaceNameLower + '.' + enumNameLower))) === null || _e === void 0 ? void 0 : _e.item;
940
+ //if we found an enum with this name
941
+ if (enumStatement) {
942
+ for (const member of enumStatement.getMembers()) {
943
+ const name = enumStatement.fullName + '.' + member.name;
944
+ const nameLower = name.toLowerCase();
945
+ results.set(nameLower, {
946
+ label: member.name,
947
+ kind: vscode_languageserver_1.CompletionItemKind.EnumMember
948
+ });
949
+ }
950
+ }
951
+ return [...results.values()];
952
+ }
953
+ getGlobalInterfaceStatementCompletions(currentToken, parseMode, scope) {
954
+ var _a;
955
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
956
+ return [];
957
+ }
958
+ let results = new Map();
959
+ let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
960
+ if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
961
+ return [];
962
+ }
963
+ let ifaceMap = scope.getInterfaceMap();
964
+ for (const key of [...ifaceMap.keys()]) {
965
+ let cs = ifaceMap.get(key).item;
966
+ if (!results.has(cs.name.text)) {
967
+ results.set(cs.name.text, {
968
+ label: cs.name.text,
969
+ kind: vscode_languageserver_1.CompletionItemKind.Interface
970
+ });
605
971
  }
606
972
  }
607
973
  return [...results.values()];
608
974
  }
609
975
  getNamespaceCompletions(currentToken, parseMode, scope) {
610
976
  //BrightScript does not support namespaces, so return an empty list in that case
611
- if (parseMode === parser_1.ParseMode.BrightScript) {
977
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
612
978
  return [];
613
979
  }
614
- let completionName = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
615
- if (!completionName) {
980
+ const completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
981
+ //if we don't have a completion name, or if there's no period in the name, then this is not a namespaced variable
982
+ if (!completionName || !completionName.includes('.')) {
616
983
  return [];
617
984
  }
618
985
  //remove any trailing identifer and then any trailing dot, to give us the
619
986
  //name of its immediate parent namespace
620
- let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
621
- let newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
622
- let namespaceLookup = scope.namespaceLookup;
987
+ let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
988
+ let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
623
989
  let result = new Map();
624
- for (let key in namespaceLookup) {
625
- let namespace = namespaceLookup[key.toLowerCase()];
990
+ for (let [, namespace] of scope.namespaceLookup) {
626
991
  //completionName = "NameA."
627
992
  //completionName = "NameA.Na
628
993
  //NameA
629
994
  //NameA.NameB
630
995
  //NameA.NameB.NameC
631
- if (namespace.fullName.toLowerCase() === closestParentNamespaceName.toLowerCase()) {
996
+ if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
632
997
  //add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
633
- for (let childKey in namespace.namespaces) {
634
- const ns = namespace.namespaces[childKey];
635
- if (!newToken || ns.statements.find((s) => reflection_1.isClassStatement(s))) {
998
+ for (let [, ns] of namespace.namespaces) {
999
+ if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
636
1000
  if (!result.has(ns.lastPartName)) {
637
1001
  result.set(ns.lastPartName, {
638
1002
  label: ns.lastPartName,
@@ -643,21 +1007,23 @@ class BrsFile {
643
1007
  }
644
1008
  //add function and class statement completions
645
1009
  for (let stmt of namespace.statements) {
646
- if (reflection_1.isClassStatement(stmt)) {
647
- if (!result.has(stmt.name.text)) {
648
- result.set(stmt.name.text, {
649
- label: stmt.name.text,
650
- kind: vscode_languageserver_1.CompletionItemKind.Class
651
- });
652
- }
1010
+ if ((0, reflection_1.isClassStatement)(stmt)) {
1011
+ result.set(stmt.name.text, {
1012
+ label: stmt.name.text,
1013
+ kind: vscode_languageserver_1.CompletionItemKind.Class
1014
+ });
653
1015
  }
654
- else if (reflection_1.isFunctionStatement(stmt) && !newToken) {
655
- if (!result.has(stmt.name.text)) {
656
- result.set(stmt.name.text, {
657
- label: stmt.name.text,
658
- kind: vscode_languageserver_1.CompletionItemKind.Function
659
- });
660
- }
1016
+ else if ((0, reflection_1.isFunctionStatement)(stmt) && !newToken) {
1017
+ result.set(stmt.name.text, {
1018
+ label: stmt.name.text,
1019
+ kind: vscode_languageserver_1.CompletionItemKind.Function
1020
+ });
1021
+ }
1022
+ else if ((0, reflection_1.isEnumStatement)(stmt) && !newToken) {
1023
+ result.set(stmt.name, {
1024
+ label: stmt.name,
1025
+ kind: vscode_languageserver_1.CompletionItemKind.Enum
1026
+ });
661
1027
  }
662
1028
  }
663
1029
  }
@@ -670,18 +1036,18 @@ class BrsFile {
670
1036
  return undefined;
671
1037
  }
672
1038
  let location;
673
- const nameParts = this.getPartialVariableName(token, [lexer_1.TokenKind.New]).split('.');
1039
+ const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
674
1040
  const endName = nameParts[nameParts.length - 1].toLowerCase();
675
1041
  const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
676
1042
  const statementHandler = (statement) => {
677
- if (!location && statement.getName(parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
1043
+ if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
678
1044
  const namespaceItemStatementHandler = (statement) => {
679
1045
  if (!location && statement.name.text.toLowerCase() === endName) {
680
1046
  const uri = util_1.util.pathToUri(file.srcPath);
681
1047
  location = vscode_languageserver_1.Location.create(uri, statement.range);
682
1048
  }
683
1049
  };
684
- file.parser.ast.walk(visitors_1.createVisitor({
1050
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
685
1051
  ClassStatement: namespaceItemStatementHandler,
686
1052
  FunctionStatement: namespaceItemStatementHandler
687
1053
  }), {
@@ -689,7 +1055,7 @@ class BrsFile {
689
1055
  });
690
1056
  }
691
1057
  };
692
- file.parser.ast.walk(visitors_1.createVisitor({
1058
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
693
1059
  NamespaceStatement: statementHandler
694
1060
  }), {
695
1061
  walkMode: visitors_1.WalkMode.visitStatements
@@ -700,7 +1066,7 @@ class BrsFile {
700
1066
  * Given a current token, walk
701
1067
  */
702
1068
  getPartialVariableName(currentToken, excludeTokens = null) {
703
- let identifierAndDotKinds = [lexer_1.TokenKind.Identifier, ...lexer_1.AllowedLocalIdentifiers, lexer_1.TokenKind.Dot];
1069
+ let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
704
1070
  //consume tokens backwards until we find something other than a dot or an identifier
705
1071
  let tokens = [];
706
1072
  const parser = this.parser;
@@ -721,79 +1087,21 @@ class BrsFile {
721
1087
  return undefined;
722
1088
  }
723
1089
  }
724
- isPositionNextToTokenKind(position, tokenKind) {
725
- const closestToken = this.getClosestToken(position);
726
- const previousToken = this.getPreviousToken(closestToken);
727
- const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
728
- //next to matched token
729
- if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
730
- return false;
731
- }
732
- else if (closestToken.kind === tokenKind) {
733
- return true;
734
- }
735
- else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
736
- return false;
737
- //next to an identifier, which is next to token kind
738
- }
739
- else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
740
- return true;
741
- }
742
- else {
743
- return false;
744
- }
745
- }
746
- getTokenBefore(currentToken, tokenKind) {
747
- const index = this.parser.tokens.indexOf(currentToken);
748
- for (let i = index - 1; i >= 0; i--) {
749
- currentToken = this.parser.tokens[i];
750
- if (currentToken.kind === lexer_1.TokenKind.Newline) {
751
- break;
752
- }
753
- else if (currentToken.kind === tokenKind) {
754
- return currentToken;
755
- }
756
- }
757
- return undefined;
758
- }
759
- tokenFollows(currentToken, tokenKind) {
760
- const index = this.parser.tokens.indexOf(currentToken);
761
- if (index > 0) {
762
- return this.parser.tokens[index - 1].kind === tokenKind;
763
- }
764
- return false;
765
- }
766
- getTokensUntil(currentToken, tokenKind, direction = -1) {
767
- let tokens = [];
768
- for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
769
- currentToken = this.parser.tokens[i];
770
- if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
771
- break;
772
- }
773
- tokens.push(currentToken);
774
- }
775
- return tokens;
776
- }
777
- getPreviousToken(token) {
778
- const parser = this.parser;
779
- let idx = parser.tokens.indexOf(token);
780
- return parser.tokens[idx - 1];
781
- }
782
1090
  /**
783
1091
  * Find the first scope that has a namespace with this name.
784
1092
  * Returns false if no namespace was found with that name
785
1093
  */
786
1094
  calleeStartsWithNamespace(callee) {
787
1095
  let left = callee;
788
- while (reflection_1.isDottedGetExpression(left)) {
1096
+ while ((0, reflection_1.isDottedGetExpression)(left)) {
789
1097
  left = left.obj;
790
1098
  }
791
- if (reflection_1.isVariableExpression(left)) {
1099
+ if ((0, reflection_1.isVariableExpression)(left)) {
792
1100
  let lowerName = left.name.text.toLowerCase();
793
1101
  //find the first scope that contains this namespace
794
1102
  let scopes = this.program.getScopesForFile(this);
795
1103
  for (let scope of scopes) {
796
- if (scope.namespaceLookup[lowerName]) {
1104
+ if (scope.namespaceLookup.has(lowerName)) {
797
1105
  return true;
798
1106
  }
799
1107
  }
@@ -806,12 +1114,12 @@ class BrsFile {
806
1114
  calleeIsKnownNamespaceFunction(callee, namespaceName) {
807
1115
  var _a, _b;
808
1116
  //if we have a variable and a namespace
809
- if (reflection_1.isVariableExpression(callee) && namespaceName) {
1117
+ if ((0, reflection_1.isVariableExpression)(callee) && namespaceName) {
810
1118
  let lowerCalleeName = (_b = (_a = callee === null || callee === void 0 ? void 0 : callee.name) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.toLowerCase();
811
1119
  if (lowerCalleeName) {
812
1120
  let scopes = this.program.getScopesForFile(this);
813
1121
  for (let scope of scopes) {
814
- let namespace = scope.namespaceLookup[namespaceName.toLowerCase()];
1122
+ let namespace = scope.namespaceLookup.get(namespaceName.toLowerCase());
815
1123
  if (namespace.functionStatements[lowerCalleeName]) {
816
1124
  return true;
817
1125
  }
@@ -820,28 +1128,6 @@ class BrsFile {
820
1128
  }
821
1129
  return false;
822
1130
  }
823
- /**
824
- * Get the token closest to the position. if no token is found, the previous token is returned
825
- * @param position
826
- * @param tokens
827
- */
828
- getClosestToken(position) {
829
- let tokens = this.parser.tokens;
830
- for (let i = 0; i < tokens.length; i++) {
831
- let token = tokens[i];
832
- if (util_1.util.rangeContains(token.range, position)) {
833
- return token;
834
- }
835
- //if the position less than this token range, then this position touches no token,
836
- if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
837
- let t = tokens[i - 1];
838
- //return the token or the first token
839
- return t ? t : tokens[0];
840
- }
841
- }
842
- //return the last token
843
- return tokens[tokens.length - 1];
844
- }
845
1131
  /**
846
1132
  * Builds a list of document symbols for this file. Used by LanguageServer's onDocumentSymbol functionality
847
1133
  */
@@ -881,16 +1167,16 @@ class BrsFile {
881
1167
  getDocumentSymbol(statement) {
882
1168
  let symbolKind;
883
1169
  const children = [];
884
- if (reflection_1.isFunctionStatement(statement)) {
1170
+ if ((0, reflection_1.isFunctionStatement)(statement)) {
885
1171
  symbolKind = vscode_languageserver_1.SymbolKind.Function;
886
1172
  }
887
- else if (reflection_1.isClassMethodStatement(statement)) {
1173
+ else if ((0, reflection_1.isClassMethodStatement)(statement)) {
888
1174
  symbolKind = vscode_languageserver_1.SymbolKind.Method;
889
1175
  }
890
- else if (reflection_1.isClassFieldStatement(statement)) {
1176
+ else if ((0, reflection_1.isClassFieldStatement)(statement)) {
891
1177
  symbolKind = vscode_languageserver_1.SymbolKind.Field;
892
1178
  }
893
- else if (reflection_1.isNamespaceStatement(statement)) {
1179
+ else if ((0, reflection_1.isNamespaceStatement)(statement)) {
894
1180
  symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
895
1181
  for (const childStatement of statement.body.statements) {
896
1182
  const symbol = this.getDocumentSymbol(childStatement);
@@ -899,7 +1185,7 @@ class BrsFile {
899
1185
  }
900
1186
  }
901
1187
  }
902
- else if (reflection_1.isClassStatement(statement)) {
1188
+ else if ((0, reflection_1.isClassStatement)(statement)) {
903
1189
  symbolKind = vscode_languageserver_1.SymbolKind.Class;
904
1190
  for (const childStatement of statement.body) {
905
1191
  const symbol = this.getDocumentSymbol(childStatement);
@@ -911,7 +1197,7 @@ class BrsFile {
911
1197
  else {
912
1198
  return;
913
1199
  }
914
- const name = reflection_1.isClassFieldStatement(statement) ? statement.name.text : statement.getName(parser_1.ParseMode.BrighterScript);
1200
+ const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
915
1201
  return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
916
1202
  }
917
1203
  /**
@@ -920,13 +1206,13 @@ class BrsFile {
920
1206
  generateWorkspaceSymbols(statement, containerStatement) {
921
1207
  let symbolKind;
922
1208
  const symbols = [];
923
- if (reflection_1.isFunctionStatement(statement)) {
1209
+ if ((0, reflection_1.isFunctionStatement)(statement)) {
924
1210
  symbolKind = vscode_languageserver_1.SymbolKind.Function;
925
1211
  }
926
- else if (reflection_1.isClassMethodStatement(statement)) {
1212
+ else if ((0, reflection_1.isClassMethodStatement)(statement)) {
927
1213
  symbolKind = vscode_languageserver_1.SymbolKind.Method;
928
1214
  }
929
- else if (reflection_1.isNamespaceStatement(statement)) {
1215
+ else if ((0, reflection_1.isNamespaceStatement)(statement)) {
930
1216
  symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
931
1217
  for (const childStatement of statement.body.statements) {
932
1218
  for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
@@ -934,7 +1220,7 @@ class BrsFile {
934
1220
  }
935
1221
  }
936
1222
  }
937
- else if (reflection_1.isClassStatement(statement)) {
1223
+ else if ((0, reflection_1.isClassStatement)(statement)) {
938
1224
  symbolKind = vscode_languageserver_1.SymbolKind.Class;
939
1225
  for (const childStatement of statement.body) {
940
1226
  for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
@@ -945,9 +1231,9 @@ class BrsFile {
945
1231
  else {
946
1232
  return symbols;
947
1233
  }
948
- const name = statement.getName(parser_1.ParseMode.BrighterScript);
1234
+ const name = statement.getName(Parser_1.ParseMode.BrighterScript);
949
1235
  const uri = util_1.util.pathToUri(this.srcPath);
950
- 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));
1236
+ 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));
951
1237
  symbols.push(symbol);
952
1238
  return symbols;
953
1239
  }
@@ -958,19 +1244,19 @@ class BrsFile {
958
1244
  getDefinition(position) {
959
1245
  let results = [];
960
1246
  //get the token at the position
961
- const token = this.getTokenAt(position);
1247
+ const token = this.parser.getTokenAt(position);
962
1248
  // 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
963
1249
  let definitionTokenTypes = [
964
- lexer_1.TokenKind.Identifier,
965
- lexer_1.TokenKind.StringLiteral
1250
+ TokenKind_1.TokenKind.Identifier,
1251
+ TokenKind_1.TokenKind.StringLiteral
966
1252
  ];
967
1253
  //throw out invalid tokens and the wrong kind of tokens
968
1254
  if (!token || !definitionTokenTypes.includes(token.kind)) {
969
1255
  return results;
970
1256
  }
971
1257
  let textToSearchFor = token.text.toLowerCase();
972
- const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
973
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Callfunc) {
1258
+ const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
1259
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
974
1260
  for (const scope of this.program.getScopes()) {
975
1261
  //to only get functions defined in interface methods
976
1262
  const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
@@ -980,7 +1266,7 @@ class BrsFile {
980
1266
  }
981
1267
  return results;
982
1268
  }
983
- let classToken = this.getTokenBefore(token, lexer_1.TokenKind.Class);
1269
+ let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
984
1270
  if (classToken) {
985
1271
  let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
986
1272
  if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
@@ -992,7 +1278,7 @@ class BrsFile {
992
1278
  }
993
1279
  return results;
994
1280
  }
995
- if (token.kind === lexer_1.TokenKind.StringLiteral) {
1281
+ if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
996
1282
  // We need to strip off the quotes but only if present
997
1283
  const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
998
1284
  let endIndex = textToSearchFor.length;
@@ -1002,20 +1288,22 @@ class BrsFile {
1002
1288
  textToSearchFor = textToSearchFor.substring(startIndex, endIndex);
1003
1289
  }
1004
1290
  const func = this.getFunctionExpressionAtPosition(position);
1005
- //look through local variables first
1006
- //find any variable with this name
1007
- for (const symbol of func.symbolTable.ownSymbols) {
1008
- //we found a variable declaration with this token text
1009
- if (symbol.name.toLowerCase() === textToSearchFor) {
1010
- const uri = util_1.util.pathToUri(this.srcPath);
1011
- results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
1012
- }
1013
- }
1014
- if (this.tokenFollows(token, lexer_1.TokenKind.Goto)) {
1015
- for (const label of func.labelStatements) {
1016
- if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
1291
+ if (func) {
1292
+ //look through local variables first
1293
+ //find any variable with this name
1294
+ for (const symbol of func.symbolTable.getOwnSymbols()) {
1295
+ //we found a variable declaration with this token text
1296
+ if (symbol.name.toLowerCase() === textToSearchFor) {
1017
1297
  const uri = util_1.util.pathToUri(this.srcPath);
1018
- results.push(vscode_languageserver_1.Location.create(uri, label.tokens.identifier.range));
1298
+ results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
1299
+ }
1300
+ }
1301
+ if (this.parser.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
1302
+ for (const label of func.labelStatements) {
1303
+ if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
1304
+ const uri = util_1.util.pathToUri(this.srcPath);
1305
+ results.push(vscode_languageserver_1.Location.create(uri, label.tokens.identifier.range));
1306
+ }
1019
1307
  }
1020
1308
  }
1021
1309
  }
@@ -1023,11 +1311,11 @@ class BrsFile {
1023
1311
  //look through all files in scope for matches
1024
1312
  for (const scope of this.program.getScopesForFile(this)) {
1025
1313
  for (const file of scope.getAllFiles()) {
1026
- if (reflection_1.isXmlFile(file) || filesSearched.has(file)) {
1314
+ if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
1027
1315
  continue;
1028
1316
  }
1029
1317
  filesSearched.add(file);
1030
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot && file.parseMode === parser_1.ParseMode.BrighterScript) {
1318
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1031
1319
  results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1032
1320
  const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1033
1321
  if (namespaceDefinition) {
@@ -1040,7 +1328,7 @@ class BrsFile {
1040
1328
  results.push(vscode_languageserver_1.Location.create(uri, statement.range));
1041
1329
  }
1042
1330
  };
1043
- file.parser.ast.walk(visitors_1.createVisitor({
1331
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
1044
1332
  FunctionStatement: statementHandler
1045
1333
  }), {
1046
1334
  walkMode: visitors_1.WalkMode.visitStatements
@@ -1062,7 +1350,7 @@ class BrsFile {
1062
1350
  results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), statement.range));
1063
1351
  }
1064
1352
  };
1065
- file.parser.ast.walk(visitors_1.createVisitor({
1353
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
1066
1354
  ClassMethodStatement: statementHandler,
1067
1355
  ClassFieldStatement: fieldStatementHandler
1068
1356
  }), {
@@ -1071,15 +1359,16 @@ class BrsFile {
1071
1359
  return results;
1072
1360
  }
1073
1361
  getHover(position) {
1074
- var _a;
1362
+ var _a, _b, _c;
1363
+ const fence = (code) => util_1.util.mdFence(code, 'brightscript');
1075
1364
  //get the token at the position
1076
- let token = this.getTokenAt(position);
1365
+ let token = this.parser.getTokenAt(position);
1077
1366
  let hoverTokenTypes = [
1078
- lexer_1.TokenKind.Identifier,
1079
- lexer_1.TokenKind.Function,
1080
- lexer_1.TokenKind.EndFunction,
1081
- lexer_1.TokenKind.Sub,
1082
- lexer_1.TokenKind.EndSub
1367
+ TokenKind_1.TokenKind.Identifier,
1368
+ TokenKind_1.TokenKind.Function,
1369
+ TokenKind_1.TokenKind.EndFunction,
1370
+ TokenKind_1.TokenKind.Sub,
1371
+ TokenKind_1.TokenKind.EndSub
1083
1372
  ];
1084
1373
  //throw out invalid tokens and the wrong kind of tokens
1085
1374
  if (!token || !hoverTokenTypes.includes(token.kind)) {
@@ -1089,63 +1378,114 @@ class BrsFile {
1089
1378
  //look through local variables first
1090
1379
  {
1091
1380
  const func = this.getFunctionExpressionAtPosition(position);
1092
- for (const labelStatement of func.labelStatements) {
1093
- if (labelStatement.tokens.identifier.text.toLocaleLowerCase() === lowerTokenText) {
1094
- return {
1095
- range: token.range,
1096
- contents: `${labelStatement.tokens.identifier.text}: label`
1097
- };
1381
+ if (func) {
1382
+ // this identifier could possibly be a class field, so no function expression is available
1383
+ for (const labelStatement of (_a = func === null || func === void 0 ? void 0 : func.labelStatements) !== null && _a !== void 0 ? _a : []) {
1384
+ if (labelStatement.tokens.identifier.text.toLocaleLowerCase() === lowerTokenText) {
1385
+ return {
1386
+ range: token.range,
1387
+ contents: `${labelStatement.tokens.identifier.text}: label`
1388
+ };
1389
+ }
1098
1390
  }
1099
1391
  }
1100
- const typeTexts = [];
1101
- for (const scope of this.program.getScopesForFile(this)) {
1392
+ const typeTexts = new Set();
1393
+ const fileScopes = this.program.getScopesForFile(this).sort((a, b) => { var _a; return (_a = a.dependencyGraphKey) === null || _a === void 0 ? void 0 : _a.localeCompare(b.dependencyGraphKey); });
1394
+ const callables = [];
1395
+ for (const scope of fileScopes) {
1102
1396
  scope.linkSymbolTable();
1103
- if (func.symbolTable.hasSymbol(lowerTokenText)) {
1104
- const type = (_a = func.symbolTable) === null || _a === void 0 ? void 0 : _a.getSymbolType(lowerTokenText);
1397
+ const typeContext = { file: this, scope: scope, position: position };
1398
+ const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
1399
+ if (typeTextPair) {
1105
1400
  let scopeTypeText = '';
1106
- if (reflection_1.isFunctionType(type)) {
1107
- scopeTypeText = type.toString();
1401
+ if ((0, reflection_1.isTypedFunctionType)(typeTextPair.type)) {
1402
+ scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString(typeContext);
1403
+ //keep unique references to the callables for this function
1404
+ if (!typeTexts.has(scopeTypeText)) {
1405
+ callables.push(scope.getCallableByName(lowerTokenText));
1406
+ }
1407
+ }
1408
+ else if (typeTextPair.useExpandedTextOnly) {
1409
+ scopeTypeText = typeTextPair.expandedTokenText;
1108
1410
  }
1109
1411
  else {
1110
- scopeTypeText = `${token.text} as ${type.toString()}`;
1412
+ scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString(typeContext)}`;
1111
1413
  }
1112
- if (!typeTexts.includes(scopeTypeText)) {
1113
- typeTexts.push(scopeTypeText);
1414
+ if (scopeTypeText) {
1415
+ typeTexts.add(scopeTypeText);
1114
1416
  }
1115
1417
  }
1116
1418
  scope.unlinkSymbolTable();
1117
1419
  }
1118
- const typeText = typeTexts.join(' | ');
1119
- if (typeText) {
1420
+ if (callables.length === typeTexts.size) {
1421
+ //this is a function in all scopes, so build the function hover
1422
+ return {
1423
+ range: token.range,
1424
+ contents: this.getCallableDocumentation([...typeTexts], callables)
1425
+ };
1426
+ }
1427
+ else if ((typeTexts === null || typeTexts === void 0 ? void 0 : typeTexts.size) > 0) {
1428
+ const typeText = [...typeTexts].join(' | ');
1120
1429
  return {
1121
1430
  range: token.range,
1122
- contents: typeText
1431
+ contents: fence(typeText)
1123
1432
  };
1124
1433
  }
1125
1434
  }
1126
- //look through all callables in relevant scopes
1127
- {
1128
- let scopes = this.program.getScopesForFile(this);
1129
- for (let scope of scopes) {
1130
- let callable = scope.getCallableByName(lowerTokenText);
1131
- if (callable) {
1132
- return {
1133
- range: token.range,
1134
- contents: callable.type.toString()
1135
- };
1136
- }
1435
+ // //look through all callables in relevant scopes
1436
+ // {
1437
+ // let scopes = this.program.getScopesForFile(this);
1438
+ // for (let scope of scopes) {
1439
+ // let callable = scope.getCallableByName(lowerTokenText);
1440
+ // if (callable) {
1441
+ // return {
1442
+ // range: token.range,
1443
+ // contents: this.getCallableDocumentation(callables)
1444
+ // };
1445
+ // }
1446
+ // }
1447
+ // }
1448
+ }
1449
+ /**
1450
+ * Build a hover documentation for a callable.
1451
+ */
1452
+ getCallableDocumentation(typeTexts, callables) {
1453
+ var _a;
1454
+ const callable = callables[0];
1455
+ const typeText = typeTexts[0];
1456
+ const comments = [];
1457
+ const tokens = callable === null || callable === void 0 ? void 0 : callable.file.parser.tokens;
1458
+ const idx = tokens === null || tokens === void 0 ? void 0 : tokens.indexOf((_a = callable.functionStatement) === null || _a === void 0 ? void 0 : _a.func.functionType);
1459
+ for (let i = idx - 1; i >= 0; i--) {
1460
+ const token = tokens[i];
1461
+ //skip whitespace and newline chars
1462
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
1463
+ comments.push(token);
1464
+ }
1465
+ else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
1466
+ //skip these tokens
1467
+ continue;
1468
+ //any other token means there are no more comments
1469
+ }
1470
+ else {
1471
+ break;
1137
1472
  }
1138
1473
  }
1474
+ //message indicating if there are variations. example: (+3 variations) if there are 4 unique function signatures
1475
+ const multiText = callables.length > 1 ? ` (+${callables.length - 1} variations)` : '';
1476
+ let result = util_1.util.mdFence(typeText + multiText, 'brightscript');
1477
+ if (comments.length > 0) {
1478
+ result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
1479
+ }
1480
+ return result;
1139
1481
  }
1140
1482
  getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
1141
1483
  var _a;
1142
1484
  if (!dottedGetText) {
1143
1485
  return [];
1144
1486
  }
1145
- let namespaceLookup = scope.namespaceLookup;
1146
1487
  let resultsMap = new Map();
1147
- for (let key in namespaceLookup) {
1148
- let namespace = namespaceLookup[key.toLowerCase()];
1488
+ for (let [, namespace] of scope.namespaceLookup) {
1149
1489
  //completionName = "NameA."
1150
1490
  //completionName = "NameA.Na
1151
1491
  //NameA
@@ -1154,7 +1494,7 @@ class BrsFile {
1154
1494
  if (namespace.fullName.toLowerCase() === dottedGetText.toLowerCase()) {
1155
1495
  //add function and class statement completions
1156
1496
  for (let stmt of namespace.statements) {
1157
- if (reflection_1.isFunctionStatement(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
1497
+ if ((0, reflection_1.isFunctionStatement)(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
1158
1498
  const result = (_a = namespace.file) === null || _a === void 0 ? void 0 : _a.getSignatureHelpForStatement(stmt);
1159
1499
  if (!resultsMap.has(result.key)) {
1160
1500
  resultsMap.set(result.key, result);
@@ -1166,16 +1506,16 @@ class BrsFile {
1166
1506
  return [...resultsMap.values()];
1167
1507
  }
1168
1508
  getSignatureHelpForStatement(statement) {
1169
- if (!reflection_1.isFunctionStatement(statement) && !reflection_1.isClassMethodStatement(statement)) {
1509
+ if (!(0, reflection_1.isFunctionStatement)(statement) && !(0, reflection_1.isClassMethodStatement)(statement)) {
1170
1510
  return undefined;
1171
1511
  }
1172
1512
  const func = statement.func;
1173
1513
  const funcStartPosition = func.range.start;
1174
1514
  // Get function comments in reverse order
1175
- let currentToken = this.getTokenAt(funcStartPosition);
1515
+ let currentToken = this.parser.getTokenAt(funcStartPosition);
1176
1516
  let functionComments = [];
1177
1517
  while (currentToken) {
1178
- currentToken = this.getPreviousToken(currentToken);
1518
+ currentToken = this.parser.getPreviousToken(currentToken);
1179
1519
  if (!currentToken) {
1180
1520
  break;
1181
1521
  }
@@ -1185,12 +1525,12 @@ class BrsFile {
1185
1525
  }
1186
1526
  }
1187
1527
  const kind = currentToken.kind;
1188
- if (kind === lexer_1.TokenKind.Comment) {
1528
+ if (kind === TokenKind_1.TokenKind.Comment) {
1189
1529
  // Strip off common leading characters to make it easier to read
1190
1530
  const commentText = currentToken.text.replace(/^[' *\/]+/, '');
1191
1531
  functionComments.unshift(commentText);
1192
1532
  }
1193
- else if (kind === lexer_1.TokenKind.Newline) {
1533
+ else if (kind === TokenKind_1.TokenKind.Newline) {
1194
1534
  if (functionComments.length === 0) {
1195
1535
  continue;
1196
1536
  }
@@ -1212,14 +1552,15 @@ class BrsFile {
1212
1552
  params.push(vscode_languageserver_1.ParameterInformation.create(param.name.text));
1213
1553
  key += param.name.text;
1214
1554
  }
1215
- const label = util_1.util.getTextForRange(lines, util_1.util.createRangeFromPositions(func.functionType.range.start, func.body.range.start)).trim();
1555
+ const label = util_1.util.getTextForRange(lines, func.functionDeclarationRange).trim();
1216
1556
  const signature = vscode_languageserver_1.SignatureInformation.create(label, documentation, ...params);
1217
1557
  const index = 1;
1218
1558
  return { key: key, signature: signature, index: index };
1219
1559
  }
1220
1560
  getClassMethod(classStatement, name, walkParents = true) {
1221
1561
  var _a;
1222
- //TODO - would like to write this with getClassHieararchy; but got stuck on working out the scopes to use... :(
1562
+ //TODO - would like to write this with getClassHierarchy; but got stuck on working out the scopes to use... :(
1563
+ //TODO types - this could be solved with symbolTable?
1223
1564
  let statement;
1224
1565
  const statementHandler = (e) => {
1225
1566
  if (!statement && e.name.text.toLowerCase() === name.toLowerCase()) {
@@ -1227,7 +1568,7 @@ class BrsFile {
1227
1568
  }
1228
1569
  };
1229
1570
  while (classStatement) {
1230
- classStatement.walk(visitors_1.createVisitor({
1571
+ classStatement.walk((0, visitors_1.createVisitor)({
1231
1572
  ClassMethodStatement: statementHandler
1232
1573
  }), {
1233
1574
  walkMode: visitors_1.WalkMode.visitStatements
@@ -1249,24 +1590,24 @@ class BrsFile {
1249
1590
  const classConstructor = this.getClassMethod(classStatement, 'new');
1250
1591
  let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
1251
1592
  if (sigHelp) {
1252
- sigHelp.key = classStatement.getName(parser_1.ParseMode.BrighterScript);
1593
+ sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
1253
1594
  sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
1254
1595
  }
1255
1596
  return sigHelp;
1256
1597
  }
1257
1598
  getReferences(position) {
1258
- const callSiteToken = this.getTokenAt(position);
1599
+ const callSiteToken = this.parser.getTokenAt(position);
1259
1600
  let locations = [];
1260
1601
  const searchFor = callSiteToken.text.toLowerCase();
1261
1602
  const scopes = this.program.getScopesForFile(this);
1262
1603
  for (const scope of scopes) {
1263
1604
  const processedFiles = new Set();
1264
1605
  for (const file of scope.getAllFiles()) {
1265
- if (reflection_1.isXmlFile(file) || processedFiles.has(file)) {
1606
+ if ((0, reflection_1.isXmlFile)(file) || processedFiles.has(file)) {
1266
1607
  continue;
1267
1608
  }
1268
1609
  processedFiles.add(file);
1269
- file.ast.walk(visitors_1.createVisitor({
1610
+ file.ast.walk((0, visitors_1.createVisitor)({
1270
1611
  VariableExpression: (e) => {
1271
1612
  if (e.name.text.toLowerCase() === searchFor) {
1272
1613
  locations.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), e.range));
@@ -1317,8 +1658,15 @@ class BrsFile {
1317
1658
  return programNode.toString();
1318
1659
  }
1319
1660
  dispose() {
1320
- var _a;
1661
+ var _a, _b;
1321
1662
  (_a = this._parser) === null || _a === void 0 ? void 0 : _a.dispose();
1663
+ //unsubscribe from any DependencyGraph subscriptions
1664
+ (_b = this.unsubscribeFromDependencyGraph) === null || _b === void 0 ? void 0 : _b.call(this);
1665
+ //deleting these properties result in lower memory usage (garbage collection is magic!)
1666
+ delete this.fileContents;
1667
+ delete this._parser;
1668
+ delete this.callables;
1669
+ delete this.functionCalls;
1322
1670
  }
1323
1671
  }
1324
1672
  exports.BrsFile = BrsFile;
@@ -1326,7 +1674,7 @@ exports.BrsFile = BrsFile;
1326
1674
  * List of completions for all valid keywords/reserved words.
1327
1675
  * Build this list once because it won't change for the lifetime of this process
1328
1676
  */
1329
- exports.KeywordCompletions = Object.keys(lexer_1.Keywords)
1677
+ exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
1330
1678
  //remove any keywords with whitespace
1331
1679
  .filter(x => !x.includes(' '))
1332
1680
  //create completions