brighterscript 1.0.0-alpha.23 → 1.0.0-alpha.25

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 (536) hide show
  1. package/CHANGELOG.md +585 -218
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +41 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +39 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +79 -15
  33. package/dist/DiagnosticMessages.js +134 -21
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +222 -87
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +162 -81
  54. package/dist/Program.js +903 -732
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +132 -104
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +95 -134
  60. package/dist/Scope.js +477 -551
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +95 -29
  65. package/dist/SymbolTable.js +256 -102
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -6
  74. package/dist/XmlScope.js +74 -68
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +68 -64
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +26 -16
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -100
  90. package/dist/astUtils/reflection.js +225 -166
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +208 -126
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +54 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +178 -33
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +12 -2
  105. package/dist/bscPlugin/BscPlugin.js +41 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +135 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +21 -12
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +86 -12
  120. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +57 -0
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js +544 -0
  123. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  125. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  128. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  129. package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
  130. package/dist/bscPlugin/hover/HoverProcessor.js +188 -0
  131. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js +513 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +3 -1
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +102 -29
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +167 -6
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  140. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  141. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  142. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  143. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  144. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  146. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  147. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +16 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +123 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  152. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  153. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  155. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  156. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  157. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +22 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.js +316 -29
  159. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  160. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +264 -0
  162. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  163. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  164. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  165. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  166. package/dist/bscPlugin/validation/ScopeValidator.d.ts +56 -8
  167. package/dist/bscPlugin/validation/ScopeValidator.js +514 -116
  168. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  169. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  170. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  171. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  172. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  173. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  174. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  175. package/dist/cli.js +107 -8
  176. package/dist/cli.js.map +1 -1
  177. package/dist/deferred.d.ts +3 -3
  178. package/dist/deferred.js.map +1 -1
  179. package/dist/diagnosticUtils.d.ts +8 -2
  180. package/dist/diagnosticUtils.js +47 -17
  181. package/dist/diagnosticUtils.js.map +1 -1
  182. package/dist/examples/plugins/removePrint.js +8 -10
  183. package/dist/examples/plugins/removePrint.js.map +1 -1
  184. package/dist/files/AssetFile.d.ts +26 -0
  185. package/dist/files/AssetFile.js +26 -0
  186. package/dist/files/AssetFile.js.map +1 -0
  187. package/dist/files/BrsFile.Class.spec.js +529 -486
  188. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  189. package/dist/files/BrsFile.d.ts +124 -112
  190. package/dist/files/BrsFile.js +819 -1131
  191. package/dist/files/BrsFile.js.map +1 -1
  192. package/dist/files/BrsFile.spec.js +1869 -1277
  193. package/dist/files/BrsFile.spec.js.map +1 -1
  194. package/dist/files/BscFile.d.ts +104 -0
  195. package/dist/files/BscFile.js +16 -0
  196. package/dist/files/BscFile.js.map +1 -0
  197. package/dist/files/Factory.d.ts +25 -0
  198. package/dist/files/Factory.js +22 -0
  199. package/dist/files/Factory.js.map +1 -0
  200. package/dist/files/LazyFileData.d.ts +20 -0
  201. package/dist/files/LazyFileData.js +54 -0
  202. package/dist/files/LazyFileData.js.map +1 -0
  203. package/dist/files/LazyFileData.spec.d.ts +1 -0
  204. package/dist/files/LazyFileData.spec.js +27 -0
  205. package/dist/files/LazyFileData.spec.js.map +1 -0
  206. package/dist/files/XmlFile.d.ts +70 -32
  207. package/dist/files/XmlFile.js +106 -117
  208. package/dist/files/XmlFile.js.map +1 -1
  209. package/dist/files/XmlFile.spec.js +325 -262
  210. package/dist/files/XmlFile.spec.js.map +1 -1
  211. package/dist/files/tests/imports.spec.js +49 -41
  212. package/dist/files/tests/imports.spec.js.map +1 -1
  213. package/dist/files/tests/optionalChaning.spec.js +104 -40
  214. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  215. package/dist/globalCallables.js +16 -18
  216. package/dist/globalCallables.js.map +1 -1
  217. package/dist/index.d.ts +13 -2
  218. package/dist/index.js +15 -2
  219. package/dist/index.js.map +1 -1
  220. package/dist/interfaces.d.ts +440 -150
  221. package/dist/interfaces.js +27 -0
  222. package/dist/interfaces.js.map +1 -1
  223. package/dist/lexer/Character.spec.js +5 -5
  224. package/dist/lexer/Character.spec.js.map +1 -1
  225. package/dist/lexer/Lexer.d.ts +12 -5
  226. package/dist/lexer/Lexer.js +28 -13
  227. package/dist/lexer/Lexer.js.map +1 -1
  228. package/dist/lexer/Lexer.spec.js +187 -134
  229. package/dist/lexer/Lexer.spec.js.map +1 -1
  230. package/dist/lexer/Token.d.ts +9 -1
  231. package/dist/lexer/Token.js +9 -1
  232. package/dist/lexer/Token.js.map +1 -1
  233. package/dist/lexer/TokenKind.d.ts +9 -0
  234. package/dist/lexer/TokenKind.js +30 -5
  235. package/dist/lexer/TokenKind.js.map +1 -1
  236. package/dist/parser/AstNode.d.ts +162 -0
  237. package/dist/parser/AstNode.js +225 -0
  238. package/dist/parser/AstNode.js.map +1 -0
  239. package/dist/parser/AstNode.spec.d.ts +1 -0
  240. package/dist/parser/AstNode.spec.js +165 -0
  241. package/dist/parser/AstNode.spec.js.map +1 -0
  242. package/dist/parser/BrsTranspileState.d.ts +4 -7
  243. package/dist/parser/BrsTranspileState.js +4 -12
  244. package/dist/parser/BrsTranspileState.js.map +1 -1
  245. package/dist/parser/Expression.d.ts +126 -167
  246. package/dist/parser/Expression.js +524 -394
  247. package/dist/parser/Expression.js.map +1 -1
  248. package/dist/parser/Parser.Class.spec.js +152 -146
  249. package/dist/parser/Parser.Class.spec.js.map +1 -1
  250. package/dist/parser/Parser.d.ts +45 -196
  251. package/dist/parser/Parser.js +470 -926
  252. package/dist/parser/Parser.js.map +1 -1
  253. package/dist/parser/Parser.spec.d.ts +3 -1
  254. package/dist/parser/Parser.spec.js +1034 -805
  255. package/dist/parser/Parser.spec.js.map +1 -1
  256. package/dist/parser/SGParser.d.ts +9 -8
  257. package/dist/parser/SGParser.js +10 -8
  258. package/dist/parser/SGParser.js.map +1 -1
  259. package/dist/parser/SGParser.spec.js +27 -38
  260. package/dist/parser/SGParser.spec.js.map +1 -1
  261. package/dist/parser/SGTypes.d.ts +98 -35
  262. package/dist/parser/SGTypes.js +169 -99
  263. package/dist/parser/SGTypes.js.map +1 -1
  264. package/dist/parser/Statement.d.ts +208 -122
  265. package/dist/parser/Statement.js +599 -364
  266. package/dist/parser/Statement.js.map +1 -1
  267. package/dist/parser/Statement.spec.js +45 -21
  268. package/dist/parser/Statement.spec.js.map +1 -1
  269. package/dist/parser/TranspileState.d.ts +1 -1
  270. package/dist/parser/TranspileState.js +7 -12
  271. package/dist/parser/TranspileState.js.map +1 -1
  272. package/dist/parser/tests/Parser.spec.js +3 -2
  273. package/dist/parser/tests/Parser.spec.js.map +1 -1
  274. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  275. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  276. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  277. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  278. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  279. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  280. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  281. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  282. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  283. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  284. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  285. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  286. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  287. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  288. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  289. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  290. package/dist/parser/tests/expression/Call.spec.js +129 -21
  291. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  292. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  293. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  294. package/dist/parser/tests/expression/Function.spec.js +36 -36
  295. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  296. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  297. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  298. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  299. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  300. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +123 -81
  301. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  302. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  303. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  304. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  305. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  306. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  307. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  308. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  309. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  310. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  311. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  312. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +221 -81
  313. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  314. package/dist/parser/tests/expression/TernaryExpression.spec.js +287 -105
  315. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  316. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  318. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  321. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  323. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  324. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  325. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  326. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  327. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  328. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  329. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  330. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  331. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  333. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Enum.spec.js +111 -300
  335. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/For.spec.js +9 -10
  337. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  339. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Function.spec.js +44 -35
  341. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  343. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  345. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  347. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  349. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  351. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/PrintStatement.spec.js +107 -90
  353. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  355. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Set.spec.js +48 -35
  357. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  359. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  361. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  363. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  364. package/dist/preprocessor/Manifest.d.ts +1 -1
  365. package/dist/preprocessor/Manifest.js +3 -3
  366. package/dist/preprocessor/Manifest.js.map +1 -1
  367. package/dist/preprocessor/Manifest.spec.js +8 -8
  368. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  369. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  370. package/dist/preprocessor/Preprocessor.js +15 -11
  371. package/dist/preprocessor/Preprocessor.js.map +1 -1
  372. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  373. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  374. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  375. package/dist/preprocessor/PreprocessorParser.js +7 -1
  376. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  377. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  378. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  379. package/dist/roku-types/data.json +6544 -10519
  380. package/dist/roku-types/index.d.ts +662 -1934
  381. package/dist/types/ArrayType.d.ts +10 -9
  382. package/dist/types/ArrayType.js +65 -60
  383. package/dist/types/ArrayType.js.map +1 -1
  384. package/dist/types/ArrayType.spec.js +36 -68
  385. package/dist/types/ArrayType.spec.js.map +1 -1
  386. package/dist/types/AssociativeArrayType.d.ts +11 -0
  387. package/dist/types/AssociativeArrayType.js +52 -0
  388. package/dist/types/AssociativeArrayType.js.map +1 -0
  389. package/dist/types/BaseFunctionType.d.ts +9 -0
  390. package/dist/types/BaseFunctionType.js +25 -0
  391. package/dist/types/BaseFunctionType.js.map +1 -0
  392. package/dist/types/BooleanType.d.ts +8 -5
  393. package/dist/types/BooleanType.js +14 -7
  394. package/dist/types/BooleanType.js.map +1 -1
  395. package/dist/types/BooleanType.spec.js +10 -6
  396. package/dist/types/BooleanType.spec.js.map +1 -1
  397. package/dist/types/BscType.d.ts +32 -21
  398. package/dist/types/BscType.js +118 -21
  399. package/dist/types/BscType.js.map +1 -1
  400. package/dist/types/BscTypeKind.d.ts +25 -0
  401. package/dist/types/BscTypeKind.js +30 -0
  402. package/dist/types/BscTypeKind.js.map +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  404. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  405. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  406. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  407. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  409. package/dist/types/ClassType.d.ts +17 -0
  410. package/dist/types/ClassType.js +58 -0
  411. package/dist/types/ClassType.js.map +1 -0
  412. package/dist/types/ClassType.spec.d.ts +1 -0
  413. package/dist/types/ClassType.spec.js +77 -0
  414. package/dist/types/ClassType.spec.js.map +1 -0
  415. package/dist/types/ComponentType.d.ts +26 -0
  416. package/dist/types/ComponentType.js +83 -0
  417. package/dist/types/ComponentType.js.map +1 -0
  418. package/dist/types/DoubleType.d.ts +8 -5
  419. package/dist/types/DoubleType.js +18 -16
  420. package/dist/types/DoubleType.js.map +1 -1
  421. package/dist/types/DoubleType.spec.js +12 -6
  422. package/dist/types/DoubleType.spec.js.map +1 -1
  423. package/dist/types/DynamicType.d.ts +10 -5
  424. package/dist/types/DynamicType.js +16 -4
  425. package/dist/types/DynamicType.js.map +1 -1
  426. package/dist/types/DynamicType.spec.js +16 -5
  427. package/dist/types/DynamicType.spec.js.map +1 -1
  428. package/dist/types/EnumType.d.ts +30 -12
  429. package/dist/types/EnumType.js +43 -17
  430. package/dist/types/EnumType.js.map +1 -1
  431. package/dist/types/EnumType.spec.d.ts +1 -0
  432. package/dist/types/EnumType.spec.js +33 -0
  433. package/dist/types/EnumType.spec.js.map +1 -0
  434. package/dist/types/FloatType.d.ts +8 -5
  435. package/dist/types/FloatType.js +18 -16
  436. package/dist/types/FloatType.js.map +1 -1
  437. package/dist/types/FloatType.spec.js +4 -6
  438. package/dist/types/FloatType.spec.js.map +1 -1
  439. package/dist/types/FunctionType.d.ts +13 -8
  440. package/dist/types/FunctionType.js +30 -14
  441. package/dist/types/FunctionType.js.map +1 -1
  442. package/dist/types/InheritableType.d.ts +28 -0
  443. package/dist/types/InheritableType.js +152 -0
  444. package/dist/types/InheritableType.js.map +1 -0
  445. package/dist/types/IntegerType.d.ts +8 -5
  446. package/dist/types/IntegerType.js +18 -16
  447. package/dist/types/IntegerType.js.map +1 -1
  448. package/dist/types/IntegerType.spec.js +8 -6
  449. package/dist/types/IntegerType.spec.js.map +1 -1
  450. package/dist/types/InterfaceType.d.ts +12 -13
  451. package/dist/types/InterfaceType.js +20 -48
  452. package/dist/types/InterfaceType.js.map +1 -1
  453. package/dist/types/InterfaceType.spec.js +90 -56
  454. package/dist/types/InterfaceType.spec.js.map +1 -1
  455. package/dist/types/InvalidType.d.ts +7 -5
  456. package/dist/types/InvalidType.js +13 -7
  457. package/dist/types/InvalidType.js.map +1 -1
  458. package/dist/types/InvalidType.spec.js +8 -6
  459. package/dist/types/InvalidType.spec.js.map +1 -1
  460. package/dist/types/LongIntegerType.d.ts +8 -5
  461. package/dist/types/LongIntegerType.js +17 -15
  462. package/dist/types/LongIntegerType.js.map +1 -1
  463. package/dist/types/LongIntegerType.spec.js +10 -6
  464. package/dist/types/LongIntegerType.spec.js.map +1 -1
  465. package/dist/types/NamespaceType.d.ts +12 -0
  466. package/dist/types/NamespaceType.js +28 -0
  467. package/dist/types/NamespaceType.js.map +1 -0
  468. package/dist/types/ObjectType.d.ts +9 -8
  469. package/dist/types/ObjectType.js +21 -11
  470. package/dist/types/ObjectType.js.map +1 -1
  471. package/dist/types/ObjectType.spec.js +3 -3
  472. package/dist/types/ObjectType.spec.js.map +1 -1
  473. package/dist/types/ReferenceType.d.ts +63 -0
  474. package/dist/types/ReferenceType.js +423 -0
  475. package/dist/types/ReferenceType.js.map +1 -0
  476. package/dist/types/ReferenceType.spec.d.ts +1 -0
  477. package/dist/types/ReferenceType.spec.js +137 -0
  478. package/dist/types/ReferenceType.spec.js.map +1 -0
  479. package/dist/types/StringType.d.ts +11 -5
  480. package/dist/types/StringType.js +18 -7
  481. package/dist/types/StringType.js.map +1 -1
  482. package/dist/types/StringType.spec.js +3 -5
  483. package/dist/types/StringType.spec.js.map +1 -1
  484. package/dist/types/TypedFunctionType.d.ts +22 -17
  485. package/dist/types/TypedFunctionType.js +78 -60
  486. package/dist/types/TypedFunctionType.js.map +1 -1
  487. package/dist/types/TypedFunctionType.spec.js +105 -20
  488. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  489. package/dist/types/UninitializedType.d.ts +8 -6
  490. package/dist/types/UninitializedType.js +13 -7
  491. package/dist/types/UninitializedType.js.map +1 -1
  492. package/dist/types/UnionType.d.ts +20 -0
  493. package/dist/types/UnionType.js +123 -0
  494. package/dist/types/UnionType.js.map +1 -0
  495. package/dist/types/UnionType.spec.d.ts +1 -0
  496. package/dist/types/UnionType.spec.js +130 -0
  497. package/dist/types/UnionType.spec.js.map +1 -0
  498. package/dist/types/VoidType.d.ts +8 -5
  499. package/dist/types/VoidType.js +14 -7
  500. package/dist/types/VoidType.js.map +1 -1
  501. package/dist/types/VoidType.spec.js +3 -3
  502. package/dist/types/VoidType.spec.js.map +1 -1
  503. package/dist/types/helper.spec.d.ts +1 -0
  504. package/dist/types/helper.spec.js +145 -0
  505. package/dist/types/helper.spec.js.map +1 -0
  506. package/dist/types/helpers.d.ts +19 -37
  507. package/dist/types/helpers.js +159 -99
  508. package/dist/types/helpers.js.map +1 -1
  509. package/dist/types/index.d.ts +22 -0
  510. package/dist/types/index.js +39 -0
  511. package/dist/types/index.js.map +1 -0
  512. package/dist/util.d.ts +167 -131
  513. package/dist/util.js +890 -350
  514. package/dist/util.js.map +1 -1
  515. package/dist/validators/ClassValidator.d.ts +7 -25
  516. package/dist/validators/ClassValidator.js +103 -194
  517. package/dist/validators/ClassValidator.js.map +1 -1
  518. package/package.json +165 -149
  519. package/dist/astUtils/AstEditor.js.map +0 -1
  520. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  521. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +0 -8
  522. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +0 -40
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/hover/HoverProcessor.spec.d.ts} +0 -0
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.KeywordCompletions = exports.BrsFile = void 0;
3
+ exports.BrsFile = void 0;
4
4
  const source_map_1 = require("source-map");
