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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/CHANGELOG.md +585 -218
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +41 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +39 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +79 -15
  33. package/dist/DiagnosticMessages.js +134 -21
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +222 -87
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +162 -81
  54. package/dist/Program.js +903 -732
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +132 -104
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +95 -134
  60. package/dist/Scope.js +477 -551
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +95 -29
  65. package/dist/SymbolTable.js +256 -102
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -6
  74. package/dist/XmlScope.js +74 -68
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +68 -64
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +26 -16
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -100
  90. package/dist/astUtils/reflection.js +225 -166
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +208 -126
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +54 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +178 -33
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +12 -2
  105. package/dist/bscPlugin/BscPlugin.js +41 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +135 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +21 -12
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +86 -12
  120. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +57 -0
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js +544 -0
  123. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  125. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  128. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  129. package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
  130. package/dist/bscPlugin/hover/HoverProcessor.js +188 -0
  131. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js +513 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +3 -1
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +102 -29
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +167 -6
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  140. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  141. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  142. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  143. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  144. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  146. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  147. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +16 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +123 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  152. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  153. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  155. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  156. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  157. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +22 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.js +316 -29
  159. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  160. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +264 -0
  162. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  163. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  164. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  165. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  166. package/dist/bscPlugin/validation/ScopeValidator.d.ts +56 -8
  167. package/dist/bscPlugin/validation/ScopeValidator.js +514 -116
  168. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  169. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  170. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  171. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  172. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  173. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  174. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  175. package/dist/cli.js +107 -8
  176. package/dist/cli.js.map +1 -1
  177. package/dist/deferred.d.ts +3 -3
  178. package/dist/deferred.js.map +1 -1
  179. package/dist/diagnosticUtils.d.ts +8 -2
  180. package/dist/diagnosticUtils.js +47 -17
  181. package/dist/diagnosticUtils.js.map +1 -1
  182. package/dist/examples/plugins/removePrint.js +8 -10
  183. package/dist/examples/plugins/removePrint.js.map +1 -1
  184. package/dist/files/AssetFile.d.ts +26 -0
  185. package/dist/files/AssetFile.js +26 -0
  186. package/dist/files/AssetFile.js.map +1 -0
  187. package/dist/files/BrsFile.Class.spec.js +529 -486
  188. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  189. package/dist/files/BrsFile.d.ts +124 -112
  190. package/dist/files/BrsFile.js +819 -1131
  191. package/dist/files/BrsFile.js.map +1 -1
  192. package/dist/files/BrsFile.spec.js +1869 -1277
  193. package/dist/files/BrsFile.spec.js.map +1 -1
  194. package/dist/files/BscFile.d.ts +104 -0
  195. package/dist/files/BscFile.js +16 -0
  196. package/dist/files/BscFile.js.map +1 -0
  197. package/dist/files/Factory.d.ts +25 -0
  198. package/dist/files/Factory.js +22 -0
  199. package/dist/files/Factory.js.map +1 -0
  200. package/dist/files/LazyFileData.d.ts +20 -0
  201. package/dist/files/LazyFileData.js +54 -0
  202. package/dist/files/LazyFileData.js.map +1 -0
  203. package/dist/files/LazyFileData.spec.d.ts +1 -0
  204. package/dist/files/LazyFileData.spec.js +27 -0
  205. package/dist/files/LazyFileData.spec.js.map +1 -0
  206. package/dist/files/XmlFile.d.ts +70 -32
  207. package/dist/files/XmlFile.js +106 -117
  208. package/dist/files/XmlFile.js.map +1 -1
  209. package/dist/files/XmlFile.spec.js +325 -262
  210. package/dist/files/XmlFile.spec.js.map +1 -1
  211. package/dist/files/tests/imports.spec.js +49 -41
  212. package/dist/files/tests/imports.spec.js.map +1 -1
  213. package/dist/files/tests/optionalChaning.spec.js +104 -40
  214. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  215. package/dist/globalCallables.js +16 -18
  216. package/dist/globalCallables.js.map +1 -1
  217. package/dist/index.d.ts +13 -2
  218. package/dist/index.js +15 -2
  219. package/dist/index.js.map +1 -1
  220. package/dist/interfaces.d.ts +440 -150
  221. package/dist/interfaces.js +27 -0
  222. package/dist/interfaces.js.map +1 -1
  223. package/dist/lexer/Character.spec.js +5 -5
  224. package/dist/lexer/Character.spec.js.map +1 -1
  225. package/dist/lexer/Lexer.d.ts +12 -5
  226. package/dist/lexer/Lexer.js +28 -13
  227. package/dist/lexer/Lexer.js.map +1 -1
  228. package/dist/lexer/Lexer.spec.js +187 -134
  229. package/dist/lexer/Lexer.spec.js.map +1 -1
  230. package/dist/lexer/Token.d.ts +9 -1
  231. package/dist/lexer/Token.js +9 -1
  232. package/dist/lexer/Token.js.map +1 -1
  233. package/dist/lexer/TokenKind.d.ts +9 -0
  234. package/dist/lexer/TokenKind.js +30 -5
  235. package/dist/lexer/TokenKind.js.map +1 -1
  236. package/dist/parser/AstNode.d.ts +162 -0
  237. package/dist/parser/AstNode.js +225 -0
  238. package/dist/parser/AstNode.js.map +1 -0
  239. package/dist/parser/AstNode.spec.d.ts +1 -0
  240. package/dist/parser/AstNode.spec.js +165 -0
  241. package/dist/parser/AstNode.spec.js.map +1 -0
  242. package/dist/parser/BrsTranspileState.d.ts +4 -7
  243. package/dist/parser/BrsTranspileState.js +4 -12
  244. package/dist/parser/BrsTranspileState.js.map +1 -1
  245. package/dist/parser/Expression.d.ts +126 -167
  246. package/dist/parser/Expression.js +524 -394
  247. package/dist/parser/Expression.js.map +1 -1
  248. package/dist/parser/Parser.Class.spec.js +152 -146
  249. package/dist/parser/Parser.Class.spec.js.map +1 -1
  250. package/dist/parser/Parser.d.ts +45 -196
  251. package/dist/parser/Parser.js +470 -926
  252. package/dist/parser/Parser.js.map +1 -1
  253. package/dist/parser/Parser.spec.d.ts +3 -1
  254. package/dist/parser/Parser.spec.js +1034 -805
  255. package/dist/parser/Parser.spec.js.map +1 -1
  256. package/dist/parser/SGParser.d.ts +9 -8
  257. package/dist/parser/SGParser.js +10 -8
  258. package/dist/parser/SGParser.js.map +1 -1
  259. package/dist/parser/SGParser.spec.js +27 -38
  260. package/dist/parser/SGParser.spec.js.map +1 -1
  261. package/dist/parser/SGTypes.d.ts +98 -35
  262. package/dist/parser/SGTypes.js +169 -99
  263. package/dist/parser/SGTypes.js.map +1 -1
  264. package/dist/parser/Statement.d.ts +208 -122
  265. package/dist/parser/Statement.js +599 -364
  266. package/dist/parser/Statement.js.map +1 -1
  267. package/dist/parser/Statement.spec.js +45 -21
  268. package/dist/parser/Statement.spec.js.map +1 -1
  269. package/dist/parser/TranspileState.d.ts +1 -1
  270. package/dist/parser/TranspileState.js +7 -12
  271. package/dist/parser/TranspileState.js.map +1 -1
  272. package/dist/parser/tests/Parser.spec.js +3 -2
  273. package/dist/parser/tests/Parser.spec.js.map +1 -1
  274. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  275. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  276. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  277. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  278. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  279. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  280. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  281. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  282. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  283. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  284. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  285. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  286. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  287. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  288. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  289. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  290. package/dist/parser/tests/expression/Call.spec.js +129 -21
  291. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  292. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  293. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  294. package/dist/parser/tests/expression/Function.spec.js +36 -36
  295. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  296. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  297. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  298. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  299. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  300. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +123 -81
  301. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  302. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  303. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  304. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  305. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  306. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  307. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  308. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  309. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  310. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  311. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  312. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +221 -81
  313. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  314. package/dist/parser/tests/expression/TernaryExpression.spec.js +287 -105
  315. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  316. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  318. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  321. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  323. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  324. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  325. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  326. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  327. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  328. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  329. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  330. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  331. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  333. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Enum.spec.js +111 -300
  335. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/For.spec.js +9 -10
  337. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  339. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Function.spec.js +44 -35
  341. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  343. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  345. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  347. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  349. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  351. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/PrintStatement.spec.js +107 -90
  353. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  355. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Set.spec.js +48 -35
  357. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  359. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  361. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  363. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  364. package/dist/preprocessor/Manifest.d.ts +1 -1
  365. package/dist/preprocessor/Manifest.js +3 -3
  366. package/dist/preprocessor/Manifest.js.map +1 -1
  367. package/dist/preprocessor/Manifest.spec.js +8 -8
  368. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  369. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  370. package/dist/preprocessor/Preprocessor.js +15 -11
  371. package/dist/preprocessor/Preprocessor.js.map +1 -1
  372. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  373. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  374. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  375. package/dist/preprocessor/PreprocessorParser.js +7 -1
  376. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  377. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  378. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  379. package/dist/roku-types/data.json +6544 -10519
  380. package/dist/roku-types/index.d.ts +662 -1934
  381. package/dist/types/ArrayType.d.ts +10 -9
  382. package/dist/types/ArrayType.js +65 -60
  383. package/dist/types/ArrayType.js.map +1 -1
  384. package/dist/types/ArrayType.spec.js +36 -68
  385. package/dist/types/ArrayType.spec.js.map +1 -1
  386. package/dist/types/AssociativeArrayType.d.ts +11 -0
  387. package/dist/types/AssociativeArrayType.js +52 -0
  388. package/dist/types/AssociativeArrayType.js.map +1 -0
  389. package/dist/types/BaseFunctionType.d.ts +9 -0
  390. package/dist/types/BaseFunctionType.js +25 -0
  391. package/dist/types/BaseFunctionType.js.map +1 -0
  392. package/dist/types/BooleanType.d.ts +8 -5
  393. package/dist/types/BooleanType.js +14 -7
  394. package/dist/types/BooleanType.js.map +1 -1
  395. package/dist/types/BooleanType.spec.js +10 -6
  396. package/dist/types/BooleanType.spec.js.map +1 -1
  397. package/dist/types/BscType.d.ts +32 -21
  398. package/dist/types/BscType.js +118 -21
  399. package/dist/types/BscType.js.map +1 -1
  400. package/dist/types/BscTypeKind.d.ts +25 -0
  401. package/dist/types/BscTypeKind.js +30 -0
  402. package/dist/types/BscTypeKind.js.map +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  404. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  405. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  406. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  407. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  409. package/dist/types/ClassType.d.ts +17 -0
  410. package/dist/types/ClassType.js +58 -0
  411. package/dist/types/ClassType.js.map +1 -0
  412. package/dist/types/ClassType.spec.d.ts +1 -0
  413. package/dist/types/ClassType.spec.js +77 -0
  414. package/dist/types/ClassType.spec.js.map +1 -0
  415. package/dist/types/ComponentType.d.ts +26 -0
  416. package/dist/types/ComponentType.js +83 -0
  417. package/dist/types/ComponentType.js.map +1 -0
  418. package/dist/types/DoubleType.d.ts +8 -5
  419. package/dist/types/DoubleType.js +18 -16
  420. package/dist/types/DoubleType.js.map +1 -1
  421. package/dist/types/DoubleType.spec.js +12 -6
  422. package/dist/types/DoubleType.spec.js.map +1 -1
  423. package/dist/types/DynamicType.d.ts +10 -5
  424. package/dist/types/DynamicType.js +16 -4
  425. package/dist/types/DynamicType.js.map +1 -1
  426. package/dist/types/DynamicType.spec.js +16 -5
  427. package/dist/types/DynamicType.spec.js.map +1 -1
  428. package/dist/types/EnumType.d.ts +30 -12
  429. package/dist/types/EnumType.js +43 -17
  430. package/dist/types/EnumType.js.map +1 -1
  431. package/dist/types/EnumType.spec.d.ts +1 -0
  432. package/dist/types/EnumType.spec.js +33 -0
  433. package/dist/types/EnumType.spec.js.map +1 -0
  434. package/dist/types/FloatType.d.ts +8 -5
  435. package/dist/types/FloatType.js +18 -16
  436. package/dist/types/FloatType.js.map +1 -1
  437. package/dist/types/FloatType.spec.js +4 -6
  438. package/dist/types/FloatType.spec.js.map +1 -1
  439. package/dist/types/FunctionType.d.ts +13 -8
  440. package/dist/types/FunctionType.js +30 -14
  441. package/dist/types/FunctionType.js.map +1 -1
  442. package/dist/types/InheritableType.d.ts +28 -0
  443. package/dist/types/InheritableType.js +152 -0
  444. package/dist/types/InheritableType.js.map +1 -0
  445. package/dist/types/IntegerType.d.ts +8 -5
  446. package/dist/types/IntegerType.js +18 -16
  447. package/dist/types/IntegerType.js.map +1 -1
  448. package/dist/types/IntegerType.spec.js +8 -6
  449. package/dist/types/IntegerType.spec.js.map +1 -1
  450. package/dist/types/InterfaceType.d.ts +12 -13
  451. package/dist/types/InterfaceType.js +20 -48
  452. package/dist/types/InterfaceType.js.map +1 -1
  453. package/dist/types/InterfaceType.spec.js +90 -56
  454. package/dist/types/InterfaceType.spec.js.map +1 -1
  455. package/dist/types/InvalidType.d.ts +7 -5
  456. package/dist/types/InvalidType.js +13 -7
  457. package/dist/types/InvalidType.js.map +1 -1
  458. package/dist/types/InvalidType.spec.js +8 -6
  459. package/dist/types/InvalidType.spec.js.map +1 -1
  460. package/dist/types/LongIntegerType.d.ts +8 -5
  461. package/dist/types/LongIntegerType.js +17 -15
  462. package/dist/types/LongIntegerType.js.map +1 -1
  463. package/dist/types/LongIntegerType.spec.js +10 -6
  464. package/dist/types/LongIntegerType.spec.js.map +1 -1
  465. package/dist/types/NamespaceType.d.ts +12 -0
  466. package/dist/types/NamespaceType.js +28 -0
  467. package/dist/types/NamespaceType.js.map +1 -0
  468. package/dist/types/ObjectType.d.ts +9 -8
  469. package/dist/types/ObjectType.js +21 -11
  470. package/dist/types/ObjectType.js.map +1 -1
  471. package/dist/types/ObjectType.spec.js +3 -3
  472. package/dist/types/ObjectType.spec.js.map +1 -1
  473. package/dist/types/ReferenceType.d.ts +63 -0
  474. package/dist/types/ReferenceType.js +423 -0
  475. package/dist/types/ReferenceType.js.map +1 -0
  476. package/dist/types/ReferenceType.spec.d.ts +1 -0
  477. package/dist/types/ReferenceType.spec.js +137 -0
  478. package/dist/types/ReferenceType.spec.js.map +1 -0
  479. package/dist/types/StringType.d.ts +11 -5
  480. package/dist/types/StringType.js +18 -7
  481. package/dist/types/StringType.js.map +1 -1
  482. package/dist/types/StringType.spec.js +3 -5
  483. package/dist/types/StringType.spec.js.map +1 -1
  484. package/dist/types/TypedFunctionType.d.ts +22 -17
  485. package/dist/types/TypedFunctionType.js +78 -60
  486. package/dist/types/TypedFunctionType.js.map +1 -1
  487. package/dist/types/TypedFunctionType.spec.js +105 -20
  488. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  489. package/dist/types/UninitializedType.d.ts +8 -6
  490. package/dist/types/UninitializedType.js +13 -7
  491. package/dist/types/UninitializedType.js.map +1 -1
  492. package/dist/types/UnionType.d.ts +20 -0
  493. package/dist/types/UnionType.js +123 -0
  494. package/dist/types/UnionType.js.map +1 -0
  495. package/dist/types/UnionType.spec.d.ts +1 -0
  496. package/dist/types/UnionType.spec.js +130 -0
  497. package/dist/types/UnionType.spec.js.map +1 -0
  498. package/dist/types/VoidType.d.ts +8 -5
  499. package/dist/types/VoidType.js +14 -7
  500. package/dist/types/VoidType.js.map +1 -1
  501. package/dist/types/VoidType.spec.js +3 -3
  502. package/dist/types/VoidType.spec.js.map +1 -1
  503. package/dist/types/helper.spec.d.ts +1 -0
  504. package/dist/types/helper.spec.js +145 -0
  505. package/dist/types/helper.spec.js.map +1 -0
  506. package/dist/types/helpers.d.ts +19 -37
  507. package/dist/types/helpers.js +159 -99
  508. package/dist/types/helpers.js.map +1 -1
  509. package/dist/types/index.d.ts +22 -0
  510. package/dist/types/index.js +39 -0
  511. package/dist/types/index.js.map +1 -0
  512. package/dist/util.d.ts +167 -131
  513. package/dist/util.js +890 -350
  514. package/dist/util.js.map +1 -1
  515. package/dist/validators/ClassValidator.d.ts +7 -25
  516. package/dist/validators/ClassValidator.js +103 -194
  517. package/dist/validators/ClassValidator.js.map +1 -1
  518. package/package.json +165 -149
  519. package/dist/astUtils/AstEditor.js.map +0 -1
  520. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  521. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +0 -8
  522. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +0 -40
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/hover/HoverProcessor.spec.d.ts} +0 -0
package/dist/Scope.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Scope = void 0;
4
- const vscode_languageserver_1 = require("vscode-languageserver");
4
+ const path = require("path");
5
5
  const chalk_1 = require("chalk");
