brighterscript 1.0.0-alpha.24 → 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 (530) hide show
  1. package/CHANGELOG.md +493 -233
  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 +61 -13
  33. package/dist/DiagnosticMessages.js +116 -19
  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 +150 -69
  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 +158 -79
  54. package/dist/Program.js +831 -695
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +130 -103
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +87 -133
  60. package/dist/Scope.js +450 -510
  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 +89 -34
  65. package/dist/SymbolTable.js +239 -114
  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 -69
  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 -104
  90. package/dist/astUtils/reflection.js +220 -174
  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 +53 -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 +10 -2
  105. package/dist/bscPlugin/BscPlugin.js +33 -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.js +14 -11
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  120. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  123. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  125. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  128. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  129. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  130. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  131. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  133. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +85 -23
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  140. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  141. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  142. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  143. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  144. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  146. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  147. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +33 -9
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  152. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  153. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  156. package/dist/bscPlugin/validation/BrsFileValidator.js +259 -49
  157. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  159. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  160. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  161. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  162. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  163. package/dist/bscPlugin/validation/ScopeValidator.d.ts +54 -27
  164. package/dist/bscPlugin/validation/ScopeValidator.js +483 -286
  165. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  166. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  167. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  168. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  169. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  170. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  171. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  172. package/dist/cli.js +104 -13
  173. package/dist/cli.js.map +1 -1
  174. package/dist/deferred.d.ts +3 -3
  175. package/dist/deferred.js.map +1 -1
  176. package/dist/diagnosticUtils.d.ts +8 -2
  177. package/dist/diagnosticUtils.js +47 -17
  178. package/dist/diagnosticUtils.js.map +1 -1
  179. package/dist/examples/plugins/removePrint.js +8 -10
  180. package/dist/examples/plugins/removePrint.js.map +1 -1
  181. package/dist/files/AssetFile.d.ts +26 -0
  182. package/dist/files/AssetFile.js +26 -0
  183. package/dist/files/AssetFile.js.map +1 -0
  184. package/dist/files/BrsFile.Class.spec.js +523 -493
  185. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  186. package/dist/files/BrsFile.d.ts +112 -111
  187. package/dist/files/BrsFile.js +741 -1032
  188. package/dist/files/BrsFile.js.map +1 -1
  189. package/dist/files/BrsFile.spec.js +1728 -1232
  190. package/dist/files/BrsFile.spec.js.map +1 -1
  191. package/dist/files/BscFile.d.ts +104 -0
  192. package/dist/files/BscFile.js +16 -0
  193. package/dist/files/BscFile.js.map +1 -0
  194. package/dist/files/Factory.d.ts +25 -0
  195. package/dist/files/Factory.js +22 -0
  196. package/dist/files/Factory.js.map +1 -0
  197. package/dist/files/LazyFileData.d.ts +20 -0
  198. package/dist/files/LazyFileData.js +54 -0
  199. package/dist/files/LazyFileData.js.map +1 -0
  200. package/dist/files/LazyFileData.spec.d.ts +1 -0
  201. package/dist/files/LazyFileData.spec.js +27 -0
  202. package/dist/files/LazyFileData.spec.js.map +1 -0
  203. package/dist/files/XmlFile.d.ts +70 -32
  204. package/dist/files/XmlFile.js +106 -118
  205. package/dist/files/XmlFile.js.map +1 -1
  206. package/dist/files/XmlFile.spec.js +325 -262
  207. package/dist/files/XmlFile.spec.js.map +1 -1
  208. package/dist/files/tests/imports.spec.js +48 -40
  209. package/dist/files/tests/imports.spec.js.map +1 -1
  210. package/dist/files/tests/optionalChaning.spec.js +84 -24
  211. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  212. package/dist/globalCallables.js +16 -21
  213. package/dist/globalCallables.js.map +1 -1
  214. package/dist/index.d.ts +12 -1
  215. package/dist/index.js +12 -1
  216. package/dist/index.js.map +1 -1
  217. package/dist/interfaces.d.ts +389 -161
  218. package/dist/interfaces.js +27 -0
  219. package/dist/interfaces.js.map +1 -1
  220. package/dist/lexer/Character.spec.js +5 -5
  221. package/dist/lexer/Character.spec.js.map +1 -1
  222. package/dist/lexer/Lexer.d.ts +12 -5
  223. package/dist/lexer/Lexer.js +28 -13
  224. package/dist/lexer/Lexer.js.map +1 -1
  225. package/dist/lexer/Lexer.spec.js +181 -135
  226. package/dist/lexer/Lexer.spec.js.map +1 -1
  227. package/dist/lexer/Token.d.ts +9 -1
  228. package/dist/lexer/Token.js +9 -1
  229. package/dist/lexer/Token.js.map +1 -1
  230. package/dist/lexer/TokenKind.d.ts +8 -0
  231. package/dist/lexer/TokenKind.js +24 -4
  232. package/dist/lexer/TokenKind.js.map +1 -1
  233. package/dist/parser/AstNode.d.ts +162 -0
  234. package/dist/parser/AstNode.js +225 -0
  235. package/dist/parser/AstNode.js.map +1 -0
  236. package/dist/parser/AstNode.spec.d.ts +1 -0
  237. package/dist/parser/AstNode.spec.js +165 -0
  238. package/dist/parser/AstNode.spec.js.map +1 -0
  239. package/dist/parser/BrsTranspileState.d.ts +4 -7
  240. package/dist/parser/BrsTranspileState.js +4 -12
  241. package/dist/parser/BrsTranspileState.js.map +1 -1
  242. package/dist/parser/Expression.d.ts +126 -176
  243. package/dist/parser/Expression.js +523 -405
  244. package/dist/parser/Expression.js.map +1 -1
  245. package/dist/parser/Parser.Class.spec.js +151 -145
  246. package/dist/parser/Parser.Class.spec.js.map +1 -1
  247. package/dist/parser/Parser.d.ts +43 -201
  248. package/dist/parser/Parser.js +446 -962
  249. package/dist/parser/Parser.js.map +1 -1
  250. package/dist/parser/Parser.spec.d.ts +3 -1
  251. package/dist/parser/Parser.spec.js +1002 -846
  252. package/dist/parser/Parser.spec.js.map +1 -1
  253. package/dist/parser/SGParser.d.ts +9 -8
  254. package/dist/parser/SGParser.js +10 -8
  255. package/dist/parser/SGParser.js.map +1 -1
  256. package/dist/parser/SGParser.spec.js +27 -38
  257. package/dist/parser/SGParser.spec.js.map +1 -1
  258. package/dist/parser/SGTypes.d.ts +98 -35
  259. package/dist/parser/SGTypes.js +169 -99
  260. package/dist/parser/SGTypes.js.map +1 -1
  261. package/dist/parser/Statement.d.ts +183 -131
  262. package/dist/parser/Statement.js +549 -387
  263. package/dist/parser/Statement.js.map +1 -1
  264. package/dist/parser/Statement.spec.js +45 -21
  265. package/dist/parser/Statement.spec.js.map +1 -1
  266. package/dist/parser/TranspileState.d.ts +1 -1
  267. package/dist/parser/TranspileState.js +7 -12
  268. package/dist/parser/TranspileState.js.map +1 -1
  269. package/dist/parser/tests/Parser.spec.js +3 -2
  270. package/dist/parser/tests/Parser.spec.js.map +1 -1
  271. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  272. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  273. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  274. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  275. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  276. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  278. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  279. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  280. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  281. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  282. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  283. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  284. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  286. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/Call.spec.js +129 -21
  288. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  290. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Function.spec.js +36 -36
  292. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  294. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  296. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  298. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  300. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  302. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  304. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  306. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  308. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  310. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  312. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  314. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  315. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  316. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  318. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  320. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  321. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  322. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  323. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  324. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  325. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  326. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  327. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  328. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  329. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  330. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  331. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/For.spec.js +9 -10
  333. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  335. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Function.spec.js +44 -35
  337. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  339. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  341. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  343. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  345. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  347. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/PrintStatement.spec.js +35 -33
  349. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  351. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Set.spec.js +48 -35
  353. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  355. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  357. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  359. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  360. package/dist/preprocessor/Manifest.d.ts +1 -1
  361. package/dist/preprocessor/Manifest.js +2 -2
  362. package/dist/preprocessor/Manifest.js.map +1 -1
  363. package/dist/preprocessor/Manifest.spec.js +8 -8
  364. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  365. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  366. package/dist/preprocessor/Preprocessor.js +5 -5
  367. package/dist/preprocessor/Preprocessor.js.map +1 -1
  368. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  369. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  370. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  371. package/dist/preprocessor/PreprocessorParser.js +7 -1
  372. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  373. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  374. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  375. package/dist/roku-types/data.json +5892 -10081
  376. package/dist/roku-types/index.d.ts +622 -1719
  377. package/dist/types/ArrayType.d.ts +10 -9
  378. package/dist/types/ArrayType.js +65 -60
  379. package/dist/types/ArrayType.js.map +1 -1
  380. package/dist/types/ArrayType.spec.js +36 -68
  381. package/dist/types/ArrayType.spec.js.map +1 -1
  382. package/dist/types/AssociativeArrayType.d.ts +11 -0
  383. package/dist/types/AssociativeArrayType.js +52 -0
  384. package/dist/types/AssociativeArrayType.js.map +1 -0
  385. package/dist/types/BaseFunctionType.d.ts +9 -0
  386. package/dist/types/BaseFunctionType.js +25 -0
  387. package/dist/types/BaseFunctionType.js.map +1 -0
  388. package/dist/types/BooleanType.d.ts +8 -5
  389. package/dist/types/BooleanType.js +14 -7
  390. package/dist/types/BooleanType.js.map +1 -1
  391. package/dist/types/BooleanType.spec.js +10 -6
  392. package/dist/types/BooleanType.spec.js.map +1 -1
  393. package/dist/types/BscType.d.ts +32 -21
  394. package/dist/types/BscType.js +118 -21
  395. package/dist/types/BscType.js.map +1 -1
  396. package/dist/types/BscTypeKind.d.ts +25 -0
  397. package/dist/types/BscTypeKind.js +30 -0
  398. package/dist/types/BscTypeKind.js.map +1 -0
  399. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  400. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  401. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  402. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  404. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  405. package/dist/types/ClassType.d.ts +17 -0
  406. package/dist/types/ClassType.js +58 -0
  407. package/dist/types/ClassType.js.map +1 -0
  408. package/dist/types/ClassType.spec.d.ts +1 -0
  409. package/dist/types/ClassType.spec.js +77 -0
  410. package/dist/types/ClassType.spec.js.map +1 -0
  411. package/dist/types/ComponentType.d.ts +26 -0
  412. package/dist/types/ComponentType.js +83 -0
  413. package/dist/types/ComponentType.js.map +1 -0
  414. package/dist/types/DoubleType.d.ts +8 -5
  415. package/dist/types/DoubleType.js +18 -16
  416. package/dist/types/DoubleType.js.map +1 -1
  417. package/dist/types/DoubleType.spec.js +12 -6
  418. package/dist/types/DoubleType.spec.js.map +1 -1
  419. package/dist/types/DynamicType.d.ts +9 -5
  420. package/dist/types/DynamicType.js +15 -4
  421. package/dist/types/DynamicType.js.map +1 -1
  422. package/dist/types/DynamicType.spec.js +16 -5
  423. package/dist/types/DynamicType.spec.js.map +1 -1
  424. package/dist/types/EnumType.d.ts +30 -12
  425. package/dist/types/EnumType.js +43 -17
  426. package/dist/types/EnumType.js.map +1 -1
  427. package/dist/types/EnumType.spec.d.ts +1 -0
  428. package/dist/types/EnumType.spec.js +33 -0
  429. package/dist/types/EnumType.spec.js.map +1 -0
  430. package/dist/types/FloatType.d.ts +8 -5
  431. package/dist/types/FloatType.js +18 -16
  432. package/dist/types/FloatType.js.map +1 -1
  433. package/dist/types/FloatType.spec.js +4 -6
  434. package/dist/types/FloatType.spec.js.map +1 -1
  435. package/dist/types/FunctionType.d.ts +13 -8
  436. package/dist/types/FunctionType.js +30 -14
  437. package/dist/types/FunctionType.js.map +1 -1
  438. package/dist/types/InheritableType.d.ts +28 -0
  439. package/dist/types/InheritableType.js +152 -0
  440. package/dist/types/InheritableType.js.map +1 -0
  441. package/dist/types/IntegerType.d.ts +8 -5
  442. package/dist/types/IntegerType.js +18 -16
  443. package/dist/types/IntegerType.js.map +1 -1
  444. package/dist/types/IntegerType.spec.js +8 -6
  445. package/dist/types/IntegerType.spec.js.map +1 -1
  446. package/dist/types/InterfaceType.d.ts +12 -13
  447. package/dist/types/InterfaceType.js +20 -48
  448. package/dist/types/InterfaceType.js.map +1 -1
  449. package/dist/types/InterfaceType.spec.js +90 -56
  450. package/dist/types/InterfaceType.spec.js.map +1 -1
  451. package/dist/types/InvalidType.d.ts +7 -5
  452. package/dist/types/InvalidType.js +13 -7
  453. package/dist/types/InvalidType.js.map +1 -1
  454. package/dist/types/InvalidType.spec.js +8 -6
  455. package/dist/types/InvalidType.spec.js.map +1 -1
  456. package/dist/types/LongIntegerType.d.ts +8 -5
  457. package/dist/types/LongIntegerType.js +17 -15
  458. package/dist/types/LongIntegerType.js.map +1 -1
  459. package/dist/types/LongIntegerType.spec.js +10 -6
  460. package/dist/types/LongIntegerType.spec.js.map +1 -1
  461. package/dist/types/NamespaceType.d.ts +12 -0
  462. package/dist/types/NamespaceType.js +28 -0
  463. package/dist/types/NamespaceType.js.map +1 -0
  464. package/dist/types/ObjectType.d.ts +9 -8
  465. package/dist/types/ObjectType.js +21 -11
  466. package/dist/types/ObjectType.js.map +1 -1
  467. package/dist/types/ObjectType.spec.js +3 -3
  468. package/dist/types/ObjectType.spec.js.map +1 -1
  469. package/dist/types/ReferenceType.d.ts +63 -0
  470. package/dist/types/ReferenceType.js +423 -0
  471. package/dist/types/ReferenceType.js.map +1 -0
  472. package/dist/types/ReferenceType.spec.d.ts +1 -0
  473. package/dist/types/ReferenceType.spec.js +137 -0
  474. package/dist/types/ReferenceType.spec.js.map +1 -0
  475. package/dist/types/StringType.d.ts +11 -5
  476. package/dist/types/StringType.js +18 -7
  477. package/dist/types/StringType.js.map +1 -1
  478. package/dist/types/StringType.spec.js +3 -5
  479. package/dist/types/StringType.spec.js.map +1 -1
  480. package/dist/types/TypedFunctionType.d.ts +22 -17
  481. package/dist/types/TypedFunctionType.js +78 -60
  482. package/dist/types/TypedFunctionType.js.map +1 -1
  483. package/dist/types/TypedFunctionType.spec.js +105 -20
  484. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  485. package/dist/types/UninitializedType.d.ts +8 -6
  486. package/dist/types/UninitializedType.js +13 -7
  487. package/dist/types/UninitializedType.js.map +1 -1
  488. package/dist/types/UnionType.d.ts +20 -0
  489. package/dist/types/UnionType.js +123 -0
  490. package/dist/types/UnionType.js.map +1 -0
  491. package/dist/types/UnionType.spec.d.ts +1 -0
  492. package/dist/types/UnionType.spec.js +130 -0
  493. package/dist/types/UnionType.spec.js.map +1 -0
  494. package/dist/types/VoidType.d.ts +8 -5
  495. package/dist/types/VoidType.js +14 -7
  496. package/dist/types/VoidType.js.map +1 -1
  497. package/dist/types/VoidType.spec.js +3 -3
  498. package/dist/types/VoidType.spec.js.map +1 -1
  499. package/dist/types/helper.spec.d.ts +1 -0
  500. package/dist/types/helper.spec.js +145 -0
  501. package/dist/types/helper.spec.js.map +1 -0
  502. package/dist/types/helpers.d.ts +19 -37
  503. package/dist/types/helpers.js +159 -99
  504. package/dist/types/helpers.js.map +1 -1
  505. package/dist/types/index.d.ts +22 -0
  506. package/dist/types/index.js +39 -0
  507. package/dist/types/index.js.map +1 -0
  508. package/dist/util.d.ts +132 -137
  509. package/dist/util.js +796 -362
  510. package/dist/util.js.map +1 -1
  511. package/dist/validators/ClassValidator.d.ts +8 -25
  512. package/dist/validators/ClassValidator.js +96 -176
  513. package/dist/validators/ClassValidator.js.map +1 -1
  514. package/package.json +165 -152
  515. package/dist/astUtils/AstEditor.js.map +0 -1
  516. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  517. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  518. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  519. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  520. package/dist/parser/SGTypes.spec.js +0 -351
  521. package/dist/parser/SGTypes.spec.js.map +0 -1
  522. package/dist/types/CustomType.d.ts +0 -12
  523. package/dist/types/CustomType.js +0 -44
  524. package/dist/types/CustomType.js.map +0 -1
  525. package/dist/types/LazyType.d.ts +0 -16
  526. package/dist/types/LazyType.js +0 -44
  527. package/dist/types/LazyType.js.map +0 -1
  528. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  529. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  530. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/serialize/BslibInjector.spec.d.ts} +0 -0