5
5
  const vscode_languageserver_1 = require("vscode-languageserver");
6
+ const vscode_languageserver_2 = require("vscode-languageserver");
6
7
  const chalk_1 = require("chalk");
7
8
  const path = require("path");
8
9
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
9
- const Token_1 = require("../lexer/Token");
10
+ const FunctionScope_1 = require("../FunctionScope");
10
11
  const Lexer_1 = require("../lexer/Lexer");
11
12
  const TokenKind_1 = require("../lexer/TokenKind");
12
13
  const Parser_1 = require("../parser/Parser");
@@ -19,26 +20,18 @@ const serialize_error_1 = require("serialize-error");
19
20
  const reflection_1 = require("../astUtils/reflection");
20
21
  const visitors_1 = require("../astUtils/visitors");
21
22
  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");
23
+ const vscode_uri_1 = require("vscode-uri");
24
+ const SymbolTable_1 = require("../SymbolTable");
25
+ const Editor_1 = require("../astUtils/Editor");
26
+ const AstValidationSegmenter_1 = require("../AstValidationSegmenter");
27
+ const CachedLookups_1 = require("../astUtils/CachedLookups");
25
28
  /**
26
29
  * Holds all details about this file within the scope of the whole program
27
30
  */
28
31
  class BrsFile {
29
- constructor(
30
- /**
31
- * The absolute path to the source file on disk (e.g. '/usr/you/projects/RokuApp/source/main.brs' or 'c:/projects/RokuApp/source/main.brs').
32
- */
33
- srcPath,
34
- /**
35
- * The full pkg path (i.e. `pkg:/path/to/file.brs`)
36
- */
37
- pkgPath, program) {
38
- var _a, _b;
39
- this.srcPath = srcPath;
40
- this.pkgPath = pkgPath;
41
- this.program = program;
32
+ constructor(options) {
33
+ var _a, _b, _c;
34
+ this.type = 'BrsFile';
42
35
  /**
43
36
  * The parseMode used for the parser for this file
44
37
  */
@@ -48,64 +41,103 @@ class BrsFile {
48
41
  * Files are only ever validated a single time
49
42
  */
50
43
  this.isValidated = false;
51
- this.diagnostics = [];
52
- this.commentFlags = [];
53
- this.callables = [];
54
- this.functionCalls = [];
55
44
  /**
56
- * Does this file need to be transpiled?
45
+ * A collection of diagnostics related to this file
57
46
  */
58
- this.needsTranspiled = false;
59
- this.srcPath = (0, util_1.standardizePath) `${this.srcPath}`;
60
- this.dependencyGraphKey = this.pkgPath.toLowerCase();
61
- this.extension = util_1.util.getExtension(this.srcPath);
62
- //all BrighterScript files need to be transpiled
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)) {
64
- this.needsTranspiled = true;
65
- this.parseMode = Parser_1.ParseMode.BrighterScript;
66
- }
67
- this.isTypedef = this.extension === '.d.bs';
68
- if (!this.isTypedef) {
69
- this.typedefSrcPath = util_1.util.getTypedefPath(this.srcPath);
70
- }
71
- //global file doesn't have a program, so only resolve typedef info if we have a program
72
- if (this.program) {
73
- this.resolveTypedef();
47
+ this.diagnostics = [];
48
+ this.commentFlags = [];
49
+ this.scopesByFunc = new Map();
50
+ this.validationSegmenter = new AstValidationSegmenter_1.AstValidationSegmenter();
51
+ if (options) {
52
+ this.srcPath = (0, util_1.standardizePath) `${options.srcPath}`;
53
+ this.destPath = (0, util_1.standardizePath) `${options.destPath}`;
54
+ this.program = options.program;
55
+ this._cachedLookups = new CachedLookups_1.CachedLookups(this);
56
+ this.extension = util_1.util.getExtension(this.srcPath);
57
+ if (options.pkgPath) {
58
+ this.pkgPath = options.pkgPath;
59
+ }
60
+ else {
61
+ //don't rename .d.bs files to .d.brs
62
+ if (this.extension === '.d.bs') {
63
+ this.pkgPath = this.destPath;
64
+ }
65
+ else {
66
+ this.pkgPath = this.destPath.replace(/\.bs$/i, '.brs');
67
+ }
68
+ }
69
+ //all BrighterScript files need to be transpiled
70
+ if (((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) || ((_c = (_b = this.program) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.allowBrighterScriptInBrightScript)) {
71
+ this.parseMode = Parser_1.ParseMode.BrighterScript;
72
+ }
73
+ this.isTypedef = this.extension === '.d.bs';
74
+ if (!this.isTypedef) {
75
+ this.typedefKey = util_1.util.getTypedefPath(this.srcPath);
76
+ }
77
+ //global file doesn't have a program, so only resolve typedef info if we have a program
78
+ if (this.program) {
79
+ this.resolveTypedef();
80
+ }
74
81
  }
75
82
  }
76
83
  /**
77
- * The absolute path to the source location for this file
78
- * @deprecated use `srcPath` instead
84
+ * Will this file result in only comment or whitespace output? If so, it can be excluded from the output if that bsconfig setting is enabled.
79
85
  */
80
- get pathAbsolute() {
81
- return this.srcPath;
82
- }
83
- set pathAbsolute(value) {
84
- this.srcPath = value;
86
+ get canBePruned() {
87
+ let canPrune = true;
88
+ this.ast.walk((0, visitors_1.createVisitor)({
89
+ FunctionStatement: () => {
90
+ canPrune = false;
91
+ },
92
+ ClassStatement: () => {
93
+ canPrune = false;
94
+ }
95
+ }), {
96
+ walkMode: visitors_1.WalkMode.visitStatements
97
+ });
98
+ return canPrune;
85
99
  }
100
+ /**
101
+ * @deprecated use `.diagnostics` instead
102
+ */
86
103
  getDiagnostics() {
87
- return [...this.diagnostics];
104
+ return this.diagnostics;
105
+ }
106
+ addDiagnostic(diagnostic) {
107
+ if (!diagnostic.file) {
108
+ diagnostic.file = this;
109
+ }
110
+ this.diagnostics.push(diagnostic);
88
111
  }
89
112
  addDiagnostics(diagnostics) {
90
113
  this.diagnostics.push(...diagnostics);
91
114
  }
115
+ get functionScopes() {
116
+ if (!this._functionScopes) {
117
+ this.createFunctionScopes();
118
+ }
119
+ return this._functionScopes;
120
+ }
121
+ get cache() {
122
+ // eslint-disable-next-line @typescript-eslint/dot-notation
123
+ return this._cachedLookups['cache'];
124
+ }
92
125
  /**
93
126
  * files referenced by import statements
94
127
  */
95
128
  get ownScriptImports() {
96
129
  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;
130
+ const result = (_b = (_a = this.cache) === null || _a === void 0 ? void 0 : _a.getOrAdd('BrsFile_ownScriptImports', () => {
131
+ var _a, _b, _c;
100
132
  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 : []) {
133
+ for (const statement of (_b = (_a = this._cachedLookups) === null || _a === void 0 ? void 0 : _a.importStatements) !== null && _b !== void 0 ? _b : []) {
102
134
  //register import statements
103
135
  if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
104
136
  result.push({
105
137
  filePathRange: statement.filePathToken.range,
106
- pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
138
+ destPath: util_1.util.getPkgPathFromTarget(this.destPath, statement.filePath),
107
139
  sourceFile: this,
108
- text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
140
+ text: (_c = statement.filePathToken) === null || _c === void 0 ? void 0 : _c.text
109
141
  });
110
142
  }
111
143
  }
@@ -113,11 +145,59 @@ class BrsFile {
113
145
  })) !== null && _b !== void 0 ? _b : [];
114
146
  return result;
115
147
  }
148
+ /**
149
+ * Does this file need to be transpiled?
150
+ * @deprecated use the `.editor` property to push changes to the file, which will force transpilation
151
+ */
152
+ get needsTranspiled() {
153
+ var _a, _b, _c, _d;
154
+ if (this._needsTranspiled !== undefined) {
155
+ return this._needsTranspiled;
156
+ }
157
+ return !!(((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) || ((_c = (_b = this.program) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.allowBrighterScriptInBrightScript) || ((_d = this.editor) === null || _d === void 0 ? void 0 : _d.hasChanges));
158
+ }
159
+ set needsTranspiled(value) {
160
+ this._needsTranspiled = value;
161
+ }
116
162
  /**
117
163
  * The AST for this file
118
164
  */
119
165
  get ast() {
120
- return this.parser.ast;
166
+ var _a;
167
+ return (_a = this.parser) === null || _a === void 0 ? void 0 : _a.ast;
168
+ }
169
+ /**
170
+ * Get the token at the specified position
171
+ */
172
+ getTokenAt(position) {
173
+ for (let token of this.parser.tokens) {
174
+ if (util_1.util.rangeContains(token.range, position)) {
175
+ return token;
176
+ }
177
+ }
178
+ }
179
+ /**
180
+ * Walk the AST and find the expression that this token is most specifically contained within
181
+ */
182
+ getClosestExpression(position) {
183
+ const handle = new vscode_languageserver_1.CancellationTokenSource();
184
+ let containingNode;
185
+ this.ast.walk((node) => {
186
+ const latestContainer = containingNode;
187
+ //bsc walks depth-first
188
+ if (util_1.util.rangeContains(node.range, position)) {
189
+ containingNode = node;
190
+ }
191
+ //we had a match before, and don't now. this means we've finished walking down the whole way, and found our match
192
+ if (latestContainer && !containingNode) {
193
+ containingNode = latestContainer;
194
+ handle.cancel();
195
+ }
196
+ }, {
197
+ walkMode: visitors_1.WalkMode.visitAllRecursive,
198
+ cancel: handle.token
199
+ });
200
+ return containingNode;
121
201
  }
122
202
  get parser() {
123
203
  if (!this._parser) {
@@ -135,38 +215,32 @@ class BrsFile {
135
215
  * Find and set the typedef variables (if a matching typedef file exists)
136
216
  */
137
217
  resolveTypedef() {
138
- this.typedefFile = this.program.getFile(this.typedefSrcPath);
218
+ this.typedefFile = this.program.getFile(this.typedefKey);
139
219
  this.hasTypedef = !!this.typedefFile;
140
220
  }
221
+ onDependenciesChanged() {
222
+ this.resolveTypedef();
223
+ }
141
224
  /**
142
225
  * Attach the file to the dependency graph so it can monitor changes.
143
226
  * Also notify the dependency graph of our current dependencies so other dependents can be notified.
227
+ * @deprecated this does nothing. This functionality is now handled by the file api and will be deleted in v1
144
228
  */
145
- attachDependencyGraph(dependencyGraph) {
146
- var _a;
147
- (_a = this.unsubscribeFromDependencyGraph) === null || _a === void 0 ? void 0 : _a.call(this);
148
- //event that fires anytime a dependency changes
149
- this.unsubscribeFromDependencyGraph = dependencyGraph.onchange(this.dependencyGraphKey, () => {
150
- this.resolveTypedef();
151
- });
152
- const dependencies = this.ownScriptImports.filter(x => !!x.pkgPath).map(x => x.pkgPath.toLowerCase());
229
+ attachDependencyGraph(dependencyGraph) { }
230
+ /**
231
+ * The list of files that this file depends on
232
+ */
233
+ get dependencies() {
234
+ const result = this.ownScriptImports.filter(x => !!x.destPath).map(x => x.destPath.toLowerCase());
153
235
  //if this is a .brs file, watch for typedef changes
154
236
  if (this.extension === '.brs') {
155
- dependencies.push(util_1.util.getTypedefPath(this.pkgPath));
237
+ result.push(util_1.util.getTypedefPath(this.destPath));
156
238
  }
157
- dependencyGraph.addOrReplace(this.dependencyGraphKey, dependencies);
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;
239
+ return result;
166
240
  }
167
241
  /**
168
242
  * Calculate the AST for this file
169
- * @param fileContents
243
+ * @param fileContents the raw source code to parse
170
244
  */
171
245
  parse(fileContents) {
172
246
  try {
@@ -179,7 +253,7 @@ class BrsFile {
179
253
  return;
180
254
  }
181
255
  //tokenize the input file
182
- let lexer = this.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
256
+ let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
183
257
  return Lexer_1.Lexer.scan(fileContents, {
184
258
  includeWhitespace: false
185
259
  });
@@ -190,7 +264,7 @@ class BrsFile {
190
264
  //TODO preprocessor should go away in favor of the AST handling this internally (because it affects transpile)
191
265
  //currently the preprocessor throws exceptions on syntax errors...so we need to catch it
192
266
  try {
193
- this.logger.time(Logger_1.LogLevel.debug, ['preprocessor.process', chalk_1.default.green(this.srcPath)], () => {
267
+ this.program.logger.time(Logger_1.LogLevel.debug, ['preprocessor.process', chalk_1.default.green(this.srcPath)], () => {
194
268
  preprocessor.process(lexer.tokens, this.program.getManifest());
195
269
  });
196
270
  }
@@ -202,18 +276,14 @@ class BrsFile {
202
276
  }
203
277
  //if the preprocessor generated tokens, use them.
204
278
  let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
205
- this.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
279
+ this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
206
280
  this._parser = Parser_1.Parser.parse(tokens, {
207
281
  mode: this.parseMode,
208
- logger: this.logger
282
+ logger: this.program.logger
209
283
  });
210
284
  });
211
285
  //absorb all lexing/preprocessing/parsing diagnostics
212
286
  this.diagnostics.push(...lexer.diagnostics, ...preprocessor.diagnostics, ...this._parser.diagnostics);
213
- //extract all callables from this file
214
- this.findCallables();
215
- //find all places where a sub/function is being called
216
- this.findFunctionCalls();
217
287
  //attach this file to every diagnostic
218
288
  for (let diagnostic of this.diagnostics) {
219
289
  diagnostic.file = this;
@@ -224,45 +294,6 @@ class BrsFile {
224
294
  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)))));
225
295
  }
226
296
  }
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() {
234
- let topOfFileIncludeStatements = [];
235
- for (let stmt of this.ast.statements) {
236
- //skip comments
237
- if ((0, reflection_1.isCommentStatement)(stmt)) {
238
- continue;
239
- }
240
- //if we found a non-library statement, this statement is not at the top of the file
241
- if ((0, reflection_1.isLibraryStatement)(stmt) || (0, reflection_1.isImportStatement)(stmt)) {
242
- topOfFileIncludeStatements.push(stmt);
243
- }
244
- else {
245
- //break out of the loop, we found all of our library statements
246
- break;
247
- }
248
- }
249
- let statements = [
250
- ...this._parser.references.libraryStatements,
251
- ...this._parser.references.importStatements
252
- ];
253
- for (let result of statements) {
254
- //if this statement is not one of the top-of-file statements,
255
- //then add a diagnostic explaining that it is invalid
256
- if (!topOfFileIncludeStatements.includes(result)) {
257
- if ((0, reflection_1.isLibraryStatement)(result)) {
258
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.libraryStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
259
- }
260
- else if ((0, reflection_1.isImportStatement)(result)) {
261
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
262
- }
263
- }
264
- }
265
- }
266
297
  /**
267
298
  * Find a class. This scans all scopes for this file, and returns the first matching class that is found.
268
299
  * Returns undefined if not found.
@@ -284,12 +315,12 @@ class BrsFile {
284
315
  }
285
316
  findPropertyNameCompletions() {
286
317
  //Build completion items from all the "properties" found in the file
287
- const { propertyHints } = this.parser.references;
318
+ const { propertyHints } = this._cachedLookups;
288
319
  const results = [];
289
320
  for (const key of Object.keys(propertyHints)) {
290
321
  results.push({
291
322
  label: propertyHints[key],
292
- kind: vscode_languageserver_1.CompletionItemKind.Text
323
+ kind: vscode_languageserver_2.CompletionItemKind.Text
293
324
  });
294
325
  }
295
326
  return results;
@@ -302,7 +333,7 @@ class BrsFile {
302
333
  }
303
334
  /**
304
335
  * Find all comment flags in the source code. These enable or disable diagnostic messages.
305
- * @param lines - the lines of the program
336
+ * @param tokens - an array of tokens of which to find `TokenKind.Comment` from
306
337
  */
307
338
  getCommentFlags(tokens) {
308
339
  const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
@@ -315,738 +346,250 @@ class BrsFile {
315
346
  this.commentFlags.push(...processor.commentFlags);
316
347
  this.diagnostics.push(...processor.diagnostics);
317
348
  }
318
- findCallables() {
349
+ /**
350
+ * Create a scope for every function in this file
351
+ */
352
+ createFunctionScopes() {
319
353
  var _a;
320
- for (let statement of (_a = this.parser.references.functionStatements) !== null && _a !== void 0 ? _a : []) {
321
- let functionType = statement.func.getFunctionType();
322
- functionType.setName(statement.name.text);
323
- this.callables.push({
324
- isSub: statement.func.functionType.text.toLowerCase() === 'sub',
325
- name: statement.name.text,
326
- nameRange: statement.name.range,
327
- file: this,
328
- params: functionType.params,
329
- range: statement.func.range,
330
- type: functionType,
331
- getName: statement.getName.bind(statement),
332
- hasNamespace: !!statement.namespaceName,
333
- functionStatement: statement
354
+ //find every function
355
+ let functions = this._cachedLookups.functionExpressions;
356
+ //create a functionScope for every function
357
+ this._functionScopes = [];
358
+ for (let func of functions) {
359
+ let scope = new FunctionScope_1.FunctionScope(func);
360
+ //find parent function, and add this scope to it if found
361
+ {
362
+ let parentScope = this.scopesByFunc.get(func.findAncestor(reflection_1.isFunctionExpression));
363
+ //add this child scope to its parent
364
+ if (parentScope) {
365
+ parentScope.childrenScopes.push(scope);
366
+ }
367
+ //store the parent scope for this scope
368
+ scope.parentScope = parentScope;
369
+ }
370
+ //add every parameter
371
+ for (let param of func.parameters) {
372
+ scope.variableDeclarations.push({
373
+ nameRange: param.name.range,
374
+ lineIndex: param.name.range.start.line,
375
+ name: param.name.text,
376
+ getType: () => {
377
+ return param.getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
378
+ }
379
+ });
380
+ }
381
+ //add all of ForEachStatement loop varibales
382
+ (_a = func.body) === null || _a === void 0 ? void 0 : _a.walk((0, visitors_1.createVisitor)({
383
+ ForEachStatement: (stmt) => {
384
+ scope.variableDeclarations.push({
385
+ nameRange: stmt.item.range,
386
+ lineIndex: stmt.item.range.start.line,
387
+ name: stmt.item.text,
388
+ getType: () => DynamicType_1.DynamicType.instance //TODO: Infer types from array
389
+ });
390
+ },
391
+ LabelStatement: (stmt) => {
392
+ const { identifier } = stmt.tokens;
393
+ scope.labelStatements.push({
394
+ nameRange: identifier.range,
395
+ lineIndex: identifier.range.start.line,
396
+ name: identifier.text
397
+ });
398
+ }
399
+ }), {
400
+ walkMode: visitors_1.WalkMode.visitStatements
334
401
  });
402
+ this.scopesByFunc.set(func, scope);
403
+ //find every statement in the scope
404
+ this._functionScopes.push(scope);
405
+ }
406
+ //find every variable assignment in the whole file
407
+ let assignmentStatements = this._cachedLookups.assignmentStatements;
408
+ for (let statement of assignmentStatements) {
409
+ //find this statement's function scope
410
+ let scope = this.scopesByFunc.get(statement.findAncestor(reflection_1.isFunctionExpression));
411
+ //skip variable declarations that are outside of any scope
412
+ if (scope) {
413
+ scope.variableDeclarations.push({
414
+ nameRange: statement.name.range,
415
+ lineIndex: statement.name.range.start.line,
416
+ name: statement.name.text,
417
+ getType: () => {
418
+ return statement.getType({ flags: SymbolTable_1.SymbolTypeFlag.runtime });
419
+ }
420
+ });
421
+ }
335
422
  }
336
423
  }
337
- findFunctionCalls() {
338
- var _a;
339
- this.functionCalls = [];
340
- //for every function in the file
341
- for (let func of this._parser.references.functionExpressions) {
342
- //for all function calls in this function
343
- for (let expression of func.callExpressions) {
344
- if (
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) ||
349
- //filter out callees without a name (immediately-invoked function expressions)
350
- !expression.callee.name) {
351
- continue;
424
+ get callables() {
425
+ if (this.staticCallables) {
426
+ // globalFile can statically set the callables
427
+ return this.staticCallables;
428
+ }
429
+ return this.cache.getOrAdd(`BrsFile_callables`, () => {
430
+ var _a, _b, _c, _d;
431
+ const callables = [];
432
+ for (let statement of (_a = this._cachedLookups.functionStatements) !== null && _a !== void 0 ? _a : []) {
433
+ //extract the parameters
434
+ let params = [];
435
+ for (let param of statement.func.parameters) {
436
+ const paramType = param.getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
437
+ let callableParam = {
438
+ name: (_b = param.name) === null || _b === void 0 ? void 0 : _b.text,
439
+ type: paramType,
440
+ isOptional: !!param.defaultValue,
441
+ isRestArgument: false
442
+ };
443
+ params.push(callableParam);
352
444
  }
353
- //Flag dotted function invocations (i.e. object.doSomething())
354
- const dottedInvocation = expression.callee.obj;
355
- let functionName = expression.callee.name;
356
- //callee is the name of the function being called
357
- let callee = expression.callee;
358
- let columnIndexBegin = callee.range.start.character;
359
- let columnIndexEnd = callee.range.end.character;
360
- let args = [];
361
- //TODO convert if stmts to use instanceof instead
362
- for (let arg of expression.args) {
363
- let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
364
- let argText = '';
365
- // Get the text to display for the arg
366
- if (arg.token) {
367
- argText = arg.token.text;
368
- //is a function call being passed into argument
445
+ const funcType = statement.getType({ flags: SymbolTable_1.SymbolTypeFlag.typetime });
446
+ callables.push({
447
+ isSub: statement.func.functionType.text.toLowerCase() === 'sub',
448
+ name: (_c = statement.name) === null || _c === void 0 ? void 0 : _c.text,
449
+ nameRange: (_d = statement.name) === null || _d === void 0 ? void 0 : _d.range,
450
+ file: this,
451
+ params: params,
452
+ range: statement.func.range,
453
+ type: funcType,
454
+ getName: statement.getName.bind(statement),
455
+ hasNamespace: !!statement.findAncestor(reflection_1.isNamespaceStatement),
456
+ functionStatement: statement
457
+ });
458
+ }
459
+ return callables;
460
+ });
461
+ }
462
+ get functionCalls() {
463
+ return this.cache.getOrAdd(`BrsFile_functionCalls`, () => {
464
+ const functionCalls = [];
465
+ //for every function in the file
466
+ for (let func of this._cachedLookups.functionExpressions) {
467
+ //for all function calls in this function
468
+ for (let expression of func.callExpressions) {
469
+ if (
470
+ //filter out dotted function invocations (i.e. object.doSomething()) (not currently supported. TODO support it)
471
+ expression.callee.obj ||
472
+ //filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
473
+ expression.callee.callee ||
474
+ //filter out callees without a name (immediately-invoked function expressions)
475
+ !expression.callee.name) {
476
+ continue;
369
477
  }
370
- else if (arg.name) {
371
- if ((0, Token_1.isToken)(arg.name)) {
372
- argText = arg.name.text;
478
+ let functionName = expression.callee.name.text;
479
+ //callee is the name of the function being called
480
+ let callee = expression.callee;
481
+ let columnIndexBegin = callee.range.start.character;
482
+ let columnIndexEnd = callee.range.end.character;
483
+ let args = [];
484
+ //TODO convert if stmts to use instanceof instead
485
+ for (let arg of expression.args) {
486
+ //is a literal parameter value
487
+ if ((0, reflection_1.isLiteralExpression)(arg)) {
488
+ args.push({
489
+ range: arg.range,
490
+ type: arg.getType(),
491
+ text: arg.token.text,
492
+ expression: arg,
493
+ typeToken: undefined
494
+ });
495
+ //is variable being passed into argument
373
496
  }
374
- }
375
- else if (arg.value) {
376
- /* istanbul ignore next: TODO figure out why value is undefined sometimes */
377
- if (arg.value.value) {
378
- if (arg.value.value.toString) {
379
- argText = arg.value.value.toString();
497
+ else if (arg.name) {
498
+ args.push({
499
+ range: arg.range,
500
+ //TODO - look up the data type of the actual variable
501
+ type: new DynamicType_1.DynamicType(),
502
+ text: arg.name.text,
503
+ expression: arg,
504
+ typeToken: undefined
505
+ });
506
+ }
507
+ else if (arg.value) {
508
+ let text = '';
509
+ /* istanbul ignore next: TODO figure out why value is undefined sometimes */
510
+ if (arg.value.value) {
511
+ text = arg.value.value.toString();
380
512
  }
513
+ let callableArg = {
514
+ range: arg.range,
515
+ //TODO not sure what to do here
516
+ type: new DynamicType_1.DynamicType(),
517
+ text: text,
518
+ expression: arg,
519
+ typeToken: undefined
520
+ };
521
+ //wrap the value in quotes because that's how it appears in the code
522
+ if ((0, reflection_1.isStringType)(callableArg.type)) {
523
+ callableArg.text = '"' + callableArg.text + '"';
524
+ }
525
+ args.push(callableArg);
381
526
  }
382
- //wrap the value in quotes because that's how it appears in the code
383
- if (argText && (0, reflection_1.isStringType)(inferredType)) {
384
- argText = '"' + argText + '"';
527
+ else {
528
+ args.push({
529
+ range: arg.range,
530
+ type: new DynamicType_1.DynamicType(),
531
+ //TODO get text from other types of args
532
+ text: '',
533
+ expression: arg,
534
+ typeToken: undefined
535
+ });
385
536
  }
386
537
  }
387
- args.push({
388
- range: arg.range,
389
- type: inferredType,
390
- text: argText,
391
- expression: arg,
392
- typeToken: undefined
393
- });
538
+ let functionCall = {
539
+ range: expression.range,
540
+ functionScope: this.getFunctionScopeAtPosition(callee.range.start),
541
+ file: this,
542
+ name: functionName,
543
+ nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
544
+ //TODO keep track of parameters
545
+ args: args,
546
+ expression: expression
547
+ };
548
+ functionCalls.push(functionCall);
394
549
  }
395
- let functionCall = {
396
- range: util_1.util.createRangeFromPositions(expression.range.start, expression.closingParen.range.end),
397
- functionExpression: this.getFunctionExpressionAtPosition(callee.range.start),
398
- file: this,
399
- name: functionName,
400
- nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
401
- args: args,
402
- isDottedInvocation: dottedInvocation
403
- };
404
- this.functionCalls.push(functionCall);
405
550
  }
406
- }
551
+ return functionCalls;
552
+ });
407
553
  }
408
554
  /**
409
- * Find the function expression at the given position.
555
+ * Find the function scope at the given position.
556
+ * @param position the position used to find the deepest scope that contains it
410
557
  */
411
- getFunctionExpressionAtPosition(position, functionExpressions) {
412
- if (!functionExpressions) {
413
- functionExpressions = this.parser.references.functionExpressions;
558
+ getFunctionScopeAtPosition(position) {
559
+ return this.cache.getOrAdd(`functionScope-${position.line}:${position.character}`, () => {
560
+ return this._getFunctionScopeAtPosition(position, this.functionScopes);
561
+ });
562
+ }
563
+ _getFunctionScopeAtPosition(position, functionScopes) {
564
+ if (!functionScopes) {
565
+ functionScopes = this.functionScopes;
414
566
  }
415
- for (let functionExpression of functionExpressions) {
416
- if (util_1.util.rangeContains(functionExpression.range, position)) {
567
+ for (let scope of functionScopes) {
568
+ if (util_1.util.rangeContains(scope.range, position)) {
417
569
  //see if any of that scope's children match the position also, and give them priority
418
- let childFunc = this.getFunctionExpressionAtPosition(position, functionExpression.childFunctionExpressions);
419
- if (childFunc) {
420
- return childFunc;
570
+ let childScope = this._getFunctionScopeAtPosition(position, scope.childrenScopes);
571
+ if (childScope) {
572
+ return childScope;
421
573
  }
422
574
  else {
423
- return functionExpression;
575
+ return scope;
424
576
  }
425
577
  }
426
578
  }
427
579
  }
428
580
  /**
429
581
  * Find the NamespaceStatement enclosing the given position
430
- * @param position
431
- * @param functionScopes
432
582
  */
433
583
  getNamespaceStatementForPosition(position) {
434
584
  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
- }
442
- /**
443
- * Get completions available at the given cursor. This aggregates all values from this file and the current scope.
444
- */
445
- getCompletions(position, scope) {
446
- var _a;
447
- let result = [];
448
- //a map of lower-case names of all added options
449
- let names = {};
450
- //handle script import completions
451
- let scriptImport = util_1.util.getScriptImportAtPosition(this.ownScriptImports, position);
452
- if (scriptImport) {
453
- return this.program.getScriptImportCompletions(this.pkgPath, scriptImport);
454
- }
455
- //if cursor is within a comment, disable completions
456
- let currentToken = this.parser.getTokenAt(position);
457
- const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
458
- if (tokenKind === TokenKind_1.TokenKind.Comment) {
459
- return [];
460
- }
461
- else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
462
- const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
463
- if (match) {
464
- const [, openingQuote, fileProtocol] = match;
465
- //include every pkgPath from this scope
466
- for (const file of scope.getAllFiles()) {
467
- const pkgPath = `${fileProtocol}:/${file.pkgPath.replace('pkg:/', '')}`;
468
- result.push({
469
- label: pkgPath,
470
- textEdit: vscode_languageserver_1.TextEdit.replace(util_1.util.createRange(currentToken.range.start.line,
471
- //+1 to step past the opening quote
472
- currentToken.range.start.character + (openingQuote ? 1 : 0), currentToken.range.end.line,
473
- //-1 to exclude the closing quotemark (or the end character if there is no closing quotemark)
474
- currentToken.range.end.character + (currentToken.text.endsWith('"') ? -1 : 0)), pkgPath),
475
- kind: vscode_languageserver_1.CompletionItemKind.File
476
- });
477
- }
478
- return result;
479
- }
480
- else {
481
- //do nothing. we don't want to show completions inside of strings...
482
- return [];
483
- }
484
- }
485
- const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
486
- if (namespaceCompletions.length > 0) {
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;
493
- }
494
- //determine if cursor is inside a function
495
- let functionExpression = this.getFunctionExpressionAtPosition(position);
496
- if (!functionExpression) {
497
- //we aren't in any function scope, so return the keyword completions and namespaces
498
- if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
499
- // there's a new keyword, so only class types are viable here
500
- return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope)];
501
- }
502
- else {
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);
515
- if (newToken) {
516
- //we are after a new keyword; so we can only be top-level namespaces or classes at this point
517
- result.push(...classNameCompletions);
518
- result.push(...namespaceCompletions);
519
- return result;
520
- }
521
- if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
522
- return this.getLabelCompletion(functionExpression);
523
- }
524
- if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
525
- const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
526
- if (selfClassMemberCompletions.size > 0) {
527
- return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
528
- }
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) {
535
- //and anything from any class in scope to a non m class
536
- let classMemberCompletions = scope.getAllClassMemberCompletions();
537
- result.push(...classMemberCompletions.values());
538
- result.push(...scope.getPropertyNameCompletions().filter((i) => !classMemberCompletions.has(i.label)));
539
- }
540
- else {
541
- result.push(...scope.getPropertyNameCompletions());
542
- }
543
- }
544
- else {
545
- //include namespaces
546
- result.push(...namespaceCompletions);
547
- //include class names
548
- result.push(...classNameCompletions);
549
- //include interfaces
550
- result.push(...interfaceNameCompletions);
551
- //include enums
552
- result.push(...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope));
553
- //include the global callables
554
- result.push(...scope.getCallablesAsCompletions(this.parseMode));
555
- //add `m` because that's always valid within a function
556
- result.push({
557
- label: 'm',
558
- kind: vscode_languageserver_1.CompletionItemKind.Variable
559
- });
560
- names.m = true;
561
- result.push(...exports.KeywordCompletions);
562
- //include local variables
563
- for (let symbol of functionExpression.symbolTable.getOwnSymbols()) {
564
- const symbolNameLower = symbol.name.toLowerCase();
565
- //skip duplicate variable names
566
- if (names[symbolNameLower]) {
567
- continue;
568
- }
569
- names[symbolNameLower] = true;
570
- // TODO TYPES (This may be a performance hit?)
571
- // const foundType = getTypeFromContext(symbol.type, { scope: scope, file: this });
572
- result.push({
573
- //TODO does this work?
574
- label: symbol.name,
575
- //TODO TYPES find type for local vars - SEE above
576
- kind: vscode_languageserver_1.CompletionItemKind.Variable
577
- // kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
578
- });
579
- }
580
- if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
581
- //include the first part of namespaces
582
- let namespaces = scope.getAllNamespaceStatements();
583
- for (let stmt of namespaces) {
584
- let firstPart = stmt.nameExpression.getNameParts().shift();
585
- //skip duplicate namespace names
586
- if (names[firstPart.toLowerCase()]) {
587
- continue;
585
+ return this.cache.getOrAdd(`namespaceStatementForPosition-${position.line}:${position.character}`, () => {
586
+ for (const statement of this._cachedLookups.namespaceStatements) {
587
+ if (util_1.util.rangeContains(statement.range, position)) {
588
+ return statement;
588
589
  }
589
- names[firstPart.toLowerCase()] = true;
590
- result.push({
591
- label: firstPart,
592
- kind: vscode_languageserver_1.CompletionItemKind.Module
593
- });
594
- }
595
- }
596
- }
597
- return result;
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
- }
607
- getLabelCompletion(func) {
608
- return func.labelStatements.map(label => ({
609
- label: label.tokens.identifier.text,
610
- kind: vscode_languageserver_1.CompletionItemKind.Reference
611
- }));
612
- }
613
- getClassMemberCompletions(position, currentToken, functionExpression, scope) {
614
- var _a, _b, _c, _d;
615
- let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
616
- let results = new Map();
617
- if (classStatement) {
618
- let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
619
- for (let cs of classes) {
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 : []]) {
621
- if (!results.has(member.name.text.toLowerCase())) {
622
- results.set(member.name.text.toLowerCase(), {
623
- label: member.name.text,
624
- kind: (0, reflection_1.isFieldStatement)(member) ? vscode_languageserver_1.CompletionItemKind.Field : vscode_languageserver_1.CompletionItemKind.Method
625
- });
626
- }
627
- }
628
- }
629
- }
630
- return results;
631
- }
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 };
654
- }
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
- }
660
- }
661
- return undefined;
662
- }
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) {
687
- var _a;
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
590
  }
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) {
901
- return [];
902
- }
903
- let results = new Map();
904
- let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
905
- if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
906
- return [];
907
- }
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
- });
989
- }
990
- }
991
- return [...results.values()];
992
- }
993
- getNamespaceCompletions(currentToken, parseMode, scope) {
994
- //BrightScript does not support namespaces, so return an empty list in that case
995
- if (parseMode === Parser_1.ParseMode.BrightScript) {
996
- return [];
997
- }
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('.')) {
1001
- return [];
1002
- }
1003
- //remove any trailing identifer and then any trailing dot, to give us the
1004
- //name of its immediate parent namespace
1005
- let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
1006
- let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
1007
- let result = new Map();
1008
- for (let [, namespace] of scope.namespaceLookup) {
1009
- //completionName = "NameA."
1010
- //completionName = "NameA.Na
1011
- //NameA
1012
- //NameA.NameB
1013
- //NameA.NameB.NameC
1014
- if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
1015
- //add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
1016
- for (let [, ns] of namespace.namespaces) {
1017
- if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
1018
- if (!result.has(ns.lastPartName)) {
1019
- result.set(ns.lastPartName, {
1020
- label: ns.lastPartName,
1021
- kind: vscode_languageserver_1.CompletionItemKind.Module
1022
- });
1023
- }
1024
- }
1025
- }
1026
- //add function and class statement completions
1027
- for (let stmt of namespace.statements) {
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
- });
1033
- }
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
- });
1045
- }
1046
- }
1047
- }
591
+ });
1048
592
  }