6
6
  const DiagnosticMessages_1 = require("./DiagnosticMessages");
7
+ const interfaces_1 = require("./interfaces");
7
8
  const ClassValidator_1 = require("./validators/ClassValidator");
8
9
  const Parser_1 = require("./parser/Parser");
9
10
  const util_1 = require("./util");
@@ -13,10 +14,18 @@ const vscode_uri_1 = require("vscode-uri");
13
14
  const Logger_1 = require("./Logger");
14
15
  const reflection_1 = require("./astUtils/reflection");
15
16
  const SymbolTable_1 = require("./SymbolTable");
16
- const BscType_1 = require("./types/BscType");
17
- const DynamicType_1 = require("./types/DynamicType");
18
- const ObjectType_1 = require("./types/ObjectType");
19
- const UninitializedType_1 = require("./types/UninitializedType");
17
+ const NamespaceType_1 = require("./types/NamespaceType");
18
+ const ReferenceType_1 = require("./types/ReferenceType");
19
+ const UnionType_1 = require("./types/UnionType");
20
+ const AssociativeArrayType_1 = require("./types/AssociativeArrayType");
21
+ const AstNode_1 = require("./parser/AstNode");
22
+ const visitors_1 = require("./astUtils/visitors");
23
+ /**
24
+ * Assign some few factories to the SymbolTable to prevent cyclical imports. This file seems like the most intuitive place to do the linking
25
+ * since Scope will be used by pretty much everything
26
+ */
27
+ SymbolTable_1.SymbolTable.referenceTypeFactory = ReferenceType_1.referenceTypeFactory;
28
+ SymbolTable_1.SymbolTable.unionTypeFactory = UnionType_1.unionTypeFactory;
20
29
  /**
21
30
  * A class to keep track of all declarations within a given scope (like source scope, component scope)
22
31
  */