@@ -1,13 +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
6
  const vscode_languageserver_2 = require("vscode-languageserver");
7
7
  const chalk_1 = require("chalk");
8
8
  const path = require("path");
9
9
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
10
- const Token_1 = require("../lexer/Token");
10
+ const FunctionScope_1 = require("../FunctionScope");
11
11
  const Lexer_1 = require("../lexer/Lexer");
12
12
  const TokenKind_1 = require("../lexer/TokenKind");
13
13
  const Parser_1 = require("../parser/Parser");
@@ -18,29 +18,20 @@ const Preprocessor_1 = require("../preprocessor/Preprocessor");
18
18
  const Logger_1 = require("../Logger");
19
19
  const serialize_error_1 = require("serialize-error");
20
20
  const reflection_1 = require("../astUtils/reflection");
21
- const BscType_1 = require("../types/BscType");
22
21
  const visitors_1 = require("../astUtils/visitors");
23
22
  const CommentFlagProcessor_1 = require("../CommentFlagProcessor");
24
23
  const vscode_uri_1 = require("vscode-uri");
25
- const InvalidType_1 = require("../types/InvalidType");
26
- const UninitializedType_1 = require("../types/UninitializedType");
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");
27
28
  /**
28
29
  * Holds all details about this file within the scope of the whole program
29
30
  */