1049
- return [...result.values()];
1050
593
  }
1051
594
  getNamespaceDefinitions(token, file) {
1052
595
  //BrightScript does not support namespaces, so return an empty list in that case
@@ -1062,7 +605,7 @@ class BrsFile {
1062
605
  const namespaceItemStatementHandler = (statement) => {
1063
606
  if (!location && statement.name.text.toLowerCase() === endName) {
1064
607
  const uri = util_1.util.pathToUri(file.srcPath);
1065
- location = vscode_languageserver_1.Location.create(uri, statement.range);
608
+ location = util_1.util.createLocation(uri, statement.range);
1066
609
  }
1067
610
  };
1068
611
  file.parser.ast.walk((0, visitors_1.createVisitor)({
@@ -1105,6 +648,70 @@ class BrsFile {
1105
648
  return undefined;
1106
649
  }
1107
650
  }
651
+ isPositionNextToTokenKind(position, tokenKind) {
652
+ const closestToken = this.getClosestToken(position);
653
+ return this.isTokenNextToTokenKind(closestToken, tokenKind);
654
+ }
655
+ isTokenNextToTokenKind(closestToken, tokenKind) {
656
+ const previousToken = this.getPreviousToken(closestToken);
657
+ const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
658
+ //next to matched token
659
+ if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
660
+ return false;
661
+ }
662
+ else if (closestToken.kind === tokenKind) {
663
+ return true;
664
+ }
665
+ else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
666
+ return false;
667
+ //next to an identifier, which is next to token kind
668
+ }
669
+ else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
670
+ return true;
671
+ }
672
+ else {
673
+ return false;
674
+ }
675
+ }
676
+ getTokenBefore(currentToken, tokenKind) {
677
+ const index = this.parser.tokens.indexOf(currentToken);
678
+ if (!tokenKind) {
679
+ return this.parser.tokens[index - 1];
680
+ }
681
+ for (let i = index - 1; i >= 0; i--) {
682
+ currentToken = this.parser.tokens[i];
683
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
684
+ break;
685
+ }
686
+ else if (currentToken.kind === tokenKind) {
687
+ return currentToken;
688
+ }
689
+ }
690
+ return undefined;
691
+ }
692
+ tokenFollows(currentToken, tokenKind) {
693
+ const index = this.parser.tokens.indexOf(currentToken);
694
+ if (index > 0) {
695
+ return this.parser.tokens[index - 1].kind === tokenKind;
696
+ }
697
+ return false;
698
+ }
699
+ getTokensUntil(currentToken, tokenKind, direction = -1) {
700
+ let tokens = [];
701
+ for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
702
+ currentToken = this.parser.tokens[i];
703
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
704
+ break;
705
+ }
706
+ tokens.push(currentToken);
707
+ }
708
+ return tokens;
709
+ }
710
+ getPreviousToken(token) {
711
+ const parser = this.parser;
712
+ let idx = parser.tokens.indexOf(token);
713
+ return parser.tokens[idx - 1];
714
+ }
1108
715
  /**
1109
716
  * Find the first scope that has a namespace with this name.
1110
717
  * Returns false if no namespace was found with that name
@@ -1138,14 +745,60 @@ class BrsFile {
1138
745
  let scopes = this.program.getScopesForFile(this);
1139
746
  for (let scope of scopes) {
1140
747
  let namespace = scope.namespaceLookup.get(namespaceName.toLowerCase());
1141
- if (namespace.functionStatements[lowerCalleeName]) {
748
+ if (namespace.functionStatements.has(lowerCalleeName)) {
1142
749
  return true;
1143
750
  }
751
+ if (namespace.classStatements.has(lowerCalleeName)) {
752
+ return true;
753
+ }
754
+ }
755
+ }
756
+ }
757
+ return false;
758
+ }
759
+ /**
760
+ * Determine if the callee (i.e. function name) is a known function
761
+ */
762
+ calleeIsKnownFunction(callee, namespaceName) {
763
+ var _a, _b;
764
+ //if we have a variable and a namespace
765
+ if ((0, reflection_1.isVariableExpression)(callee)) {
766
+ if (namespaceName) {
767
+ return this.calleeIsKnownNamespaceFunction(callee, namespaceName);
768
+ }
769
+ let scopes = this.program.getScopesForFile(this);
770
+ 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();
771
+ for (let scope of scopes) {
772
+ if (scope.getCallableByName(lowerCalleeName)) {
773
+ return true;
774
+ }
775
+ if (scope.getClass(lowerCalleeName)) {
776
+ return true;
1144
777
  }
1145
778
  }
1146
779
  }
1147
780
  return false;
1148
781
  }