@@ -30,6 +39,11 @@ class Scope {
30
39
  * The list of diagnostics found specifically for this scope. Individual file diagnostics are stored on the files themselves.
31
40
  */
32
41
  this.diagnostics = [];
42
+ /**
43
+ * A list of functions that will be called whenever `unlinkSymbolTable` is called
44
+ */
45
+ this.linkSymbolTableDisposables = [];
46
+ this.symbolsAddedDuringLinking = [];
33
47
  this.isValidated = false;
34
48
  //used for improved logging performance
35
49
  this._debugLogComponentName = `Scope '${chalk_1.default.redBright(this.name)}'`;
@@ -43,8 +57,52 @@ class Scope {
43
57
  * "namea", "namea.nameb", "namea.nameb.namec"
44
58
  */
45
59
  get namespaceLookup() {
60
+ let allFilesValidated = true;
61
+ for (const file of this.getAllFiles()) {
62
+ if ((0, reflection_1.isBrsFile)(file) && !file.hasTypedef) {
63
+ allFilesValidated = allFilesValidated && file.isValidated;
64
+ if (!allFilesValidated) {
65
+ break;
66
+ }
67
+ }
68
+ }
69
+ if (!allFilesValidated) {
70
+ // This is not fit to cache
71
+ // Since the files have not been validated, all namespace info might not have been available
72
+ return this.buildNamespaceLookup();
73
+ }
46
74
  return this.cache.getOrAdd('namespaceLookup', () => this.buildNamespaceLookup());
47
75
  }
76
+ /**
77
+ * Get a NamespaceContainer by its name, looking for a fully qualified version first, then global version next if not found
78
+ */
79
+ getNamespace(name, containingNamespace) {
80
+ const nameLower = name === null || name === void 0 ? void 0 : name.toLowerCase();
81
+ const lookup = this.namespaceLookup;
82
+ let ns;
83
+ if (containingNamespace) {
84
+ ns = lookup.get(`${containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()}.${nameLower}`);
85
+ }
86
+ //if we couldn't find the namespace by its full namespaced name, look for a global version
87
+ if (!ns) {
88
+ ns = lookup.get(nameLower);
89
+ }
90
+ return ns;
91
+ }
92
+ /**
93
+ * Get a NamespaceContainer by its name, looking for a fully qualified version first, then global version next if not found
94
+ */
95
+ getNamespacesWithRoot(rootName, containingNamespace) {
96
+ const nameLower = rootName === null || rootName === void 0 ? void 0 : rootName.toLowerCase();
97
+ const lookup = this.namespaceLookup;
98
+ const lookupKeys = [...lookup.keys()];
99
+ let lookupName = nameLower;
100
+ if (containingNamespace) {
101
+ lookupName = `${containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()}.${nameLower}`;
102
+ }
103
+ const nsList = lookupKeys.filter(key => key === lookupName).map(key => lookup.get(key));
104
+ return nsList;
105
+ }
48
106
  /**
49
107
  * Get the class with the specified name.
50
108
  * @param className - The class name, including the namespace of the class if possible
@@ -63,23 +121,6 @@ class Scope {
63
121
  var _a;
64
122
  return (_a = this.getInterfaceFileLink(ifaceName, containingNamespace)) === null || _a === void 0 ? void 0 : _a.item;
65
123
  }
66
- /**
67
- * Get either the class or interface, etc. with a given name
68
- * @param name - The name, including the namespace of the interface if possible
69
- * @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find the interface or class)
70
- */
71
- getNamedTypeStatement(name, containingNamespace) {
72
- var _a;
73
- return (_a = this.getNamedTypeFileLink(name, containingNamespace)) === null || _a === void 0 ? void 0 : _a.item;
74
- }
75
- /**
76
- * A cache of a map of tokens -> TokenSymbolLookups, which are the result of getSymbolTypeFromToken()
77
- * Sometimes the lookup of symbols may take a while if there are lazyTypes or multiple tokens in a chain
78
- * By caching the result of this lookup, subsequent lookups of the same tokens are quicker
79
- */
80
- get symbolCache() {
81
- return this.cache.getOrAdd('symbolCache', () => new Map());
82
- }
83
124
  /**
84
125
  * Get the enum with the specified name.
85
126
  * @param enumName - The enum name, including the namespace if possible
@@ -105,10 +146,10 @@ class Scope {
105
146
  return cls;
106
147
  }
107
148
  /**
108
- * Get an interface and its containing file by the interface name
109
- * @param ifaceName - The interface name, including the namespace of the interface if possible
110
- * @param containingNamespace - The namespace used to resolve relative interface names. (i.e. the namespace around the current statement trying to find a interface)
111
- */
149
+ * Get an interface and its containing file by the interface name
150
+ * @param ifaceName - The interface name, including the namespace of the interface if possible
151
+ * @param containingNamespace - The namespace used to resolve relative interface names. (i.e. the namespace around the current statement trying to find a interface)
152
+ */
112
153
  getInterfaceFileLink(ifaceName, containingNamespace) {
113
154
  const lowerName = ifaceName === null || ifaceName === void 0 ? void 0 : ifaceName.toLowerCase();
114
155
  const ifaceMap = this.getInterfaceMap();
@@ -135,68 +176,68 @@ class Scope {
135
176
  return enumeration;
136
177
  }
137
178
  /**
138
- * Get a Named Type (e.g. Class, Interface, Enum) and its containing file by the name
139
- * @param name - The name of the type, including the namespace of the class/interface/enum, etc. if possible
140
- * @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
141
- */
142
- getNamedTypeFileLink(name, containingNamespace) {
143
- return this.getInheritableFileLink(name, containingNamespace) || this.getEnumFileLink(name, containingNamespace);
144
- }
145
- /**
146
- * Get a InheritableStatement and its containing file by the name of the interface or class
147
- * @param name - The name of the interface or class, including the namespace of the class if possible
148
- * @param containingNamespace - The namespace used to resolve relative names. (i.e. the namespace around the current statement trying to find a class)
149
- */
150
- getInheritableFileLink(name, containingNamespace) {
151
- return this.getClassFileLink(name, containingNamespace) || this.getInterfaceFileLink(name, containingNamespace);
152
- }
153
- /**
154
- * Gets the parent class of the given class
155
- * @param klass - The class to get the parent of, if possible
179
+ * Get an Enum and its containing file by the Enum name
180
+ * @param enumMemberName - The Enum name, including the namespace of the enum if possible
181
+ * @param containingNamespace - The namespace used to resolve relative enum names. (i.e. the namespace around the current statement trying to find a enum)
156
182
  */
157
- getParentClass(klass) {
158
- if (klass === null || klass === void 0 ? void 0 : klass.hasParent()) {
159
- const lowerParentClassNames = klass.getPossibleFullParentNames().map(name => name.toLowerCase());
160
- for (const lowerParentClassName of lowerParentClassNames) {
161
- const foundParent = this.getClassMap().get(lowerParentClassName);
162
- if (foundParent) {
163
- return foundParent.item;
164
- }
165
- }
183
+ getEnumMemberFileLink(enumMemberName, containingNamespace) {
184
+ var _a, _b;
185
+ let lowerNameParts = (_a = enumMemberName === null || enumMemberName === void 0 ? void 0 : enumMemberName.toLowerCase()) === null || _a === void 0 ? void 0 : _a.split('.');
186
+ let memberName = (_b = lowerNameParts === null || lowerNameParts === void 0 ? void 0 : lowerNameParts.splice(lowerNameParts.length - 1, 1)) === null || _b === void 0 ? void 0 : _b[0];
187
+ let lowerName = lowerNameParts === null || lowerNameParts === void 0 ? void 0 : lowerNameParts.join('.');
188
+ const enumMap = this.getEnumMap();
189
+ let enumeration = enumMap.get(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
190
+ //if we couldn't find the enum by its full namespaced name, look for a global enum with that name
191
+ if (!enumeration) {
192
+ enumeration = enumMap.get(lowerName);
193
+ }
194
+ if (enumeration) {
195
+ let member = enumeration.item.findChild((child) => { var _a; return (0, reflection_1.isEnumMemberStatement)(child) && ((_a = child.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === memberName; });
196
+ return member ? { item: member, file: enumeration.file } : undefined;
166
197
  }
167
198
  }
168
199
  /**
169
- * Gets the parent interface of the given interface
170
- * @param iface - The interface to get the parent of, if possible
200
+ * Get a constant and its containing file by the constant name
201
+ * @param constName - The constant name, including the namespace of the constant if possible
202
+ * @param containingNamespace - The namespace used to resolve relative constant names. (i.e. the namespace around the current statement trying to find a constant)
171
203
  */
172
- getParentInterface(iface) {
173
- if (iface === null || iface === void 0 ? void 0 : iface.hasParent()) {
174
- const lowerParentClassNames = iface.getPossibleFullParentNames().map(name => name.toLowerCase());
175
- for (const lowerParentClassName of lowerParentClassNames) {
176
- const foundParent = this.getInterfaceMap().get(lowerParentClassName);
177
- if (foundParent) {
178
- return foundParent.item;
179
- }
180
- }
204
+ getConstFileLink(constName, containingNamespace) {
205
+ const lowerName = constName === null || constName === void 0 ? void 0 : constName.toLowerCase();
206
+ const constMap = this.getConstMap();
207
+ let result = constMap.get(util_1.util.getFullyQualifiedClassName(lowerName, containingNamespace === null || containingNamespace === void 0 ? void 0 : containingNamespace.toLowerCase()));
208
+ //if we couldn't find the constant by its full namespaced name, look for a global constant with that name
209
+ if (!result) {
210
+ result = constMap.get(lowerName);
181
211
  }
212
+ return result;
182
213
  }
183
- /**
184
- * Gets the parent of an Interface or Class
185
- * @param stmt - The class or interface to get the parent of, if possible
186
- */
187
- getParentStatement(stmt) {
188
- if ((0, reflection_1.isInterfaceStatement)(stmt)) {
189
- return this.getParentInterface(stmt);
214
+ getAllFileLinks(name, containingNamespace) {
215
+ var _a, _b, _c, _d, _e, _f;
216
+ let links = [];
217
+ links.push((_a = this.getClassFileLink(name)) !== null && _a !== void 0 ? _a : this.getClassFileLink(name, containingNamespace), (_b = this.getInterfaceFileLink(name)) !== null && _b !== void 0 ? _b : this.getInterfaceFileLink(name, containingNamespace), (_c = this.getConstFileLink(name)) !== null && _c !== void 0 ? _c : this.getConstFileLink(name, containingNamespace), (_d = this.getEnumFileLink(name)) !== null && _d !== void 0 ? _d : this.getEnumFileLink(name, containingNamespace));
218
+ const nameSpaces = this.getNamespacesWithRoot(name, containingNamespace);
219
+ if ((nameSpaces === null || nameSpaces === void 0 ? void 0 : nameSpaces.length) > 0) {
220
+ const nsContainersWithStatement = (_e = nameSpaces.filter(nsContainer => { var _a; return ((_a = nsContainer === null || nsContainer === void 0 ? void 0 : nsContainer.namespaceStatements) === null || _a === void 0 ? void 0 : _a.length) > 0; })) === null || _e === void 0 ? void 0 : _e[0];
221
+ if (nsContainersWithStatement) {
222
+ links.push({ item: (_f = nsContainersWithStatement === null || nsContainersWithStatement === void 0 ? void 0 : nsContainersWithStatement.namespaceStatements) === null || _f === void 0 ? void 0 : _f[0], file: nsContainersWithStatement === null || nsContainersWithStatement === void 0 ? void 0 : nsContainersWithStatement.file });
223
+ }
190
224
  }
191
- else if ((0, reflection_1.isClassStatement)(stmt)) {
192
- return this.getParentClass(stmt);
225
+ const fullNameLower = (containingNamespace ? `${containingNamespace}.${name}` : name).toLowerCase();
226
+ const callable = this.getCallableByName(name);
227
+ if (callable) {
228
+ if (!callable.hasNamespace || callable.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === fullNameLower) {
229
+ // this callable has no namespace, or has same namespace
230
+ links.push({ item: callable.functionStatement, file: callable.file });
231
+ }
193
232
  }
233
+ // remove empty links
234
+ return links.filter(link => link);
194
235
  }
195
- /*
196
- * Get a map of all enums by their member name.
197
- * The keys are lower-case fully-qualified paths to the enum and its member. For example:
198
- * namespace.enum.value
199
- */
236
+ /**
237
+ * Get a map of all enums by their member name.
238
+ * The keys are lower-case fully-qualified paths to the enum and its member. For example:
239
+ * namespace.enum.value
240
+ */
200
241
  getEnumMemberMap() {
201
242
  return this.cache.getOrAdd('enumMemberMap', () => {
202
243
  const result = new Map();
@@ -209,36 +250,28 @@ class Scope {
209
250
  });
210
251
  }
211
252
  /**
212
- * Tests if a class exists with the specified name
213
- * @param className - the all-lower-case namespace-included class name
214
- * @param namespaceName - the current namespace name
215
- */
253
+ * Tests if a class exists with the specified name
254
+ * @param className - the all-lower-case namespace-included class name
255
+ * @param namespaceName - The namespace used to resolve relative class names. (i.e. the namespace around the current statement trying to find a class)
256
+ */
216
257
  hasClass(className, namespaceName) {
217
258
  return !!this.getClass(className, namespaceName);
218
259
  }
219
260
  /**
220
- * Tests if an interface exists with the specified name
221
- * @param ifaceName - the all-lower-case namespace-included interface name
222
- * @param namespaceName - the current namespace name
223
- */
261
+ * Tests if an interface exists with the specified name
262
+ * @param ifaceName - the all-lower-case namespace-included interface name
263
+ * @param namespaceName - the current namespace name
264
+ */
224
265
  hasInterface(ifaceName, namespaceName) {
225
266
  return !!this.getInterface(ifaceName, namespaceName);
226
267
  }
227
268
  /**
228
- * Tests if an enum exists with the specified name
229
- * @param enumName - the all-lower-case namespace-included enum name
230
- * @param namespaceName - the current namespace name
231
- */
232
- hasEnum(enumName, namespaceName) {
233
- return !!this.getEnum(enumName, namespaceName);
234
- }
235
- /**
236
- * Tests if a class OR an interface, etc. exists with the specified name
237
- * @param name - the all-lower-case namespace-included class or interface name
269
+ * Tests if an enum exists with the specified name
270
+ * @param enumName - the all-lower-case namespace-included enum name
238
271
  * @param namespaceName - the current namespace name
239
272
  */
240
- hasNamedType(name, namespaceName) {
241
- return !!this.getNamedTypeStatement(name, namespaceName);
273
+ hasEnum(enumName, namespaceName) {
274
+ return !!this.getEnum(enumName, namespaceName);
242
275
  }
243
276
  /**
244
277
  * A dictionary of all classes in this scope. This includes namespaced classes always with their full name.
@@ -248,13 +281,12 @@ class Scope {
248
281
  return this.cache.getOrAdd('classMap', () => {
249
282
  const map = new Map();
250
283
  this.enumerateBrsFiles((file) => {
251
- var _a;
252
284
  if ((0, reflection_1.isBrsFile)(file)) {
253
- for (let cls of file.parser.references.classStatements) {
254
- const lowerClassName = (_a = cls.getName(Parser_1.ParseMode.BrighterScript)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
285
+ for (let cls of file['_cachedLookups'].classStatements) {
286
+ const className = cls.getName(Parser_1.ParseMode.BrighterScript);
255
287
  //only track classes with a defined name (i.e. exclude nameless malformed classes)
256
- if (lowerClassName) {
257
- map.set(lowerClassName, { item: cls, file: file });
288
+ if (className) {
289
+ map.set(className.toLowerCase(), { item: cls, file: file });
258
290
  }
259
291
  }
260
292
  }
@@ -262,29 +294,20 @@ class Scope {
262
294
  return map;
263
295
  });
264
296
  }
265
- getAncestorTypeListByContext(thisType, context) {
266
- var _a;
267
- const funcExpr = (_a = context === null || context === void 0 ? void 0 : context.file) === null || _a === void 0 ? void 0 : _a.getFunctionExpressionAtPosition(context === null || context === void 0 ? void 0 : context.position);
268
- if ((0, reflection_1.isCustomType)(thisType) || (0, reflection_1.isInterfaceType)(thisType)) {
269
- return this.getAncestorTypeList(thisType.name, funcExpr);
270
- }
271
- return [];
272
- }
273
297
  /**
274
- * A dictionary of all Interfaces in this scope. This includes namespaced Interfaces always with their full name.
275
- * The key is stored in lower case
276
- */
298
+ * A dictionary of all Interfaces in this scope. This includes namespaced Interfaces always with their full name.
299
+ * The key is stored in lower case
300
+ */
277
301
  getInterfaceMap() {
278
302
  return this.cache.getOrAdd('interfaceMap', () => {
279
303
  const map = new Map();
280
304
  this.enumerateBrsFiles((file) => {
281
- var _a;
282
305
  if ((0, reflection_1.isBrsFile)(file)) {
283
- for (let iface of file.parser.references.interfaceStatements) {
284
- const lowerIfaceName = (_a = iface.getName(Parser_1.ParseMode.BrighterScript)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
306
+ for (let iface of file['_cachedLookups'].interfaceStatements) {
307
+ const ifaceName = iface.getName(Parser_1.ParseMode.BrighterScript);
285
308
  //only track classes with a defined name (i.e. exclude nameless malformed classes)
286
- if (lowerIfaceName) {
287
- map.set(lowerIfaceName, { item: iface, file: file });
309
+ if (ifaceName) {
310
+ map.set(ifaceName.toLowerCase(), { item: iface, file: file });
288
311
  }
289
312
  }
290
313
  }
@@ -292,21 +315,6 @@ class Scope {
292
315
  return map;
293
316
  });
294
317
  }
295
- getAncestorTypeList(className, functionExpression) {
296
- var _a, _b;
297
- const lowerNamespaceName = (_a = functionExpression.namespaceName) === null || _a === void 0 ? void 0 : _a.getName().toLowerCase();
298
- const ancestors = [];
299
- let currentClassOrIFace = (_b = this.getInheritableFileLink(className, lowerNamespaceName)) === null || _b === void 0 ? void 0 : _b.item;
300
- if (currentClassOrIFace) {
301
- ancestors.push(currentClassOrIFace === null || currentClassOrIFace === void 0 ? void 0 : currentClassOrIFace.getThisBscType());
302
- }
303
- while (currentClassOrIFace === null || currentClassOrIFace === void 0 ? void 0 : currentClassOrIFace.hasParent()) {
304
- currentClassOrIFace = this.getParentStatement(currentClassOrIFace);
305
- ancestors.push(currentClassOrIFace === null || currentClassOrIFace === void 0 ? void 0 : currentClassOrIFace.getThisBscType());
306
- }
307
- // TODO TYPES: this should probably be cached
308
- return ancestors;
309
- }
310
318
  /**
311
319
  * A dictionary of all enums in this scope. This includes namespaced enums always with their full name.
312
320
  * The key is stored in lower case
@@ -315,11 +323,28 @@ class Scope {
315
323
  return this.cache.getOrAdd('enumMap', () => {
316
324
  const map = new Map();
317
325
  this.enumerateBrsFiles((file) => {
318
- for (let enumStmt of file.parser.references.enumStatements) {
319
- const lowerEnumName = enumStmt.fullName.toLowerCase();
326
+ for (let enumStmt of file['_cachedLookups'].enumStatements) {
327
+ //only track enums with a defined name (i.e. exclude nameless malformed enums)
328
+ if (enumStmt.fullName) {
329
+ map.set(enumStmt.fullName.toLowerCase(), { item: enumStmt, file: file });
330
+ }
331
+ }
332
+ });
333
+ return map;
334
+ });
335
+ }
336
+ /**
337
+ * A dictionary of all constants in this scope. This includes namespaced constants always with their full name.
338
+ * The key is stored in lower case
339
+ */
340
+ getConstMap() {
341
+ return this.cache.getOrAdd('constMap', () => {
342
+ const map = new Map();
343
+ this.enumerateBrsFiles((file) => {
344
+ for (let stmt of file['_cachedLookups'].constStatements) {
320
345
  //only track enums with a defined name (i.e. exclude nameless malformed enums)
321
- if (lowerEnumName) {
322
- map.set(lowerEnumName, { item: enumStmt, file: file });
346
+ if (stmt.fullName) {
347
+ map.set(stmt.fullName.toLowerCase(), { item: stmt, file: file });
323
348
  }
324
349
  }
325
350
  });
@@ -344,7 +369,7 @@ class Scope {
344
369
  isKnownNamespace(namespaceName) {
345
370
  let namespaceNameLower = namespaceName.toLowerCase();
346
371
  this.enumerateBrsFiles((file) => {
347
- for (let namespace of file.parser.references.namespaceStatements) {
372
+ for (let namespace of file['_cachedLookups'].namespaceStatements) {
348
373
  let loopNamespaceNameLower = namespace.name.toLowerCase();
349
374
  if (loopNamespaceNameLower === namespaceNameLower || loopNamespaceNameLower.startsWith(namespaceNameLower + '.')) {
350
375
  return true;
@@ -360,7 +385,7 @@ class Scope {
360
385
  */
361
386
  getParentScope() {
362
387
  let scope;
363
- //use the global scope if we didn't find a scope and this is not the global scope
388
+ //use the global scope if we didn't find a sope and this is not the global scope
364
389
  if (this.program.globalScope !== this) {
365
390
  scope = this.program.globalScope;
366
391
  }
@@ -383,20 +408,23 @@ class Scope {
383
408
  this.invalidate();
384
409
  }
385
410
  /**
386
- * Get the file with the specified pkgPath
387
- * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
411
+ * Get the file from this scope with the given path.
412
+ * @param filePath can be a srcPath or destPath
388
413
  * @param normalizePath should this function repair and standardize the path? Passing false should have a performance boost if you can guarantee your path is already sanitized
389
414
  */
390
- getFile(srcPath, normalizePath = true) {
391
- if (normalizePath) {
392
- srcPath = (0, util_1.standardizePath) `${srcPath}`;
415
+ getFile(filePath, normalizePath = true) {
416
+ if (typeof filePath !== 'string') {
417
+ return undefined;
393
418
  }
394
- let files = this.getAllFiles();
395
- for (let file of files) {
396
- if (file.srcPath === srcPath) {
397
- return file;
419
+ const key = path.isAbsolute(filePath) ? 'srcPath' : 'destPath';
420
+ let map = this.cache.getOrAdd('fileMaps-srcPath', () => {
421
+ const result = new Map();
422
+ for (const file of this.getAllFiles()) {
423
+ result.set(file[key].toLowerCase(), file);
398
424
  }
399
- }
425
+ return result;
426
+ });
427
+ return map.get((normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase());
400
428
  }
401
429
  /**
402
430
  * Get the list of files referenced by this scope that are actually loaded in the program.
@@ -423,32 +451,32 @@ class Scope {
423
451
  }
424
452
  }
425
453
  else {
426
- let file = this.program.getFile(dependency, false);
454
+ let file = this.program.getFile(dependency);
427
455
  if (file) {
428
456
  result.push(file);
429
457
  }
430
458
  }
431
459
  }
432
- this.logDebug('getAllFiles', () => result.map(x => x.pkgPath));
460
+ this.logDebug('getAllFiles', () => result.map(x => x.destPath));
433
461
  return result;
434
462
  });
435
463
  }
436
464
  /**
437
- * Get the list of errors for this scope. It's calculated on the fly, so
438
- * call this sparingly.
465
+ * Get the list of errors for this scope. It's calculated on the fly, so call this sparingly.
439
466
  */
440
467
  getDiagnostics() {
441
- let diagnosticLists = [this.diagnostics];
442
468
  //add diagnostics from every referenced file
443
- this.enumerateOwnFiles((file) => {
444
- diagnosticLists.push(file.getDiagnostics());
445
- });
446
- let allDiagnostics = Array.prototype.concat.apply([], diagnosticLists);
447
- let filteredDiagnostics = allDiagnostics.filter((x) => {
469
+ const diagnostics = [
470
+ //diagnostics raised on this scope
471
+ ...this.diagnostics,
472
+ //get diagnostics from all files
473
+ ...this.getOwnFiles().map(x => { var _a; return (_a = x.diagnostics) !== null && _a !== void 0 ? _a : []; }).flat()
474
+ ]
475
+ //exclude diagnostics that match any of the comment flags
476
+ .filter((x) => {
448
477
  return !util_1.util.diagnosticIsSuppressed(x);
449
478
  });
450
- //filter out diangostics that match any of the comment flags
451
- return filteredDiagnostics;
479
+ return diagnostics;
452
480
  }
453
481
  addDiagnostics(diagnostics) {
454
482
  this.diagnostics.push(...diagnostics);
@@ -469,27 +497,23 @@ class Scope {
469
497
  /**
470
498
  * Get the callable with the specified name.
471
499
  * If there are overridden callables with the same name, the closest callable to this scope is returned
472
- * @param name
473
500
  */
474
501
  getCallableByName(name) {
475
- var _a;
476
- let lowerName = name.toLowerCase();
477
- let callables = this.getAllCallables();
478
- for (let callable of callables) {
479
- const callableName = callable.callable.getName(Parser_1.ParseMode.BrighterScript);
480
- // Split by `.` and check the last term to consider namespaces.
481
- if (callableName.toLowerCase() === lowerName || ((_a = callableName.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === lowerName) {
482
- return callable.callable;
483
- }
484
- }
502
+ return this.getCallableMap().get(name.toLowerCase());
485
503
  }
486
- /**
487
- * Get the global callable with the specified name.
488
- * If there are overridden callables with the same name, the closest callable to this scope is returned
489
- * @param name
490
- */
491
- getGlobalCallableByName(name) {
492
- return globalCallables_1.globalCallableMap.get(name.toLowerCase());
504
+ getCallableMap() {
505
+ return this.cache.getOrAdd('callableMap', () => {
506
+ var _a, _b;
507
+ const result = new Map();
508
+ for (let callable of this.getAllCallables()) {
509
+ const callableName = (_a = callable.callable.getName(Parser_1.ParseMode.BrighterScript)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
510
+ result.set(callableName, callable.callable);
511
+ result.set(
512
+ // Split by `.` and check the last term to consider namespaces.
513
+ (_b = callableName.split('.').pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase(), callable.callable);
514
+ }
515
+ return result;
516
+ });
493
517
  }
494
518
  /**
495
519
  * Iterate over Brs files not shadowed by typedefs
@@ -510,7 +534,7 @@ class Scope {
510
534
  const files = this.getOwnFiles();
511
535
  for (const file of files) {
512
536
  //either XML components or files without a typedef
513
- if ((0, reflection_1.isXmlFile)(file) || !file.hasTypedef) {
537
+ if ((0, reflection_1.isXmlFile)(file) || ((0, reflection_1.isBrsFile)(file) && !file.hasTypedef)) {
514
538
  callback(file);
515
539
  }
516
540
  }
@@ -521,14 +545,16 @@ class Scope {
521
545
  */
522
546
  getOwnCallables() {
523
547
  let result = [];
524
- this.logDebug('getOwnCallables() files: ', () => this.getOwnFiles().map(x => x.pkgPath));
548
+ this.logDebug('getOwnCallables() files: ', () => this.getOwnFiles().map(x => x.destPath));
525
549
  //get callables from own files
526
550
  this.enumerateOwnFiles((file) => {
527
- for (let callable of file.callables) {
528
- result.push({
529
- callable: callable,
530
- scope: this
531
- });
551
+ if ((0, reflection_1.isBrsFile)(file)) {
552
+ for (let callable of file.callables) {
553
+ result.push({
554
+ callable: callable,
555
+ scope: this
556
+ });
557
+ }
532
558
  }
533
559
  });
534
560
  return result;
@@ -536,60 +562,27 @@ class Scope {
536
562
  /**
537
563
  * Builds a tree of namespace objects
538
564
  */
539
- buildNamespaceLookup() {
565
+ buildNamespaceLookup(options = { okToCache: true }) {
540
566
  let namespaceLookup = new Map();
567
+ options.okToCache = true;
541
568
  this.enumerateBrsFiles((file) => {
542
- for (let namespace of file.parser.references.namespaceStatements) {
543
- //TODO should we handle non-brighterscript?
544
- let name = namespace.nameExpression.getName(Parser_1.ParseMode.BrighterScript);
545
- let nameParts = name.split('.');
546
- let loopName = null;
547
- //ensure each namespace section is represented in the results
548
- //(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"
549
- for (let part of nameParts) {
550
- loopName = loopName === null ? part : `${loopName}.${part}`;
551
- let lowerLoopName = loopName.toLowerCase();
552
- if (!namespaceLookup.has(lowerLoopName)) {
553
- namespaceLookup.set(lowerLoopName, {
554
- file: file,
555
- fullName: loopName,
556
- nameRange: namespace.nameExpression.range,
557
- lastPartName: part,
558
- namespaces: new Map(),
559
- classStatements: {},
560
- functionStatements: {},
561
- enumStatements: new Map(),
562
- statements: [],
563
- symbolTable: new SymbolTable_1.SymbolTable(this.symbolTable)
564
- });
565
- }
569
+ options.okToCache = options.okToCache && file.isValidated;
570
+ const fileNamespaceLookup = file.getNamespaceLookupObject();
571
+ for (const [lowerNamespaceName, nsContainer] of fileNamespaceLookup) {
572
+ if (!namespaceLookup.has(lowerNamespaceName)) {
573
+ const clonedNsContainer = Object.assign(Object.assign({}, nsContainer), { namespaceStatements: [...nsContainer.namespaceStatements], symbolTable: new SymbolTable_1.SymbolTable(`Namespace Aggregate: '${nsContainer.fullName}'`) });
574
+ clonedNsContainer.symbolTable.mergeSymbolTable(nsContainer.symbolTable);
575
+ namespaceLookup.set(lowerNamespaceName, clonedNsContainer);
566
576
  }
567
- let ns = namespaceLookup.get(name.toLowerCase());
568
- ns.statements.push(...namespace.body.statements);
569
- for (let statement of namespace.body.statements) {
570
- if ((0, reflection_1.isClassStatement)(statement) && statement.name) {
571
- ns.classStatements[statement.name.text.toLowerCase()] = statement;
572
- }
573
- else if ((0, reflection_1.isFunctionStatement)(statement) && statement.name) {
574
- ns.functionStatements[statement.name.text.toLowerCase()] = statement;
575
- }
576
- else if ((0, reflection_1.isEnumStatement)(statement) && statement.fullName) {
577
- ns.enumStatements.set(statement.fullName.toLowerCase(), statement);
578
- }
579
- }
580
- // Merges all the symbol tables of the namespace statements into the new symbol table created above.
581
- // Set those symbol tables to have this new merged table as a parent
582
- ns.symbolTable.mergeSymbolTable(namespace.symbolTable);
583
- }
584
- //associate child namespaces with their parents
585
- for (let [, ns] of namespaceLookup) {
586
- let parts = ns.fullName.split('.');
587
- if (parts.length > 1) {
588
- //remove the last part
589
- parts.pop();
590
- let parentName = parts.join('.');
591
- const parent = namespaceLookup.get(parentName.toLowerCase());
592
- parent.namespaces.set(ns.lastPartName.toLowerCase(), ns);
577
+ else {
578
+ const existingContainer = namespaceLookup.get(lowerNamespaceName);
579
+ existingContainer.classStatements = new Map([...existingContainer.classStatements, ...nsContainer.classStatements]);
580
+ existingContainer.constStatements = new Map([...existingContainer.constStatements, ...nsContainer.constStatements]);
581
+ existingContainer.enumStatements = new Map([...existingContainer.enumStatements, ...nsContainer.enumStatements]);
582
+ existingContainer.functionStatements = new Map([...existingContainer.functionStatements, ...nsContainer.functionStatements]);
583
+ existingContainer.namespaces = new Map([...existingContainer.namespaces, ...nsContainer.namespaces]);
584
+ existingContainer.namespaceStatements.push(...nsContainer.namespaceStatements);
585
+ existingContainer.symbolTable.mergeSymbolTable(nsContainer.symbolTable);
593
586
  }
594
587
  }
595
588
  });
@@ -598,43 +591,69 @@ class Scope {
598
591
  getAllNamespaceStatements() {
599
592
  let result = [];
600
593
  this.enumerateBrsFiles((file) => {
601
- result.push(...file.parser.references.namespaceStatements);
594
+ result.push(...file['_cachedLookups'].namespaceStatements);
602
595
  });
603
596
  return result;
604
597
  }
605
598
  logDebug(...args) {
606
599
  this.program.logger.debug(this._debugLogComponentName, ...args);
607
600
  }
608
- validate() {
601
+ validate(validationOptions = { force: false }) {
602
+ //if this scope is already validated, no need to revalidate
603
+ if (this.isValidated === true && !validationOptions.force) {
604
+ this.logDebug('validate(): already validated');
605
+ return;
606
+ }
609
607
  this.program.logger.time(Logger_1.LogLevel.debug, [this._debugLogComponentName, 'validate()'], () => {
610
608
  let parentScope = this.getParentScope();
611
609
  //validate our parent before we validate ourself
612
- if ((parentScope === null || parentScope === void 0 ? void 0 : parentScope.isValidated) === false) {
610
+ if (parentScope && parentScope.isValidated === false) {
613
611
  this.logDebug('validate(): validating parent first');
614
- parentScope.validate();
612
+ parentScope.validate(validationOptions);
615
613
  }
616
614
  //clear the scope's errors list (we will populate them from this method)
617
- this.diagnostics = [];
618
- // link the symbol table
619
- this.linkSymbolTable();
615
+ this.clearScopeLevelDiagnostics();
620
616
  let callables = this.getAllCallables();
621
617
  //sort the callables by filepath and then method name, so the errors will be consistent
618
+ // eslint-disable-next-line prefer-arrow-callback
622
619
  callables = callables.sort((a, b) => {
623
- return (
620
+ const pathA = a.callable.file.srcPath;
621
+ const pathB = b.callable.file.srcPath;
624
622
  //sort by path
625
- a.callable.file.srcPath.localeCompare(b.callable.file.srcPath) ||
626
- //then sort by method name
627
- a.callable.name.localeCompare(b.callable.name));
623
+ if (pathA < pathB) {
624
+ return -1;
625
+ }
626
+ else if (pathA > pathB) {
627
+ return 1;
628
+ }
629
+ //sort by function name
630
+ const funcA = b.callable.name;
631
+ const funcB = b.callable.name;
632
+ if (funcA < funcB) {
633
+ return -1;
634
+ }
635
+ else if (funcA > funcB) {
636
+ return 1;
637
+ }
638
+ return 0;
628
639
  });
629
640
  //get a list of all callables, indexed by their lower case names
630
641
  let callableContainerMap = util_1.util.getCallableContainersByLowerName(callables);
631
- this.program.plugins.emit('onScopeValidate', {
642
+ //Since statements from files are shared across multiple scopes, we need to link those statements to the current scope
643
+ this.linkSymbolTable();
644
+ const scopeValidateEvent = {
632
645
  program: this.program,
633
- scope: this
634
- });
646
+ scope: this,
647
+ changedFiles: validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.changedFiles,
648
+ changedSymbols: validationOptions === null || validationOptions === void 0 ? void 0 : validationOptions.changedSymbols
649
+ };
650
+ this.program.plugins.emit('beforeScopeValidate', scopeValidateEvent);
651
+ this.program.plugins.emit('onScopeValidate', scopeValidateEvent);
635
652
  this._validate(callableContainerMap);
636
- // unlink the symbol table so it can't be accessed from the wrong scope
653
+ this.program.plugins.emit('afterScopeValidate', scopeValidateEvent);
654
+ //unlink all symbol tables from this scope (so they don't accidentally stick around)
637
655
  this.unlinkSymbolTable();
656
+ this.isValidated = true;
638
657
  });
639
658
  }
640
659
  _validate(callableContainerMap) {
@@ -642,17 +661,26 @@ class Scope {
642
661
  this.diagnosticFindDuplicateFunctionDeclarations(callableContainerMap);
643
662
  //detect missing and incorrect-case script imports
644
663
  this.diagnosticValidateScriptImportPaths();
664
+ //enforce a series of checks on the bodies of class methods
665
+ this.validateClasses();
645
666
  //do many per-file checks
646
667
  this.enumerateBrsFiles((file) => {
647
- //enforce a series of checks on the bodies of class methods
648
- this.validateClasses(file);
649
668
  this.diagnosticDetectShadowedLocalVars(file, callableContainerMap);
650
669
  this.diagnosticDetectFunctionCollisions(file);
651
670
  this.detectVariableNamespaceCollisions(file);
652
- this.diagnosticDetectInvalidFunctionExpressionTypes(file);
653
- this.diagnosticDetectInvalidFunctionCalls(file, callableContainerMap);
671
+ this.detectNameCollisions(file);
654
672
  });
655
673
  }
674
+ clearAstSegmentDiagnostics(astSegment) {
675
+ this.diagnostics = this.diagnostics.filter(diag => !(diag.origin === interfaces_1.DiagnosticOrigin.ASTSegment && diag.astSegment === astSegment));
676
+ }
677
+ clearAstSegmentDiagnosticsByFile(file) {
678
+ const lowerSrcPath = file.srcPath.toLowerCase();
679
+ this.diagnostics = this.diagnostics.filter(diag => !(diag.origin === interfaces_1.DiagnosticOrigin.ASTSegment && diag.file.srcPath.toLowerCase() === lowerSrcPath));
680
+ }
681
+ clearScopeLevelDiagnostics() {
682
+ this.diagnostics = this.diagnostics.filter(diag => diag.origin !== interfaces_1.DiagnosticOrigin.Scope);
683
+ }
656
684
  /**
657
685
  * Mark this scope as invalid, which means its `validate()` function needs to be called again before use.
658
686
  */
@@ -660,120 +688,131 @@ class Scope {
660
688
  this.isValidated = false;
661
689
  //clear out various lookups (they'll get regenerated on demand the next time they're requested)
662
690
  this.cache.clear();
663
- this.clearSymbolTable();
664
- this.symbolCache.clear();
665
691
  }
666
692
  get symbolTable() {
667
- var _a, _b;
668
- if (!this._symbolTable) {
669
- this._symbolTable = new SymbolTable_1.SymbolTable((_a = this.getParentScope()) === null || _a === void 0 ? void 0 : _a.symbolTable);
670
- this._symbolTable.addSymbol('m', null, new ObjectType_1.ObjectType('object', this.memberTable));
693
+ return this.cache.getOrAdd('symbolTable', () => {
694
+ var _a;
695
+ const result = new SymbolTable_1.SymbolTable(`Scope: '${this.name}'`, () => { var _a; return (_a = this.getParentScope()) === null || _a === void 0 ? void 0 : _a.symbolTable; });
696
+ result.addSymbol('m', undefined, new AssociativeArrayType_1.AssociativeArrayType(), SymbolTable_1.SymbolTypeFlag.runtime);
671
697
  for (let file of this.getOwnFiles()) {
672
698
  if ((0, reflection_1.isBrsFile)(file)) {
673
- this._symbolTable.mergeSymbolTable((_b = file.parser) === null || _b === void 0 ? void 0 : _b.symbolTable);
699
+ result.mergeSymbolTable((_a = file.parser) === null || _a === void 0 ? void 0 : _a.symbolTable);
674
700
  }
675
701
  }
676
- }
677
- return this._symbolTable;
678
- }
679
- get memberTable() {
680
- var _a;
681
- if (!this._memberTable) {
682
- this._memberTable = new SymbolTable_1.SymbolTable((_a = this.getParentScope()) === null || _a === void 0 ? void 0 : _a.memberTable);
683
- if (!this.getParentScope()) {
684
- this._memberTable.addSymbol('global', null, new ObjectType_1.ObjectType());
685
- }
686
- }
687
- return this._memberTable;
688
- }
689
- clearSymbolTable() {
690
- this._symbolTable = null;
691
- this._memberTable = null;
702
+ return result;
703
+ });
692
704
  }
693
705
  /**
694
- * Builds the current symbol table for the scope, by merging the tables for all the files in this scope.
695
- * Also links all file symbols tables to this new table
696
- * This will only rebuilt if the symbol table has not been built before
697
- */
706
+ * Builds the current symbol table for the scope, by merging the tables for all the files in this scope.
707
+ * Also links all file symbols tables to this new table
708
+ * This will only rebuilt if the symbol table has not been built before
709
+ *
710
+ * Tree of symbol tables:
711
+ * ```
712
+ * Global Scope Symbol Table
713
+ * - Source Scope Symbol Table :: Aggregate Namespaces Symbol Table (Siblings)
714
+ * - File 1 Symbol Table
715
+ * - File 2 Symbol Table
716
+ * - Component A Scope Symbol Table :: Aggregate Namespaces Symbol Table (Siblings)
717
+ * - File 1 Symbol Table
718
+ * - File 2 Symbol Table
719
+ * - Component B Scope Symbol Table :: Aggregate Namespaces Symbol Table (Siblings)
720
+ * - File 1 Symbol Table
721
+ * - File 2 Symbol Table
722
+ * ```
723
+ */
698
724
  linkSymbolTable() {
699
- var _a, _b, _c;
725
+ var _a;
726
+ SymbolTable_1.SymbolTable.cacheVerifier.generateToken();
700
727
  for (const file of this.getAllFiles()) {
701
728
  if ((0, reflection_1.isBrsFile)(file)) {
702
- file.parser.symbolTable.setParent(this.symbolTable);
703
- for (const namespace of file.parser.references.namespaceStatements) {
704
- const namespaceNameLower = namespace.nameExpression.getName(Parser_1.ParseMode.BrighterScript).toLowerCase();
705
- const namespaceSymbolTable = this.namespaceLookup.get(namespaceNameLower).symbolTable;
706
- namespace.symbolTable.setParent(namespaceSymbolTable);
729
+ this.linkSymbolTableDisposables.push(file.parser.symbolTable.pushParentProvider(() => this.symbolTable));
730
+ }
731
+ }
732
+ //Add namespace aggregates to namespace member tables
733
+ const namespaceTypesKnown = new Map();
734
+ // eslint-disable-next-line no-bitwise
735
+ let getTypeOptions = { flags: SymbolTable_1.SymbolTypeFlag.runtime | SymbolTable_1.SymbolTypeFlag.typetime };
736
+ for (const [nsName, nsContainer] of this.namespaceLookup) {
737
+ let currentNSType = null;
738
+ let parentNSType = null;
739
+ const existingNsStmt = (_a = nsContainer.namespaceStatements) === null || _a === void 0 ? void 0 : _a[0];
740
+ if (!nsContainer.isTopLevel) {
741
+ parentNSType = namespaceTypesKnown.get(nsContainer.parentNameLower);
742
+ if (!parentNSType) {
743
+ // we don't know about the parent namespace... uh, oh!
744
+ break;
707
745
  }
708
- //TODO TYPES: build symbol tables for dotted set assignments using actual values
709
- // Currently this is prone to call-stack issues.
710
- // eg. m.key = "value"
711
- for (const dotSetStmt of file.parser.references.dottedSetStatements) {
712
- if ((0, reflection_1.isVariableExpression)(dotSetStmt.obj)) {
713
- if (dotSetStmt.obj.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === 'm') {
714
- this.memberTable.addSymbol(dotSetStmt.name.text, dotSetStmt.range, new DynamicType_1.DynamicType());
715
- // TODO TYPES: get actual types: getBscTypeFromExpression(dotSetStmt.value, file.parser.references.getContainingFunctionExpression(dotSetStmt.name)));
716
- }
746
+ currentNSType = parentNSType.getMemberType(nsContainer.fullNameLower, getTypeOptions);
747
+ }
748
+ else {
749
+ currentNSType = this.symbolTable.getSymbolType(nsContainer.fullNameLower, getTypeOptions);
750
+ }
751
+ if (!(0, reflection_1.isNamespaceType)(currentNSType)) {
752
+ if (!currentNSType || (0, reflection_1.isReferenceType)(currentNSType)) {
753
+ currentNSType = existingNsStmt
754
+ ? existingNsStmt.getType(getTypeOptions)
755
+ : new NamespaceType_1.NamespaceType(nsName);
756
+ if (parentNSType) {
757
+ // adding as a member of existing NS
758
+ parentNSType.addMember(nsContainer.lastPartName, { definingNode: existingNsStmt }, currentNSType, getTypeOptions.flags);
759
+ this.symbolsAddedDuringLinking.push({ symbolTable: parentNSType.getMemberTable(), name: nsContainer.lastPartName, flags: getTypeOptions.flags });
717
760
  }
718
761
  else {
719
- // TODO TYPES: What other types of expressions could these be?
762
+ this.symbolTable.addSymbol(nsContainer.lastPartName, { definingNode: existingNsStmt }, currentNSType, getTypeOptions.flags);
763
+ this.symbolsAddedDuringLinking.push({ symbolTable: this.symbolTable, name: nsContainer.lastPartName, flags: getTypeOptions.flags });
720
764
  }
721
765
  }
766
+ else {
767
+ break;
768
+ }
722
769
  }
723
- }
724
- // also link classes
725
- const classMap = this.getClassMap();
726
- for (const pair of classMap) {
727
- const classStmt = (_a = pair[1]) === null || _a === void 0 ? void 0 : _a.item;
728
- classStmt === null || classStmt === void 0 ? void 0 : classStmt.buildSymbolTable(this.getParentClass(classStmt));
729
- }
730
- // also link interfaces
731
- const ifaceMap = this.getInterfaceMap();
732
- for (const pair of ifaceMap) {
733
- const ifaceStmt = (_b = pair[1]) === null || _b === void 0 ? void 0 : _b.item;
734
- ifaceStmt === null || ifaceStmt === void 0 ? void 0 : ifaceStmt.buildSymbolTable(this.getParentInterface(ifaceStmt));
735
- }
736
- //also link enums
737
- const enumMap = this.getEnumMap();
738
- for (const pair of enumMap) {
739
- const enumStmt = (_c = pair[1]) === null || _c === void 0 ? void 0 : _c.item;
740
- enumStmt === null || enumStmt === void 0 ? void 0 : enumStmt.buildSymbolTable();
770
+ else {
771
+ // Existing known namespace
772
+ }
773
+ if (!namespaceTypesKnown.has(nsName)) {
774
+ namespaceTypesKnown.set(nsName, currentNSType);
775
+ }
776
+ for (let nsStmt of nsContainer.namespaceStatements) {
777
+ this.linkSymbolTableDisposables.push(nsStmt === null || nsStmt === void 0 ? void 0 : nsStmt.getSymbolTable().addSibling(nsContainer.symbolTable));
778
+ }
779
+ this.linkSymbolTableDisposables.push(currentNSType.memberTable.addSibling(nsContainer.symbolTable));
741
780
  }
742
781
  }
743
782
  unlinkSymbolTable() {
744
- var _a;
745
- for (let file of this.getOwnFiles()) {
746
- if ((0, reflection_1.isBrsFile)(file)) {
747
- (_a = file.parser) === null || _a === void 0 ? void 0 : _a.symbolTable.setParent(null);
748
- for (const namespace of file.parser.references.namespaceStatements) {
749
- namespace.symbolTable.setParent(null);
750
- }
751
- }
783
+ for (const symbolToRemove of this.symbolsAddedDuringLinking) {
784
+ this.symbolTable.removeSymbol(symbolToRemove.name);
752
785
  }
786
+ this.symbolsAddedDuringLinking = [];
787
+ for (const dispose of this.linkSymbolTableDisposables) {
788
+ dispose();
789
+ }
790
+ this.linkSymbolTableDisposables = [];
753
791
  }
754
792
  detectVariableNamespaceCollisions(file) {
793
+ var _a, _b;
755
794
  //find all function parameters
756
- for (let func of file.parser.references.functionExpressions) {
795
+ for (let func of file['_cachedLookups'].functionExpressions) {
757
796
  for (let param of func.parameters) {
758
797
  let lowerParamName = param.name.text.toLowerCase();
759
- let namespace = this.namespaceLookup.get(lowerParamName);
798
+ let namespace = this.getNamespace(lowerParamName, (_a = param.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
760
799
  //see if the param matches any starting namespace part
761
800
  if (namespace) {
762
- this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.parameterMayNotHaveSameNameAsNamespace(param.name.text)), { range: param.name.range, relatedInformation: [{
801
+ this.diagnostics.push(Object.assign(Object.assign({ origin: interfaces_1.DiagnosticOrigin.Scope, file: file }, DiagnosticMessages_1.DiagnosticMessages.parameterMayNotHaveSameNameAsNamespace(param.name.text)), { range: param.name.range, relatedInformation: [{
763
802
  message: 'Namespace declared here',
764
- location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
803
+ location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
765
804
  }] }));
766
805
  }
767
806
  }
768
807
  }
769
- for (let assignment of file.parser.references.assignmentStatements) {
808
+ for (let assignment of file['_cachedLookups'].assignmentStatements) {
770
809
  let lowerAssignmentName = assignment.name.text.toLowerCase();
771
- let namespace = this.namespaceLookup.get(lowerAssignmentName);
810
+ let namespace = this.getNamespace(lowerAssignmentName, (_b = assignment.findAncestor(reflection_1.isNamespaceStatement)) === null || _b === void 0 ? void 0 : _b.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
772
811
  //see if the param matches any starting namespace part
773
812
  if (namespace) {
774
- this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.variableMayNotHaveSameNameAsNamespace(assignment.name.text)), { range: assignment.name.range, relatedInformation: [{
813
+ this.diagnostics.push(Object.assign(Object.assign({ origin: interfaces_1.DiagnosticOrigin.Scope, file: file }, DiagnosticMessages_1.DiagnosticMessages.variableMayNotHaveSameNameAsNamespace(assignment.name.text)), { range: assignment.name.range, relatedInformation: [{
775
814
  message: 'Namespace declared here',
776
- location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
815
+ location: util_1.util.createLocation(vscode_uri_1.URI.file(namespace.file.srcPath).toString(), namespace.nameRange)
777
816
  }] }));
778
817
  }
779
818
  }
@@ -788,132 +827,84 @@ class Scope {
788
827
  if (lowerFuncName) {
789
828
  //find function declarations with the same name as a stdlib function
790
829
  if (globalCallables_1.globalCallableMap.has(lowerFuncName)) {
791
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scopeFunctionShadowedByBuiltInFunction()), { range: func.nameRange, file: file }));
830
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scopeFunctionShadowedByBuiltInFunction()), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
792
831
  }
793
832
  //find any functions that have the same name as a class
794
- if (this.hasClass(lowerFuncName)) {
795
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionCannotHaveSameNameAsClass(funcName)), { range: func.nameRange, file: file }));
833
+ const klassLink = this.getClassFileLink(lowerFuncName);
834
+ if (klassLink) {
835
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionCannotHaveSameNameAsClass(funcName)), { range: func.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope, relatedInformation: [{
836
+ location: util_1.util.createLocation(vscode_uri_1.URI.file(klassLink.file.srcPath).toString(), klassLink.item.name.range),
837
+ message: 'Original class declared here'
838
+ }] }));
796
839
  }
797
840
  }
798
841
  }
799
842
  }
800
- /**
801
- * Find function parameters and function return types that are neither built-in types or known Class references
802
- */
803
- diagnosticDetectInvalidFunctionExpressionTypes(file) {
804
- var _a, _b, _c, _d;
805
- for (let func of file.parser.references.functionExpressions) {
806
- const returnType = (0, BscType_1.getTypeFromContext)(func.getReturnType(), { file: file, scope: this, position: (_a = func.range) === null || _a === void 0 ? void 0 : _a.start });
807
- if (!returnType && func.returnType) {
808
- // check if this custom type is in our class map
809
- const returnTypeName = func.returnType.getText();
810
- const currentNamespaceName = (_b = func.namespaceName) === null || _b === void 0 ? void 0 : _b.getName(Parser_1.ParseMode.BrighterScript);
811
- if (!this.hasClass(returnTypeName, currentNamespaceName) && !this.hasInterface(returnTypeName) && !this.hasEnum(returnTypeName)) {
812
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType(returnTypeName)), { range: func.returnType.range, file: file }));
813
- }
814
- }
815
- for (let param of func.parameters) {
816
- const typeContext = { file: file, scope: this, position: (_c = param.range) === null || _c === void 0 ? void 0 : _c.start };
817
- let paramType = (0, BscType_1.getTypeFromContext)(param.getType(), typeContext);
818
- while ((0, reflection_1.isArrayType)(paramType)) {
819
- paramType = (0, BscType_1.getTypeFromContext)(paramType.getDefaultType(typeContext), typeContext);
820
- }
821
- if (!paramType && param.type) {
822
- const paramTypeName = param.type.getText();
823
- const currentNamespaceName = (_d = func.namespaceName) === null || _d === void 0 ? void 0 : _d.getName(Parser_1.ParseMode.BrighterScript);
824
- if (!this.hasClass(paramTypeName, currentNamespaceName) && !this.hasInterface(paramTypeName) && !this.hasEnum(paramTypeName)) {
825
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(param.name.text, paramTypeName)), { range: param.type.range, file: file }));
826
- }
827
- }
843
+ detectNameCollisions(file) {
844
+ file.ast.walk((0, visitors_1.createVisitor)({
845
+ NamespaceStatement: (nsStmt) => {
846
+ var _a;
847
+ this.validateNameCollision(file, nsStmt, (_a = nsStmt.getNameParts()) === null || _a === void 0 ? void 0 : _a[0]);
848
+ },
849
+ ClassStatement: (classStmt) => {
850
+ this.validateNameCollision(file, classStmt, classStmt.name);
851
+ },
852
+ InterfaceStatement: (ifaceStmt) => {
853
+ this.validateNameCollision(file, ifaceStmt, ifaceStmt.tokens.name);
854
+ },
855
+ ConstStatement: (constStmt) => {
856
+ this.validateNameCollision(file, constStmt, constStmt.tokens.name);
857
+ },
858
+ EnumStatement: (enumStmt) => {
859
+ this.validateNameCollision(file, enumStmt, enumStmt.tokens.name);
828
860
  }
829
- }
861
+ }), {
862
+ walkMode: visitors_1.WalkMode.visitStatements
863
+ });
830
864
  }
831
- /**
832
- * Find functions with either the wrong type of parameters, or the wrong number of parameters
833
- */
834
- diagnosticDetectInvalidFunctionCalls(file, callableContainersByLowerName) {
835
- var _a, _b, _c, _d;
836
- if ((0, reflection_1.isBrsFile)(file)) {
837
- for (let expCall of file.functionCalls) {
838
- const symbolTypeInfo = file.getSymbolTypeFromToken(expCall.name, expCall.functionExpression, this);
839
- let funcType = symbolTypeInfo.type;
840
- if (!(0, reflection_1.isTypedFunctionType)(funcType) && !(0, reflection_1.isDynamicType)(funcType)) {
841
- // We don't know if this is a function. Try seeing if it is a global
842
- const callableContainer = util_1.util.getCallableContainerByFunctionCall(callableContainersByLowerName, expCall);
843
- if (callableContainer) {
844
- // We found a global callable with correct number of params - use that
845
- funcType = (_a = callableContainer.callable) === null || _a === void 0 ? void 0 : _a.type;
846
- }
847
- else {
848
- const allowedParamCount = util_1.util.getMinMaxParamCountByFunctionCall(callableContainersByLowerName, expCall);
849
- if (allowedParamCount) {
850
- // We found a global callable, but it needs a different number of args
851
- this.addMismatchParamCountDiagnostic(allowedParamCount, expCall, file);
852
- continue;
853
- }
854
- }
855
- }
856
- if ((0, reflection_1.isFunctionType)(funcType)) {
857
- // This is a generic function, and it is callable
858
- }
859
- else if ((0, reflection_1.isTypedFunctionType)(funcType)) {
860
- // Check for Argument count mismatch.
861
- //get min/max parameter count for callable
862
- let paramCount = util_1.util.getMinMaxParamCount(funcType.params);
863
- if (expCall.args.length > paramCount.max || expCall.args.length < paramCount.min) {
864
- this.addMismatchParamCountDiagnostic(paramCount, expCall, file);
865
- }
866
- // Check for Argument type mismatch.
867
- const paramTypeContext = { file: file, scope: this, position: (_b = expCall.functionExpression.range) === null || _b === void 0 ? void 0 : _b.start };
868
- const argTypeContext = { file: file, scope: this, position: (_c = expCall.range) === null || _c === void 0 ? void 0 : _c.start };
869
- for (let index = 0; index < funcType.params.length; index++) {
870
- const param = funcType.params[index];
871
- const arg = expCall.args[index];
872
- if (!arg) {
873
- // not enough args
874
- break;
875
- }
876
- let argType = (_d = arg.type) !== null && _d !== void 0 ? _d : new UninitializedType_1.UninitializedType();
877
- const paramType = (0, BscType_1.getTypeFromContext)(param.type, paramTypeContext);
878
- if (!paramType) {
879
- // other error - can not determine what type this parameter should be
880
- continue;
881
- }
882
- argType = (0, BscType_1.getTypeFromContext)(argType, argTypeContext);
883
- let assignable = argType === null || argType === void 0 ? void 0 : argType.isAssignableTo(paramType, argTypeContext);
884
- if (!assignable) {
885
- // TODO TYPES: perhaps this should be a strict mode setting?
886
- assignable = argType === null || argType === void 0 ? void 0 : argType.isConvertibleTo(paramType, argTypeContext);
887
- }
888
- if (!assignable) {
889
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch(argType === null || argType === void 0 ? void 0 : argType.toString(argTypeContext), paramType.toString(paramTypeContext))), { range: arg === null || arg === void 0 ? void 0 : arg.range, file: file }));
890
- }
891
- }
892
- }
893
- else if ((0, reflection_1.isInvalidType)(symbolTypeInfo.type)) {
894
- // TODO TYPES: standard member functions like integer.ToStr() are not detectable yet.
895
- }
896
- else if ((0, reflection_1.isDynamicType)(symbolTypeInfo.type)) {
897
- // maybe this is a function? who knows
865
+ validateNameCollision(file, node, nameIdentifier) {
866
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
867
+ const name = nameIdentifier === null || nameIdentifier === void 0 ? void 0 : nameIdentifier.text;
868
+ if (!name || !node) {
869
+ return;
870
+ }
871
+ const nameRange = nameIdentifier.range;
872
+ const containingNamespace = (_a = node.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript);
873
+ const links = this.getAllFileLinks(name, containingNamespace);
874
+ for (let link of links) {
875
+ if (!link || link.item === node) {
876
+ // refers to same node
877
+ continue;
878
+ }
879
+ if ((0, reflection_1.isNamespaceStatement)(link.item) && (0, reflection_1.isNamespaceStatement)(node)) {
880
+ // namespace can be declared multiple times
881
+ continue;
882
+ }
883
+ const thisNodeKindName = util_1.util.getAstNodeFriendlyName(node);
884
+ const thatNodeKindName = link.file.srcPath === 'global' ? 'Global Function' : (_b = util_1.util.getAstNodeFriendlyName(link.item)) !== null && _b !== void 0 ? _b : '';
885
+ let thatNameRange = (_f = (_e = (_d = (_c = link.item) === null || _c === void 0 ? void 0 : _c.tokens) === null || _d === void 0 ? void 0 : _d.name) === null || _e === void 0 ? void 0 : _e.range) !== null && _f !== void 0 ? _f : (_g = link.item) === null || _g === void 0 ? void 0 : _g.range;
886
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
887
+ switch ((_h = link.item) === null || _h === void 0 ? void 0 : _h.kind) {
888
+ case AstNode_1.AstNodeKind.ClassStatement: {
889
+ thatNameRange = (_j = link.item.name) === null || _j === void 0 ? void 0 : _j.range;
890
+ break;
898
891
  }
899
- else {
900
- const functionNameText = symbolTypeInfo.expandedTokenText;
901
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callToUnknownFunction(functionNameText, this.name)), { range: expCall.nameRange,
902
- //TODO detect end of expression call
903
- file: file }));
892
+ case AstNode_1.AstNodeKind.NamespaceStatement: {
893
+ thatNameRange = (_l = (_k = link.item.getNameParts()) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.range;
894
+ break;
904
895
  }
905
896
  }
897
+ const relatedInformation = thatNameRange ? [{
898
+ message: `${thatNodeKindName} declared here`,
899
+ location: util_1.util.createLocation(vscode_uri_1.URI.file((_m = link.file) === null || _m === void 0 ? void 0 : _m.srcPath).toString(), thatNameRange)
900
+ }] : undefined;
901
+ this.diagnostics.push(Object.assign(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.nameCollision(thisNodeKindName, thatNodeKindName, name)), { origin: interfaces_1.DiagnosticOrigin.Scope, range: nameRange, relatedInformation: relatedInformation }));
906
902
  }
907
903
  }
908
- addMismatchParamCountDiagnostic(paramCount, expCall, file) {
909
- const minMaxParamsText = paramCount.min === paramCount.max ? paramCount.max : `${paramCount.min}-${paramCount.max}`;
910
- const expCallArgCount = expCall.args.length;
911
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(minMaxParamsText, expCallArgCount)), { range: expCall.nameRange, file: file }));
912
- }
913
904
  getNewExpressions() {
914
905
  let result = [];
915
906
  this.enumerateBrsFiles((file) => {
916
- let expressions = file.parser.references.newExpressions;
907
+ let expressions = file['_cachedLookups'].newExpressions;
917
908
  for (let expression of expressions) {
918
909
  expression.file = file;
919
910
  result.push(expression);
@@ -921,57 +912,54 @@ class Scope {
921
912
  });
922
913
  return result;
923
914
  }
924
- validateClasses(file) {
925
- let validator = new ClassValidator_1.BsClassValidator();
926
- validator.validate(this, file);
927
- this.diagnostics.push(...validator.diagnostics);
915
+ validateClasses() {
916
+ let validator = new ClassValidator_1.BsClassValidator(this);
917
+ validator.validate();
918
+ this.diagnostics.push(...validator.diagnostics.map(diag => {
919
+ return Object.assign(Object.assign({}, diag), { origin: interfaces_1.DiagnosticOrigin.Scope });
920
+ }));
928
921
  }
929
922
  /**
930
- * Detect local variables (vars declared within a function expression) that have the same name as scope calls
931
- * @param file
932
- * @param callableContainerMap
923
+ * Detect local variables (function scope) that have the same name as scope calls
933
924
  */
934
925
  diagnosticDetectShadowedLocalVars(file, callableContainerMap) {
926
+ var _a;
935
927
  const classMap = this.getClassMap();
936
- for (let func of file.parser.references.functionExpressions) {
937
- //every var declaration in this function expression
938
- for (let symbol of func.symbolTable.getOwnSymbols()) {
939
- const symbolNameLower = symbol.name.toLowerCase();
940
- //if the var is a function
941
- if ((0, reflection_1.isTypedFunctionType)(symbol.type)) {
928
+ //loop through every function scope
929
+ for (let funcScope of file.functionScopes) {
930
+ //every var declaration in this function scope
931
+ for (let varDeclaration of funcScope.variableDeclarations) {
932
+ const varName = varDeclaration.name;
933
+ const lowerVarName = varName.toLowerCase();
934
+ const varIsFunction = () => {
935
+ return (0, reflection_1.isCallableType)(varDeclaration.getType());
936
+ };
937
+ if (
938
+ //has same name as stdlib
939
+ globalCallables_1.globalCallableMap.has(lowerVarName)) {
942
940
  //local var function with same name as stdlib function
943
- if (
944
- //has same name as stdlib
945
- globalCallables_1.globalCallableMap.has(symbolNameLower)) {
946
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib')), { range: symbol.range, file: file }));
947
- //this check needs to come after the stdlib one, because the stdlib functions are included
948
- //in the scope function list
949
- }
950
- else if (
951
- //has same name as scope function
952
- callableContainerMap.has(symbolNameLower)) {
953
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('scope')), { range: symbol.range, file: file }));
941
+ if (varIsFunction()) {
942
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('stdlib')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
954
943
  }
955
- //var is not a function
956
944
  }
957
- else if (
958
- //is NOT a callable from stdlib (because non-function local vars can have same name as stdlib names)
959
- !globalCallables_1.globalCallableMap.has(symbolNameLower)) {
945
+ else if (callableContainerMap.has(lowerVarName)) {
960
946
  //is same name as a callable
961
- if (callableContainerMap.has(symbolNameLower)) {
962
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarShadowedByScopedFunction()), { range: symbol.range, file: file }));
963
- //has the same name as an in-scope class
947
+ if (varIsFunction()) {
948
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarFunctionShadowsParentFunction('scope')), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
964
949
  }
965
- else if (classMap.has(symbolNameLower)) {
966
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarSameNameAsClass(classMap.get(symbolNameLower).item.getName(Parser_1.ParseMode.BrighterScript))), { range: symbol.range, file: file }));
950
+ else {
951
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarShadowedByScopedFunction()), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
967
952
  }
953
+ //has the same name as an in-scope class
954
+ }
955
+ else if (classMap.has(lowerVarName)) {
956
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.localVarSameNameAsClass((_a = classMap.get(lowerVarName)) === null || _a === void 0 ? void 0 : _a.item.getName(Parser_1.ParseMode.BrighterScript))), { range: varDeclaration.nameRange, file: file, origin: interfaces_1.DiagnosticOrigin.Scope }));
968
957
  }
969
958
  }
970
959
  }
971
960
  }
972
961
  /**
973
962
  * Create diagnostics for any duplicate function declarations
974
- * @param callablesByLowerName
975
963
  */
976
964
  diagnosticFindDuplicateFunctionDeclarations(callableContainersByLowerName) {
977
965
  //for each list of callables with the same name
@@ -1004,9 +992,9 @@ class Scope {
1004
992
  //same file: skip redundant imports
1005
993
  continue;
1006
994
  }
1007
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.overridesAncestorFunction(container.callable.name, container.scope.name, shadowedCallable.callable.file.pkgPath,
995
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.overridesAncestorFunction(container.callable.name, container.scope.name, shadowedCallable.callable.file.destPath,
1008
996
  //grab the last item in the list, which should be the closest ancestor's version
1009
- shadowedCallable.scope.name)), { range: container.callable.nameRange, file: container.callable.file }));
997
+ shadowedCallable.scope.name)), { range: container.callable.nameRange, file: container.callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
1010
998
  }
1011
999
  }
1012
1000
  }
@@ -1014,7 +1002,7 @@ class Scope {
1014
1002
  if (ownCallables.length > 1) {
1015
1003
  for (let callableContainer of ownCallables) {
1016
1004
  let callable = callableContainer.callable;
1017
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateFunctionImplementation(callable.name, callableContainer.scope.name)), { range: util_1.util.createRange(callable.nameRange.start.line, callable.nameRange.start.character, callable.nameRange.start.line, callable.nameRange.end.character), file: callable.file }));
1005
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateFunctionImplementation(callable.name, callableContainer.scope.name)), { range: util_1.util.createRange(callable.nameRange.start.line, callable.nameRange.start.character, callable.nameRange.start.line, callable.nameRange.end.character), file: callable.file, origin: interfaces_1.DiagnosticOrigin.Scope }));
1018
1006
  }
1019
1007
  }
1020
1008
  }
@@ -1041,11 +1029,11 @@ class Scope {
1041
1029
  let scriptImports = this.getOwnScriptImports();
1042
1030
  //verify every script import
1043
1031
  for (let scriptImport of scriptImports) {
1044
- let referencedFile = this.getFileByRelativePath(scriptImport.pkgPath);
1032
+ let referencedFile = this.getFileByRelativePath(scriptImport.destPath);
1045
1033
  //if we can't find the file
1046
1034
  if (!referencedFile) {
1047
1035
  //skip the default bslib file, it will exist at transpile time but should not show up in the program during validation cycle
1048
- if (scriptImport.pkgPath === `pkg:/source/bslib.brs`) {
1036
+ if (scriptImport.destPath === this.program.bslibPkgPath) {
1049
1037
  continue;
1050
1038
  }
1051
1039
  let dInfo;
@@ -1055,17 +1043,16 @@ class Scope {
1055
1043
  else {
1056
1044
  dInfo = DiagnosticMessages_1.DiagnosticMessages.referencedFileDoesNotExist();
1057
1045
  }
1058
- this.diagnostics.push(Object.assign(Object.assign({}, dInfo), { range: scriptImport.filePathRange, file: scriptImport.sourceFile }));
1046
+ this.diagnostics.push(Object.assign(Object.assign({}, dInfo), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
1059
1047
  //if the character casing of the script import path does not match that of the actual path
1060
1048
  }
1061
- else if (scriptImport.pkgPath !== referencedFile.pkgPath) {
1062
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scriptImportCaseMismatch(referencedFile.pkgPath)), { range: scriptImport.filePathRange, file: scriptImport.sourceFile }));
1049
+ else if (scriptImport.destPath !== referencedFile.destPath) {
1050
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.scriptImportCaseMismatch(referencedFile.destPath)), { range: scriptImport.filePathRange, file: scriptImport.sourceFile, origin: interfaces_1.DiagnosticOrigin.Scope }));
1063
1051
  }
1064
1052
  }
1065
1053
  }
1066
1054
  /**
1067
1055
  * Find the file with the specified relative path
1068
- * @param relativePath
1069
1056
  */
1070
1057
  getFileByRelativePath(relativePath) {
1071
1058
  if (!relativePath) {
@@ -1073,49 +1060,19 @@ class Scope {
1073
1060
  }
1074
1061
  let files = this.getAllFiles();
1075
1062
  for (let file of files) {
1076
- if (file.pkgPath.toLowerCase() === relativePath.toLowerCase()) {
1063
+ if (file.destPath.toLowerCase() === relativePath.toLowerCase()) {
1077
1064
  return file;
1078
1065
  }
1079
1066
  }
1080
1067
  }
1081
1068
  /**
1082
1069
  * Determine if this file is included in this scope (excluding parent scopes)
1083
- * @param file
1084
1070
  */
1085
1071
  hasFile(file) {
1086
1072
  let files = this.getOwnFiles();
1087
1073
  let hasFile = files.includes(file);
1088
1074
  return hasFile;
1089
1075
  }
1090
- /**
1091
- * Get all callables as completionItems
1092
- */
1093
- getCallablesAsCompletions(parseMode) {
1094
- let completions = [];
1095
- let callables = this.getAllCallables();
1096
- if (parseMode === Parser_1.ParseMode.BrighterScript) {
1097
- //throw out the namespaced callables (they will be handled by another method)
1098
- callables = callables.filter(x => x.callable.hasNamespace === false);
1099
- }
1100
- for (let callableContainer of callables) {
1101
- completions.push(this.createCompletionFromCallable(callableContainer));
1102
- }
1103
- return completions;
1104
- }
1105
- createCompletionFromCallable(callableContainer) {
1106
- return {
1107
- label: callableContainer.callable.getName(Parser_1.ParseMode.BrighterScript),
1108
- kind: vscode_languageserver_1.CompletionItemKind.Function,
1109
- detail: callableContainer.callable.shortDescription,
1110
- documentation: callableContainer.callable.documentation ? { kind: 'markdown', value: callableContainer.callable.documentation } : undefined
1111
- };
1112
- }
1113
- createCompletionFromFunctionStatement(statement) {
1114
- return {
1115
- label: statement.getName(Parser_1.ParseMode.BrighterScript),
1116
- kind: vscode_languageserver_1.CompletionItemKind.Function
1117
- };
1118
- }
1119
1076
  /**
1120
1077
  * Get the definition (where was this thing first defined) of the symbol under the position
1121
1078
  */
@@ -1123,41 +1080,10 @@ class Scope {
1123
1080
  // Overridden in XMLScope. Brs files use implementation in BrsFile
1124
1081
  return [];
1125
1082
  }
1126
- /**
1127
- * Scan all files for property names, and return them as completions
1128
- */
1129
- getPropertyNameCompletions() {
1130
- let results = [];
1131
- this.enumerateBrsFiles((file) => {
1132
- results.push(...file.propertyNameCompletions);
1133
- });
1134
- return results;
1135
- }
1136
- getAllClassMemberCompletions() {
1137
- let results = new Map();
1138
- let filesSearched = new Set();
1139
- for (const file of this.getAllFiles()) {
1140
- if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
1141
- continue;
1142
- }
1143
- filesSearched.add(file);
1144
- for (let cs of file.parser.references.classStatements) {
1145
- for (let s of [...cs.methods, ...cs.fields]) {
1146
- if (!results.has(s.name.text) && s.name.text.toLowerCase() !== 'new') {
1147
- results.set(s.name.text, {
1148
- label: s.name.text,
1149
- kind: (0, reflection_1.isMethodStatement)(s) ? vscode_languageserver_1.CompletionItemKind.Method : vscode_languageserver_1.CompletionItemKind.Field
1150
- });
1151
- }
1152
- }
1153
- }
1154
- }
1155
- return results;
1156
- }
1157
1083
  /**
1158
1084
  * @param className - The name of the class (including namespace if possible)
1159
1085
  * @param callsiteNamespace - the name of the namespace where the call site resides (this is NOT the known namespace of the class).
1160
- * This is used to help resolve non-namespaced class names that reside in the same namespace as the call site.
1086
+ * This is used to help resolve non-namespaced class names that reside in the same namespac as the call site.
1161
1087
  */
1162
1088
  getClassHierarchy(className, callsiteNamespace) {
1163
1089
  var _a, _b;
@@ -1165,7 +1091,7 @@ class Scope {
1165
1091
  let link = this.getClassFileLink(className, callsiteNamespace);
1166
1092
  while (link) {
1167
1093
  items.push(link);
1168
- link = this.getClassFileLink((_b = (_a = link.item.parentClassName) === null || _a === void 0 ? void 0 : _a.getName(Parser_1.ParseMode.BrighterScript)) === null || _b === void 0 ? void 0 : _b.toLowerCase(), callsiteNamespace);
1094
+ link = this.getClassFileLink((_b = (_a = link.item.parentClassName) === null || _a === void 0 ? void 0 : _a.getName()) === null || _b === void 0 ? void 0 : _b.toLowerCase(), callsiteNamespace);
1169
1095
  }
1170
1096
  return items;
1171
1097
  }