30
31
  class BrsFile {
31
- constructor(
32
- /**
33
- * 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').
34
- */
35
- srcPath,
36
- /**
37
- * The full pkg path (i.e. `pkg:/path/to/file.brs`)
38
- */
39
- pkgPath, program) {
40
- var _a, _b;
41
- this.srcPath = srcPath;
42
- this.pkgPath = pkgPath;
43
- this.program = program;
32
+ constructor(options) {
33
+ var _a, _b, _c;
34
+ this.type = 'BrsFile';
44
35
  /**
45
36
  * The parseMode used for the parser for this file
46
37
  */
@@ -50,43 +41,67 @@ class BrsFile {
50
41
  * Files are only ever validated a single time
51
42
  */
52
43
  this.isValidated = false;
53
- this.diagnostics = [];
54
- this.commentFlags = [];
55
- this.callables = [];
56
- this.functionCalls = [];
57
44
  /**
58
- * Does this file need to be transpiled?
45
+ * A collection of diagnostics related to this file
59
46
  */
60
- this.needsTranspiled = false;
61
- this.srcPath = (0, util_1.standardizePath) `${this.srcPath}`;
62
- this.dependencyGraphKey = this.pkgPath.toLowerCase();
63
- this.extension = util_1.util.getExtension(this.srcPath);
64
- //all BrighterScript files need to be transpiled
65
- 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)) {
66
- this.needsTranspiled = true;
67
- this.parseMode = Parser_1.ParseMode.BrighterScript;
68
- }
69
- this.isTypedef = this.extension === '.d.bs';
70
- if (!this.isTypedef) {
71
- this.typedefSrcPath = util_1.util.getTypedefPath(this.srcPath);
72
- }
73
- //global file doesn't have a program, so only resolve typedef info if we have a program
74
- if (this.program) {
75
- 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
+ }
76
81
  }
77
82
  }
78
83
  /**
79
- * The absolute path to the source location for this file
80
- * @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.
81
85
  */
82
- get pathAbsolute() {
83
- return this.srcPath;
84
- }
85
- set pathAbsolute(value) {
86
- 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;
87
99
  }
100
+ /**
101
+ * @deprecated use `.diagnostics` instead
102
+ */
88
103
  getDiagnostics() {
89
- return [...this.diagnostics];
104
+ return this.diagnostics;
90
105
  }
91
106
  addDiagnostic(diagnostic) {
92
107
  if (!diagnostic.file) {
@@ -97,10 +112,15 @@ class BrsFile {
97
112
  addDiagnostics(diagnostics) {
98
113
  this.diagnostics.push(...diagnostics);
99
114
  }
115
+ get functionScopes() {
116
+ if (!this._functionScopes) {
117
+ this.createFunctionScopes();
118
+ }
119
+ return this._functionScopes;
120
+ }
100
121
  get cache() {
101
- var _a;
102
122
  // eslint-disable-next-line @typescript-eslint/dot-notation
103
- return (_a = this._parser) === null || _a === void 0 ? void 0 : _a.references['cache'];
123
+ return this._cachedLookups['cache'];
104
124
  }
105
125
  /**
106
126
  * files referenced by import statements
@@ -108,16 +128,16 @@ class BrsFile {
108
128
  get ownScriptImports() {
109
129
  var _a, _b;
110
130
  const result = (_b = (_a = this.cache) === null || _a === void 0 ? void 0 : _a.getOrAdd('BrsFile_ownScriptImports', () => {
111
- var _a, _b, _c, _d;
131
+ var _a, _b, _c;
112
132
  const result = [];
113
- 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 : []) {
114
134
  //register import statements
115
135
  if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
116
136
  result.push({
117
137
  filePathRange: statement.filePathToken.range,
118
- pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
138
+ destPath: util_1.util.getPkgPathFromTarget(this.destPath, statement.filePath),
119
139
  sourceFile: this,
120
- 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
121
141
  });
122
142
  }
123
143
  }
@@ -125,15 +145,29 @@ class BrsFile {
125
145
  })) !== null && _b !== void 0 ? _b : [];
126
146
  return result;
127
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
+ }
128
162
  /**
129
163
  * The AST for this file
130
164
  */
131
165
  get ast() {
132
- return this.parser.ast;
166
+ var _a;
167
+ return (_a = this.parser) === null || _a === void 0 ? void 0 : _a.ast;
133
168
  }
134
169
  /**
135
170
  * Get the token at the specified position
136
- * @param position
137
171
  */
138
172
  getTokenAt(position) {
139
173
  for (let token of this.parser.tokens) {
@@ -181,38 +215,32 @@ class BrsFile {
181
215
  * Find and set the typedef variables (if a matching typedef file exists)
182
216
  */
183
217
  resolveTypedef() {
184
- this.typedefFile = this.program.getFile(this.typedefSrcPath);
218
+ this.typedefFile = this.program.getFile(this.typedefKey);
185
219
  this.hasTypedef = !!this.typedefFile;
186
220
  }
221
+ onDependenciesChanged() {
222
+ this.resolveTypedef();
223
+ }
187
224
  /**
188
225
  * Attach the file to the dependency graph so it can monitor changes.
189
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
190
228
  */
191
- attachDependencyGraph(dependencyGraph) {
192
- var _a;
193
- (_a = this.unsubscribeFromDependencyGraph) === null || _a === void 0 ? void 0 : _a.call(this);
194
- //event that fires anytime a dependency changes
195
- this.unsubscribeFromDependencyGraph = dependencyGraph.onchange(this.dependencyGraphKey, () => {
196
- this.resolveTypedef();
197
- });
198
- 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());
199
235
  //if this is a .brs file, watch for typedef changes
200
236
  if (this.extension === '.brs') {
201
- dependencies.push(util_1.util.getTypedefPath(this.pkgPath));
202
- }
203
- dependencyGraph.addOrReplace(this.dependencyGraphKey, dependencies);
204
- }
205
- get logger() {
206
- var _a;
207
- const logger = (_a = this.program) === null || _a === void 0 ? void 0 : _a.logger;
208
- if (!logger && !this._logger) {
209
- this._logger = new Logger_1.Logger();
237
+ result.push(util_1.util.getTypedefPath(this.destPath));
210
238
  }
211
- return logger !== null && logger !== void 0 ? logger : this._logger;
239
+ return result;
212
240
  }
213
241
  /**
214
242
  * Calculate the AST for this file
215
- * @param fileContents
243
+ * @param fileContents the raw source code to parse
216
244
  */
217
245
  parse(fileContents) {
218
246
  try {
@@ -225,7 +253,7 @@ class BrsFile {
225
253
  return;
226
254
  }
227
255
  //tokenize the input file
228
- 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)], () => {
229
257
  return Lexer_1.Lexer.scan(fileContents, {
230
258
  includeWhitespace: false
231
259
  });
@@ -236,7 +264,7 @@ class BrsFile {
236
264
  //TODO preprocessor should go away in favor of the AST handling this internally (because it affects transpile)
237
265
  //currently the preprocessor throws exceptions on syntax errors...so we need to catch it
238
266
  try {
239
- 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)], () => {
240
268
  preprocessor.process(lexer.tokens, this.program.getManifest());
241
269
  });
242
270
  }
@@ -248,18 +276,14 @@ class BrsFile {
248
276
  }
249
277
  //if the preprocessor generated tokens, use them.
250
278
  let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
251
- 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)], () => {
252
280
  this._parser = Parser_1.Parser.parse(tokens, {
253
281
  mode: this.parseMode,
254
- logger: this.logger
282
+ logger: this.program.logger
255
283
  });
256
284
  });
257
285
  //absorb all lexing/preprocessing/parsing diagnostics
258
286
  this.diagnostics.push(...lexer.diagnostics, ...preprocessor.diagnostics, ...this._parser.diagnostics);
259
- //extract all callables from this file
260
- this.findCallables();
261
- //find all places where a sub/function is being called
262
- this.findFunctionCalls();
263
287
  //attach this file to every diagnostic
264
288
  for (let diagnostic of this.diagnostics) {
265
289
  diagnostic.file = this;
@@ -270,46 +294,6 @@ class BrsFile {
270
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)))));
271
295
  }
272
296
  }
273
- validate() {
274
- util_1.util.validateTooDeepFile(this);
275
- //only validate the file if it was actually parsed (skip files containing typedefs)
276
- if (!this.hasTypedef) {
277
- this.validateImportStatements();
278
- }
279
- }
280
- validateImportStatements() {
281
- let topOfFileIncludeStatements = [];
282
- for (let stmt of this.ast.statements) {
283
- //skip comments
284
- if ((0, reflection_1.isCommentStatement)(stmt)) {
285
- continue;
286
- }
287
- //if we found a non-library statement, this statement is not at the top of the file
288
- if ((0, reflection_1.isLibraryStatement)(stmt) || (0, reflection_1.isImportStatement)(stmt)) {
289
- topOfFileIncludeStatements.push(stmt);
290
- }
291
- else {
292
- //break out of the loop, we found all of our library statements
293
- break;
294
- }
295
- }
296
- let statements = [
297
- ...this._parser.references.libraryStatements,
298
- ...this._parser.references.importStatements
299
- ];
300
- for (let result of statements) {
301
- //if this statement is not one of the top-of-file statements,
302
- //then add a diagnostic explaining that it is invalid
303
- if (!topOfFileIncludeStatements.includes(result)) {
304
- if ((0, reflection_1.isLibraryStatement)(result)) {
305
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.libraryStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
306
- }
307
- else if ((0, reflection_1.isImportStatement)(result)) {
308
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
309
- }
310
- }
311
- }
312
- }
313
297
  /**
314
298
  * Find a class. This scans all scopes for this file, and returns the first matching class that is found.
315
299
  * Returns undefined if not found.
@@ -331,7 +315,7 @@ class BrsFile {
331
315
  }
332
316
  findPropertyNameCompletions() {
333
317
  //Build completion items from all the "properties" found in the file
334
- const { propertyHints } = this.parser.references;
318
+ const { propertyHints } = this._cachedLookups;
335
319
  const results = [];
336
320
  for (const key of Object.keys(propertyHints)) {
337
321
  results.push({
@@ -349,7 +333,7 @@ class BrsFile {
349
333
  }
350
334
  /**
351
335
  * Find all comment flags in the source code. These enable or disable diagnostic messages.
352
- * @param lines - the lines of the program
336
+ * @param tokens - an array of tokens of which to find `TokenKind.Comment` from
353
337
  */