782
+ /**
783
+ * Get the token closest to the position. if no token is found, the previous token is returned
784
+ */
785
+ getClosestToken(position) {
786
+ let tokens = this.parser.tokens;
787
+ for (let i = 0; i < tokens.length; i++) {
788
+ let token = tokens[i];
789
+ if (util_1.util.rangeContains(token.range, position)) {
790
+ return token;
791
+ }
792
+ //if the position less than this token range, then this position touches no token,
793
+ if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
794
+ let t = tokens[i - 1];
795
+ //return the token or the first token
796
+ return t ? t : tokens[0];
797
+ }
798
+ }
799
+ //return the last token
800
+ return tokens[tokens.length - 1];
801
+ }
1149
802
  /**
1150
803
  * Builds a list of document symbols for this file. Used by LanguageServer's onDocumentSymbol functionality
1151
804
  */
@@ -1186,16 +839,16 @@ class BrsFile {
1186
839
  let symbolKind;
1187
840
  const children = [];
1188
841
  if ((0, reflection_1.isFunctionStatement)(statement)) {
1189
- symbolKind = vscode_languageserver_1.SymbolKind.Function;
842
+ symbolKind = vscode_languageserver_2.SymbolKind.Function;
1190
843
  }
1191
844
  else if ((0, reflection_1.isMethodStatement)(statement)) {
1192
- symbolKind = vscode_languageserver_1.SymbolKind.Method;
845
+ symbolKind = vscode_languageserver_2.SymbolKind.Method;
1193
846
  }
1194
847
  else if ((0, reflection_1.isFieldStatement)(statement)) {
1195
- symbolKind = vscode_languageserver_1.SymbolKind.Field;
848
+ symbolKind = vscode_languageserver_2.SymbolKind.Field;
1196
849
  }
1197
850
  else if ((0, reflection_1.isNamespaceStatement)(statement)) {
1198
- symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
851
+ symbolKind = vscode_languageserver_2.SymbolKind.Namespace;
1199
852
  for (const childStatement of statement.body.statements) {
1200
853
  const symbol = this.getDocumentSymbol(childStatement);
1201
854
  if (symbol) {
@@ -1204,7 +857,7 @@ class BrsFile {
1204
857
  }
1205
858
  }
1206
859
  else if ((0, reflection_1.isClassStatement)(statement)) {
1207
- symbolKind = vscode_languageserver_1.SymbolKind.Class;
860
+ symbolKind = vscode_languageserver_2.SymbolKind.Class;
1208
861
  for (const childStatement of statement.body) {
1209
862
  const symbol = this.getDocumentSymbol(childStatement);
1210
863
  if (symbol) {
@@ -1216,7 +869,7 @@ class BrsFile {
1216
869
  return;
1217
870
  }
1218
871
  const name = (0, reflection_1.isFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
1219
- return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
872
+ return vscode_languageserver_2.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
1220
873
  }
1221
874
  /**
1222
875
  * Builds a single SymbolInformation object for use by LanguageServer's onWorkspaceSymbol functionality
@@ -1225,13 +878,13 @@ class BrsFile {
1225
878
  let symbolKind;
1226
879
  const symbols = [];
1227
880
  if ((0, reflection_1.isFunctionStatement)(statement)) {
1228
- symbolKind = vscode_languageserver_1.SymbolKind.Function;
881
+ symbolKind = vscode_languageserver_2.SymbolKind.Function;
1229
882
  }
1230
883
  else if ((0, reflection_1.isMethodStatement)(statement)) {
1231
- symbolKind = vscode_languageserver_1.SymbolKind.Method;
884
+ symbolKind = vscode_languageserver_2.SymbolKind.Method;
1232
885
  }
1233
886
  else if ((0, reflection_1.isNamespaceStatement)(statement)) {
1234
- symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
887
+ symbolKind = vscode_languageserver_2.SymbolKind.Namespace;
1235
888
  for (const childStatement of statement.body.statements) {
1236
889
  for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
1237
890
  symbols.push(symbol);
@@ -1239,7 +892,7 @@ class BrsFile {
1239
892
  }
1240
893
  }
1241
894
  else if ((0, reflection_1.isClassStatement)(statement)) {
1242
- symbolKind = vscode_languageserver_1.SymbolKind.Class;
895
+ symbolKind = vscode_languageserver_2.SymbolKind.Class;
1243
896
  for (const childStatement of statement.body) {
1244
897
  for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
1245
898
  symbols.push(symbol);
@@ -1251,7 +904,7 @@ class BrsFile {
1251
904
  }
1252
905
  const name = statement.getName(Parser_1.ParseMode.BrighterScript);
1253
906
  const uri = util_1.util.pathToUri(this.srcPath);
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));
907
+ const symbol = vscode_languageserver_2.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(Parser_1.ParseMode.BrighterScript));
1255
908
  symbols.push(symbol);
1256
909
  return symbols;
1257
910
  }
@@ -1260,9 +913,10 @@ class BrsFile {
1260
913
  * go to the definition of that identifier (where this thing was first defined)
1261
914
  */
1262
915
  getDefinition(position) {
916
+ var _a, _b;
1263
917
  let results = [];
1264
918
  //get the token at the position
1265
- const token = this.parser.getTokenAt(position);
919
+ const token = this.getTokenAt(position);
1266
920
  // 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
1267
921
  let definitionTokenTypes = [
1268
922
  TokenKind_1.TokenKind.Identifier,
@@ -1272,26 +926,62 @@ class BrsFile {
1272
926
  if (!token || !definitionTokenTypes.includes(token.kind)) {
1273
927
  return results;
1274
928
  }
929
+ const scopesForFile = this.program.getScopesForFile(this);
930
+ const [scope] = scopesForFile;
931
+ const expression = this.getClosestExpression(position);
932
+ if (scope && expression) {
933
+ scope.linkSymbolTable();
934
+ let containingNamespace = (_a = expression.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
935
+ const fullName = (_b = util_1.util.getAllDottedGetParts(expression)) === null || _b === void 0 ? void 0 : _b.map(x => x.text).join('.');
936
+ //find a constant with this name
937
+ const constant = scope === null || scope === void 0 ? void 0 : scope.getConstFileLink(fullName, containingNamespace);
938
+ if (constant) {
939
+ results.push(util_1.util.createLocation(vscode_uri_1.URI.file(constant.file.srcPath).toString(), constant.item.tokens.name.range));
940
+ return results;
941
+ }
942
+ if ((0, reflection_1.isDottedGetExpression)(expression) || (0, reflection_1.isVariableExpression)(expression)) {
943
+ const enumLink = scope.getEnumFileLink(fullName, containingNamespace);
944
+ if (enumLink) {
945
+ results.push(util_1.util.createLocation(vscode_uri_1.URI.file(enumLink.file.srcPath).toString(), enumLink.item.tokens.name.range));
946
+ return results;
947
+ }
948
+ const enumMemberLink = scope.getEnumMemberFileLink(fullName, containingNamespace);
949
+ if (enumMemberLink) {
950
+ results.push(util_1.util.createLocation(vscode_uri_1.URI.file(enumMemberLink.file.srcPath).toString(), enumMemberLink.item.tokens.name.range));
951
+ return results;
952
+ }
953
+ const interfaceFileLink = scope.getInterfaceFileLink(fullName, containingNamespace);
954
+ if (interfaceFileLink) {
955
+ results.push(util_1.util.createLocation(vscode_uri_1.URI.file(interfaceFileLink.file.srcPath).toString(), interfaceFileLink.item.tokens.name.range));
956
+ return results;
957
+ }
958
+ const classFileLink = scope.getClassFileLink(fullName, containingNamespace);
959
+ if (classFileLink) {
960
+ results.push(util_1.util.createLocation(vscode_uri_1.URI.file(classFileLink.file.srcPath).toString(), classFileLink.item.name.range));
961
+ return results;
962
+ }
963
+ }
964
+ }
1275
965
  let textToSearchFor = token.text.toLowerCase();
1276
- const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
966
+ const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
1277
967
  if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
1278
- for (const scope of this.program.getScopes()) {
968
+ for (const scope of scopesForFile) {
1279
969
  //to only get functions defined in interface methods
1280
970
  const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
1281
971
  if (callable) {
1282
- results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(callable.callable.file.srcPath), callable.callable.functionStatement.range));
972
+ results.push(util_1.util.createLocation(util_1.util.pathToUri(callable.callable.file.srcPath), callable.callable.functionStatement.range));
1283
973
  }
1284
974
  }
1285
975
  return results;
1286
976
  }
1287
- let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
977
+ let classToken = this.getTokenBefore(token, TokenKind_1.TokenKind.Class);
1288
978
  if (classToken) {
1289
- let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
979
+ let cs = this._cachedLookups.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
1290
980
  if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
1291
981
  const nameParts = cs.parentClassName.getNameParts();
1292
982
  let extendedClass = this.getClassFileLink(nameParts[nameParts.length - 1], nameParts.slice(0, -1).join('.'));
1293
983
  if (extendedClass) {
1294
- results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(extendedClass.file.srcPath), extendedClass.item.range));
984
+ results.push(util_1.util.createLocation(util_1.util.pathToUri(extendedClass.file.srcPath), extendedClass.item.range));
1295
985
  }
1296
986
  }
1297
987
  return results;
@@ -1305,52 +995,51 @@ class BrsFile {
1305
995
  }
1306
996
  textToSearchFor = textToSearchFor.substring(startIndex, endIndex);
1307
997
  }
1308
- const func = this.getFunctionExpressionAtPosition(position);
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) {
998
+ //look through local variables first, get the function scope for this position (if it exists)
999
+ const functionScope = this.getFunctionScopeAtPosition(position);
1000
+ if (functionScope) {
1001
+ //find any variable or label with this name
1002
+ for (const varDeclaration of functionScope.variableDeclarations) {
1003
+ //we found a variable declaration with this token text!
1004
+ if (varDeclaration.name.toLowerCase() === textToSearchFor) {
1315
1005
  const uri = util_1.util.pathToUri(this.srcPath);
1316
- results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
1006
+ results.push(util_1.util.createLocation(uri, varDeclaration.nameRange));
1317
1007
  }
1318
1008
  }
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) {
1009
+ if (this.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
1010
+ for (const label of functionScope.labelStatements) {
1011
+ if (label.name.toLocaleLowerCase() === textToSearchFor) {
1322
1012
  const uri = util_1.util.pathToUri(this.srcPath);
1323
- results.push(vscode_languageserver_1.Location.create(uri, label.tokens.identifier.range));
1013
+ results.push(util_1.util.createLocation(uri, label.nameRange));
1324
1014
  }
1325
1015
  }
1326
1016
  }
1327
1017
  }
1328
1018
  const filesSearched = new Set();
1329
1019
  //look through all files in scope for matches
1330
- for (const scope of this.program.getScopesForFile(this)) {
1020
+ for (const scope of scopesForFile) {
1331
1021
  for (const file of scope.getAllFiles()) {
1332
- if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
1333
- continue;
1334
- }
1335
- filesSearched.add(file);
1336
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1337
- results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1338
- const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1339
- if (namespaceDefinition) {
1340
- results.push(namespaceDefinition);
1022
+ if ((0, reflection_1.isBrsFile)(file) && !filesSearched.has(file)) {
1023
+ filesSearched.add(file);
1024
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1025
+ results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1026
+ const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1027
+ if (namespaceDefinition) {
1028
+ results.push(namespaceDefinition);
1029
+ }
1341
1030
  }
1031
+ const statementHandler = (statement) => {
1032
+ if (statement.getName(this.parseMode).toLowerCase() === textToSearchFor) {
1033
+ const uri = util_1.util.pathToUri(file.srcPath);
1034
+ results.push(util_1.util.createLocation(uri, statement.range));
1035
+ }
1036
+ };
1037
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
1038
+ FunctionStatement: statementHandler
1039
+ }), {
1040
+ walkMode: visitors_1.WalkMode.visitStatements
1041
+ });
1342
1042
  }
1343
- const statementHandler = (statement) => {
1344
- if (statement.getName(this.parseMode).toLowerCase() === textToSearchFor) {
1345
- const uri = util_1.util.pathToUri(file.srcPath);
1346
- results.push(vscode_languageserver_1.Location.create(uri, statement.range));
1347
- }
1348
- };
1349
- file.parser.ast.walk((0, visitors_1.createVisitor)({
1350
- FunctionStatement: statementHandler
1351
- }), {
1352
- walkMode: visitors_1.WalkMode.visitStatements
1353
- });
1354
1043
  }
1355
1044
  }
1356
1045
  return results;
@@ -1358,225 +1047,27 @@ class BrsFile {
1358
1047
  getClassMemberDefinitions(textToSearchFor, file) {
1359
1048
  let results = [];
1360
1049
  //get class fields and members
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
- }
1050
+ const statementHandler = (statement) => {
1051
+ if (statement.getName(file.parseMode).toLowerCase() === textToSearchFor) {
1052
+ results.push(util_1.util.createLocation(util_1.util.pathToUri(file.srcPath), statement.range));
1053
+ }
1054
+ };
1055
+ const fieldStatementHandler = (statement) => {
1056
+ if (statement.name.text.toLowerCase() === textToSearchFor) {
1057
+ results.push(util_1.util.createLocation(util_1.util.pathToUri(file.srcPath), statement.range));
1371
1058
  }
1059
+ };
1060
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
1061
+ MethodStatement: statementHandler,
1062
+ FieldStatement: fieldStatementHandler
1372
1063
  }), {
1373
1064
  walkMode: visitors_1.WalkMode.visitStatements
1374
1065
  });
