brighterscript 1.0.0-alpha.2 → 1.0.0-alpha.22

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