354
338
  getCommentFlags(tokens) {
355
339
  const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
@@ -362,130 +346,244 @@ class BrsFile {
362
346
  this.commentFlags.push(...processor.commentFlags);
363
347
  this.diagnostics.push(...processor.diagnostics);
364
348
  }
365
- findCallables() {
349
+ /**
350
+ * Create a scope for every function in this file
351
+ */
352
+ createFunctionScopes() {
366
353
  var _a;
367
- for (let statement of (_a = this.parser.references.functionStatements) !== null && _a !== void 0 ? _a : []) {
368
- let functionType = statement.func.getFunctionType();
369
- functionType.setName(statement.name.text);
370
- this.callables.push({
371
- isSub: statement.func.functionType.text.toLowerCase() === 'sub',
372
- name: statement.name.text,
373
- nameRange: statement.name.range,
374
- file: this,
375
- params: functionType.params,
376
- range: statement.func.range,
377
- type: functionType,
378
- getName: statement.getName.bind(statement),
379
- hasNamespace: !!statement.namespaceName,
380
- 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
381
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
+ }
382
422
  }
383
423
  }
384
- findFunctionCalls() {
385
- var _a;
386
- this.functionCalls = [];
387
- //for every function in the file
388
- for (let func of this._parser.references.functionExpressions) {
389
- //for all function calls in this function
390
- for (let expression of func.callExpressions) {
391
- if (
392
- //filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
393
- expression.callee.callee ||
394
- //filter out method calls on regexp literals for now
395
- (0, reflection_1.isRegexLiteralExpression)((_a = expression.callee) === null || _a === void 0 ? void 0 : _a.obj) ||
396
- //filter out callees without a name (immediately-invoked function expressions)
397
- !expression.callee.name) {
398
- 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);
399
444
  }
400
- //Flag dotted function invocations (i.e. object.doSomething())
401
- const dottedInvocation = expression.callee.obj;
402
- let functionName = expression.callee.name;
403
- //callee is the name of the function being called
404
- let callee = expression.callee;
405
- let columnIndexBegin = callee.range.start.character;
406
- let columnIndexEnd = callee.range.end.character;
407
- let args = [];
408
- //TODO convert if stmts to use instanceof instead
409
- for (let arg of expression.args) {
410
- let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
411
- let argText = '';
412
- // Get the text to display for the arg
413
- if (arg.token) {
414
- argText = arg.token.text;
415
- //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;
416
477
  }
417
- else if (arg.name) {
418
- if ((0, Token_1.isToken)(arg.name)) {
419
- 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
420
496
  }
421
- }
422
- else if (arg.value) {
423
- /* istanbul ignore next: TODO figure out why value is undefined sometimes */
424
- if (arg.value.value) {
425
- if (arg.value.value.toString) {
426
- 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();
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 + '"';
427
524
  }
525
+ args.push(callableArg);
428
526
  }
429
- //wrap the value in quotes because that's how it appears in the code
430
- if (argText && (0, reflection_1.isStringType)(inferredType)) {
431
- 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
+ });
432
536
  }
433
537
  }
434
- args.push({
435
- range: arg.range,
436
- type: inferredType,
437
- text: argText,
438
- expression: arg,
439
- typeToken: undefined
440
- });
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);
441
549
  }
442
- let functionCall = {
443
- range: util_1.util.createRangeFromPositions(expression.range.start, expression.closingParen.range.end),
444
- functionExpression: this.getFunctionExpressionAtPosition(callee.range.start),
445
- file: this,
446
- name: functionName,
447
- nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
448
- args: args,
449
- isDottedInvocation: dottedInvocation
450
- };
451
- this.functionCalls.push(functionCall);
452
550
  }
453
- }
454
- }
455
- getFunctionExpressionAtPosition(position) {
456
- return this.cache.getOrAdd(`functionExpressionAtPosition-${position.line}:${position.character}`, () => {
457
- return this._getFunctionExpressionAtPosition(position, this.parser.references.functionExpressions);
551
+ return functionCalls;
458
552
  });
459
553
  }
460
554
  /**
461
- * 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
462
557
  */