1375
1066
  return results;
1376
1067
  }
1377
- getHover(position) {
1378
- var _a, _b, _c;
1379
- const fence = (code) => util_1.util.mdFence(code, 'brightscript');
1380
- //get the token at the position
1381
- let token = this.parser.getTokenAt(position);
1382
- let hoverTokenTypes = [
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
1388
- ];
1389
- //throw out invalid tokens and the wrong kind of tokens
1390
- if (!token || !hoverTokenTypes.includes(token.kind)) {
1391
- return null;
1392
- }
1393
- let lowerTokenText = token.text.toLowerCase();
1394
- //look through local variables first
1395
- {
1396
- const func = this.getFunctionExpressionAtPosition(position);
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
- }
1406
- }
1407
- }
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) {
1412
- scope.linkSymbolTable();
1413
- const typeContext = { file: this, scope: scope, position: position };
1414
- const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
1415
- if (typeTextPair) {
1416
- let scopeTypeText = '';
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;
1426
- }
1427
- else {
1428
- scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString(typeContext)}`;
1429
- }
1430
- if (scopeTypeText) {
1431
- typeTexts.add(scopeTypeText);
1432
- }
1433
- }
1434
- scope.unlinkSymbolTable();
1435
- }
1436
- if (callables.length === typeTexts.size) {
1437
- //this is a function in all scopes, so build the function hover
1438
- return {
1439
- range: token.range,
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)
1448
- };
1449
- }
1450
- }
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
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');
1495
- }
1496
- return result;
1497
- }
1498
- getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
1499
- var _a;
1500
- if (!dottedGetText) {
1501
- return [];
1502
- }
1503
- let resultsMap = new Map();
1504
- for (let [, namespace] of scope.namespaceLookup) {
1505
- //completionName = "NameA."
1506
- //completionName = "NameA.Na
1507
- //NameA
1508
- //NameA.NameB
1509
- //NameA.NameB.NameC
1510
- if (namespace.fullName.toLowerCase() === dottedGetText.toLowerCase()) {
1511
- //add function and class statement completions
1512
- for (let stmt of namespace.statements) {
1513
- if ((0, reflection_1.isFunctionStatement)(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
1514
- const result = (_a = namespace.file) === null || _a === void 0 ? void 0 : _a.getSignatureHelpForStatement(stmt);
1515
- if (!resultsMap.has(result.key)) {
1516
- resultsMap.set(result.key, result);
1517
- }
1518
- }
1519
- }
1520
- }
1521
- }
1522
- return [...resultsMap.values()];
1523
- }
1524
- getSignatureHelpForStatement(statement) {
1525
- if (!(0, reflection_1.isFunctionStatement)(statement) && !(0, reflection_1.isMethodStatement)(statement)) {
1526
- return undefined;
1527
- }
1528
- const func = statement.func;
1529
- const funcStartPosition = func.range.start;
1530
- // Get function comments in reverse order
1531
- let currentToken = this.parser.getTokenAt(funcStartPosition);
1532
- let functionComments = [];
1533
- while (currentToken) {
1534
- currentToken = this.parser.getPreviousToken(currentToken);
1535
- if (!currentToken) {
1536
- break;
1537
- }
1538
- if (currentToken.range.start.line + 1 < funcStartPosition.line) {
1539
- if (functionComments.length === 0) {
1540
- break;
1541
- }
1542
- }
1543
- const kind = currentToken.kind;
1544
- if (kind === TokenKind_1.TokenKind.Comment) {
1545
- // Strip off common leading characters to make it easier to read
1546
- const commentText = currentToken.text.replace(/^[' *\/]+/, '');
1547
- functionComments.unshift(commentText);
1548
- }
1549
- else if (kind === TokenKind_1.TokenKind.Newline) {
1550
- if (functionComments.length === 0) {
1551
- continue;
1552
- }
1553
- // if we already had a new line as the last token then exit out
1554
- if (functionComments[0] === currentToken.text) {
1555
- break;
1556
- }
1557
- functionComments.unshift(currentToken.text);
1558
- }
1559
- else {
1560
- break;
1561
- }
1562
- }
1563
- const documentation = functionComments.join('').trim();
1564
- const lines = util_1.util.splitIntoLines(this.fileContents);
1565
- let key = statement.name.text + documentation;
1566
- const params = [];
1567
- for (const param of func.parameters) {
1568
- params.push(vscode_languageserver_1.ParameterInformation.create(param.name.text));
1569
- key += param.name.text;
1570
- }
1571
- const label = util_1.util.getTextForRange(lines, func.functionDeclarationRange).trim();
1572
- const signature = vscode_languageserver_1.SignatureInformation.create(label, documentation, ...params);
1573
- const index = 1;
1574
- return { key: key, signature: signature, index: index };
1575
- }
1576
1068
  getClassMethod(classStatement, name, walkParents = true) {
1577
1069
  var _a;
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?
1070
+ //TODO - would like to write this with getClassHieararchy; but got stuck on working out the scopes to use... :(
1580
1071
  let statement;
1581
1072
  const statementHandler = (e) => {
1582
1073
  if (!statement && e.name.text.toLowerCase() === name.toLowerCase()) {
@@ -1602,45 +1093,55 @@ class BrsFile {
1602
1093
  }
1603
1094
  return statement;
1604
1095
  }
1605
- getClassSignatureHelp(classStatement) {
1606
- const classConstructor = this.getClassMethod(classStatement, 'new');
1607
- let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
1608
- if (sigHelp) {
1609
- sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
1610
- sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
1611
- }
1612
- return sigHelp;
1613
- }
1614
1096
  getReferences(position) {
1615
- const callSiteToken = this.parser.getTokenAt(position);
1097
+ const callSiteToken = this.getTokenAt(position);
1616
1098
  let locations = [];
1617
1099
  const searchFor = callSiteToken.text.toLowerCase();
1618
1100
  const scopes = this.program.getScopesForFile(this);
1619
1101
  for (const scope of scopes) {
1620
1102
  const processedFiles = new Set();
1621
1103
  for (const file of scope.getAllFiles()) {
1622
- if ((0, reflection_1.isXmlFile)(file) || processedFiles.has(file)) {
1623
- continue;
1624
- }
1625
- processedFiles.add(file);
1626
- file.ast.walk((0, visitors_1.createVisitor)({
1627
- VariableExpression: (e) => {
1628
- if (e.name.text.toLowerCase() === searchFor) {
1629
- locations.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), e.range));
1104
+ if ((0, reflection_1.isBrsFile)(file) && !processedFiles.has(file)) {
1105
+ processedFiles.add(file);
1106
+ file.ast.walk((0, visitors_1.createVisitor)({
1107
+ VariableExpression: (e) => {
1108
+ if (e.name.text.toLowerCase() === searchFor) {
1109
+ locations.push(util_1.util.createLocation(util_1.util.pathToUri(file.srcPath), e.range));
1110
+ }
1630
1111
  }
1631
- }
1632
- }), {
1633
- walkMode: visitors_1.WalkMode.visitExpressionsRecursive
1634
- });
1112
+ }), {
1113
+ walkMode: visitors_1.WalkMode.visitExpressionsRecursive
1114
+ });
1115
+ }
1635
1116
  }
1636
1117
  }
1637
1118
  return locations;
1638
1119
  }
1120
+ /**
1121
+ * Generate the code, map, and typedef for this file
1122
+ */
1123
+ serialize() {
1124
+ const result = {};
1125
+ const transpiled = this.transpile();
1126
+ if (typeof transpiled.code === 'string') {
1127
+ result.code = transpiled.code;
1128
+ }
1129
+ if (transpiled.map) {
1130
+ result.map = transpiled.map.toString();
1131
+ }
1132
+ //generate the typedef (if this is not a typedef itself, and if enabled)
1133
+ if (!this.isTypedef && this.program.options.emitDefinitions) {
1134
+ result.typedef = this.getTypedef();
1135
+ }
1136
+ return result;
1137
+ }
1639
1138
  /**
1640
1139
  * Convert the brightscript/brighterscript source code into valid brightscript
1641
1140
  */
1642
1141
  transpile() {
1142
+ var _a;
1643
1143
  const state = new BrsTranspileState_1.BrsTranspileState(this);
1144
+ state.editor = (_a = this.editor) !== null && _a !== void 0 ? _a : new Editor_1.Editor();
1644
1145
  let transpileResult;
1645
1146
  if (this.needsTranspiled) {
1646
1147
  transpileResult = new source_map_1.SourceNode(null, null, state.srcPath, this.ast.transpile(state));
@@ -1653,8 +1154,11 @@ class BrsFile {
1653
1154
  //simple SourceNode wrapping the entire file to simplify the logic below
1654
1155
  transpileResult = new source_map_1.SourceNode(null, null, state.srcPath, this.fileContents);
1655
1156
  }
1656
- //undo any AST edits that the transpile cycle has made
1657
- state.editor.undoAll();
1157
+ //if we created an editor for this flow, undo the edits now
1158
+ if (!this.editor) {
1159
+ //undo any AST edits that the transpile cycle has made
1160
+ state.editor.undoAll();
1161
+ }
1658
1162
  if (this.program.options.sourceMap) {
1659
1163
  return new source_map_1.SourceNode(null, null, null, [
1660
1164
  transpileResult,
@@ -1669,6 +1173,206 @@ class BrsFile {
1669
1173
  };
1670
1174
  }
1671
1175
  }
1176
+ processSymbolInformation() {
1177
+ this.validationSegmenter.processTree(this.ast);
1178
+ this.program.addFileSymbolInfo(this);
1179
+ }
1180
+ getValidationSegments(changedSymbols) {
1181
+ const segments = this.validationSegmenter.getSegments(changedSymbols);
1182
+ return segments;
1183
+ }
1184
+ get requiredSymbols() {
1185
+ return this.cache.getOrAdd(`requiredSymbols`, () => {
1186
+ var _a, _b, _c;
1187
+ const allNeededSymbolSets = this.validationSegmenter.unresolvedSegmentsSymbols.values();
1188
+ const requiredSymbols = [];
1189
+ const addedSymbols = new Map();
1190
+ addedSymbols.set(SymbolTable_1.SymbolTypeFlag.runtime, new Set());
1191
+ addedSymbols.set(SymbolTable_1.SymbolTypeFlag.typetime, new Set());
1192
+ for (const setOfSymbols of allNeededSymbolSets) {
1193
+ for (const symbol of setOfSymbols) {
1194
+ const fullSymbolKey = symbol.typeChain.map(tce => tce.name).join('.').toLowerCase();
1195
+ for (const flag of [SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.typetime]) {
1196
+ // eslint-disable-next-line no-bitwise
1197
+ if (symbol.flags & flag) {
1198
+ if ((_a = this.providedSymbols.symbolMap.get(flag)) === null || _a === void 0 ? void 0 : _a.has(fullSymbolKey)) {
1199
+ // this catches namespaced things
1200
+ continue;
1201
+ }
1202
+ if (!((_b = addedSymbols.get(flag)) === null || _b === void 0 ? void 0 : _b.has(fullSymbolKey))) {
1203
+ requiredSymbols.push(symbol);
1204
+ (_c = addedSymbols.get(flag)) === null || _c === void 0 ? void 0 : _c.add(fullSymbolKey);
1205
+ }
1206
+ }
1207
+ }
1208
+ }
1209
+ }
1210
+ return requiredSymbols;
1211
+ });
1212
+ }
1213
+ get providedSymbols() {
1214
+ var _a;
1215
+ return (_a = this.cache) === null || _a === void 0 ? void 0 : _a.getOrAdd(`providedSymbols`, () => {
1216
+ return this.getProvidedSymbols();
1217
+ });
1218
+ }
1219
+ getProvidedSymbols() {
1220
+ var _a, _b;
1221
+ const symbolMap = new Map();
1222
+ const runTimeSymbolMap = new Map();
1223
+ const typeTimeSymbolMap = new Map();
1224
+ const tablesToGetSymbolsFrom = [{
1225
+ table: this.parser.symbolTable
1226
+ }];
1227
+ for (const namespaceStatement of this._cachedLookups.namespaceStatements) {
1228
+ tablesToGetSymbolsFrom.push({
1229
+ table: namespaceStatement.body.getSymbolTable(),
1230
+ namePrefixLower: namespaceStatement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase()
1231
+ });
1232
+ }
1233
+ for (const symbolTable of tablesToGetSymbolsFrom) {
1234
+ const runTimeSymbols = symbolTable.table.getOwnSymbols(SymbolTable_1.SymbolTypeFlag.runtime);
1235
+ const typeTimeSymbols = symbolTable.table.getOwnSymbols(SymbolTable_1.SymbolTypeFlag.typetime);
1236
+ for (const symbol of runTimeSymbols) {
1237
+ if (!(0, reflection_1.isAnyReferenceType)(symbol.type)) {
1238
+ const symbolNameLower = symbolTable.namePrefixLower
1239
+ ? `${symbolTable.namePrefixLower}.${symbol.name.toLowerCase()}`
1240
+ : symbol.name.toLowerCase();
1241
+ runTimeSymbolMap.set(symbolNameLower, symbol);
1242
+ }
1243
+ }
1244
+ for (const symbol of typeTimeSymbols) {
1245
+ if (!(0, reflection_1.isAnyReferenceType)(symbol.type)) {
1246
+ const symbolNameLower = symbolTable.namePrefixLower
1247
+ ? `${symbolTable.namePrefixLower}.${symbol.name.toLowerCase()}`
1248
+ : symbol.name.toLowerCase();
1249
+ typeTimeSymbolMap.set(symbolNameLower, symbol);
1250
+ }
1251
+ }
1252
+ }
1253
+ symbolMap.set(SymbolTable_1.SymbolTypeFlag.runtime, runTimeSymbolMap);
1254
+ symbolMap.set(SymbolTable_1.SymbolTypeFlag.typetime, typeTimeSymbolMap);
1255
+ const changes = new Map();
1256
+ changes.set(SymbolTable_1.SymbolTypeFlag.runtime, new Set());
1257
+ changes.set(SymbolTable_1.SymbolTypeFlag.typetime, new Set());
1258
+ const previouslyProvidedSymbols = (_a = this.program.getFileSymbolInfo(this)) === null || _a === void 0 ? void 0 : _a.provides.symbolMap;
1259
+ const previousSymbolsChecked = new Map();
1260
+ previousSymbolsChecked.set(SymbolTable_1.SymbolTypeFlag.runtime, new Set());
1261
+ previousSymbolsChecked.set(SymbolTable_1.SymbolTypeFlag.typetime, new Set());
1262
+ for (const flag of [SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.typetime]) {
1263
+ const newSymbolMapForFlag = symbolMap.get(flag);
1264
+ const oldSymbolMapForFlag = previouslyProvidedSymbols === null || previouslyProvidedSymbols === void 0 ? void 0 : previouslyProvidedSymbols.get(flag);
1265
+ const previousSymbolsCheckedForFlag = previousSymbolsChecked.get(flag);
1266
+ const changesForFlag = changes.get(flag);
1267
+ if (!oldSymbolMapForFlag) {
1268
+ for (const key of newSymbolMapForFlag.keys()) {
1269
+ changesForFlag.add(key);
1270
+ }
1271
+ continue;
1272
+ }
1273
+ for (const [symbolKey, symbol] of newSymbolMapForFlag) {
1274
+ const symbolType = symbol.type;
1275
+ const previousType = (_b = oldSymbolMapForFlag === null || oldSymbolMapForFlag === void 0 ? void 0 : oldSymbolMapForFlag.get(symbolKey)) === null || _b === void 0 ? void 0 : _b.type;
1276
+ previousSymbolsCheckedForFlag.add(symbolKey);
1277
+ if (!previousType) {
1278
+ changesForFlag.add(symbolKey);
1279
+ continue;
1280
+ }
1281
+ const data = {};
1282
+ if (!symbolType.isEqual(previousType, data)) {
1283
+ changesForFlag.add(symbolKey);
1284
+ }
1285
+ }
1286
+ for (const [symbolKey] of previouslyProvidedSymbols.get(flag)) {
1287
+ if (!previousSymbolsCheckedForFlag.has(symbolKey)) {
1288
+ changesForFlag.add(symbolKey);
1289
+ }
1290
+ }
1291
+ }
1292
+ return {
1293
+ symbolMap: symbolMap,
1294
+ changes: changes
1295
+ };
1296
+ }
1297
+ markSegmentAsValidated(node) {
1298
+ this.validationSegmenter.markSegmentAsValidated(node);
1299
+ }
1300
+ getNamespaceLookupObject() {
1301
+ if (!this.isValidated) {
1302
+ return this.buildNamespaceLookup();
1303
+ }
1304
+ return this.cache.getOrAdd(`namespaceLookup`, () => {
1305
+ const nsLookup = this.buildNamespaceLookup();
1306
+ return nsLookup;
1307
+ });
1308
+ }
1309
+ buildNamespaceLookup() {
1310
+ const namespaceLookup = new Map();
1311
+ for (let namespaceStatement of this._cachedLookups.namespaceStatements) {
1312
+ let nameParts = namespaceStatement.getNameParts();
1313
+ let loopName = null;
1314
+ let lowerLoopName = null;
1315
+ let parentNameLower = null;
1316
+ //ensure each namespace section is represented in the results
1317
+ //(so if the namespace name is A.B.C, this will make an entry for "A", an entry for "A.B", and an entry for "A.B.C"
1318
+ for (let i = 0; i < nameParts.length; i++) {
1319
+ let part = nameParts[i];
1320
+ let lowerPartName = part.text.toLowerCase();
1321
+ if (i === 0) {
1322
+ loopName = part.text;
1323
+ lowerLoopName = lowerPartName;
1324
+ }
1325
+ else {
1326
+ parentNameLower = lowerLoopName;
1327
+ loopName += '.' + part.text;
1328
+ lowerLoopName += '.' + lowerPartName;
1329
+ }
1330
+ if (!namespaceLookup.has(lowerLoopName)) {
1331
+ namespaceLookup.set(lowerLoopName, {
1332
+ isTopLevel: i === 0,
1333
+ file: this,
1334
+ fullName: loopName,
1335
+ fullNameLower: lowerLoopName,
1336
+ parentNameLower: parentNameLower,
1337
+ nameParts: nameParts.slice(0, i),
1338
+ nameRange: namespaceStatement.nameExpression.range,
1339
+ lastPartName: part.text,
1340
+ lastPartNameLower: lowerPartName,
1341
+ functionStatements: new Map(),
1342
+ namespaceStatements: [],
1343
+ namespaces: new Map(),
1344
+ classStatements: new Map(),
1345
+ enumStatements: new Map(),
1346
+ constStatements: new Map(),
1347
+ statements: [],
1348
+ // the aggregate symbol table should have no parent. It should include just the symbols of the namespace.
1349
+ symbolTable: new SymbolTable_1.SymbolTable(`Namespace Aggregate: '${loopName}'`)
1350
+ });
1351
+ }
1352
+ }
1353
+ let ns = namespaceLookup.get(lowerLoopName);
1354
+ ns.namespaceStatements.push(namespaceStatement);
1355
+ ns.statements.push(...namespaceStatement.body.statements);
1356
+ for (let statement of namespaceStatement.body.statements) {
1357
+ if ((0, reflection_1.isClassStatement)(statement) && statement.name) {
1358
+ ns.classStatements.set(statement.name.text.toLowerCase(), statement);
1359
+ }
1360
+ else if ((0, reflection_1.isFunctionStatement)(statement) && statement.name) {
1361
+ ns.functionStatements.set(statement.name.text.toLowerCase(), statement);
1362
+ }
1363
+ else if ((0, reflection_1.isEnumStatement)(statement) && statement.fullName) {
1364
+ ns.enumStatements.set(statement.fullName.toLowerCase(), statement);
1365
+ }
1366
+ else if ((0, reflection_1.isConstStatement)(statement) && statement.fullName) {
1367
+ ns.constStatements.set(statement.fullName.toLowerCase(), statement);
1368
+ }
1369
+ }
1370
+ // Merges all the symbol tables of the namespace statements into the new symbol table created above.
1371
+ // Set those symbol tables to have this new merged table as a parent
1372
+ ns.symbolTable.mergeSymbolTable(namespaceStatement.body.getSymbolTable());
1373
+ }
1374
+ return namespaceLookup;
1375
+ }
1672
1376
  getTypedef() {
1673
1377
  const state = new BrsTranspileState_1.BrsTranspileState(this);
1674
1378
  const typedef = this.ast.getTypedef(state);
@@ -1676,30 +1380,14 @@ class BrsFile {
1676
1380
  return programNode.toString();
1677
1381
  }
1678
1382
  dispose() {
1679
- var _a, _b;
1383
+ var _a;
1680
1384
  (_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
1385
  //deleting these properties result in lower memory usage (garbage collection is magic!)
1684
1386
  delete this.fileContents;
1685
1387
  delete this._parser;
1686
- delete this.callables;
1687
- delete this.functionCalls;
1388
+ delete this._functionScopes;
1389
+ delete this.scopesByFunc;
1688
1390
  }
1689
1391
  }
1690
1392
  exports.BrsFile = BrsFile;
1691
- /**
1692
- * List of completions for all valid keywords/reserved words.
1693
- * Build this list once because it won't change for the lifetime of this process
1694
- */
1695
- exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
1696
- //remove any keywords with whitespace
1697
- .filter(x => !x.includes(' '))
1698
- //create completions
1699
- .map(x => {
1700
- return {
1701
- label: x,
1702
- kind: vscode_languageserver_1.CompletionItemKind.Keyword
1703
- };
1704
- });
1705
1393
  //# sourceMappingURL=BrsFile.js.map