463
- _getFunctionExpressionAtPosition(position, functionExpressions) {
464
- if (!functionExpressions) {
465
- 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;
466
566
  }
467
- for (let functionExpression of functionExpressions) {
468
- if (util_1.util.rangeContains(functionExpression.range, position)) {
567
+ for (let scope of functionScopes) {
568
+ if (util_1.util.rangeContains(scope.range, position)) {
469
569
  //see if any of that scope's children match the position also, and give them priority
470
- let childFunc = this._getFunctionExpressionAtPosition(position, functionExpression.childFunctionExpressions);
471
- if (childFunc) {
472
- return childFunc;
570
+ let childScope = this._getFunctionScopeAtPosition(position, scope.childrenScopes);
571
+ if (childScope) {
572
+ return childScope;
473
573
  }
474
574
  else {
475
- return functionExpression;
575
+ return scope;
476
576
  }
477
577
  }
478
578
  }
479
579
  }
480
580
  /**
481
581
  * Find the NamespaceStatement enclosing the given position
482
- * @param position
483
- * @param functionScopes
484
582
  */
485
583
  getNamespaceStatementForPosition(position) {
486
584
  if (position) {
487
585
  return this.cache.getOrAdd(`namespaceStatementForPosition-${position.line}:${position.character}`, () => {
488
- for (const statement of this.parser.references.namespaceStatements) {
586
+ for (const statement of this._cachedLookups.namespaceStatements) {
489
587
  if (util_1.util.rangeContains(statement.range, position)) {
490
588
  return statement;
491
589
  }
@@ -493,646 +591,6 @@ class BrsFile {
493
591
  });
494
592
  }
495
593
  }
496
- /**
497
- * Get completions available at the given cursor. This aggregates all values from this file and the current scope.
498
- */
499
- getCompletions(position, scope) {
500
- var _a;
501
- let result = [];
502
- //a map of lower-case names of all added options
503
- let names = {};
504
- //handle script import completions
505
- let scriptImport = util_1.util.getScriptImportAtPosition(this.ownScriptImports, position);
506
- if (scriptImport) {
507
- return this.program.getScriptImportCompletions(this.pkgPath, scriptImport);
508
- }
509
- //if cursor is within a comment, disable completions
510
- let currentToken = this.parser.getTokenAt(position);
511
- const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
512
- if (tokenKind === TokenKind_1.TokenKind.Comment) {
513
- return [];
514
- }
515
- else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
516
- const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
517
- if (match) {
518
- const [, openingQuote, fileProtocol] = match;
519
- //include every pkgPath from this scope
520
- for (const file of scope.getAllFiles()) {
521
- const pkgPath = `${fileProtocol}:/${file.pkgPath.replace('pkg:/', '')}`;
522
- result.push({
523
- label: pkgPath,
524
- textEdit: vscode_languageserver_2.TextEdit.replace(util_1.util.createRange(currentToken.range.start.line,
525
- //+1 to step past the opening quote
526
- currentToken.range.start.character + (openingQuote ? 1 : 0), currentToken.range.end.line,
527
- //-1 to exclude the closing quotemark (or the end character if there is no closing quotemark)
528
- currentToken.range.end.character + (currentToken.text.endsWith('"') ? -1 : 0)), pkgPath),
529
- kind: vscode_languageserver_2.CompletionItemKind.File
530
- });
531
- }
532
- return result;
533
- }
534
- else {
535
- //do nothing. we don't want to show completions inside of strings...
536
- return [];
537
- }
538
- }
539
- const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
540
- if (namespaceCompletions.length > 0) {
541
- return [...namespaceCompletions];
542
- }
543
- const enumMemberCompletions = this.getEnumMemberStatementCompletions(currentToken, this.parseMode, scope);
544
- if (enumMemberCompletions.length > 0) {
545
- // no other completion is valid in this case
546
- return enumMemberCompletions;
547
- }
548
- //determine if cursor is inside a function
549
- let functionExpression = this.getFunctionExpressionAtPosition(position);
550
- if (!functionExpression) {
551
- //we aren't in any function scope, so return the keyword completions and namespaces
552
- if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
553
- // there's a new keyword, so only class types are viable here
554
- return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope)];
555
- }
556
- else {
557
- return [
558
- ...exports.KeywordCompletions,
559
- ...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope),
560
- ...namespaceCompletions,
561
- ...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope),
562
- ...this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope)
563
- ];
564
- }
565
- }
566
- const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope);
567
- const interfaceNameCompletions = this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope);
568
- const newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
569
- if (newToken) {
570
- //we are after a new keyword; so we can only be top-level namespaces or classes at this point
571
- result.push(...classNameCompletions);
572
- result.push(...namespaceCompletions);
573
- return result;
574
- }
575
- if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
576
- return this.getLabelCompletion(functionExpression);
577
- }
578
- if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
579
- const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
580
- if (selfClassMemberCompletions.size > 0) {
581
- return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
582
- }
583
- const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
584
- if ((_a = tokenLookup.symbolContainer) === null || _a === void 0 ? void 0 : _a.memberTable) {
585
- return this.getCompletionsFromSymbolTable(tokenLookup.symbolContainer.memberTable);
586
- }
587
- const foundClassLink = this.getClassFromTokenLookup(tokenLookup, scope);
588
- if (!foundClassLink) {
589
- //and anything from any class in scope to a non m class
590
- let classMemberCompletions = scope.getAllClassMemberCompletions();
591
- result.push(...classMemberCompletions.values());
592
- result.push(...scope.getPropertyNameCompletions().filter((i) => !classMemberCompletions.has(i.label)));
593
- }
594
- else {
595
- result.push(...scope.getPropertyNameCompletions());
596
- }
597
- }
598
- else {
599
- result.push(
600
- //include namespaces
601
- ...namespaceCompletions,
602
- //include class names
603
- ...classNameCompletions,
604
- //include interfaces
605
- ...interfaceNameCompletions,
606
- //include enums
607
- ...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope),
608
- //include constants
609
- ...this.getNonNamespacedConstStatementCompletions(currentToken, this.parseMode, scope),
610
- //include the global callables
611
- ...scope.getCallablesAsCompletions(this.parseMode));
612
- //add `m` because that's always valid within a function
613
- result.push({
614
- label: 'm',
615
- kind: vscode_languageserver_2.CompletionItemKind.Variable
616
- });
617
- names.m = true;
618
- result.push(...exports.KeywordCompletions);
619
- //include local variables
620
- for (let symbol of functionExpression.symbolTable.getOwnSymbols()) {
621
- const symbolNameLower = symbol.name.toLowerCase();
622
- //skip duplicate variable names
623
- if (names[symbolNameLower]) {
624
- continue;
625
- }
626
- names[symbolNameLower] = true;
627
- // TODO TYPES (This may be a performance hit?)
628
- // const foundType = getTypeFromContext(symbol.type, { scope: scope, file: this });
629
- result.push({
630
- //TODO does this work?
631
- label: symbol.name,
632
- //TODO TYPES find type for local vars - SEE above
633
- kind: vscode_languageserver_2.CompletionItemKind.Variable
634
- // kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
635
- });
636
- }
637
- if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
638
- //include the first part of namespaces
639
- let namespaces = scope.getAllNamespaceStatements();
640
- for (let stmt of namespaces) {
641
- let firstPart = stmt.nameExpression.getNameParts().shift();
642
- //skip duplicate namespace names
643
- if (names[firstPart.toLowerCase()]) {
644
- continue;
645
- }
646
- names[firstPart.toLowerCase()] = true;
647
- result.push({
648
- label: firstPart,
649
- kind: vscode_languageserver_2.CompletionItemKind.Module
650
- });
651
- }
652
- }
653
- }
654
- return result;
655
- }
656
- getCompletionsFromSymbolTable(symbolTable) {
657
- return symbolTable.getAllSymbols().map(bscType => {
658
- return {
659
- label: bscType.name,
660
- kind: (0, reflection_1.isTypedFunctionType)(bscType.type) ? vscode_languageserver_2.CompletionItemKind.Method : vscode_languageserver_2.CompletionItemKind.Field
661
- };
662
- });
663
- }
664
- getLabelCompletion(func) {
665
- return func.labelStatements.map(label => ({
666
- label: label.tokens.identifier.text,
667
- kind: vscode_languageserver_2.CompletionItemKind.Reference
668
- }));
669
- }
670
- getClassMemberCompletions(position, currentToken, functionExpression, scope) {
671
- var _a, _b, _c, _d;
672
- let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
673
- let results = new Map();
674
- if (classStatement) {
675
- let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
676
- for (let cs of classes) {
677
- 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 : []]) {
678
- if (!results.has(member.name.text.toLowerCase())) {
679
- results.set(member.name.text.toLowerCase(), {
680
- label: member.name.text,
681
- kind: (0, reflection_1.isFieldStatement)(member) ? vscode_languageserver_2.CompletionItemKind.Field : vscode_languageserver_2.CompletionItemKind.Method
682
- });
683
- }
684
- }
685
- }
686
- }
687
- return results;
688
- }
689
- /**
690
- * Gets the class (if any) of a given token based on the scope
691
- * @param currentToken token in question
692
- * @param functionExpression current functionExpression
693
- * @param scope the current scope
694
- * @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
695
- */
696
- getClassFromToken(currentToken, functionExpression, scope) {
697
- const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
698
- return this.getClassFromTokenLookup(tokenLookup, scope);
699
- }
700
- /**
701
- * Gets the class (if any) of a given token based on the scope
702
- * @param currentToken token in question
703
- * @param functionExpression current functionExpression
704
- * @param scope the current scope
705
- * @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
706
- */
707
- getClassFromTokenLookup(tokenLookup, scope) {
708
- const currentClass = tokenLookup === null || tokenLookup === void 0 ? void 0 : tokenLookup.symbolContainer;
709
- if ((0, reflection_1.isClassStatement)(currentClass)) {
710
- return { item: currentClass, file: this };
711
- }
712
- else if ((0, reflection_1.isCustomType)(currentClass)) {
713
- const foundClass = scope.getClass(currentClass.name);
714
- if (foundClass) {
715
- return { item: foundClass, file: this };
716
- }
717
- }
718
- return undefined;
719
- }
720
- findNamespaceFromTokenChain(originalTokenChain, scope) {
721
- let namespaceTokens = [];
722
- let startsWithNamespace = '';
723
- let namespaceContainer;
724
- let tokenChain = [...originalTokenChain];
725
- while (tokenChain[0] && tokenChain[0].usage === Parser_1.TokenUsage.Direct) {
726
- const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
727
- const foundNamespace = scope.namespaceLookup.get(namespaceNameToCheck);
728
- if (foundNamespace) {
729
- namespaceContainer = foundNamespace;
730
- namespaceTokens.push(tokenChain[0].token);
731
- startsWithNamespace = namespaceTokens.map(token => token.text).join('.');
732
- tokenChain.shift();
733
- }
734
- else {
735
- break;
736
- }
737
- }
738
- if (namespaceTokens.length > 0) {
739
- namespaceContainer = scope.namespaceLookup.get(startsWithNamespace.toLowerCase());
740
- }
741
- return { namespaceContainer: namespaceContainer, tokenChain: tokenChain };
742
- }
743
- checkForSpecialClassSymbol(currentToken, scope, func) {
744
- var _a;
745
- const containingClass = this.parser.getContainingClass(currentToken);
746
- let symbolType;
747
- let currentClassRef;
748
- const currentTokenLower = currentToken.text.toLowerCase();
749
- const typeContext = { file: this, scope: scope, position: currentToken.range.start };
750
- if (containingClass) {
751
- // Special cases for a single token inside a class
752
- let expandedText = '';
753
- let useExpandedTextOnly = false;
754
- if (containingClass.name === currentToken) {
755
- symbolType = containingClass.getThisBscType();
756
- expandedText = `class ${containingClass.getName(Parser_1.ParseMode.BrighterScript)}`;
757
- useExpandedTextOnly = true;
758
- currentClassRef = containingClass;
759
- }
760
- else if (currentTokenLower === 'm') {
761
- symbolType = containingClass.getThisBscType();
762
- expandedText = currentToken.text;
763
- currentClassRef = containingClass;
764
- }
765
- else if (currentTokenLower === 'super') {
766
- symbolType = (0, BscType_1.getTypeFromContext)(containingClass.symbolTable.getSymbolType(currentTokenLower, true, typeContext), typeContext);
767
- if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
768
- currentClassRef = scope.getParentClass(containingClass);
769
- }
770
- }
771
- else if (((_a = func === null || func === void 0 ? void 0 : func.functionStatement) === null || _a === void 0 ? void 0 : _a.name) === currentToken) {
772
- // check if this is a method declaration
773
- currentClassRef = containingClass;
774
- symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
775
- expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
776
- }
777
- else if (!func) {
778
- // check if this is a field declaration
779
- currentClassRef = containingClass;
780
- symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
781
- expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
782
- }
783
- if (symbolType) {
784
- return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
785
- }
786
- }
787
- }
788
- checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope) {
789
- var _a;
790
- const tokenChain = (_a = nameSpacedTokenChain.tokenChain) !== null && _a !== void 0 ? _a : [];
791
- if (nameSpacedTokenChain.namespaceContainer && tokenChain.length === 0) {
792
- //currentToken was part of a namespace
793
- return {
794
- type: null,
795
- expandedTokenText: `namespace ${nameSpacedTokenChain.namespaceContainer.fullName}`,
796
- useExpandedTextOnly: true
797
- };
798
- }
799
- const specialCase = tokenChain.length === 1 ? this.checkForSpecialClassSymbol(tokenChain[0].token, scope, functionExpression) : null;
800
- if (specialCase) {
801
- return specialCase;
802
- }
803
- }
804
- /**
805
- * Checks previous tokens for the start of a symbol chain (eg. m.property.subProperty.method())
806
- * @param currentToken The token to check
807
- * @param functionExpression The current function context
808
- * @param scope use this scope for finding class maps
809
- * @returns the BscType, expanded text (e.g <Class.field>) and classStatement (if available) for the token
810
- */
811
- getSymbolTypeFromToken(currentToken, functionExpression, scope) {
812
- var _a, _b, _c, _d;
813
- if (!scope || !currentToken) {
814
- return undefined;
815
- }
816
- const cachedSymbolData = scope.symbolCache.get(currentToken);
817
- if (cachedSymbolData) {
818
- return cachedSymbolData;
819
- }
820
- const tokenChainResponse = this.parser.getTokenChain(currentToken);
821
- if (tokenChainResponse.includesUnknowableTokenType) {
822
- const symbolData = { type: new DynamicType_1.DynamicType(), expandedTokenText: currentToken.text };
823
- scope.symbolCache.set(currentToken, symbolData);
824
- return symbolData;
825
- }
826
- const nameSpacedTokenChain = this.findNamespaceFromTokenChain(tokenChainResponse.chain, scope);
827
- const specialCase = this.checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope);
828
- if (specialCase) {
829
- scope.symbolCache.set(currentToken, specialCase);
830
- return specialCase;
831
- }
832
- const tokenChain = nameSpacedTokenChain.tokenChain;
833
- let symbolContainer = this.parser.getContainingAA(currentToken) || this.parser.getContainingClass(currentToken);
834
- 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;
835
- let tokenFoundCount = 0;
836
- let symbolTypeBeforeReference;
837
- let symbolType;
838
- let tokenText = [];
839
- let justReturnDynamic = false;
840
- let fullNamespaceName = nameSpacedTokenChain.namespaceContainer ? nameSpacedTokenChain.namespaceContainer.fullName + '.' : '';
841
- const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
842
- for (const tokenChainMember of tokenChain) {
843
- const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
844
- const tokenUsage = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.usage;
845
- const tokenLowerText = token.text.toLowerCase();
846
- if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
847
- /// Special cases for first item in chain inside a class
848
- symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
849
- currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
850
- if (symbolContainer && currentSymbolTable) {
851
- tokenText.push(symbolContainer.getName(Parser_1.ParseMode.BrighterScript));
852
- tokenFoundCount++;
853
- continue;
854
- }
855
- }
856
- if (!currentSymbolTable) {
857
- // uh oh... no symbol table to continue to check
858
- break;
859
- }
860
- symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
861
- if (tokenFoundCount === 0 && !symbolType) {
862
- //check for global callable
863
- symbolType = (_d = scope.getGlobalCallableByName(tokenLowerText)) === null || _d === void 0 ? void 0 : _d.type;
864
- }
865
- if (symbolType) {
866
- // found this symbol, and it's valid. increase found counter
867
- tokenFoundCount++;
868
- }
869
- symbolTypeBeforeReference = symbolType;
870
- if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
871
- // this is a function, and it is in the start or middle of the chain
872
- // the next symbol to check will be the return value of this function
873
- symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
874
- if (tokenFoundCount < tokenChain.length) {
875
- // We still have more tokens, but remember the last known reference
876
- symbolTypeBeforeReference = symbolType;
877
- }
878
- }
879
- if ((0, reflection_1.isArrayType)(symbolType) && tokenUsage === Parser_1.TokenUsage.ArrayReference) {
880
- symbolType = (0, BscType_1.getTypeFromContext)(symbolType.getDefaultType(typeContext), typeContext);
881
- }
882
- if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
883
- if ((0, reflection_1.isCustomType)(symbolType) || (0, reflection_1.isInterfaceType)(symbolType) || (0, reflection_1.isEnumType)(symbolType)) {
884
- // we're currently looking at a type that has its own symbol table
885
- // use the name of the custom type
886
- // TODO TYPES: get proper parent name for methods/fields defined in super classes
887
- tokenText.push(tokenChain.length === 1 ? token.text : symbolType.name);
888
- }
889
- else {
890
- justReturnDynamic = true;
891
- tokenText.push(token.text);
892
- }
893
- symbolContainer = symbolType;
894
- currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
895
- }
896
- else if ((0, reflection_1.isObjectType)(symbolType) || (0, reflection_1.isArrayType)(symbolType) || (0, reflection_1.isDynamicType)(symbolType)) {
897
- // this is an object that has no member table
898
- // this could happen if a parameter is marked as object
899
- // assume all fields are dynamic
900
- symbolContainer = undefined;
901
- tokenText.push(token.text);
902
- justReturnDynamic = true;
903
- break;
904
- }
905
- else {
906
- // No further symbol tables were found
907
- symbolContainer = undefined;
908
- tokenText.push(token.text);
909
- break;
910
- }
911
- }
912
- if (tokenText.length > 2) {
913
- // TokenText is used for hovers. We only need the last two tokens for a hover
914
- // So in a long chain (e.g. klass.getData()[0].anotherKlass.property), the hover
915
- // for the last token should just be "AnotherKlass.property", not the whole chain
916
- tokenText = tokenText.slice(-2);
917
- }
918
- let expandedTokenText = tokenText.join('.');
919
- let backUpReturnType;
920
- if (tokenFoundCount === tokenChain.length) {
921
- // did we complete the chain? if so, we have a valid token at the end
922
- const symbolData = { type: symbolTypeBeforeReference, expandedTokenText: tokenText.join('.'), symbolContainer: symbolContainer };
923
- scope.symbolCache.set(currentToken, symbolData);
924
- return symbolData;
925
- }
926
- if ((0, reflection_1.isDynamicType)(symbolTypeBeforeReference) || (0, reflection_1.isArrayType)(symbolTypeBeforeReference) || justReturnDynamic) {
927
- // last type in chain is dynamic... so currentToken could be anything.
928
- backUpReturnType = new DynamicType_1.DynamicType();
929
- expandedTokenText = currentToken.text;
930
- }
931
- else if ((0, reflection_1.isPrimitiveType)(symbolTypeBeforeReference)) {
932
- // last type in chain is dynamic... so currentToken could be anything.
933
- backUpReturnType = new DynamicType_1.DynamicType();
934
- expandedTokenText = currentToken.text;
935
- }
936
- else if (tokenChain.length === 1) {
937
- // variable that has not been assigned
938
- expandedTokenText = currentToken.text;
939
- backUpReturnType = new UninitializedType_1.UninitializedType();
940
- }
941
- else if (tokenFoundCount === tokenChain.length - 1) {
942
- // member field that is not known
943
- if (symbolContainer) {
944
- backUpReturnType = new InvalidType_1.InvalidType();
945
- }
946
- else {
947
- // TODO TYPES: once we have stricter object/node member type checking, we could say this is invalid, but until then, call it dynamic
948
- backUpReturnType = new DynamicType_1.DynamicType();
949
- expandedTokenText = currentToken.text;
950
- }
951
- }
952
- const symbolData = { type: backUpReturnType, expandedTokenText: expandedTokenText, fullName: fullNamespaceName + expandedTokenText };
953
- scope.symbolCache.set(currentToken, symbolData);
954
- return symbolData;
955
- }
956
- getGlobalClassStatementCompletions(currentToken, parseMode, scope) {
957
- var _a;
958
- if (parseMode === Parser_1.ParseMode.BrightScript) {
959
- return [];
960
- }
961
- let results = new Map();
962
- let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
963
- if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
964
- return [];
965
- }
966
- let classMap = scope.getClassMap();
967
- // let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
968
- for (const key of [...classMap.keys()]) {
969
- let cs = classMap.get(key).item;
970
- if (!results.has(cs.name.text)) {
971
- results.set(cs.name.text, {
972
- label: cs.name.text,
973
- kind: vscode_languageserver_2.CompletionItemKind.Class
974
- });
975
- }
976
- }
977
- return [...results.values()];
978
- }
979
- getNonNamespacedEnumStatementCompletions(currentToken, parseMode, scope) {
980
- var _a, _b;
981
- if (parseMode !== Parser_1.ParseMode.BrighterScript) {
982
- return [];
983
- }
984
- 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) + '.';
985
- const results = new Map();
986
- const enumMap = scope.getEnumMap();
987
- for (const key of [...enumMap.keys()]) {
988
- const enumStatement = enumMap.get(key).item;
989
- const fullName = enumStatement.fullName;
990
- //if the enum is contained within our own namespace, or if it's a non-namespaced enum
991
- if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
992
- results.set(fullName, {
993
- label: enumStatement.name,
994
- kind: vscode_languageserver_2.CompletionItemKind.Enum
995
- });
996
- }
997
- }
998
- return [...results.values()];
999
- }
1000
- getNonNamespacedConstStatementCompletions(currentToken, parseMode, scope) {
1001
- var _a, _b;
1002
- if (parseMode !== Parser_1.ParseMode.BrighterScript) {
1003
- return [];
1004
- }
1005
- 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) + '.';
1006
- const results = new Map();
1007
- const map = scope.getConstMap();
1008
- for (const key of [...map.keys()]) {
1009
- const statement = map.get(key).item;
1010
- const fullName = statement.fullName;
1011
- //if the item is contained within our own namespace, or if it's non-namespaced
1012
- if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
1013
- results.set(fullName, {
1014
- label: statement.name,
1015
- kind: vscode_languageserver_2.CompletionItemKind.Constant
1016
- });
1017
- }
1018
- }
1019
- return [...results.values()];
1020
- }
1021
- getEnumMemberStatementCompletions(currentToken, parseMode, scope) {
1022
- var _a, _b, _c, _d, _e;
1023
- if (parseMode === Parser_1.ParseMode.BrightScript || !currentToken) {
1024
- return [];
1025
- }
1026
- const results = new Map();
1027
- const completionName = (_a = this.getPartialVariableName(currentToken)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
1028
- //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
1029
- if (!completionName || !completionName.includes('.')) {
1030
- return [];
1031
- }
1032
- const enumNameLower = (_b = completionName === null || completionName === void 0 ? void 0 : completionName.split(/\.(\w+)?$/)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
1033
- const namespaceNameLower = (_c = this.getNamespaceStatementForPosition(currentToken.range.end)) === null || _c === void 0 ? void 0 : _c.name.toLowerCase();
1034
- const enumMap = scope.getEnumMap();
1035
- //get the enum statement with this name (check without namespace prefix first, then with inferred namespace prefix next)
1036
- const enumStatement = (_e = ((_d = enumMap.get(enumNameLower)) !== null && _d !== void 0 ? _d : enumMap.get(namespaceNameLower + '.' + enumNameLower))) === null || _e === void 0 ? void 0 : _e.item;
1037
- //if we found an enum with this name
1038
- if (enumStatement) {
1039
- for (const member of enumStatement.getMembers()) {
1040
- const name = enumStatement.fullName + '.' + member.name;
1041
- const nameLower = name.toLowerCase();
1042
- results.set(nameLower, {
1043
- label: member.name,
1044
- kind: vscode_languageserver_2.CompletionItemKind.EnumMember
1045
- });
1046
- }
1047
- }
1048
- return [...results.values()];
1049
- }
1050
- getGlobalInterfaceStatementCompletions(currentToken, parseMode, scope) {
1051
- var _a;
1052
- if (parseMode === Parser_1.ParseMode.BrightScript) {
1053
- return [];
1054
- }
1055
- let results = new Map();
1056
- let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
1057
- if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
1058
- return [];
1059
- }
1060
- let ifaceMap = scope.getInterfaceMap();
1061
- for (const key of [...ifaceMap.keys()]) {
1062
- let cs = ifaceMap.get(key).item;
1063
- if (!results.has(cs.name.text)) {
1064
- results.set(cs.name.text, {
1065
- label: cs.name.text,
1066
- kind: vscode_languageserver_2.CompletionItemKind.Interface
1067
- });
1068
- }
1069
- }
1070
- return [...results.values()];
1071
- }
1072
- getNamespaceCompletions(currentToken, parseMode, scope) {
1073
- //BrightScript does not support namespaces, so return an empty list in that case
1074
- if (parseMode === Parser_1.ParseMode.BrightScript) {
1075
- return [];
1076
- }
1077
- const completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
1078
- //if we don't have a completion name, or if there's no period in the name, then this is not a namespaced variable
1079
- if (!completionName || !completionName.includes('.')) {
1080
- return [];
1081
- }
1082
- //remove any trailing identifer and then any trailing dot, to give us the
1083
- //name of its immediate parent namespace
1084
- let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
1085
- let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
1086
- let result = new Map();
1087
- for (let [, namespace] of scope.namespaceLookup) {
1088
- //completionName = "NameA."
1089
- //completionName = "NameA.Na
1090
- //NameA
1091
- //NameA.NameB
1092
- //NameA.NameB.NameC
1093
- if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
1094
- //add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
1095
- for (let [, ns] of namespace.namespaces) {
1096
- if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
1097
- if (!result.has(ns.lastPartName)) {
1098
- result.set(ns.lastPartName, {
1099
- label: ns.lastPartName,
1100
- kind: vscode_languageserver_2.CompletionItemKind.Module
1101
- });
1102
- }
1103
- }
1104
- }
1105
- //add function and class statement completions
1106
- for (let stmt of namespace.statements) {
1107
- if ((0, reflection_1.isClassStatement)(stmt)) {
1108
- result.set(stmt.name.text, {
1109
- label: stmt.name.text,
1110
- kind: vscode_languageserver_2.CompletionItemKind.Class
1111
- });
1112
- }
1113
- else if ((0, reflection_1.isFunctionStatement)(stmt) && !newToken) {
1114
- result.set(stmt.name.text, {
1115
- label: stmt.name.text,
1116
- kind: vscode_languageserver_2.CompletionItemKind.Function
1117
- });
1118
- }
1119
- else if ((0, reflection_1.isEnumStatement)(stmt) && !newToken) {
1120
- result.set(stmt.name, {
1121
- label: stmt.name,
1122
- kind: vscode_languageserver_2.CompletionItemKind.Enum
1123
- });
1124
- }
1125
- else if ((0, reflection_1.isConstStatement)(stmt) && !newToken) {
1126
- result.set(stmt.name, {
1127
- label: stmt.name,
1128
- kind: vscode_languageserver_2.CompletionItemKind.Constant
1129
- });
1130
- }
1131
- }
1132
- }
1133
- }
1134
- return [...result.values()];
1135
- }
1136
594
  getNamespaceDefinitions(token, file) {
1137
595
  //BrightScript does not support namespaces, so return an empty list in that case
1138
596
  if (!token) {
@@ -1190,6 +648,70 @@ class BrsFile {
1190
648
  return undefined;
1191
649
  }
1192
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
+ }
1193
715
  /**
1194
716
  * Find the first scope that has a namespace with this name.
1195
717
  * Returns false if no namespace was found with that name
@@ -1223,14 +745,60 @@ class BrsFile {
1223
745
  let scopes = this.program.getScopesForFile(this);
1224
746
  for (let scope of scopes) {
1225
747
  let namespace = scope.namespaceLookup.get(namespaceName.toLowerCase());
1226
- if (namespace.functionStatements[lowerCalleeName]) {
748
+ if (namespace.functionStatements.has(lowerCalleeName)) {
1227
749
  return true;
1228
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;
1229
777
  }
1230
778
  }
1231
779
  }
1232
780
  return false;
1233
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
+ }
1234
802
  /**
1235
803
  * Builds a list of document symbols for this file. Used by LanguageServer's onDocumentSymbol functionality
1236
804
  */
@@ -1348,7 +916,7 @@ class BrsFile {
1348
916
  var _a, _b;
1349
917
  let results = [];
1350
918
  //get the token at the position
1351
- const token = this.parser.getTokenAt(position);
919
+ const token = this.getTokenAt(position);
1352
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
1353
921
  let definitionTokenTypes = [
1354
922
  TokenKind_1.TokenKind.Identifier,
@@ -1360,20 +928,42 @@ class BrsFile {
1360
928
  }
1361
929
  const scopesForFile = this.program.getScopesForFile(this);
1362
930
  const [scope] = scopesForFile;
1363
- scope.linkSymbolTable();
1364
931
  const expression = this.getClosestExpression(position);
1365
- if (expression) {
1366
- let containingNamespace = (_a = this.getNamespaceStatementForPosition(expression.range.start)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
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);
1367
935
  const fullName = (_b = util_1.util.getAllDottedGetParts(expression)) === null || _b === void 0 ? void 0 : _b.map(x => x.text).join('.');
1368
936
  //find a constant with this name
1369
- const constant = scope.getConstFileLink(fullName, containingNamespace);
937
+ const constant = scope === null || scope === void 0 ? void 0 : scope.getConstFileLink(fullName, containingNamespace);
1370
938
  if (constant) {
1371
939
  results.push(util_1.util.createLocation(vscode_uri_1.URI.file(constant.file.srcPath).toString(), constant.item.tokens.name.range));
1372
940
  return results;
1373
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
+ }
1374
964
  }
1375
965
  let textToSearchFor = token.text.toLowerCase();
1376
- 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 });
1377
967
  if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
1378
968
  for (const scope of scopesForFile) {
1379
969
  //to only get functions defined in interface methods
@@ -1384,9 +974,9 @@ class BrsFile {
1384
974
  }
1385
975
  return results;
1386
976
  }
1387
- let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
977
+ let classToken = this.getTokenBefore(token, TokenKind_1.TokenKind.Class);
1388
978
  if (classToken) {
1389
- 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);
1390
980
  if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
1391
981
  const nameParts = cs.parentClassName.getNameParts();
1392
982
  let extendedClass = this.getClassFileLink(nameParts[nameParts.length - 1], nameParts.slice(0, -1).join('.'));
@@ -1405,22 +995,22 @@ class BrsFile {
1405
995
  }
1406
996
  textToSearchFor = textToSearchFor.substring(startIndex, endIndex);
1407
997
  }
1408
- const func = this.getFunctionExpressionAtPosition(position);
1409
- if (func) {
1410
- //look through local variables first
1411
- //find any variable with this name
1412
- for (const symbol of func.symbolTable.getOwnSymbols()) {
1413
- //we found a variable declaration with this token text
1414
- 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) {
1415
1005
  const uri = util_1.util.pathToUri(this.srcPath);
1416
- results.push(util_1.util.createLocation(uri, symbol.range));
1006
+ results.push(util_1.util.createLocation(uri, varDeclaration.nameRange));
1417
1007
  }
1418
1008
  }
1419
- if (this.parser.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
1420
- for (const label of func.labelStatements) {
1421
- 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) {
1422
1012
  const uri = util_1.util.pathToUri(this.srcPath);
1423
- results.push(util_1.util.createLocation(uri, label.tokens.identifier.range));
1013
+ results.push(util_1.util.createLocation(uri, label.nameRange));
1424
1014
  }
1425
1015
  }
1426
1016
  }
@@ -1429,28 +1019,27 @@ class BrsFile {
1429
1019
  //look through all files in scope for matches
1430
1020
  for (const scope of scopesForFile) {
1431
1021
  for (const file of scope.getAllFiles()) {
1432
- if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
1433
- continue;
1434
- }
1435
- filesSearched.add(file);
1436
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1437
- results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1438
- const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1439
- if (namespaceDefinition) {
1440
- 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
+ }
1441
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
+ });
1442
1042
  }
1443
- const statementHandler = (statement) => {
1444
- if (statement.getName(this.parseMode).toLowerCase() === textToSearchFor) {
1445
- const uri = util_1.util.pathToUri(file.srcPath);
1446
- results.push(util_1.util.createLocation(uri, statement.range));
1447
- }
1448
- };
1449
- file.parser.ast.walk((0, visitors_1.createVisitor)({
1450
- FunctionStatement: statementHandler
1451
- }), {
1452
- walkMode: visitors_1.WalkMode.visitStatements
1453
- });
1454
1043
  }
1455
1044
  }
1456
1045
  return results;
@@ -1458,104 +1047,27 @@ class BrsFile {
1458
1047
  getClassMemberDefinitions(textToSearchFor, file) {
1459
1048
  let results = [];
1460
1049
  //get class fields and members
1461
- file.parser.ast.walk((0, visitors_1.createVisitor)({
1462
- MethodStatement: (statement) => {
1463
- if (statement.getName(file.parseMode).toLowerCase() === textToSearchFor) {
1464
- results.push(util_1.util.createLocation(util_1.util.pathToUri(file.srcPath), statement.range));
1465
- }
1466
- },
1467
- FieldStatement: (statement) => {
1468
- if (statement.name.text.toLowerCase() === textToSearchFor) {
1469
- results.push(util_1.util.createLocation(util_1.util.pathToUri(file.srcPath), statement.range));
1470
- }
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));
1471
1058
  }
1059
+ };
1060
+ file.parser.ast.walk((0, visitors_1.createVisitor)({
1061
+ MethodStatement: statementHandler,
1062
+ FieldStatement: fieldStatementHandler
1472
1063
  }), {
1473
1064
  walkMode: visitors_1.WalkMode.visitStatements
1474
1065
  });
1475
1066
  return results;
1476
1067
  }
1477
- getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
1478
- var _a;
1479
- if (!dottedGetText) {
1480
- return [];
1481
- }
1482
- let resultsMap = new Map();
1483
- for (let [, namespace] of scope.namespaceLookup) {
1484
- //completionName = "NameA."
1485
- //completionName = "NameA.Na
1486
- //NameA
1487
- //NameA.NameB
1488
- //NameA.NameB.NameC
1489
- if (namespace.fullName.toLowerCase() === dottedGetText.toLowerCase()) {
1490
- //add function and class statement completions
1491
- for (let stmt of namespace.statements) {
1492
- if ((0, reflection_1.isFunctionStatement)(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
1493
- const result = (_a = namespace.file) === null || _a === void 0 ? void 0 : _a.getSignatureHelpForStatement(stmt);
1494
- if (!resultsMap.has(result.key)) {
1495
- resultsMap.set(result.key, result);
1496
- }
1497
- }
1498
- }
1499
- }
1500
- }
1501
- return [...resultsMap.values()];
1502
- }
1503
- getSignatureHelpForStatement(statement) {
1504
- if (!(0, reflection_1.isFunctionStatement)(statement) && !(0, reflection_1.isMethodStatement)(statement)) {
1505
- return undefined;
1506
- }
1507
- const func = statement.func;
1508
- const funcStartPosition = func.range.start;
1509
- // Get function comments in reverse order
1510
- let currentToken = this.parser.getTokenAt(funcStartPosition);
1511
- let functionComments = [];
1512
- while (currentToken) {
1513
- currentToken = this.parser.getPreviousToken(currentToken);
1514
- if (!currentToken) {
1515
- break;
1516
- }
1517
- if (currentToken.range.start.line + 1 < funcStartPosition.line) {
1518
- if (functionComments.length === 0) {
1519
- break;
1520
- }
1521
- }
1522
- const kind = currentToken.kind;
1523
- if (kind === TokenKind_1.TokenKind.Comment) {
1524
- // Strip off common leading characters to make it easier to read
1525
- const commentText = currentToken.text.replace(/^[' *\/]+/, '');
1526
- functionComments.unshift(commentText);
1527
- }
1528
- else if (kind === TokenKind_1.TokenKind.Newline) {
1529
- if (functionComments.length === 0) {
1530
- continue;
1531
- }
1532
- // if we already had a new line as the last token then exit out
1533
- if (functionComments[0] === currentToken.text) {
1534
- break;
1535
- }
1536
- functionComments.unshift(currentToken.text);
1537
- }
1538
- else {
1539
- break;
1540
- }
1541
- }
1542
- const documentation = functionComments.join('').trim();
1543
- const lines = util_1.util.splitIntoLines(this.fileContents);
1544
- let key = statement.name.text + documentation;
1545
- const params = [];
1546
- for (const param of func.parameters) {
1547
- params.push(vscode_languageserver_2.ParameterInformation.create(param.name.text));
1548
- key += param.name.text;
1549
- }
1550
- const label = util_1.util.getTextForRange(lines, func.functionDeclarationRange).trim();
1551
- const signature = vscode_languageserver_2.SignatureInformation.create(label, documentation, ...params);
1552
- const index = 1;
1553
- return { key: key, signature: signature, index: index };
1554
- }
1555
1068
  getClassMethod(classStatement, name, walkParents = true) {
1556
1069
  var _a;
1557
- //TODO - would like to write this with getClassHierarchy; but got stuck on working out the scopes to use... :(
1558
- //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... :(
1559
1071
  let statement;
1560
1072
  const statementHandler = (e) => {
1561
1073
  if (!statement && e.name.text.toLowerCase() === name.toLowerCase()) {
@@ -1581,45 +1093,55 @@ class BrsFile {
1581
1093
  }
1582
1094
  return statement;
1583
1095
  }
1584
- getClassSignatureHelp(classStatement) {
1585
- const classConstructor = this.getClassMethod(classStatement, 'new');
1586
- let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
1587
- if (sigHelp) {
1588
- sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
1589
- sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
1590
- }
1591
- return sigHelp;
1592
- }
1593
1096
  getReferences(position) {
1594
- const callSiteToken = this.parser.getTokenAt(position);
1097
+ const callSiteToken = this.getTokenAt(position);
1595
1098
  let locations = [];
1596
1099
  const searchFor = callSiteToken.text.toLowerCase();
1597
1100
  const scopes = this.program.getScopesForFile(this);
1598
1101
  for (const scope of scopes) {
1599
1102
  const processedFiles = new Set();
1600
1103
  for (const file of scope.getAllFiles()) {
1601
- if ((0, reflection_1.isXmlFile)(file) || processedFiles.has(file)) {
1602
- continue;
1603
- }
1604
- processedFiles.add(file);
1605
- file.ast.walk((0, visitors_1.createVisitor)({
1606
- VariableExpression: (e) => {
1607
- if (e.name.text.toLowerCase() === searchFor) {
1608
- locations.push(util_1.util.createLocation(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
+ }
1609
1111
  }
1610
- }
1611
- }), {
1612
- walkMode: visitors_1.WalkMode.visitExpressionsRecursive
1613
- });
1112
+ }), {
1113
+ walkMode: visitors_1.WalkMode.visitExpressionsRecursive
1114
+ });
1115
+ }
1614
1116
  }
1615
1117
  }
1616
1118
  return locations;
1617
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
+ }
1618
1138
  /**
1619
1139
  * Convert the brightscript/brighterscript source code into valid brightscript
1620
1140
  */
1621
1141
  transpile() {
1142
+ var _a;
1622
1143
  const state = new BrsTranspileState_1.BrsTranspileState(this);
1144
+ state.editor = (_a = this.editor) !== null && _a !== void 0 ? _a : new Editor_1.Editor();
1623
1145
  let transpileResult;
1624
1146
  if (this.needsTranspiled) {
1625
1147
  transpileResult = new source_map_1.SourceNode(null, null, state.srcPath, this.ast.transpile(state));
@@ -1632,8 +1154,11 @@ class BrsFile {
1632
1154
  //simple SourceNode wrapping the entire file to simplify the logic below
1633
1155
  transpileResult = new source_map_1.SourceNode(null, null, state.srcPath, this.fileContents);
1634
1156
  }
1635
- //undo any AST edits that the transpile cycle has made
1636
- 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
+ }
1637
1162
  if (this.program.options.sourceMap) {
1638
1163
  return new source_map_1.SourceNode(null, null, null, [
1639
1164
  transpileResult,
@@ -1648,6 +1173,206 @@ class BrsFile {
1648
1173
  };
1649
1174
  }
1650
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
+ }
1651
1376
  getTypedef() {
1652
1377
  const state = new BrsTranspileState_1.BrsTranspileState(this);
1653
1378
  const typedef = this.ast.getTypedef(state);
@@ -1655,30 +1380,14 @@ class BrsFile {
1655
1380
  return programNode.toString();
1656
1381
  }
1657
1382
  dispose() {
1658
- var _a, _b;
1383
+ var _a;
1659
1384
  (_a = this._parser) === null || _a === void 0 ? void 0 : _a.dispose();
1660
- //unsubscribe from any DependencyGraph subscriptions
1661
- (_b = this.unsubscribeFromDependencyGraph) === null || _b === void 0 ? void 0 : _b.call(this);
1662
1385
  //deleting these properties result in lower memory usage (garbage collection is magic!)
1663
1386
  delete this.fileContents;
1664
1387
  delete this._parser;
1665
- delete this.callables;
1666
- delete this.functionCalls;
1388
+ delete this._functionScopes;
1389
+ delete this.scopesByFunc;
1667
1390
  }
1668
1391
  }
1669
1392
  exports.BrsFile = BrsFile;
1670
- /**
1671
- * List of completions for all valid keywords/reserved words.
1672
- * Build this list once because it won't change for the lifetime of this process
1673
- */
1674
- exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
1675
- //remove any keywords with whitespace
1676
- .filter(x => !x.includes(' '))
1677
- //create completions
1678
- .map(x => {
1679
- return {
1680
- label: x,
1681
- kind: vscode_languageserver_2.CompletionItemKind.Keyword
1682
- };
1683
- });
1684
1393
  //# sourceMappingURL=BrsFile.js.map