brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.26

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 +521 -233
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +46 -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 +40 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +61 -13
  33. package/dist/DiagnosticMessages.js +116 -19
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +150 -69
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +158 -79
  54. package/dist/Program.js +841 -706
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +130 -103
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +86 -137
  60. package/dist/Scope.js +453 -519
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +89 -34
  65. package/dist/SymbolTable.js +239 -114
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -11
  74. package/dist/XmlScope.js +75 -88
  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} +69 -65
  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 +54 -24
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -104
  90. package/dist/astUtils/reflection.js +220 -174
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +256 -157
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +53 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +208 -52
  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 +11 -2
  105. package/dist/bscPlugin/BscPlugin.js +37 -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 +136 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +16 -13
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  120. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  123. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  125. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  126. package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
  127. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  128. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
  129. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  130. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  131. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  132. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  134. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  135. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  136. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  137. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  139. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +83 -23
  140. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  141. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  142. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  143. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  144. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  145. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  146. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  147. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  148. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  149. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  150. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  151. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  152. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  153. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +38 -12
  154. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  156. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  157. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  158. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  159. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  160. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  162. package/dist/bscPlugin/validation/BrsFileValidator.js +262 -52
  163. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  164. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  165. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  166. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  167. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  168. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  169. package/dist/bscPlugin/validation/ScopeValidator.d.ts +58 -27
  170. package/dist/bscPlugin/validation/ScopeValidator.js +514 -286
  171. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  172. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  173. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2527 -0
  174. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  175. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  176. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  177. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  178. package/dist/cli.js +104 -13
  179. package/dist/cli.js.map +1 -1
  180. package/dist/deferred.d.ts +3 -3
  181. package/dist/deferred.js.map +1 -1
  182. package/dist/diagnosticUtils.d.ts +8 -2
  183. package/dist/diagnosticUtils.js +47 -17
  184. package/dist/diagnosticUtils.js.map +1 -1
  185. package/dist/examples/plugins/removePrint.js +8 -10
  186. package/dist/examples/plugins/removePrint.js.map +1 -1
  187. package/dist/files/AssetFile.d.ts +26 -0
  188. package/dist/files/AssetFile.js +26 -0
  189. package/dist/files/AssetFile.js.map +1 -0
  190. package/dist/files/BrsFile.Class.spec.js +523 -493
  191. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  192. package/dist/files/BrsFile.d.ts +111 -117
  193. package/dist/files/BrsFile.js +684 -1142
  194. package/dist/files/BrsFile.js.map +1 -1
  195. package/dist/files/BrsFile.spec.js +1783 -1233
  196. package/dist/files/BrsFile.spec.js.map +1 -1
  197. package/dist/files/BscFile.d.ts +104 -0
  198. package/dist/files/BscFile.js +16 -0
  199. package/dist/files/BscFile.js.map +1 -0
  200. package/dist/files/Factory.d.ts +25 -0
  201. package/dist/files/Factory.js +22 -0
  202. package/dist/files/Factory.js.map +1 -0
  203. package/dist/files/LazyFileData.d.ts +20 -0
  204. package/dist/files/LazyFileData.js +54 -0
  205. package/dist/files/LazyFileData.js.map +1 -0
  206. package/dist/files/LazyFileData.spec.d.ts +1 -0
  207. package/dist/files/LazyFileData.spec.js +27 -0
  208. package/dist/files/LazyFileData.spec.js.map +1 -0
  209. package/dist/files/XmlFile.d.ts +70 -32
  210. package/dist/files/XmlFile.js +106 -118
  211. package/dist/files/XmlFile.js.map +1 -1
  212. package/dist/files/XmlFile.spec.js +325 -262
  213. package/dist/files/XmlFile.spec.js.map +1 -1
  214. package/dist/files/tests/imports.spec.js +48 -40
  215. package/dist/files/tests/imports.spec.js.map +1 -1
  216. package/dist/files/tests/optionalChaning.spec.js +84 -24
  217. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  218. package/dist/globalCallables.js +16 -21
  219. package/dist/globalCallables.js.map +1 -1
  220. package/dist/index.d.ts +12 -1
  221. package/dist/index.js +12 -1
  222. package/dist/index.js.map +1 -1
  223. package/dist/interfaces.d.ts +421 -162
  224. package/dist/interfaces.js +27 -0
  225. package/dist/interfaces.js.map +1 -1
  226. package/dist/lexer/Character.spec.js +5 -5
  227. package/dist/lexer/Character.spec.js.map +1 -1
  228. package/dist/lexer/Lexer.d.ts +12 -5
  229. package/dist/lexer/Lexer.js +28 -13
  230. package/dist/lexer/Lexer.js.map +1 -1
  231. package/dist/lexer/Lexer.spec.js +181 -135
  232. package/dist/lexer/Lexer.spec.js.map +1 -1
  233. package/dist/lexer/Token.d.ts +9 -1
  234. package/dist/lexer/Token.js +9 -1
  235. package/dist/lexer/Token.js.map +1 -1
  236. package/dist/lexer/TokenKind.d.ts +8 -0
  237. package/dist/lexer/TokenKind.js +24 -4
  238. package/dist/lexer/TokenKind.js.map +1 -1
  239. package/dist/parser/AstNode.d.ts +162 -0
  240. package/dist/parser/AstNode.js +225 -0
  241. package/dist/parser/AstNode.js.map +1 -0
  242. package/dist/parser/AstNode.spec.d.ts +1 -0
  243. package/dist/parser/AstNode.spec.js +165 -0
  244. package/dist/parser/AstNode.spec.js.map +1 -0
  245. package/dist/parser/BrsTranspileState.d.ts +4 -7
  246. package/dist/parser/BrsTranspileState.js +4 -12
  247. package/dist/parser/BrsTranspileState.js.map +1 -1
  248. package/dist/parser/Expression.d.ts +376 -283
  249. package/dist/parser/Expression.js +742 -585
  250. package/dist/parser/Expression.js.map +1 -1
  251. package/dist/parser/Parser.Class.spec.js +151 -145
  252. package/dist/parser/Parser.Class.spec.js.map +1 -1
  253. package/dist/parser/Parser.d.ts +48 -201
  254. package/dist/parser/Parser.js +705 -1026
  255. package/dist/parser/Parser.js.map +1 -1
  256. package/dist/parser/Parser.spec.d.ts +3 -1
  257. package/dist/parser/Parser.spec.js +861 -848
  258. package/dist/parser/Parser.spec.js.map +1 -1
  259. package/dist/parser/SGParser.d.ts +9 -8
  260. package/dist/parser/SGParser.js +10 -8
  261. package/dist/parser/SGParser.js.map +1 -1
  262. package/dist/parser/SGParser.spec.js +27 -38
  263. package/dist/parser/SGParser.spec.js.map +1 -1
  264. package/dist/parser/SGTypes.d.ts +98 -35
  265. package/dist/parser/SGTypes.js +169 -99
  266. package/dist/parser/SGTypes.js.map +1 -1
  267. package/dist/parser/Statement.d.ts +468 -272
  268. package/dist/parser/Statement.js +904 -631
  269. package/dist/parser/Statement.js.map +1 -1
  270. package/dist/parser/Statement.spec.js +47 -23
  271. package/dist/parser/Statement.spec.js.map +1 -1
  272. package/dist/parser/TranspileState.d.ts +1 -1
  273. package/dist/parser/TranspileState.js +7 -12
  274. package/dist/parser/TranspileState.js.map +1 -1
  275. package/dist/parser/tests/Parser.spec.js +3 -2
  276. package/dist/parser/tests/Parser.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  278. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  279. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  280. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  281. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  282. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  283. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  284. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  286. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  288. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +62 -21
  290. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  292. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Call.spec.js +129 -21
  294. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  296. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/Function.spec.js +36 -36
  298. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/Indexing.spec.js +92 -22
  300. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  302. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  304. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  306. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  308. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  310. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  312. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  314. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  315. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  316. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  317. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  318. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  319. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  321. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  323. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  324. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  325. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  326. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  327. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  328. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  329. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  330. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  331. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  332. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  333. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  335. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  337. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/For.spec.js +9 -10
  339. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  341. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Function.spec.js +44 -35
  343. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  345. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  347. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  349. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  351. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  353. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/PrintStatement.spec.js +36 -34
  355. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  357. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Set.spec.js +48 -35
  359. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  361. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  363. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  364. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  365. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  366. package/dist/preprocessor/Manifest.d.ts +1 -1
  367. package/dist/preprocessor/Manifest.js +2 -2
  368. package/dist/preprocessor/Manifest.js.map +1 -1
  369. package/dist/preprocessor/Manifest.spec.js +8 -8
  370. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  371. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  372. package/dist/preprocessor/Preprocessor.js +5 -5
  373. package/dist/preprocessor/Preprocessor.js.map +1 -1
  374. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  375. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  376. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  377. package/dist/preprocessor/PreprocessorParser.js +7 -1
  378. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  379. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  380. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  381. package/dist/roku-types/data.json +5892 -10081
  382. package/dist/roku-types/index.d.ts +622 -1719
  383. package/dist/types/ArrayType.d.ts +10 -9
  384. package/dist/types/ArrayType.js +65 -60
  385. package/dist/types/ArrayType.js.map +1 -1
  386. package/dist/types/ArrayType.spec.js +36 -68
  387. package/dist/types/ArrayType.spec.js.map +1 -1
  388. package/dist/types/AssociativeArrayType.d.ts +11 -0
  389. package/dist/types/AssociativeArrayType.js +52 -0
  390. package/dist/types/AssociativeArrayType.js.map +1 -0
  391. package/dist/types/BaseFunctionType.d.ts +9 -0
  392. package/dist/types/BaseFunctionType.js +25 -0
  393. package/dist/types/BaseFunctionType.js.map +1 -0
  394. package/dist/types/BooleanType.d.ts +8 -5
  395. package/dist/types/BooleanType.js +14 -7
  396. package/dist/types/BooleanType.js.map +1 -1
  397. package/dist/types/BooleanType.spec.js +10 -6
  398. package/dist/types/BooleanType.spec.js.map +1 -1
  399. package/dist/types/BscType.d.ts +32 -21
  400. package/dist/types/BscType.js +118 -21
  401. package/dist/types/BscType.js.map +1 -1
  402. package/dist/types/BscTypeKind.d.ts +25 -0
  403. package/dist/types/BscTypeKind.js +30 -0
  404. package/dist/types/BscTypeKind.js.map +1 -0
  405. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  406. package/dist/types/BuiltInInterfaceAdder.js +171 -0
  407. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  409. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  410. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  411. package/dist/types/ClassType.d.ts +17 -0
  412. package/dist/types/ClassType.js +58 -0
  413. package/dist/types/ClassType.js.map +1 -0
  414. package/dist/types/ClassType.spec.d.ts +1 -0
  415. package/dist/types/ClassType.spec.js +77 -0
  416. package/dist/types/ClassType.spec.js.map +1 -0
  417. package/dist/types/ComponentType.d.ts +26 -0
  418. package/dist/types/ComponentType.js +83 -0
  419. package/dist/types/ComponentType.js.map +1 -0
  420. package/dist/types/DoubleType.d.ts +8 -5
  421. package/dist/types/DoubleType.js +18 -16
  422. package/dist/types/DoubleType.js.map +1 -1
  423. package/dist/types/DoubleType.spec.js +12 -6
  424. package/dist/types/DoubleType.spec.js.map +1 -1
  425. package/dist/types/DynamicType.d.ts +9 -5
  426. package/dist/types/DynamicType.js +15 -4
  427. package/dist/types/DynamicType.js.map +1 -1
  428. package/dist/types/DynamicType.spec.js +16 -5
  429. package/dist/types/DynamicType.spec.js.map +1 -1
  430. package/dist/types/EnumType.d.ts +30 -12
  431. package/dist/types/EnumType.js +43 -17
  432. package/dist/types/EnumType.js.map +1 -1
  433. package/dist/types/EnumType.spec.d.ts +1 -0
  434. package/dist/types/EnumType.spec.js +33 -0
  435. package/dist/types/EnumType.spec.js.map +1 -0
  436. package/dist/types/FloatType.d.ts +8 -5
  437. package/dist/types/FloatType.js +18 -16
  438. package/dist/types/FloatType.js.map +1 -1
  439. package/dist/types/FloatType.spec.js +4 -6
  440. package/dist/types/FloatType.spec.js.map +1 -1
  441. package/dist/types/FunctionType.d.ts +13 -8
  442. package/dist/types/FunctionType.js +30 -14
  443. package/dist/types/FunctionType.js.map +1 -1
  444. package/dist/types/InheritableType.d.ts +28 -0
  445. package/dist/types/InheritableType.js +152 -0
  446. package/dist/types/InheritableType.js.map +1 -0
  447. package/dist/types/IntegerType.d.ts +8 -5
  448. package/dist/types/IntegerType.js +18 -16
  449. package/dist/types/IntegerType.js.map +1 -1
  450. package/dist/types/IntegerType.spec.js +8 -6
  451. package/dist/types/IntegerType.spec.js.map +1 -1
  452. package/dist/types/InterfaceType.d.ts +12 -13
  453. package/dist/types/InterfaceType.js +20 -48
  454. package/dist/types/InterfaceType.js.map +1 -1
  455. package/dist/types/InterfaceType.spec.js +90 -56
  456. package/dist/types/InterfaceType.spec.js.map +1 -1
  457. package/dist/types/InvalidType.d.ts +7 -5
  458. package/dist/types/InvalidType.js +13 -7
  459. package/dist/types/InvalidType.js.map +1 -1
  460. package/dist/types/InvalidType.spec.js +8 -6
  461. package/dist/types/InvalidType.spec.js.map +1 -1
  462. package/dist/types/LongIntegerType.d.ts +8 -5
  463. package/dist/types/LongIntegerType.js +17 -15
  464. package/dist/types/LongIntegerType.js.map +1 -1
  465. package/dist/types/LongIntegerType.spec.js +10 -6
  466. package/dist/types/LongIntegerType.spec.js.map +1 -1
  467. package/dist/types/NamespaceType.d.ts +12 -0
  468. package/dist/types/NamespaceType.js +28 -0
  469. package/dist/types/NamespaceType.js.map +1 -0
  470. package/dist/types/ObjectType.d.ts +9 -8
  471. package/dist/types/ObjectType.js +21 -11
  472. package/dist/types/ObjectType.js.map +1 -1
  473. package/dist/types/ObjectType.spec.js +3 -3
  474. package/dist/types/ObjectType.spec.js.map +1 -1
  475. package/dist/types/ReferenceType.d.ts +63 -0
  476. package/dist/types/ReferenceType.js +423 -0
  477. package/dist/types/ReferenceType.js.map +1 -0
  478. package/dist/types/ReferenceType.spec.d.ts +1 -0
  479. package/dist/types/ReferenceType.spec.js +137 -0
  480. package/dist/types/ReferenceType.spec.js.map +1 -0
  481. package/dist/types/StringType.d.ts +11 -5
  482. package/dist/types/StringType.js +18 -7
  483. package/dist/types/StringType.js.map +1 -1
  484. package/dist/types/StringType.spec.js +3 -5
  485. package/dist/types/StringType.spec.js.map +1 -1
  486. package/dist/types/TypedFunctionType.d.ts +22 -17
  487. package/dist/types/TypedFunctionType.js +78 -60
  488. package/dist/types/TypedFunctionType.js.map +1 -1
  489. package/dist/types/TypedFunctionType.spec.js +105 -20
  490. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  491. package/dist/types/UninitializedType.d.ts +8 -6
  492. package/dist/types/UninitializedType.js +13 -7
  493. package/dist/types/UninitializedType.js.map +1 -1
  494. package/dist/types/UnionType.d.ts +20 -0
  495. package/dist/types/UnionType.js +123 -0
  496. package/dist/types/UnionType.js.map +1 -0
  497. package/dist/types/UnionType.spec.d.ts +1 -0
  498. package/dist/types/UnionType.spec.js +130 -0
  499. package/dist/types/UnionType.spec.js.map +1 -0
  500. package/dist/types/VoidType.d.ts +8 -5
  501. package/dist/types/VoidType.js +14 -7
  502. package/dist/types/VoidType.js.map +1 -1
  503. package/dist/types/VoidType.spec.js +3 -3
  504. package/dist/types/VoidType.spec.js.map +1 -1
  505. package/dist/types/helper.spec.d.ts +1 -0
  506. package/dist/types/helper.spec.js +145 -0
  507. package/dist/types/helper.spec.js.map +1 -0
  508. package/dist/types/helpers.d.ts +19 -37
  509. package/dist/types/helpers.js +159 -99
  510. package/dist/types/helpers.js.map +1 -1
  511. package/dist/types/index.d.ts +22 -0
  512. package/dist/types/index.js +39 -0
  513. package/dist/types/index.js.map +1 -0
  514. package/dist/util.d.ts +143 -139
  515. package/dist/util.js +864 -385
  516. package/dist/util.js.map +1 -1
  517. package/dist/validators/ClassValidator.d.ts +8 -25
  518. package/dist/validators/ClassValidator.js +99 -179
  519. package/dist/validators/ClassValidator.js.map +1 -1
  520. package/package.json +165 -152
  521. package/dist/astUtils/AstEditor.js.map +0 -1
  522. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  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/definition/DefinitionProvider.spec.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBscTypeFromExpression = exports.TokenUsage = exports.References = exports.ParseMode = exports.Parser = void 0;
3
+ exports.ParseMode = exports.Parser = void 0;
4
4
  const Token_1 = require("../lexer/Token");
5
5
  const Lexer_1 = require("../lexer/Lexer");
6
6
  const TokenKind_1 = require("../lexer/TokenKind");
@@ -10,14 +10,8 @@ const util_1 = require("../util");
10
10
  const Expression_1 = require("./Expression");
11
11
  const Logger_1 = require("../Logger");
12
12
  const reflection_1 = require("../astUtils/reflection");
13
- const visitors_1 = require("../astUtils/visitors");
14
13
  const creators_1 = require("../astUtils/creators");
15
- const Cache_1 = require("../Cache");
16
14
  const SymbolTable_1 = require("../SymbolTable");
17
- const DynamicType_1 = require("../types/DynamicType");
18
- const ArrayType_1 = require("../types/ArrayType");
19
- const helpers_1 = require("../types/helpers");
20
- const ObjectType_1 = require("../types/ObjectType");
21
15
  class Parser {
22
16
  constructor() {
23
17
  /**
@@ -27,12 +21,7 @@ class Parser {
27
21
  /**
28
22
  * The list of statements for the parsed file
29
23
  */
30
- this.ast = new Statement_1.Body([]);
31
- /**
32
- * The top-level symbol table for this file. Things like top-level namespaces, non-namespaced classes, enums, interfaces, and functions beling here.
33
- */
34
- this.symbolTable = new SymbolTable_1.SymbolTable(undefined, `File Parser`);
35
- this._references = new References();
24
+ this.ast = new Statement_1.Body({ statements: [] });
36
25
  this.globalTerminators = [];
37
26
  /**
38
27
  * An array of CallExpression for the current function body
@@ -42,48 +31,11 @@ class Parser {
42
31
  get statements() {
43
32
  return this.ast.statements;
44
33
  }
45
- get currentSymbolTable() {
46
- var _a, _b, _c, _d;
47
- return (_d = (_b = (_a = this.currentFunctionExpression) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : (_c = this.currentNamespace) === null || _c === void 0 ? void 0 : _c.symbolTable) !== null && _d !== void 0 ? _d : this.symbolTable;
48
- }
49
- /**
50
- * References for significant statements/expressions in the parser.
51
- * These are initially extracted during parse-time to improve performance, but will also be dynamically regenerated if need be.
52
- *
53
- * If a plugin modifies the AST, then the plugin should call Parser#invalidateReferences() to force this object to refresh
54
- */
55
- get references() {
56
- //build the references object if it's missing.
57
- if (!this._references) {
58
- this.findReferences();
59
- }
60
- return this._references;
61
- }
62
34
  /**
63
- * Invalidates (clears) the references collection. This should be called anytime the AST has been manipulated.
35
+ * The top-level symbol table for the body of this file.
64
36
  */
65
- invalidateReferences() {
66
- this._references = undefined;
67
- }
68
- addPropertyHints(item) {
69
- if ((0, Token_1.isToken)(item)) {
70
- const name = item.text;
71
- this._references.propertyHints[name.toLowerCase()] = name;
72
- }
73
- else {
74
- for (const member of item.elements) {
75
- if (!(0, reflection_1.isCommentStatement)(member)) {
76
- const name = member.keyToken.text;
77
- if (!name.startsWith('"')) {
78
- this._references.propertyHints[name.toLowerCase()] = name;
79
- }
80
- }
81
- }
82
- }
83
- }
84
- get currentNamespaceName() {
85
- var _a;
86
- return (_a = this.currentNamespace) === null || _a === void 0 ? void 0 : _a.nameExpression;
37
+ get symbolTable() {
38
+ return this.ast.symbolTable;
87
39
  }
88
40
  /**
89
41
  * Get the currently active global terminators
@@ -125,11 +77,13 @@ class Parser {
125
77
  this.namespaceAndFunctionDepth = 0;
126
78
  this.pendingAnnotations = [];
127
79
  this.ast = this.body();
80
+ //now that we've built the AST, link every node to its parent
81
+ this.ast.link();
128
82
  return this;
129
83
  }
130
84
  body() {
131
85
  const parentAnnotations = this.enterAnnotationBlock();
132
- let body = new Statement_1.Body([], this.symbolTable);
86
+ let body = new Statement_1.Body({ statements: [] });
133
87
  if (this.tokens.length > 0) {
134
88
  this.consumeStatementSeparators(true);
135
89
  try {
@@ -190,7 +144,7 @@ class Parser {
190
144
  declaration() {
191
145
  try {
192
146
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
193
- return this.functionStatement({ hasName: true, hasBody: true, hasEnd: true });
147
+ return this.functionDeclaration(false);
194
148
  }
195
149
  if (this.checkLibrary()) {
196
150
  return this.libraryStatement();
@@ -236,75 +190,125 @@ class Parser {
236
190
  return identifier;
237
191
  }
238
192
  enumMemberStatement() {
239
- const tokens = {};
240
- let value;
241
- tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
193
+ const statement = new Statement_1.EnumMemberStatement({});
194
+ statement.tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
242
195
  //look for `= SOME_EXPRESSION`
243
196
  if (this.check(TokenKind_1.TokenKind.Equal)) {
244
- tokens.equal = this.advance();
245
- value = this.expression();
197
+ statement.tokens.equals = this.advance();
198
+ statement.value = this.expression();
246
199
  }
247
- return new Statement_1.EnumMemberStatement(tokens, value);
200
+ return statement;
248
201
  }
249
202
  /**
250
- * Create a new InterfaceFieldStatement. This should only be called from within `interfaceDeclaration`
203
+ * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration`
251
204
  */
252
- interfaceFieldStatement() {
205
+ interfaceFieldStatement(optionalKeyword) {
253
206
  const name = this.identifier(...TokenKind_1.AllowedProperties);
254
207
  let asToken;
255
- let typeExpr;
256
- //look for `as SOME_TYPE`
208
+ let typeExpression;
257
209
  if (this.check(TokenKind_1.TokenKind.As)) {
258
- asToken = this.consumeToken(TokenKind_1.TokenKind.As);
259
- typeExpr = this.typeExpression();
260
- //no field type specified
261
- if (!typeExpr.isValidType()) {
262
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
210
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
211
+ }
212
+ return new Statement_1.InterfaceFieldStatement({ name: name, as: asToken, typeExpression: typeExpression, optional: optionalKeyword });
213
+ }
214
+ consumeAsTokenAndTypeExpression(ignoreDiagnostics = false) {
215
+ let asToken = this.consumeToken(TokenKind_1.TokenKind.As);
216
+ let typeExpression;
217
+ if (asToken) {
218
+ //if there's nothing after the `as`, add a diagnostic and continue
219
+ if (this.checkEndOfStatement()) {
220
+ if (!ignoreDiagnostics) {
221
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(asToken.text)), { range: asToken.range }));
222
+ }
223
+ //consume the statement separator
224
+ this.consumeStatementSeparators();
225
+ }
226
+ else if (this.peek().kind !== TokenKind_1.TokenKind.Identifier && !this.checkAny(...TokenKind_1.DeclarableTypes, ...TokenKind_1.AllowedTypeIdentifiers)) {
227
+ if (!ignoreDiagnostics) {
228
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(asToken.text)), { range: asToken.range }));
229
+ }
230
+ }
231
+ else {
232
+ typeExpression = this.typeExpression();
263
233
  }
264
234
  }
265
- return new Statement_1.InterfaceFieldStatement(name, asToken, typeExpr, this.currentNamespaceName);
235
+ return [asToken, typeExpression];
236
+ }
237
+ /**
238
+ * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration()`
239
+ */
240
+ interfaceMethodStatement(optionalKeyword) {
241
+ const functionType = this.advance();
242
+ const name = this.identifier(...TokenKind_1.AllowedProperties);
243
+ const leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.LeftParen), TokenKind_1.TokenKind.LeftParen);
244
+ let params = [];
245
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
246
+ do {
247
+ if (params.length >= Expression_1.CallExpression.MaximumArguments) {
248
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
249
+ }
250
+ params.push(this.functionParameter());
251
+ } while (this.match(TokenKind_1.TokenKind.Comma));
252
+ }
253
+ const rightParen = this.consumeToken(TokenKind_1.TokenKind.RightParen);
254
+ // let asToken = null as Token;
255
+ // let returnTypeExpression: TypeExpression;
256
+ let asToken;
257
+ let returnTypeExpression;
258
+ if (this.check(TokenKind_1.TokenKind.As)) {
259
+ [asToken, returnTypeExpression] = this.consumeAsTokenAndTypeExpression();
260
+ }
261
+ return new Statement_1.InterfaceMethodStatement({
262
+ functionType: functionType,
263
+ name: name,
264
+ leftParen: leftParen,
265
+ params: params,
266
+ rightParen: rightParen,
267
+ as: asToken,
268
+ returnTypeExpression: returnTypeExpression,
269
+ optional: optionalKeyword
270
+ });
266
271
  }
267
272
  interfaceDeclaration() {
268
273
  this.warnIfNotBrighterScriptMode('interface declarations');
269
274
  const parentAnnotations = this.enterAnnotationBlock();
270
275
  const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
271
- //get the interface name
272
- let nameToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('interface'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
276
+ const nameToken = this.identifier(...this.allowedLocalIdentifiers);
273
277
  let extendsToken;
274
278
  let parentInterfaceName;
275
279
  if (this.peek().text.toLowerCase() === 'extends') {
276
280
  extendsToken = this.advance();
277
- parentInterfaceName = this.getNamespacedVariableNameExpression();
281
+ if (this.checkEndOfStatement()) {
282
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(extendsToken.text)), { range: extendsToken.range }));
283
+ }
284
+ else {
285
+ parentInterfaceName = this.typeExpression();
286
+ }
278
287
  }
279
288
  this.consumeStatementSeparators();
280
289
  //gather up all interface members (Fields, Methods)
281
290
  let body = [];
282
291
  while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
283
292
  try {
284
- //break out of this loop if we encountered the `EndInterface` token not followed by `as`
285
- if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
286
- break;
287
- }
288
293
  let decl;
289
294
  //collect leading annotations
290
295
  if (this.check(TokenKind_1.TokenKind.At)) {
291
296
  this.annotationExpression();
292
297
  }
298
+ const optionalKeyword = this.consumeTokenIf(TokenKind_1.TokenKind.Optional);
293
299
  //fields
294
- if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.As)) {
300
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkAnyNext(TokenKind_1.TokenKind.As, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
301
+ decl = this.interfaceFieldStatement(optionalKeyword);
302
+ //field with name = 'optional'
303
+ }
304
+ else if (optionalKeyword && this.checkAny(TokenKind_1.TokenKind.As, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
305
+ //rewind one place, so that 'optional' is the field name
306
+ this.current--;
295
307
  decl = this.interfaceFieldStatement();
296
308
  //methods (function/sub keyword followed by opening paren)
297
309
  }
298
- else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
299
- const functionStatement = this.functionStatement({
300
- hasName: true,
301
- hasBody: false,
302
- hasEnd: false,
303
- onlyCallableAsMember: true
304
- });
305
- decl = new Statement_1.InterfaceMethodStatement(functionStatement.name, functionStatement.func);
306
- //refer to this statement as parent of the expression
307
- functionStatement.func.functionStatement = decl;
310
+ else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
311
+ decl = this.interfaceMethodStatement(optionalKeyword);
308
312
  //comments
309
313
  }
310
314
  else if (this.check(TokenKind_1.TokenKind.Comment)) {
@@ -314,6 +318,10 @@ class Parser {
314
318
  this.consumePendingAnnotations(decl);
315
319
  body.push(decl);
316
320
  }
321
+ else {
322
+ //we didn't find a declaration...flag tokens until next line
323
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
324
+ }
317
325
  }
318
326
  catch (e) {
319
327
  //throw out any failed members and move on to the next line
@@ -321,24 +329,30 @@ class Parser {
321
329
  }
322
330
  //ensure statement separator
323
331
  this.consumeStatementSeparators();
332
+ //break out of this loop if we encountered the `EndInterface` token not followed by `as`
333
+ if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
334
+ break;
335
+ }
324
336
  }
325
337
  //consume the final `end interface` token
326
- let endingKeyword = this.advance();
327
- if (endingKeyword.kind !== TokenKind_1.TokenKind.EndInterface) {
328
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('interface')), { range: endingKeyword.range }));
329
- }
330
- const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endingKeyword, this.currentNamespaceName);
331
- this._references.interfaceStatements.push(statement);
338
+ const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
339
+ const statement = new Statement_1.InterfaceStatement({
340
+ interface: interfaceToken,
341
+ name: nameToken,
342
+ extends: extendsToken,
343
+ parentInterfaceName: parentInterfaceName,
344
+ body: body,
345
+ endInterface: endInterfaceToken
346
+ });
332
347
  this.exitAnnotationBlock(parentAnnotations);
333
348
  return statement;
334
349
  }
335
350
  enumDeclaration() {
351
+ const result = new Statement_1.EnumStatement({ name: {}, body: [] });
336
352
  this.warnIfNotBrighterScriptMode('enum declarations');
337
353
  const parentAnnotations = this.enterAnnotationBlock();
338
- const tokens = {};
339
- const body = [];
340
- tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
341
- tokens.name = this.tryIdentifier();
354
+ result.tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
355
+ result.tokens.name = this.tryIdentifier(...this.allowedLocalIdentifiers);
342
356
  this.consumeStatementSeparators();
343
357
  //gather up all members
344
358
  while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
@@ -358,7 +372,7 @@ class Parser {
358
372
  }
359
373
  if (decl) {
360
374
  this.consumePendingAnnotations(decl);
361
- body.push(decl);
375
+ result.body.push(decl);
362
376
  }
363
377
  else {
364
378
  //we didn't find a declaration...flag tokens until next line
@@ -377,12 +391,7 @@ class Parser {
377
391
  }
378
392
  }
379
393
  //consume the final `end interface` token
380
- tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
381
- const result = new Statement_1.EnumStatement(tokens, body, this.currentNamespaceName);
382
- if (tokens.name) {
383
- this.currentSymbolTable.addSymbol(tokens.name.text, tokens.name.range, result.getThisBscType());
384
- }
385
- this._references.enumStatements.push(result);
394
+ result.tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
386
395
  this.exitAnnotationBlock(parentAnnotations);
387
396
  return result;
388
397
  }
@@ -400,7 +409,12 @@ class Parser {
400
409
  //see if the class inherits from parent
401
410
  if (this.peek().text.toLowerCase() === 'extends') {
402
411
  extendsKeyword = this.advance();
403
- parentClassName = this.getNamespacedVariableNameExpression();
412
+ if (this.checkEndOfStatement()) {
413
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(extendsKeyword.text)), { range: extendsKeyword.range }));
414
+ }
415
+ else {
416
+ parentClassName = this.typeExpression();
417
+ }
404
418
  }
405
419
  //ensure statement separator
406
420
  this.consumeStatementSeparators();
@@ -423,16 +437,19 @@ class Parser {
423
437
  }
424
438
  //methods (function/sub keyword OR identifier followed by opening paren)
425
439
  if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) || (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.LeftParen))) {
426
- const functionStatement = this.functionStatement({ hasName: true, hasBody: true, hasEnd: true, onlyCallableAsMember: true });
440
+ const funcDeclaration = this.functionDeclaration(false, false);
427
441
  //if we have an overrides keyword AND this method is called 'new', that's not allowed
428
- if (overrideKeyword && functionStatement.name.text.toLowerCase() === 'new') {
442
+ if (overrideKeyword && funcDeclaration.tokens.name.text.toLowerCase() === 'new') {
429
443
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { range: overrideKeyword.range }));
430
444
  }
431
- decl = new Statement_1.MethodStatement(accessModifier, functionStatement.name, functionStatement.func, overrideKeyword);
445
+ decl = new Statement_1.MethodStatement({
446
+ modifiers: accessModifier,
447
+ name: funcDeclaration.tokens.name,
448
+ func: funcDeclaration.func,
449
+ override: overrideKeyword
450
+ });
432
451
  //refer to this statement as parent of the expression
433
- functionStatement.func.functionStatement = decl;
434
- //cache the range property so that plugins can't affect it
435
- decl.cacheRange();
452
+ funcDeclaration.func.functionStatement = decl;
436
453
  //fields
437
454
  }
438
455
  else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
@@ -462,26 +479,50 @@ class Parser {
462
479
  if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
463
480
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
464
481
  }
465
- const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName, this.currentSymbolTable);
466
- if (className) {
467
- this.currentSymbolTable.addSymbol(className.text, className.range, result.getConstructorFunctionType());
468
- }
469
- this._references.classStatements.push(result);
482
+ const result = new Statement_1.ClassStatement({
483
+ class: classKeyword,
484
+ name: className,
485
+ body: body,
486
+ endClass: endingKeyword,
487
+ extends: extendsKeyword,
488
+ parentClassName: parentClassName
489
+ });
470
490
  this.exitAnnotationBlock(parentAnnotations);
471
491
  return result;
472
492
  }
473
493
  fieldDeclaration(accessModifier) {
494
+ let optionalKeyword = this.consumeTokenIf(TokenKind_1.TokenKind.Optional);
495
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
496
+ if (this.check(TokenKind_1.TokenKind.As)) {
497
+ if (this.checkAnyNext(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Newline)) {
498
+ // as <EOL>
499
+ // `as` is the field name
500
+ }
501
+ else if (this.checkNext(TokenKind_1.TokenKind.As)) {
502
+ // as as ____
503
+ // first `as` is the field name
504
+ }
505
+ else if (optionalKeyword) {
506
+ // optional as ____
507
+ // optional is the field name, `as` starts type
508
+ // rewind current token
509
+ optionalKeyword = null;
510
+ this.current--;
511
+ }
512
+ }
513
+ }
514
+ else {
515
+ // no name after `optional` ... optional is the name
516
+ // rewind current token
517
+ optionalKeyword = null;
518
+ this.current--;
519
+ }
474
520
  let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
475
521
  let asToken;
476
- let fieldTypeExpr;
522
+ let fieldTypeExpression;
477
523
  //look for `as SOME_TYPE`
478
524
  if (this.check(TokenKind_1.TokenKind.As)) {
479
- asToken = this.advance();
480
- fieldTypeExpr = this.typeExpression();
481
- //no field type specified
482
- if (!fieldTypeExpr.isValidType(this.options.mode)) {
483
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedValidTypeToFollowAsKeyword()), { range: this.peek().range }));
484
- }
525
+ [asToken, fieldTypeExpression] = this.consumeAsTokenAndTypeExpression();
485
526
  }
486
527
  let initialValue;
487
528
  let equal;
@@ -490,43 +531,30 @@ class Parser {
490
531
  equal = this.advance();
491
532
  initialValue = this.expression();
492
533
  }
493
- return new Statement_1.FieldStatement(accessModifier, name, asToken, fieldTypeExpr, equal, initialValue, this.currentNamespaceName);
494
- }
495
- functionStatement(options) {
496
- options.hasName = true;
497
- const funcResult = this.functionDeclaration(options);
498
- if (funcResult) {
499
- let result = new Statement_1.FunctionStatement(funcResult.name, funcResult.functionExpression, this.currentNamespaceName);
500
- funcResult.functionExpression.functionStatement = result;
501
- if (!options.onlyCallableAsMember) {
502
- this._references.functionStatements.push(result);
503
- }
504
- // Add the transpiled name for namespace functions
505
- // to consider an edge case when defining namespaces in .bs files
506
- // and using them in .brs files.
507
- if (result.func.namespaceName) {
508
- const transpiledNamespaceFunctionName = result.getName(ParseMode.BrightScript);
509
- const funcType = result.func.getFunctionType();
510
- funcType.setName(transpiledNamespaceFunctionName);
511
- this.symbolTable.addSymbol(transpiledNamespaceFunctionName, result.name.range, funcType);
512
- }
513
- return result;
514
- }
534
+ return new Statement_1.FieldStatement({
535
+ accessModifier: accessModifier,
536
+ name: name,
537
+ as: asToken,
538
+ typeExpression: fieldTypeExpression,
539
+ equals: equal,
540
+ initialValue: initialValue,
541
+ optional: optionalKeyword
542
+ });
515
543
  }
516
- functionDeclaration(options = {}) {
517
- var _a, _b, _c;
544
+ functionDeclaration(isAnonymous, checkIdentifier = true, onlyCallableAsMember = false) {
545
+ var _a;
518
546
  let previousCallExpressions = this.callExpressions;
519
547
  this.callExpressions = [];
520
548
  try {
521
549
  //track depth to help certain statements need to know if they are contained within a function body
522
550
  this.namespaceAndFunctionDepth++;
523
- let functionKeyword;
551
+ let functionType;
524
552
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
525
- functionKeyword = this.advance();
553
+ functionType = this.advance();
526
554
  }
527
555
  else {
528
556
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
529
- functionKeyword = {
557
+ functionType = {
530
558
  isReserved: true,
531
559
  kind: TokenKind_1.TokenKind.Function,
532
560
  text: 'function',
@@ -535,33 +563,34 @@ class Parser {
535
563
  start: this.peek().range.start,
536
564
  end: this.peek().range.start
537
565
  },
538
- leadingWhitespace: ''
566
+ leadingWhitespace: '',
567
+ leadingTrivia: []
539
568
  };
540
569
  }
541
- let isSub = (functionKeyword === null || functionKeyword === void 0 ? void 0 : functionKeyword.kind) === TokenKind_1.TokenKind.Sub;
542
- let functionKeywordText = isSub ? 'sub' : 'function';
570
+ let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === TokenKind_1.TokenKind.Sub;
571
+ let functionTypeText = isSub ? 'sub' : 'function';
543
572
  let name;
544
573
  let leftParen;
545
- if (!options.hasName) {
546
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
574
+ if (isAnonymous) {
575
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), TokenKind_1.TokenKind.LeftParen);
547
576
  }
548
577
  else {
549
- name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionKeywordText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
550
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
578
+ name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
579
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), TokenKind_1.TokenKind.LeftParen);
551
580
  //prevent functions from ending with type designators
552
581
  let lastChar = name.text[name.text.length - 1];
553
582
  if (['$', '%', '!', '#', '&'].includes(lastChar)) {
554
583
  //don't throw this error; let the parser continue
555
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionKeywordText, name.text, lastChar)), { range: name.range }));
584
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { range: name.range }));
556
585
  }
557
- //flag functions with keywords for names (only for standard functions - not for class methods)
558
- if (!options.onlyCallableAsMember && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
586
+ //flag functions with keywords for names (only for standard functions)
587
+ if (checkIdentifier && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
559
588
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
560
589
  }
561
590
  }
562
591
  let params = [];
563
592
  let asToken;
564
- let typeExpr;
593
+ let typeExpression;
565
594
  if (!this.check(TokenKind_1.TokenKind.RightParen)) {
566
595
  do {
567
596
  if (params.length >= Expression_1.CallExpression.MaximumArguments) {
@@ -572,69 +601,57 @@ class Parser {
572
601
  }
573
602
  let rightParen = this.advance();
574
603
  if (this.check(TokenKind_1.TokenKind.As)) {
575
- asToken = this.advance();
576
- typeExpr = this.typeExpression();
577
- if (!typeExpr.isValidType(this.options.mode)) {
578
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a = typeExpr.getText()) !== null && _a !== void 0 ? _a : '')), { range: typeExpr.range }));
579
- }
604
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
580
605
  }
581
606
  params.reduce((haveFoundOptional, param) => {
582
607
  if (haveFoundOptional && !param.defaultValue) {
583
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(param.name.text)), { range: param.range }));
608
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(param.tokens.name.text)), { range: param.range }));
584
609
  }
585
610
  return haveFoundOptional || !!param.defaultValue;
586
611
  }, false);
587
- if (options.hasEnd && options.hasBody) {
588
- // do not go to next statement - we don't care about any other statement
589
- this.consumeStatementSeparators(true);
612
+ this.consumeStatementSeparators(true);
613
+ let func = new Expression_1.FunctionExpression({
614
+ parameters: params,
615
+ body: undefined,
616
+ functionType: functionType,
617
+ endFunctionType: undefined,
618
+ leftParen: leftParen,
619
+ rightParen: rightParen,
620
+ as: asToken,
621
+ returnTypeExpression: typeExpression
622
+ });
623
+ //support ending the function with `end sub` OR `end function`
624
+ func.body = this.block();
625
+ //if the parser was unable to produce a block, make an empty one so the AST makes some sense...
626
+ if (!func.body) {
627
+ func.body = new Statement_1.Block({
628
+ statements: [],
629
+ startingRange: util_1.util.createRangeFromPositions(func.range.start, func.range.start)
630
+ });
590
631
  }
591
- // Can Not use the current function expression symbol table for a function expression inside of itself
592
- const funcExprParentSymbolTable = (_c = (_b = this.currentNamespace) === null || _b === void 0 ? void 0 : _b.symbolTable) !== null && _c !== void 0 ? _c : this.symbolTable;
593
- let func = new Expression_1.FunctionExpression(params, undefined, //body
594
- functionKeyword, undefined, //ending keyword
595
- leftParen, rightParen, asToken, typeExpr, //return type
596
- this.currentFunctionExpression, this.currentNamespaceName, funcExprParentSymbolTable);
597
- //if there is a parent function, register this function with the parent
598
- if (this.currentFunctionExpression) {
599
- this.currentFunctionExpression.childFunctionExpressions.push(func);
600
- }
601
- // add the function to the relevant symbol tables
602
- if (!options.onlyCallableAsMember && name) {
603
- const funcType = func.getFunctionType();
604
- funcType.setName(name.text);
605
- // add the function as declared to the current symbol table
606
- this.currentSymbolTable.addSymbol(name.text, name.range, funcType);
607
- }
608
- this._references.functionExpressions.push(func);
609
- if (options.hasBody) {
610
- let previousFunctionExpression = this.currentFunctionExpression;
611
- this.currentFunctionExpression = func;
612
- //make sure to restore the currentFunctionExpression even if the body block fails to parse
613
- try {
614
- //support ending the function with `end sub` OR `end function`
615
- func.body = this.block();
616
- }
617
- finally {
618
- this.currentFunctionExpression = previousFunctionExpression;
619
- }
620
- if (!func.body) {
621
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionKeywordText)), { range: this.peek().range }));
622
- throw this.lastDiagnosticAsError();
623
- }
632
+ func.body.symbolTable = new SymbolTable_1.SymbolTable(`Block: Function '${(_a = name === null || name === void 0 ? void 0 : name.text) !== null && _a !== void 0 ? _a : ''}'`, () => func.getSymbolTable());
633
+ if (!func.body) {
634
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionTypeText)), { range: this.peek().range }));
635
+ throw this.lastDiagnosticAsError();
624
636
  }
625
- if (options.hasEnd) {
626
- // consume 'end sub' or 'end function'
627
- func.end = this.advance();
628
- let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
629
- //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
630
- //add an error but don't hard-fail so the AST can continue more gracefully
631
- if (func.end.kind !== expectedEndKind) {
632
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionKeywordText, func.end.text)), { range: this.peek().range }));
633
- }
637
+ // consume 'end sub' or 'end function'
638
+ func.tokens.endFunctionType = this.advance();
639
+ let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
640
+ //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
641
+ //add an error but don't hard-fail so the AST can continue more gracefully
642
+ if (func.tokens.endFunctionType.kind !== expectedEndKind) {
643
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, func.tokens.endFunctionType.text)), { range: func.tokens.endFunctionType.range }));
634
644
  }
635
645
  func.callExpressions = this.callExpressions;
636
- func.cacheRange();
637
- return { name: name, functionExpression: func };
646
+ if (isAnonymous) {
647
+ return func;
648
+ }
649
+ else {
650
+ let result = new Statement_1.FunctionStatement({ name: name, func: func });
651
+ func.symbolTable.name += `: '${name === null || name === void 0 ? void 0 : name.text}'`;
652
+ func.functionStatement = result;
653
+ return result;
654
+ }
638
655
  }
639
656
  finally {
640
657
  this.namespaceAndFunctionDepth--;
@@ -647,65 +664,62 @@ class Parser {
647
664
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { range: this.peek().range }));
648
665
  throw this.lastDiagnosticAsError();
649
666
  }
650
- const name = this.identifier(...TokenKind_1.AllowedLocalIdentifiers);
651
- let typeExpr;
667
+ let name = this.advance();
668
+ // force the name into an identifier so the AST makes some sense
669
+ name.kind = TokenKind_1.TokenKind.Identifier;
670
+ let typeExpression;
652
671
  let defaultValue;
653
- let equalsToken;
672
+ let equalToken;
654
673
  // parse argument default value
655
- if (this.match(TokenKind_1.TokenKind.Equal)) {
656
- equalsToken = this.previous();
674
+ if ((equalToken = this.consumeTokenIf(TokenKind_1.TokenKind.Equal))) {
657
675
  // it seems any expression is allowed here -- including ones that operate on other arguments!
658
- defaultValue = this.expression();
676
+ defaultValue = this.expression(false);
659
677
  }
660
678
  let asToken = null;
661
679
  if (this.check(TokenKind_1.TokenKind.As)) {
662
- asToken = this.advance();
663
- typeExpr = this.typeExpression();
664
- if (!typeExpr.isValidType(this.options.mode)) {
665
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
666
- throw this.lastDiagnosticAsError();
667
- }
668
- }
669
- let typeInContext;
670
- if (typeExpr) {
671
- typeInContext = typeExpr.type;
672
- }
673
- else if (defaultValue) {
674
- typeInContext = getBscTypeFromExpression(defaultValue, this.currentFunctionExpression);
675
- if ((0, reflection_1.isInvalidType)(typeInContext)) {
676
- typeInContext = new DynamicType_1.DynamicType();
677
- }
678
- }
679
- else {
680
- typeInContext = new DynamicType_1.DynamicType();
681
- }
682
- return new Expression_1.FunctionParameterExpression(name, typeInContext, equalsToken, defaultValue, asToken, typeExpr, this.currentNamespaceName);
680
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
681
+ }
682
+ return new Expression_1.FunctionParameterExpression({
683
+ name: name,
684
+ equals: equalToken,
685
+ defaultValue: defaultValue,
686
+ as: asToken,
687
+ typeExpression: typeExpression
688
+ });
683
689
  }
684
690
  assignment() {
685
- let name = this.identifier(...this.allowedLocalIdentifiers);
691
+ let name = this.advance();
686
692
  //add diagnostic if name is a reserved word that cannot be used as an identifier
687
693
  if (TokenKind_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
688
694
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
689
695
  }
696
+ let asToken;
697
+ let typeExpression;
698
+ //look for `as SOME_TYPE`
699
+ if (this.check(TokenKind_1.TokenKind.As)) {
700
+ this.warnIfNotBrighterScriptMode('typed assignment');
701
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
702
+ }
690
703
  let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(TokenKind_1.AssignmentOperators, name.text), ...TokenKind_1.AssignmentOperators);
691
704
  let value = this.expression();
692
705
  let result;
693
706
  if (operator.kind === TokenKind_1.TokenKind.Equal) {
694
- result = new Statement_1.AssignmentStatement(name, operator, value, this.currentFunctionExpression);
707
+ result = new Statement_1.AssignmentStatement({ equals: operator, name: name, value: value, as: asToken, typeExpression: typeExpression });
695
708
  }
696
709
  else {
697
- const nameExpression = new Expression_1.VariableExpression(name, this.currentNamespaceName);
698
- result = new Statement_1.AssignmentStatement(name, operator, new Expression_1.BinaryExpression(nameExpression, operator, value), this.currentFunctionExpression);
699
- this.addExpressionsToReferences(nameExpression);
700
- if ((0, reflection_1.isBinaryExpression)(value)) {
701
- //remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
702
- this._references.expressions.delete(value);
703
- }
704
- this._references.expressions.add(result);
705
- }
706
- this._references.assignmentStatements.push(result);
707
- const assignmentType = getBscTypeFromExpression(result.value, this.currentFunctionExpression);
708
- this.currentSymbolTable.addSymbol(name.text, name.range, assignmentType);
710
+ const nameExpression = new Expression_1.VariableExpression({ name: name });
711
+ result = new Statement_1.AssignmentStatement({
712
+ equals: operator,
713
+ name: name,
714
+ value: new Expression_1.BinaryExpression({
715
+ left: nameExpression,
716
+ operator: operator,
717
+ right: value
718
+ }),
719
+ as: asToken,
720
+ typeExpression: typeExpression
721
+ });
722
+ }
709
723
  return result;
710
724
  }
711
725
  checkLibrary() {
@@ -774,6 +788,10 @@ class Parser {
774
788
  if (this.check(TokenKind_1.TokenKind.Goto)) {
775
789
  return this.gotoStatement();
776
790
  }
791
+ //the continue keyword (followed by `for`, `while`, or a statement separator)
792
+ if (this.check(TokenKind_1.TokenKind.Continue) && this.checkAnyNext(TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
793
+ return this.continueStatement();
794
+ }
777
795
  //does this line look like a label? (i.e. `someIdentifier:` )
778
796
  if (this.check(TokenKind_1.TokenKind.Identifier) && this.checkNext(TokenKind_1.TokenKind.Colon) && this.checkPrevious(TokenKind_1.TokenKind.Newline)) {
779
797
  try {
@@ -789,9 +807,31 @@ class Parser {
789
807
  // BrightScript is like python, in that variables can be declared without a `var`,
790
808
  // `let`, (...) keyword. As such, we must check the token *after* an identifier to figure
791
809
  // out what to do with it.
792
- if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
793
- this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
794
- return this.assignment();
810
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
811
+ if (this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
812
+ return this.assignment();
813
+ }
814
+ else if (this.checkNext(TokenKind_1.TokenKind.As)) {
815
+ // may be a typed assignment
816
+ const backtrack = this.current;
817
+ let validTypeExpression = false;
818
+ try {
819
+ // skip the identifier, and check for valid type expression
820
+ this.advance();
821
+ const parts = this.consumeAsTokenAndTypeExpression(true);
822
+ validTypeExpression = !!((parts === null || parts === void 0 ? void 0 : parts[0]) && (parts === null || parts === void 0 ? void 0 : parts[1]));
823
+ }
824
+ catch (e) {
825
+ // ignore any errors
826
+ }
827
+ finally {
828
+ this.current = backtrack;
829
+ }
830
+ if (validTypeExpression) {
831
+ // there is a valid 'as' and type expression
832
+ return this.assignment();
833
+ }
834
+ }
795
835
  }
796
836
  //some BrighterScript keywords are allowed as a local identifiers, so we need to check for them AFTER the assignment check
797
837
  if (this.check(TokenKind_1.TokenKind.Interface)) {
@@ -824,7 +864,12 @@ class Parser {
824
864
  else {
825
865
  endWhile = this.advance();
826
866
  }
827
- return new Statement_1.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
867
+ return new Statement_1.WhileStatement({
868
+ while: whileKeyword,
869
+ endWhile: endWhile,
870
+ condition: condition,
871
+ body: whileBlock
872
+ });
828
873
  }
829
874
  exitWhile() {
830
875
  let keyword = this.advance();
@@ -859,11 +904,20 @@ class Parser {
859
904
  }
860
905
  // WARNING: BrightScript doesn't delete the loop initial value after a for/to loop! It just
861
906
  // stays around in scope with whatever value it was when the loop exited.
862
- return new Statement_1.ForStatement(forToken, initializer, toToken, finalValue, body, endForToken, stepToken, incrementExpression);
907
+ return new Statement_1.ForStatement({
908
+ for: forToken,
909
+ counterDeclaration: initializer,
910
+ to: toToken,
911
+ finalValue: finalValue,
912
+ body: body,
913
+ endFor: endForToken,
914
+ step: stepToken,
915
+ increment: incrementExpression
916
+ });
863
917
  }
864
918
  forEachStatement() {
865
919
  let forEach = this.advance();
866
- let name = this.identifier(...this.allowedLocalIdentifiers);
920
+ let name = this.advance();
867
921
  let maybeIn = this.peek();
868
922
  if (this.check(TokenKind_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
869
923
  this.advance();
@@ -877,12 +931,6 @@ class Parser {
877
931
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
878
932
  throw this.lastDiagnosticAsError();
879
933
  }
880
- let itemType = new DynamicType_1.DynamicType();
881
- const targetType = getBscTypeFromExpression(target, this.currentFunctionExpression);
882
- if ((0, reflection_1.isArrayType)(targetType)) {
883
- itemType = targetType.getDefaultType();
884
- }
885
- this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
886
934
  this.consumeStatementSeparators();
887
935
  let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
888
936
  if (!body) {
@@ -890,7 +938,14 @@ class Parser {
890
938
  throw this.lastDiagnosticAsError();
891
939
  }
892
940
  let endFor = this.advance();
893
- return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
941
+ return new Statement_1.ForEachStatement({
942
+ forEach: forEach,
943
+ in: maybeIn,
944
+ endFor: endFor,
945
+ item: name,
946
+ target: target,
947
+ body: body
948
+ });
894
949
  }
895
950
  exitFor() {
896
951
  let keyword = this.advance();
@@ -901,7 +956,7 @@ class Parser {
901
956
  //then this comment should be treated as a single-line comment
902
957
  let prev = this.previous();
903
958
  if ((prev === null || prev === void 0 ? void 0 : prev.range.end.line) === this.peek().range.start.line) {
904
- return new Statement_1.CommentStatement([this.advance()]);
959
+ return new Statement_1.CommentStatement({ comments: [this.advance()] });
905
960
  }
906
961
  else {
907
962
  let comments = [this.advance()];
@@ -909,25 +964,19 @@ class Parser {
909
964
  this.advance();
910
965
  comments.push(this.advance());
911
966
  }
912
- return new Statement_1.CommentStatement(comments);
967
+ return new Statement_1.CommentStatement({ comments: comments });
913
968
  }
914
969
  }
915
970
  namespaceStatement() {
916
971
  this.warnIfNotBrighterScriptMode('namespace');
917
972
  let keyword = this.advance();
918
- if (!this.isAtRootLevel()) {
919
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.keywordMustBeDeclaredAtRootLevel('namespace')), { range: keyword.range }));
920
- }
921
973
  this.namespaceAndFunctionDepth++;
922
- let name = this.getNamespacedVariableNameExpression();
974
+ let name = this.identifyingExpression();
923
975
  //set the current namespace name
924
- let result = new Statement_1.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
925
- this.currentNamespace = result;
976
+ let result = new Statement_1.NamespaceStatement({ namespace: keyword, nameExpression: name, body: null });
926
977
  this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
927
978
  let body = this.body();
928
979
  this.globalTerminators.pop();
929
- //unset the current namespace name
930
- this.currentNamespace = undefined;
931
980
  let endKeyword;
932
981
  if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
933
982
  endKeyword = this.advance();
@@ -938,25 +987,23 @@ class Parser {
938
987
  }
939
988
  this.namespaceAndFunctionDepth--;
940
989
  result.body = body;
941
- result.endKeyword = endKeyword;
942
- this._references.namespaceStatements.push(result);
990
+ result.tokens.endNamespace = endKeyword;
943
991
  //cache the range property so that plugins can't affect it
944
992
  result.cacheRange();
945
- if (result.name) {
946
- this.symbolTable.addSymbol(result.name.split('.')[0], result.nameExpression.range, DynamicType_1.DynamicType.instance);
947
- }
993
+ result.body.symbolTable.name += `: namespace '${result.name}'`;
948
994
  return result;
949
995
  }
950
996
  /**
951
997
  * Get an expression with identifiers separated by periods. Useful for namespaces and class extends
952
998
  */
953
- getNamespacedVariableNameExpression() {
954
- let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
999
+ identifyingExpression(allowedTokenKinds) {
1000
+ allowedTokenKinds = allowedTokenKinds !== null && allowedTokenKinds !== void 0 ? allowedTokenKinds : this.allowedLocalIdentifiers;
1001
+ let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...allowedTokenKinds);
955
1002
  let expr;
956
1003
  if (firstIdentifier) {
957
1004
  // force it into an identifier so the AST makes some sense
958
1005
  firstIdentifier.kind = TokenKind_1.TokenKind.Identifier;
959
- const varExpr = new Expression_1.VariableExpression(firstIdentifier, null);
1006
+ const varExpr = new Expression_1.VariableExpression({ name: firstIdentifier });
960
1007
  expr = varExpr;
961
1008
  //consume multiple dot identifiers (i.e. `Name.Space.Can.Have.Many.Parts`)
962
1009
  while (this.check(TokenKind_1.TokenKind.Dot)) {
@@ -964,16 +1011,16 @@ class Parser {
964
1011
  if (!dot) {
965
1012
  break;
966
1013
  }
967
- let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...TokenKind_1.AllowedProperties);
1014
+ let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...allowedTokenKinds, ...TokenKind_1.AllowedProperties);
968
1015
  if (!identifier) {
969
1016
  break;
970
1017
  }
971
1018
  // force it into an identifier so the AST makes some sense
972
1019
  identifier.kind = TokenKind_1.TokenKind.Identifier;
973
- expr = new Expression_1.DottedGetExpression(expr, identifier, dot);
1020
+ expr = new Expression_1.DottedGetExpression({ obj: expr, name: identifier, dot: dot });
974
1021
  }
975
1022
  }
976
- return new Expression_1.NamespacedVariableNameExpression(expr);
1023
+ return expr;
977
1024
  }
978
1025
  /**
979
1026
  * Add an 'unexpected token' diagnostic for any token found between current and the first stopToken found.
@@ -986,8 +1033,8 @@ class Parser {
986
1033
  }
987
1034
  /**
988
1035
  * Consume tokens until one of the `stopTokenKinds` is encountered
989
- * @param tokenKinds
990
- * @return - the list of tokens consumed, EXCLUDING the `stopTokenKind` (you can use `this.peek()` to see which one it was)
1036
+ * @param stopTokenKinds a list of tokenKinds where any tokenKind in this list will result in a match
1037
+ * @returns - the list of tokens consumed, EXCLUDING the `stopTokenKind` (you can use `this.peek()` to see which one it was)
991
1038
  */
992
1039
  consumeUntil(...stopTokenKinds) {
993
1040
  let result = [];
@@ -1006,12 +1053,9 @@ class Parser {
1006
1053
  const statement = new Statement_1.ConstStatement({
1007
1054
  const: constToken,
1008
1055
  name: nameToken,
1009
- equals: equalToken
1010
- }, expression, this.currentNamespaceName);
1011
- if (nameToken) {
1012
- this.currentSymbolTable.addSymbol(nameToken.text, nameToken.range, getBscTypeFromExpression(expression));
1013
- }
1014
- this._references.constStatements.push(statement);
1056
+ equals: equalToken,
1057
+ value: expression
1058
+ });
1015
1059
  return statement;
1016
1060
  }
1017
1061
  libraryStatement() {
@@ -1020,15 +1064,15 @@ class Parser {
1020
1064
  //grab the next token only if it's a string
1021
1065
  filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
1022
1066
  });
1023
- this._references.libraryStatements.push(libStatement);
1024
1067
  return libStatement;
1025
1068
  }
1026
1069
  importStatement() {
1027
1070
  this.warnIfNotBrighterScriptMode('import statements');
1028
- let importStatement = new Statement_1.ImportStatement(this.advance(),
1029
- //grab the next token only if it's a string
1030
- this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
1031
- this._references.importStatements.push(importStatement);
1071
+ let importStatement = new Statement_1.ImportStatement({
1072
+ import: this.advance(),
1073
+ //grab the next token only if it's a string
1074
+ filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral)
1075
+ });
1032
1076
  return importStatement;
1033
1077
  }
1034
1078
  annotationExpression() {
@@ -1037,15 +1081,13 @@ class Parser {
1037
1081
  if (identifier) {
1038
1082
  identifier.kind = TokenKind_1.TokenKind.Identifier;
1039
1083
  }
1040
- let annotation = new Expression_1.AnnotationExpression(atToken, identifier);
1084
+ let annotation = new Expression_1.AnnotationExpression({ at: atToken, name: identifier });
1041
1085
  this.pendingAnnotations.push(annotation);
1042
1086
  //optional arguments
1043
1087
  if (this.check(TokenKind_1.TokenKind.LeftParen)) {
1044
1088
  let leftParen = this.advance();
1045
1089
  annotation.call = this.finishCall(leftParen, annotation, false);
1046
1090
  }
1047
- //cache the range property so that plugins can't affect it
1048
- annotation.cacheRange();
1049
1091
  return annotation;
1050
1092
  }
1051
1093
  ternaryExpression(test) {
@@ -1077,13 +1119,23 @@ class Parser {
1077
1119
  alternate = this.expression();
1078
1120
  }
1079
1121
  catch (_b) { }
1080
- return new Expression_1.TernaryExpression(test, questionMarkToken, consequent, colonToken, alternate);
1122
+ return new Expression_1.TernaryExpression({
1123
+ test: test,
1124
+ questionMark: questionMarkToken,
1125
+ consequent: consequent,
1126
+ colon: colonToken,
1127
+ alternate: alternate
1128
+ });
1081
1129
  }
1082
1130
  nullCoalescingExpression(test) {
1083
1131
  this.warnIfNotBrighterScriptMode('null coalescing operator');
1084
1132
  const questionQuestionToken = this.advance();
1085
1133
  const alternate = this.expression();
1086
- return new Expression_1.NullCoalescingExpression(test, questionQuestionToken, alternate);
1134
+ return new Expression_1.NullCoalescingExpression({
1135
+ consequent: test,
1136
+ questionQuestion: questionQuestionToken,
1137
+ alternate: alternate
1138
+ });
1087
1139
  }
1088
1140
  regexLiteralExpression() {
1089
1141
  this.warnIfNotBrighterScriptMode('regular expression literal');
@@ -1109,16 +1161,16 @@ class Parser {
1109
1161
  let next = this.peek();
1110
1162
  if (next.kind === TokenKind_1.TokenKind.TemplateStringQuasi) {
1111
1163
  //a quasi can actually be made up of multiple quasis when it includes char literals
1112
- currentQuasiExpressionParts.push(new Expression_1.LiteralExpression(next));
1164
+ currentQuasiExpressionParts.push(new Expression_1.LiteralExpression({ value: next }));
1113
1165
  this.advance();
1114
1166
  }
1115
1167
  else if (next.kind === TokenKind_1.TokenKind.EscapedCharCodeLiteral) {
1116
- currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression(next));
1168
+ currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression({ value: next }));
1117
1169
  this.advance();
1118
1170
  }
1119
1171
  else {
1120
1172
  //finish up the current quasi
1121
- quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
1173
+ quasis.push(new Expression_1.TemplateStringQuasiExpression({ expressions: currentQuasiExpressionParts }));
1122
1174
  currentQuasiExpressionParts = [];
1123
1175
  if (next.kind === TokenKind_1.TokenKind.TemplateStringExpressionBegin) {
1124
1176
  this.advance();
@@ -1136,7 +1188,7 @@ class Parser {
1136
1188
  }
1137
1189
  }
1138
1190
  //store the final set of quasis
1139
- quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
1191
+ quasis.push(new Expression_1.TemplateStringQuasiExpression({ expressions: currentQuasiExpressionParts }));
1140
1192
  if (this.isAtEnd()) {
1141
1193
  //error - missing backtick
1142
1194
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unterminatedTemplateStringAtEndOfFile()), { range: util_1.util.getRange(openingBacktick, this.peek()) }));
@@ -1145,10 +1197,21 @@ class Parser {
1145
1197
  else {
1146
1198
  let closingBacktick = this.advance();
1147
1199
  if (isTagged) {
1148
- return new Expression_1.TaggedTemplateStringExpression(tagName, openingBacktick, quasis, expressions, closingBacktick);
1200
+ return new Expression_1.TaggedTemplateStringExpression({
1201
+ tagName: tagName,
1202
+ openingBacktick: openingBacktick,
1203
+ quasis: quasis,
1204
+ expressions: expressions,
1205
+ closingBacktick: closingBacktick
1206
+ });
1149
1207
  }
1150
1208
  else {
1151
- return new Expression_1.TemplateStringExpression(openingBacktick, quasis, expressions, closingBacktick);
1209
+ return new Expression_1.TemplateStringExpression({
1210
+ openingBacktick: openingBacktick,
1211
+ quasis: quasis,
1212
+ expressions: expressions,
1213
+ closingBacktick: closingBacktick
1214
+ });
1152
1215
  }
1153
1216
  }
1154
1217
  }
@@ -1173,7 +1236,7 @@ class Parser {
1173
1236
  if (exceptionVarToken) {
1174
1237
  // force it into an identifier so the AST makes some sense
1175
1238
  exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
1176
- catchStmt.exceptionVariable = exceptionVarToken;
1239
+ catchStmt.tokens.exceptionVariable = exceptionVarToken;
1177
1240
  }
1178
1241
  //ensure statement sepatator
1179
1242
  this.consumeStatementSeparators();
@@ -1184,9 +1247,6 @@ class Parser {
1184
1247
  else {
1185
1248
  statement.tokens.endTry = this.advance();
1186
1249
  }
1187
- if (exceptionVarToken) {
1188
- this.currentSymbolTable.addSymbol(exceptionVarToken.text, exceptionVarToken.range, DynamicType_1.DynamicType.instance);
1189
- }
1190
1250
  return statement;
1191
1251
  }
1192
1252
  throwStatement() {
@@ -1198,7 +1258,7 @@ class Parser {
1198
1258
  else {
1199
1259
  expression = this.expression();
1200
1260
  }
1201
- return new Statement_1.ThrowStatement(throwToken, expression);
1261
+ return new Statement_1.ThrowStatement({ throw: throwToken, expression: expression });
1202
1262
  }
1203
1263
  dimStatement() {
1204
1264
  const dim = this.advance();
@@ -1229,10 +1289,13 @@ class Parser {
1229
1289
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
1230
1290
  }
1231
1291
  let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
1232
- if (identifier) {
1233
- this.currentSymbolTable.addSymbol(identifier.text, identifier.range, new ArrayType_1.ArrayType(DynamicType_1.DynamicType.instance));
1234
- }
1235
- return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1292
+ return new Statement_1.DimStatement({
1293
+ dim: dim,
1294
+ name: identifier,
1295
+ openingSquare: leftSquareBracket,
1296
+ dimensions: expressions,
1297
+ closingSquare: rightSquareBracket
1298
+ });
1236
1299
  }
1237
1300
  ifStatement() {
1238
1301
  // colon before `if` is usually not allowed, unless it's after `then`
@@ -1342,8 +1405,12 @@ class Parser {
1342
1405
  if: ifToken,
1343
1406
  then: thenToken,
1344
1407
  endIf: endIfToken,
1345
- else: elseToken
1346
- }, condition, thenBranch, elseBranch, isInlineIfThen);
1408
+ else: elseToken,
1409
+ condition: condition,
1410
+ thenBranch: thenBranch,
1411
+ elseBranch: elseBranch,
1412
+ isInline: isInlineIfThen
1413
+ });
1347
1414
  }
1348
1415
  //consume a `then` or `else` branch block of an `if` statement
1349
1416
  blockConditionalBranch(ifToken) {
@@ -1414,7 +1481,7 @@ class Parser {
1414
1481
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(colon.text)), { range: colon.range }));
1415
1482
  }
1416
1483
  }
1417
- return new Statement_1.Block(statements, startingRange);
1484
+ return new Statement_1.Block({ statements: statements, startingRange: startingRange });
1418
1485
  }
1419
1486
  expressionStatement(expr) {
1420
1487
  let expressionStart = this.peek();
@@ -1428,18 +1495,15 @@ class Parser {
1428
1495
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
1429
1496
  throw this.lastDiagnosticAsError();
1430
1497
  }
1431
- const result = new Statement_1.IncrementStatement(expr, operator);
1432
- this._references.expressions.add(result);
1498
+ const result = new Statement_1.IncrementStatement({ value: expr, operator: operator });
1433
1499
  return result;
1434
1500
  }
1435
1501
  if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
1436
- return new Statement_1.ExpressionStatement(expr);
1502
+ return new Statement_1.ExpressionStatement({ expression: expr });
1437
1503
  }
1438
- //at this point, it's probably an error. However, we recover a little more gracefully by creating an assignment
1504
+ //at this point, it's probably an error. However, we recover a little more gracefully by creating an inclosing ExpressionStatement
1439
1505
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementOrFunctionCallButReceivedExpression()), { range: expressionStart.range }));
1440
- // we can also add this expression to the references, for type checking purposes
1441
- this._references.expressions.add(expr);
1442
- throw this.lastDiagnosticAsError();
1506
+ return new Statement_1.ExpressionStatement({ expression: expr });
1443
1507
  }
1444
1508
  setStatement() {
1445
1509
  /**
@@ -1455,19 +1519,31 @@ class Parser {
1455
1519
  let right = this.expression();
1456
1520
  // Create a dotted or indexed "set" based on the left-hand side's type
1457
1521
  if ((0, reflection_1.isIndexedGetExpression)(left)) {
1458
- return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
1459
- ? right
1460
- : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare, operator);
1522
+ return new Statement_1.IndexedSetStatement({
1523
+ obj: left.obj,
1524
+ indexes: left.indexes,
1525
+ value: operator.kind === TokenKind_1.TokenKind.Equal
1526
+ ? right
1527
+ : new Expression_1.BinaryExpression({ left: left, operator: operator, right: right }),
1528
+ openingSquare: left.tokens.openingSquare,
1529
+ closingSquare: left.tokens.closingSquare
1530
+ });
1461
1531
  }
1462
1532
  else if ((0, reflection_1.isDottedGetExpression)(left)) {
1463
- const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal ? right : new Expression_1.BinaryExpression(left, operator, right), left.dot, operator);
1464
- this._references.dottedSetStatements.push(dottedSetStmt);
1465
- return dottedSetStmt;
1533
+ return new Statement_1.DottedSetStatement({
1534
+ obj: left.obj,
1535
+ name: left.tokens.name,
1536
+ value: operator.kind === TokenKind_1.TokenKind.Equal
1537
+ ? right
1538
+ : new Expression_1.BinaryExpression({ left: left, operator: operator, right: right }),
1539
+ dot: left.tokens.dot
1540
+ });
1466
1541
  }
1467
1542
  }
1468
1543
  return this.expressionStatement(expr);
1469
1544
  }
1470
1545
  printStatement() {
1546
+ var _a;
1471
1547
  let printKeyword = this.advance();
1472
1548
  let values = [];
1473
1549
  while (!this.checkEndOfStatement()) {
@@ -1486,34 +1562,35 @@ class Parser {
1486
1562
  }
1487
1563
  //print statements can be empty, so look for empty print conditions
1488
1564
  if (!values.length) {
1489
- let emptyStringLiteral = (0, creators_1.createStringLiteral)('');
1565
+ const endOfStatementRange = util_1.util.createRangeFromPositions(printKeyword.range.end, (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.range.end);
1566
+ let emptyStringLiteral = (0, creators_1.createStringLiteral)('', endOfStatementRange);
1490
1567
  values.push(emptyStringLiteral);
1491
1568
  }
1492
1569
  let last = values[values.length - 1];
1493
1570
  if ((0, Token_1.isToken)(last)) {
1494
1571
  // TODO: error, expected value
1495
1572
  }
1496
- return new Statement_1.PrintStatement({ print: printKeyword }, values);
1573
+ return new Statement_1.PrintStatement({ print: printKeyword, expressions: values });
1497
1574
  }
1498
1575
  /**
1499
1576
  * Parses a return statement with an optional return value.
1500
1577
  * @returns an AST representation of a return statement.
1501
1578
  */
1502
1579
  returnStatement() {
1503
- let tokens = { return: this.previous() };
1580
+ let options = { return: this.previous() };
1504
1581
  if (this.checkEndOfStatement()) {
1505
- return new Statement_1.ReturnStatement(tokens);
1582
+ return new Statement_1.ReturnStatement(options);
1506
1583
  }
1507
1584
  let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
1508
- return new Statement_1.ReturnStatement(tokens, toReturn);
1585
+ return new Statement_1.ReturnStatement(Object.assign(Object.assign({}, options), { value: toReturn }));
1509
1586
  }
1510
1587
  /**
1511
1588
  * Parses a `label` statement
1512
1589
  * @returns an AST representation of an `label` statement.
1513
1590
  */
1514
1591
  labelStatement() {
1515
- let tokens = {
1516
- identifier: this.advance(),
1592
+ let options = {
1593
+ name: this.advance(),
1517
1594
  colon: this.advance()
1518
1595
  };
1519
1596
  //label must be alone on its line, this is probably not a label
@@ -1522,9 +1599,16 @@ class Parser {
1522
1599
  this.current -= 2;
1523
1600
  throw new CancelStatementError();
1524
1601
  }
1525
- const stmt = new Statement_1.LabelStatement(tokens);
1526
- this.currentFunctionExpression.labelStatements.push(stmt);
1527
- return stmt;
1602
+ return new Statement_1.LabelStatement(options);
1603
+ }
1604
+ /**
1605
+ * Parses a `continue` statement
1606
+ */
1607
+ continueStatement() {
1608
+ return new Statement_1.ContinueStatement({
1609
+ continue: this.advance(),
1610
+ loopType: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For), TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For)
1611
+ });
1528
1612
  }
1529
1613
  /**
1530
1614
  * Parses a `goto` statement
@@ -1542,16 +1626,16 @@ class Parser {
1542
1626
  * @returns an AST representation of an `end` statement.
1543
1627
  */
1544
1628
  endStatement() {
1545
- let endTokens = { end: this.advance() };
1546
- return new Statement_1.EndStatement(endTokens);
1629
+ let options = { end: this.advance() };
1630
+ return new Statement_1.EndStatement(options);
1547
1631
  }
1548
1632
  /**
1549
1633
  * Parses a `stop` statement
1550
1634
  * @returns an AST representation of a `stop` statement
1551
1635
  */
1552
1636
  stopStatement() {
1553
- let tokens = { stop: this.advance() };
1554
- return new Statement_1.StopStatement(tokens);
1637
+ let options = { stop: this.advance() };
1638
+ return new Statement_1.StopStatement(options);
1555
1639
  }
1556
1640
  /**
1557
1641
  * Parses a block, looking for a specific terminating TokenKind to denote completion.
@@ -1603,7 +1687,7 @@ class Parser {
1603
1687
  }
1604
1688
  }
1605
1689
  this.exitAnnotationBlock(parentAnnotations);
1606
- return new Statement_1.Block(statements, startingToken.range);
1690
+ return new Statement_1.Block({ statements: statements, startingRange: startingToken.range });
1607
1691
  }
1608
1692
  /**
1609
1693
  * Attach pending annotations to the provided statement,
@@ -1629,14 +1713,32 @@ class Parser {
1629
1713
  }
1630
1714
  this.pendingAnnotations = parentAnnotations;
1631
1715
  }
1632
- expression() {
1633
- const expression = this.anonymousFunction();
1634
- this._references.expressions.add(expression);
1716
+ expression(findTypeCast = true) {
1717
+ let expression = this.anonymousFunction();
1718
+ let asToken;
1719
+ let typeExpression;
1720
+ if (findTypeCast) {
1721
+ do {
1722
+ if (this.check(TokenKind_1.TokenKind.As)) {
1723
+ this.warnIfNotBrighterScriptMode('type cast');
1724
+ // Check if this expression is wrapped in any type casts
1725
+ // allows for multiple casts:
1726
+ // myVal = foo() as dynamic as string
1727
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
1728
+ if (asToken && typeExpression) {
1729
+ expression = new Expression_1.TypeCastExpression({ obj: expression, as: asToken, typeExpression: typeExpression });
1730
+ }
1731
+ }
1732
+ else {
1733
+ break;
1734
+ }
1735
+ } while (asToken && typeExpression);
1736
+ }
1635
1737
  return expression;
1636
1738
  }
1637
1739
  anonymousFunction() {
1638
1740
  if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
1639
- const func = this.functionDeclaration({ hasName: false, hasBody: true, hasEnd: true }).functionExpression;
1741
+ const func = this.functionDeclaration(true);
1640
1742
  //if there's an open paren after this, this is an IIFE
1641
1743
  if (this.check(TokenKind_1.TokenKind.LeftParen)) {
1642
1744
  return this.finishCall(this.advance(), func);
@@ -1661,8 +1763,7 @@ class Parser {
1661
1763
  while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
1662
1764
  let operator = this.previous();
1663
1765
  let right = this.relational();
1664
- this.addExpressionsToReferences(expr, right);
1665
- expr = new Expression_1.BinaryExpression(expr, operator, right);
1766
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1666
1767
  }
1667
1768
  return expr;
1668
1769
  }
@@ -1671,26 +1772,17 @@ class Parser {
1671
1772
  while (this.matchAny(TokenKind_1.TokenKind.Equal, TokenKind_1.TokenKind.LessGreater, TokenKind_1.TokenKind.Greater, TokenKind_1.TokenKind.GreaterEqual, TokenKind_1.TokenKind.Less, TokenKind_1.TokenKind.LessEqual)) {
1672
1773
  let operator = this.previous();
1673
1774
  let right = this.additive();
1674
- this.addExpressionsToReferences(expr, right);
1675
- expr = new Expression_1.BinaryExpression(expr, operator, right);
1775
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1676
1776
  }
1677
1777
  return expr;
1678
1778
  }
1679
- addExpressionsToReferences(...expressions) {
1680
- for (const expression of expressions) {
1681
- if (!(0, reflection_1.isBinaryExpression)(expression)) {
1682
- this.references.expressions.add(expression);
1683
- }
1684
- }
1685
- }
1686
1779
  // TODO: bitshift
1687
1780
  additive() {
1688
1781
  let expr = this.multiplicative();
1689
1782
  while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
1690
1783
  let operator = this.previous();
1691
1784
  let right = this.multiplicative();
1692
- this.addExpressionsToReferences(expr, right);
1693
- expr = new Expression_1.BinaryExpression(expr, operator, right);
1785
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1694
1786
  }
1695
1787
  return expr;
1696
1788
  }
@@ -1699,8 +1791,7 @@ class Parser {
1699
1791
  while (this.matchAny(TokenKind_1.TokenKind.Forwardslash, TokenKind_1.TokenKind.Backslash, TokenKind_1.TokenKind.Star, TokenKind_1.TokenKind.Mod, TokenKind_1.TokenKind.LeftShift, TokenKind_1.TokenKind.RightShift)) {
1700
1792
  let operator = this.previous();
1701
1793
  let right = this.exponential();
1702
- this.addExpressionsToReferences(expr, right);
1703
- expr = new Expression_1.BinaryExpression(expr, operator, right);
1794
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1704
1795
  }
1705
1796
  return expr;
1706
1797
  }
@@ -1709,40 +1800,74 @@ class Parser {
1709
1800
  while (this.match(TokenKind_1.TokenKind.Caret)) {
1710
1801
  let operator = this.previous();
1711
1802
  let right = this.prefixUnary();
1712
- this.addExpressionsToReferences(expr, right);
1713
- expr = new Expression_1.BinaryExpression(expr, operator, right);
1803
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1714
1804
  }
1715
1805
  return expr;
1716
1806
  }
1717
1807
  prefixUnary() {
1718
1808
  const nextKind = this.peek().kind;
1719
- if (nextKind === TokenKind_1.TokenKind.Not || nextKind === TokenKind_1.TokenKind.Minus) {
1809
+ if (nextKind === TokenKind_1.TokenKind.Not) {
1720
1810
  this.current++; //advance
1721
1811
  let operator = this.previous();
1722
- let right = this.prefixUnary();
1723
- return new Expression_1.UnaryExpression(operator, right);
1812
+ let right = this.relational();
1813
+ return new Expression_1.UnaryExpression({ operator: operator, right: right });
1814
+ }
1815
+ else if (nextKind === TokenKind_1.TokenKind.Minus || nextKind === TokenKind_1.TokenKind.Plus) {
1816
+ this.current++; //advance
1817
+ let operator = this.previous();
1818
+ let right = nextKind === TokenKind_1.TokenKind.Not
1819
+ ? this.boolean()
1820
+ : this.prefixUnary();
1821
+ return new Expression_1.UnaryExpression({ operator: operator, right: right });
1724
1822
  }
1725
1823
  return this.call();
1726
1824
  }
1727
1825
  indexedGet(expr) {
1728
1826
  let openingSquare = this.previous();
1729
1827
  let questionDotToken = this.getMatchingTokenAtOffset(-2, TokenKind_1.TokenKind.QuestionDot);
1828
+ let indexes = [];
1829
+ //consume leading newlines
1730
1830
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
1731
- let index = this.expression();
1831
+ try {
1832
+ indexes.push(this.expression());
1833
+ //consume additional indexes separated by commas
1834
+ while (this.check(TokenKind_1.TokenKind.Comma)) {
1835
+ //discard the comma
1836
+ this.advance();
1837
+ indexes.push(this.expression());
1838
+ }
1839
+ }
1840
+ catch (error) {
1841
+ this.rethrowNonDiagnosticError(error);
1842
+ }
1843
+ //consume trailing newlines
1732
1844
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
1733
- let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
1734
- return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare, questionDotToken);
1845
+ const closingSquare = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
1846
+ return new Expression_1.IndexedGetExpression({
1847
+ obj: expr,
1848
+ indexes: indexes,
1849
+ openingSquare: openingSquare,
1850
+ closingSquare: closingSquare,
1851
+ questionDot: questionDotToken
1852
+ });
1735
1853
  }
1736
1854
  newExpression() {
1855
+ var _a;
1737
1856
  this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
1738
1857
  let newToken = this.advance();
1739
- let nameExpr = this.getNamespacedVariableNameExpression();
1740
- let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen);
1858
+ let nameExpr = this.identifyingExpression();
1859
+ let leftParen = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen);
1860
+ if (!leftParen) {
1861
+ // new expression without a following call expression
1862
+ // wrap the name in an expression
1863
+ const endOfStatementRange = util_1.util.createRangeFromPositions(newToken.range.end, (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.range.end);
1864
+ const exprStmt = nameExpr !== null && nameExpr !== void 0 ? nameExpr : (0, creators_1.createStringLiteral)('', endOfStatementRange);
1865
+ return new Statement_1.ExpressionStatement({ expression: exprStmt });
1866
+ }
1741
1867
  let call = this.finishCall(leftParen, nameExpr);
1742
1868
  //pop the call from the callExpressions list because this is technically something else
1743
1869
  this.callExpressions.pop();
1744
- let result = new Expression_1.NewExpression(newToken, call);
1745
- this._references.newExpressions.push(result);
1870
+ let result = new Expression_1.NewExpression({ new: newToken, call: call });
1746
1871
  return result;
1747
1872
  }
1748
1873
  /**
@@ -1756,28 +1881,29 @@ class Parser {
1756
1881
  methodName.kind = TokenKind_1.TokenKind.Identifier;
1757
1882
  let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), TokenKind_1.TokenKind.LeftParen);
1758
1883
  let call = this.finishCall(openParen, callee, false);
1759
- return new Expression_1.CallfuncExpression(callee, operator, methodName, openParen, call.args, call.closingParen);
1884
+ return new Expression_1.CallfuncExpression({
1885
+ callee: callee,
1886
+ operator: operator,
1887
+ methodName: methodName,
1888
+ openingParen: openParen,
1889
+ args: call.args,
1890
+ closingParen: call.tokens.closingParen
1891
+ });
1760
1892
  }
1761
1893
  call() {
1762
1894
  if (this.check(TokenKind_1.TokenKind.New) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
1763
1895
  return this.newExpression();
1764
1896
  }
1765
1897
  let expr = this.primary();
1766
- //an expression to keep for _references
1767
- let referenceCallExpression;
1768
1898
  while (true) {
1769
1899
  if (this.matchAny(TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen)) {
1770
1900
  expr = this.finishCall(this.previous(), expr);
1771
- //store this call expression in references
1772
- referenceCallExpression = expr;
1773
1901
  }
1774
1902
  else if (this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.QuestionLeftSquare) || this.matchSequence(TokenKind_1.TokenKind.QuestionDot, TokenKind_1.TokenKind.LeftSquareBracket)) {
1775
1903
  expr = this.indexedGet(expr);
1776
1904
  }
1777
1905
  else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
1778
1906
  expr = this.callfunc(expr);
1779
- //store this callfunc expression in references
1780
- referenceCallExpression = expr;
1781
1907
  }
1782
1908
  else if (this.matchAny(TokenKind_1.TokenKind.Dot, TokenKind_1.TokenKind.QuestionDot)) {
1783
1909
  if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
@@ -1785,19 +1911,24 @@ class Parser {
1785
1911
  }
1786
1912
  else {
1787
1913
  let dot = this.previous();
1788
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1914
+ let name = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1915
+ if (!name) {
1916
+ break;
1917
+ }
1789
1918
  // force it into an identifier so the AST makes some sense
1790
1919
  name.kind = TokenKind_1.TokenKind.Identifier;
1791
- expr = new Expression_1.DottedGetExpression(expr, name, dot);
1792
- this.addPropertyHints(name);
1920
+ expr = new Expression_1.DottedGetExpression({ obj: expr, name: name, dot: dot });
1793
1921
  }
1794
1922
  }
1795
1923
  else if (this.checkAny(TokenKind_1.TokenKind.At, TokenKind_1.TokenKind.QuestionAt)) {
1796
1924
  let dot = this.advance();
1797
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1925
+ let name = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1798
1926
  // force it into an identifier so the AST makes some sense
1799
1927
  name.kind = TokenKind_1.TokenKind.Identifier;
1800
- expr = new Expression_1.XmlAttributeGetExpression(expr, name, dot);
1928
+ if (!name) {
1929
+ break;
1930
+ }
1931
+ expr = new Expression_1.XmlAttributeGetExpression({ obj: expr, name: name, at: dot });
1801
1932
  //only allow a single `@` expression
1802
1933
  break;
1803
1934
  }
@@ -1805,10 +1936,6 @@ class Parser {
1805
1936
  break;
1806
1937
  }
1807
1938
  }
1808
- //if we found a callExpression, add it to `expressions` in references
1809
- if (referenceCallExpression) {
1810
- this._references.expressions.add(referenceCallExpression);
1811
- }
1812
1939
  return expr;
1813
1940
  }
1814
1941
  finishCall(openingParen, callee, addToCallExpressionList = true) {
@@ -1821,68 +1948,109 @@ class Parser {
1821
1948
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
1822
1949
  throw this.lastDiagnosticAsError();
1823
1950
  }
1824
- args.push(this.expression());
1951
+ try {
1952
+ args.push(this.expression());
1953
+ }
1954
+ catch (error) {
1955
+ this.rethrowNonDiagnosticError(error);
1956
+ // we were unable to get an expression, so don't continue
1957
+ break;
1958
+ }
1825
1959
  } while (this.match(TokenKind_1.TokenKind.Comma));
1826
1960
  }
1827
1961
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
1828
- const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
1829
- let expression = new Expression_1.CallExpression(callee, openingParen, closingParen, args, this.currentNamespaceName);
1962
+ const closingParen = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
1963
+ let expression = new Expression_1.CallExpression({
1964
+ callee: callee,
1965
+ openingParen: openingParen,
1966
+ args: args,
1967
+ closingParen: closingParen
1968
+ });
1830
1969
  if (addToCallExpressionList) {
1831
1970
  this.callExpressions.push(expression);
1832
1971
  }
1833
1972
  return expression;
1834
1973
  }
1835
1974
  /**
1836
- * Tries to get the next token as a type
1837
- * Allows for built-in types (double, string, etc.) or namespaced custom types in Brighterscript mode
1838
- * Will return a token of whatever is next to be parsed (unless `advanceIfUnknown` is false, in which case undefined will be returned instead
1975
+ * Creates a TypeExpression, which wraps standard ASTNodes that represent a BscType
1839
1976
  */
1840
1977
  typeExpression() {
1841
- let typeToken;
1842
- if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
1843
- // Token is a built in type
1844
- typeToken = this.advance();
1845
- }
1846
- else if (this.options.mode === ParseMode.BrighterScript) {
1847
- try {
1848
- // see if we can get a namespaced identifier
1849
- const qualifiedType = this.getNamespacedVariableNameExpression();
1850
- typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
1978
+ const changedTokens = [];
1979
+ try {
1980
+ let expr = this.getTypeExpressionPart(changedTokens);
1981
+ while (this.options.mode === ParseMode.BrighterScript && this.matchAny(TokenKind_1.TokenKind.Or)) {
1982
+ // If we're in Brighterscript mode, allow union types with "or" between types
1983
+ // TODO: Handle Union types in parens? eg. "(string or integer)"
1984
+ let operator = this.previous();
1985
+ let right = this.getTypeExpressionPart(changedTokens);
1986
+ if (right) {
1987
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1988
+ }
1989
+ else {
1990
+ break;
1991
+ }
1992
+ }
1993
+ if (expr) {
1994
+ return new Expression_1.TypeExpression({ expression: expr });
1851
1995
  }
1852
- catch (_a) {
1853
- //could not get an identifier - just get whatever's next
1854
- typeToken = this.advance();
1996
+ }
1997
+ catch (error) {
1998
+ // Something went wrong - reset the kind to what it was previously
1999
+ for (const changedToken of changedTokens) {
2000
+ changedToken.token.kind = changedToken.oldKind;
1855
2001
  }
2002
+ throw error;
2003
+ }
2004
+ }
2005
+ /**
2006
+ * Gets a single "part" of a type of a potential Union type
2007
+ * Note: this does not NEED to be part of a union type, but the logic is the same
2008
+ *
2009
+ * @param changedTokens an array that is modified with any tokens that have been changed from their default kind to identifiers - eg. when a keyword is used as type
2010
+ * @returns an expression that was successfully parsed
2011
+ */
2012
+ getTypeExpressionPart(changedTokens) {
2013
+ let expr;
2014
+ if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
2015
+ // if this is just a type, just use directly
2016
+ expr = new Expression_1.VariableExpression({ name: this.advance() });
1856
2017
  }
1857
2018
  else {
1858
- // just get whatever's next
1859
- typeToken = this.advance();
2019
+ if (this.checkAny(...TokenKind_1.AllowedTypeIdentifiers)) {
2020
+ // Since the next token is allowed as a type identifier, change the kind
2021
+ let nextToken = this.peek();
2022
+ changedTokens.push({ token: nextToken, oldKind: nextToken.kind });
2023
+ nextToken.kind = TokenKind_1.TokenKind.Identifier;
2024
+ }
2025
+ expr = this.identifyingExpression(TokenKind_1.AllowedTypeIdentifiers);
1860
2026
  }
1861
- //TODO: to support InterfaceTypeLiterals - (eg. `{name as string; age as integer}`), check if "typeToken" is a curly bracket, and do something else
1862
- let typeExpr = new Expression_1.TypeExpression({ type: typeToken }, this.currentNamespaceName);
1863
- if (this.options.mode === ParseMode.BrighterScript) {
2027
+ //Check if it has square brackets, thus making it an array
2028
+ if (expr && this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
2029
+ if (this.options.mode === ParseMode.BrightScript) {
2030
+ // typed arrays not allowed in Brightscript
2031
+ this.warnIfNotBrighterScriptMode('typed arrays');
2032
+ return expr;
2033
+ }
1864
2034
  // Check if it is an array - that is, if it has `[]` after the type
1865
- // eg. `string[]` or `SomeKlass[]` or `float[][][]`
2035
+ // eg. `string[]` or `SomeKlass[]`
2036
+ // This is while loop, so it supports multidimensional arrays (eg. integer[][])
1866
2037
  while (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
1867
2038
  const leftBracket = this.advance();
1868
2039
  if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1869
2040
  const rightBracket = this.advance();
1870
- typeExpr = new Expression_1.ArrayTypeExpression([typeExpr], { leftBracket: leftBracket, rightBracket: rightBracket }, this.currentNamespaceName);
1871
- }
1872
- else {
1873
- break;
2041
+ expr = new Expression_1.TypedArrayExpression({ innerType: expr, leftBracket: leftBracket, rightBracket: rightBracket });
1874
2042
  }
1875
2043
  }
1876
2044
  }
1877
- return typeExpr;
2045
+ return expr;
1878
2046
  }
1879
2047
  primary() {
1880
2048
  switch (true) {
1881
2049
  case this.matchAny(TokenKind_1.TokenKind.False, TokenKind_1.TokenKind.True, TokenKind_1.TokenKind.Invalid, TokenKind_1.TokenKind.IntegerLiteral, TokenKind_1.TokenKind.LongIntegerLiteral, TokenKind_1.TokenKind.FloatLiteral, TokenKind_1.TokenKind.DoubleLiteral, TokenKind_1.TokenKind.StringLiteral):
1882
- return new Expression_1.LiteralExpression(this.previous());
2050
+ return new Expression_1.LiteralExpression({ value: this.previous() });
1883
2051
  //capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript)
1884
2052
  case this.matchAny(TokenKind_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : TokenKind_1.BrighterScriptSourceLiterals)):
1885
- return new Expression_1.SourceLiteralExpression(this.previous());
2053
+ return new Expression_1.SourceLiteralExpression({ value: this.previous() });
1886
2054
  //template string
1887
2055
  case this.check(TokenKind_1.TokenKind.BackTick):
1888
2056
  return this.templateString(false);
@@ -1890,12 +2058,12 @@ class Parser {
1890
2058
  case this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers) && this.checkNext(TokenKind_1.TokenKind.BackTick):
1891
2059
  return this.templateString(true);
1892
2060
  case this.matchAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
1893
- return new Expression_1.VariableExpression(this.previous(), this.currentNamespaceName);
2061
+ return new Expression_1.VariableExpression({ name: this.previous() });
1894
2062
  case this.match(TokenKind_1.TokenKind.LeftParen):
1895
2063
  let left = this.previous();
1896
2064
  let expr = this.expression();
1897
2065
  let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
1898
- return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
2066
+ return new Expression_1.GroupingExpression({ leftParen: left, rightParen: right, expression: expr });
1899
2067
  case this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket):
1900
2068
  return this.arrayLiteral();
1901
2069
  case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
@@ -1904,13 +2072,13 @@ class Parser {
1904
2072
  let token = Object.assign(this.previous(), {
1905
2073
  kind: TokenKind_1.TokenKind.Identifier
1906
2074
  });
1907
- return new Expression_1.VariableExpression(token, this.currentNamespaceName);
2075
+ return new Expression_1.VariableExpression({ name: token });
1908
2076
  case this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub):
1909
2077
  return this.anonymousFunction();
1910
2078
  case this.check(TokenKind_1.TokenKind.RegexLiteral):
1911
2079
  return this.regexLiteralExpression();
1912
2080
  case this.check(TokenKind_1.TokenKind.Comment):
1913
- return new Statement_1.CommentStatement([this.advance()]);
2081
+ return new Statement_1.CommentStatement({ comments: [this.advance()] });
1914
2082
  default:
1915
2083
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
1916
2084
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -1928,29 +2096,37 @@ class Parser {
1928
2096
  let openingSquare = this.previous();
1929
2097
  //add any comment found right after the opening square
1930
2098
  if (this.check(TokenKind_1.TokenKind.Comment)) {
1931
- elements.push(new Statement_1.CommentStatement([this.advance()]));
2099
+ elements.push(new Statement_1.CommentStatement({ comments: [this.advance()] }));
1932
2100
  }
1933
2101
  while (this.match(TokenKind_1.TokenKind.Newline)) {
1934
2102
  }
2103
+ let closingSquare;
1935
2104
  if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
1936
- elements.push(this.expression());
1937
- while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1938
- if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
1939
- let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
1940
- elements.push(new Statement_1.CommentStatement([comment]));
1941
- }
1942
- while (this.match(TokenKind_1.TokenKind.Newline)) {
1943
- }
1944
- if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
1945
- break;
1946
- }
2105
+ try {
1947
2106
  elements.push(this.expression());
2107
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
2108
+ if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
2109
+ let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
2110
+ elements.push(new Statement_1.CommentStatement({ comments: [comment] }));
2111
+ }
2112
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
2113
+ }
2114
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
2115
+ break;
2116
+ }
2117
+ elements.push(this.expression());
2118
+ }
1948
2119
  }
1949
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
2120
+ catch (error) {
2121
+ this.rethrowNonDiagnosticError(error);
2122
+ }
2123
+ closingSquare = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
2124
+ }
2125
+ else {
2126
+ closingSquare = this.previous();
1950
2127
  }
1951
- let closingSquare = this.previous();
1952
2128
  //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
1953
- return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
2129
+ return new Expression_1.ArrayLiteralExpression({ elements: elements, open: openingSquare, close: closingSquare });
1954
2130
  }
1955
2131
  aaLiteral() {
1956
2132
  let openingBrace = this.previous();
@@ -1976,51 +2152,66 @@ class Parser {
1976
2152
  return result;
1977
2153
  };
1978
2154
  while (this.match(TokenKind_1.TokenKind.Newline)) { }
2155
+ let closingBrace;
1979
2156
  if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
1980
2157
  let lastAAMember;
1981
- if (this.check(TokenKind_1.TokenKind.Comment)) {
1982
- lastAAMember = null;
1983
- members.push(new Statement_1.CommentStatement([this.advance()]));
1984
- }
1985
- else {
1986
- let k = key();
1987
- let expr = this.expression();
1988
- lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
1989
- members.push(lastAAMember);
1990
- }
1991
- while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
1992
- // collect comma at end of expression
1993
- if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
1994
- lastAAMember.commaToken = this.previous();
1995
- }
1996
- //check for comment at the end of the current line
1997
- if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
1998
- let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
1999
- members.push(new Statement_1.CommentStatement([token]));
2158
+ try {
2159
+ if (this.check(TokenKind_1.TokenKind.Comment)) {
2160
+ lastAAMember = null;
2161
+ members.push(new Statement_1.CommentStatement({ comments: [this.advance()] }));
2000
2162
  }
2001
2163
  else {
2002
- this.consumeStatementSeparators(true);
2003
- //check for a comment on its own line
2164
+ let k = key();
2165
+ let expr = this.expression();
2166
+ lastAAMember = new Expression_1.AAMemberExpression({
2167
+ key: k.keyToken,
2168
+ colon: k.colonToken,
2169
+ value: expr
2170
+ });
2171
+ members.push(lastAAMember);
2172
+ }
2173
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
2174
+ // collect comma at end of expression
2175
+ if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
2176
+ lastAAMember.tokens.comma = this.previous();
2177
+ }
2178
+ //check for comment at the end of the current line
2004
2179
  if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
2005
2180
  let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
2006
- lastAAMember = null;
2007
- members.push(new Statement_1.CommentStatement([token]));
2008
- continue;
2181
+ members.push(new Statement_1.CommentStatement({ comments: [token] }));
2009
2182
  }
2010
- if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
2011
- break;
2183
+ else {
2184
+ this.consumeStatementSeparators(true);
2185
+ //check for a comment on its own line
2186
+ if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
2187
+ let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
2188
+ lastAAMember = null;
2189
+ members.push(new Statement_1.CommentStatement({ comments: [token] }));
2190
+ continue;
2191
+ }
2192
+ if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
2193
+ break;
2194
+ }
2195
+ let k = key();
2196
+ let expr = this.expression();
2197
+ lastAAMember = new Expression_1.AAMemberExpression({
2198
+ key: k.keyToken,
2199
+ colon: k.colonToken,
2200
+ value: expr
2201
+ });
2202
+ members.push(lastAAMember);
2012
2203
  }
2013
- let k = key();
2014
- let expr = this.expression();
2015
- lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
2016
- members.push(lastAAMember);
2017
2204
  }
2018
2205
  }
2019
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
2206
+ catch (error) {
2207
+ this.rethrowNonDiagnosticError(error);
2208
+ }
2209
+ closingBrace = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
2020
2210
  }
2021
- let closingBrace = this.previous();
2022
- const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
2023
- this.addPropertyHints(aaExpr);
2211
+ else {
2212
+ closingBrace = this.previous();
2213
+ }
2214
+ const aaExpr = new Expression_1.AALiteralExpression({ elements: members, open: openingBrace, close: closingBrace });
2024
2215
  return aaExpr;
2025
2216
  }
2026
2217
  /**
@@ -2035,7 +2226,7 @@ class Parser {
2035
2226
  }
2036
2227
  /**
2037
2228
  * Pop token if we encounter a token in the specified list
2038
- * @param tokenKinds
2229
+ * @param tokenKinds a list of tokenKinds where any tokenKind in this list will result in a match
2039
2230
  */
2040
2231
  matchAny(...tokenKinds) {
2041
2232
  for (let tokenKind of tokenKinds) {
@@ -2048,7 +2239,7 @@ class Parser {
2048
2239
  }
2049
2240
  /**
2050
2241
  * If the next series of tokens matches the given set of tokens, pop them all
2051
- * @param tokenKinds
2242
+ * @param tokenKinds a list of tokenKinds used to match the next set of tokens
2052
2243
  */
2053
2244
  matchSequence(...tokenKinds) {
2054
2245
  var _a;
@@ -2075,6 +2266,14 @@ class Parser {
2075
2266
  throw error;
2076
2267
  }
2077
2268
  }
2269
+ /**
2270
+ * Consume next token IF it matches the specified kind. Otherwise, do nothing and return undefined
2271
+ */
2272
+ consumeTokenIf(tokenKind) {
2273
+ if (this.match(tokenKind)) {
2274
+ return this.previous();
2275
+ }
2276
+ }
2078
2277
  consumeToken(tokenKind) {
2079
2278
  return this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(tokenKind), tokenKind);
2080
2279
  }
@@ -2121,6 +2320,11 @@ class Parser {
2121
2320
  var _a;
2122
2321
  return ((_a = this.previous()) === null || _a === void 0 ? void 0 : _a.kind) === tokenKind;
2123
2322
  }
2323
+ /**
2324
+ * Check that the next token kind is the expected kind
2325
+ * @param tokenKind the expected next kind
2326
+ * @returns true if the next tokenKind is the expected value
2327
+ */
2124
2328
  check(tokenKind) {
2125
2329
  const nextKind = this.peek().kind;
2126
2330
  if (nextKind === TokenKind_1.TokenKind.Eof) {
@@ -2163,6 +2367,18 @@ class Parser {
2163
2367
  previous() {
2164
2368
  return this.tokens[this.current - 1];
2165
2369
  }
2370
+ /**
2371
+ * Sometimes we catch an error that is a diagnostic.
2372
+ * If that's the case, we want to continue parsing.
2373
+ * Otherwise, re-throw the error
2374
+ *
2375
+ * @param error error caught in a try/catch
2376
+ */
2377
+ rethrowNonDiagnosticError(error) {
2378
+ if (!error.isDiagnostic) {
2379
+ throw error;
2380
+ }
2381
+ }
2166
2382
  /**
2167
2383
  * Get the token that is {offset} indexes away from {this.current}
2168
2384
  * @param offset the number of index steps away from current index to fetch
@@ -2203,398 +2419,6 @@ class Parser {
2203
2419
  this.advance();
2204
2420
  }
2205
2421
  }
2206
- /**
2207
- * Get the token at the specified position
2208
- * @param position
2209
- */
2210
- getTokenAt(position) {
2211
- for (let token of this.tokens) {
2212
- if (util_1.util.rangeContains(token.range, position)) {
2213
- return token;
2214
- }
2215
- }
2216
- }
2217
- /**
2218
- * Get the token closest to the position. if no token is found, the previous token is returned
2219
- * @param position
2220
- * @param tokens
2221
- */
2222
- getClosestToken(position) {
2223
- let tokens = this.tokens;
2224
- for (let i = 0; i < tokens.length; i++) {
2225
- let token = tokens[i];
2226
- if (util_1.util.rangeContains(token.range, position)) {
2227
- return token;
2228
- }
2229
- //if the position less than this token range, then this position touches no token,
2230
- if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
2231
- let t = tokens[i - 1];
2232
- //return the token or the first token
2233
- return t ? t : tokens[0];
2234
- }
2235
- }
2236
- //return the last token
2237
- return tokens[tokens.length - 1];
2238
- }
2239
- isPositionNextToTokenKind(position, tokenKind) {
2240
- const closestToken = this.getClosestToken(position);
2241
- const previousToken = this.getPreviousToken(closestToken);
2242
- const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
2243
- //next to matched token
2244
- if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
2245
- return false;
2246
- }
2247
- else if (closestToken.kind === tokenKind) {
2248
- return true;
2249
- }
2250
- else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
2251
- return false;
2252
- //next to an identifier, which is next to token kind
2253
- }
2254
- else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
2255
- return true;
2256
- }
2257
- else {
2258
- return false;
2259
- }
2260
- }
2261
- getTokenBefore(currentToken, tokenKind) {
2262
- const index = this.tokens.indexOf(currentToken);
2263
- for (let i = index - 1; i >= 0; i--) {
2264
- currentToken = this.tokens[i];
2265
- if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
2266
- break;
2267
- }
2268
- else if (currentToken.kind === tokenKind) {
2269
- return currentToken;
2270
- }
2271
- }
2272
- return undefined;
2273
- }
2274
- tokenFollows(currentToken, tokenKind) {
2275
- const index = this.tokens.indexOf(currentToken);
2276
- if (index > 0) {
2277
- return this.tokens[index - 1].kind === tokenKind;
2278
- }
2279
- return false;
2280
- }
2281
- getTokensUntil(currentToken, tokenKind, direction = -1) {
2282
- let tokens = [];
2283
- for (let i = this.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.tokens.length; i += direction) {
2284
- currentToken = this.tokens[i];
2285
- if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
2286
- break;
2287
- }
2288
- tokens.push(currentToken);
2289
- }
2290
- return tokens;
2291
- }
2292
- getPreviousToken(token) {
2293
- let idx = this.tokens.indexOf(token);
2294
- return this.tokens[idx - 1];
2295
- }
2296
- getPreviousTokenFromIndex(idx) {
2297
- return { token: this.tokens[idx - 1], index: idx - 1 };
2298
- }
2299
- getPreviousTokenIgnoreNests(currentTokenIndex, leftBracketType, rightBracketType) {
2300
- let currentToken = this.tokens[currentTokenIndex];
2301
- let previousTokenResult;
2302
- function isRightBracket(token) {
2303
- return (token === null || token === void 0 ? void 0 : token.kind) === rightBracketType;
2304
- }
2305
- function isLeftBracket(token) {
2306
- return (token === null || token === void 0 ? void 0 : token.kind) === leftBracketType;
2307
- }
2308
- let lastTokenHadLeadingWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
2309
- let lastTokenWasLeftBracket = false;
2310
- let bracketNestCount = 0;
2311
- let hasBrackets = false;
2312
- // check for nested function call
2313
- if (isRightBracket(currentToken)) {
2314
- bracketNestCount++;
2315
- hasBrackets = true;
2316
- }
2317
- while (currentToken && bracketNestCount > 0) {
2318
- previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
2319
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2320
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2321
- lastTokenWasLeftBracket = false;
2322
- if (isRightBracket(currentToken)) {
2323
- bracketNestCount++;
2324
- }
2325
- while (isLeftBracket(currentToken)) {
2326
- bracketNestCount--;
2327
- lastTokenWasLeftBracket = true;
2328
- lastTokenHadLeadingWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
2329
- previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
2330
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2331
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2332
- }
2333
- }
2334
- const isLiteral = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.StringLiteral || (currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.IntegerLiteral || (currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.FloatLiteral || (currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.Boolean;
2335
- // We will not be able to decipher the token type if it was in brackets
2336
- // e.g (someVar+otherVar).toStr() -- we don't bother trying to decipher what "(someVar+otherVar)" is
2337
- let isUnknown = isLiteral || (lastTokenWasLeftBracket && (lastTokenHadLeadingWhitespace || !this.isAcceptableChainToken(currentToken)));
2338
- const tokenWithIndex = { token: currentToken, index: currentTokenIndex, tokenTypeIsNotKnowable: isUnknown, hasBrackets: hasBrackets };
2339
- return tokenWithIndex;
2340
- }
2341
- /**
2342
- * Finds the previous token in a chain (e.g. 'm.obj.func(someFunc()).value'), skipping over any arguments of function calls
2343
- * If this function was called with the token at 'value' above, the previous identifier in the chain is 'func'
2344
- * @param currentTokenIndex token index to start from
2345
- * @param allowCurrent can the current token be the token that's the identifier?
2346
- * @returns the previous identifer
2347
- */
2348
- getPreviousTokenInChain(currentTokenIndex, allowCurrent = false) {
2349
- let currentToken = this.tokens[currentTokenIndex];
2350
- let previousTokenResult;
2351
- let usage = TokenUsage.Direct;
2352
- if (!allowCurrent) {
2353
- previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
2354
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2355
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2356
- }
2357
- if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.Dot || (currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.QuestionDot) {
2358
- previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
2359
- currentToken = previousTokenResult.token;
2360
- currentTokenIndex = previousTokenResult.index;
2361
- }
2362
- previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.RightParen);
2363
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2364
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2365
- if (previousTokenResult.hasBrackets) {
2366
- usage = TokenUsage.Call;
2367
- }
2368
- let tokenTypeIsNotKnowable = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable;
2369
- if (currentTokenIndex) {
2370
- previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.RightSquareBracket);
2371
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2372
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2373
- if (previousTokenResult.hasBrackets) {
2374
- usage = TokenUsage.ArrayReference;
2375
- }
2376
- }
2377
- tokenTypeIsNotKnowable = tokenTypeIsNotKnowable || (previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
2378
- if (tokenTypeIsNotKnowable || this.isAcceptableChainToken(currentToken)) {
2379
- // either we have a valid chain token, or we can't know what the token type is
2380
- return { token: currentToken, index: currentTokenIndex, tokenTypeIsNotKnowable: tokenTypeIsNotKnowable, usage: usage };
2381
- }
2382
- return undefined;
2383
- }
2384
- isAcceptableChainToken(currentToken, lastTokenHasWhitespace = false) {
2385
- if (!currentToken || lastTokenHasWhitespace) {
2386
- return false;
2387
- }
2388
- if (currentToken.kind === TokenKind_1.TokenKind.Identifier) {
2389
- return true;
2390
- }
2391
- if (currentToken.leadingWhitespace.length === 0) {
2392
- // start of the chain
2393
- return TokenKind_1.AllowedLocalIdentifiers.includes(currentToken.kind);
2394
- }
2395
- // not the start of the chain
2396
- return TokenKind_1.AllowedProperties.includes(currentToken.kind);
2397
- }
2398
- /**
2399
- * Builds up a chain of tokens, starting with the first in the chain, and ending with currentToken
2400
- * e.g. m.prop.method().field (with 'field' as currentToken) -> ["m", "prop", "method", "field"], with each element as a token
2401
- * @param currentToken the token that is the end of the chain
2402
- * @returns array of tokens
2403
- */
2404
- getTokenChain(currentToken) {
2405
- const tokenChain = [];
2406
- let currentTokenIndex = this.tokens.indexOf(currentToken);
2407
- let previousTokenResult;
2408
- let lastTokenHasWhitespace = false;
2409
- let includesUnknown = false;
2410
- previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex, true);
2411
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2412
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2413
- if (this.isAcceptableChainToken(currentToken)) {
2414
- tokenChain.push(previousTokenResult);
2415
- lastTokenHasWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
2416
- }
2417
- if (!lastTokenHasWhitespace) {
2418
- previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex);
2419
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2420
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2421
- includesUnknown = !!(previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
2422
- while (!includesUnknown && this.isAcceptableChainToken(currentToken, lastTokenHasWhitespace)) {
2423
- tokenChain.push(previousTokenResult);
2424
- lastTokenHasWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
2425
- if (!lastTokenHasWhitespace) {
2426
- previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex);
2427
- currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
2428
- currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
2429
- includesUnknown = includesUnknown || (previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
2430
- }
2431
- }
2432
- }
2433
- tokenChain.reverse();
2434
- return { chain: tokenChain, includesUnknowableTokenType: !!includesUnknown };
2435
- }
2436
- /**
2437
- * References are found during the initial parse.
2438
- * However, sometimes plugins can modify the AST, requiring a full walk to re-compute all references.
2439
- * This does that walk.
2440
- */
2441
- findReferences() {
2442
- this._references = new References();
2443
- const excludedExpressions = new Set();
2444
- const visitCallExpression = (e) => {
2445
- for (const p of e.args) {
2446
- this._references.expressions.add(p);
2447
- }
2448
- //add calls that were not excluded (from loop below)
2449
- if (!excludedExpressions.has(e)) {
2450
- this._references.expressions.add(e);
2451
- }
2452
- //if this call is part of a longer expression that includes a call higher up, find that higher one and remove it
2453
- if (e.callee) {
2454
- let node = e.callee;
2455
- while (node) {
2456
- //the primary goal for this loop. If we found a parent call expression, remove it from `references`
2457
- if ((0, reflection_1.isCallExpression)(node)) {
2458
- this.references.expressions.delete(node);
2459
- excludedExpressions.add(node);
2460
- //stop here. even if there are multiple calls in the chain, each child will find and remove its closest parent, so that reduces excess walking.
2461
- break;
2462
- //when we hit a variable expression, we're definitely at the leftmost expression so stop
2463
- }
2464
- else if ((0, reflection_1.isVariableExpression)(node)) {
2465
- break;
2466
- //if
2467
- }
2468
- else if ((0, reflection_1.isDottedGetExpression)(node) || (0, reflection_1.isIndexedGetExpression)(node)) {
2469
- node = node.obj;
2470
- }
2471
- else {
2472
- //some expression we don't understand. log it and quit the loop
2473
- this.logger.info('Encountered unknown expression while calculating function expression chain', node);
2474
- break;
2475
- }
2476
- }
2477
- }
2478
- };
2479
- //gather up all the top-level statements
2480
- this.ast.walk((0, visitors_1.createVisitor)({
2481
- AssignmentStatement: s => {
2482
- this._references.assignmentStatements.push(s);
2483
- this.references.expressions.add(s.value);
2484
- },
2485
- ClassStatement: s => {
2486
- this._references.classStatements.push(s);
2487
- },
2488
- FieldStatement: s => {
2489
- if (s.initialValue) {
2490
- this._references.expressions.add(s.initialValue);
2491
- }
2492
- },
2493
- InterfaceStatement: s => {
2494
- this._references.interfaceStatements.push(s);
2495
- },
2496
- NamespaceStatement: s => {
2497
- this._references.namespaceStatements.push(s);
2498
- },
2499
- FunctionStatement: s => {
2500
- this._references.functionStatements.push(s);
2501
- },
2502
- ImportStatement: s => {
2503
- this._references.importStatements.push(s);
2504
- },
2505
- LibraryStatement: s => {
2506
- this._references.libraryStatements.push(s);
2507
- },
2508
- FunctionExpression: (expression, parent) => {
2509
- if (!(0, reflection_1.isMethodStatement)(parent) && !(0, reflection_1.isInterfaceMethodStatement)(parent)) {
2510
- this._references.functionExpressions.push(expression);
2511
- }
2512
- },
2513
- NewExpression: e => {
2514
- this._references.newExpressions.push(e);
2515
- for (const p of e.call.args) {
2516
- this._references.expressions.add(p);
2517
- }
2518
- },
2519
- ExpressionStatement: s => {
2520
- this._references.expressions.add(s.expression);
2521
- },
2522
- CallfuncExpression: e => {
2523
- visitCallExpression(e);
2524
- },
2525
- CallExpression: e => {
2526
- visitCallExpression(e);
2527
- },
2528
- AALiteralExpression: e => {
2529
- this.addPropertyHints(e);
2530
- this._references.expressions.add(e);
2531
- for (const member of e.elements) {
2532
- if ((0, reflection_1.isAAMemberExpression)(member)) {
2533
- this._references.expressions.add(member.value);
2534
- }
2535
- }
2536
- },
2537
- BinaryExpression: (e, parent) => {
2538
- //walk the chain of binary expressions and add each one to the list of expressions
2539
- const expressions = [e];
2540
- let expression;
2541
- while ((expression = expressions.pop())) {
2542
- if ((0, reflection_1.isBinaryExpression)(expression)) {
2543
- expressions.push(expression.left, expression.right);
2544
- }
2545
- else {
2546
- this._references.expressions.add(expression);
2547
- }
2548
- }
2549
- },
2550
- ArrayLiteralExpression: e => {
2551
- for (const element of e.elements) {
2552
- //keep everything except comments
2553
- if (!(0, reflection_1.isCommentStatement)(element)) {
2554
- this._references.expressions.add(element);
2555
- }
2556
- }
2557
- },
2558
- DottedGetExpression: e => {
2559
- this.addPropertyHints(e.name);
2560
- },
2561
- DottedSetStatement: e => {
2562
- this.addPropertyHints(e.name);
2563
- },
2564
- EnumStatement: e => {
2565
- this._references.enumStatements.push(e);
2566
- },
2567
- ConstStatement: s => {
2568
- this._references.constStatements.push(s);
2569
- },
2570
- UnaryExpression: e => {
2571
- this._references.expressions.add(e);
2572
- },
2573
- IncrementStatement: e => {
2574
- this._references.expressions.add(e);
2575
- }
2576
- }), {
2577
- walkMode: visitors_1.WalkMode.visitAllRecursive
2578
- });
2579
- }
2580
- getContainingExpression(currentToken) {
2581
- return [...this.references.expressions].find((cs) => util_1.util.rangeContainsRange(cs.range, currentToken.range));
2582
- }
2583
- getContainingClass(currentToken) {
2584
- return this.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
2585
- }
2586
- getContainingAA(currentToken) {
2587
- return this.references.aaLiterals.find((aa) => util_1.util.rangeContains(aa.range, currentToken.range.start));
2588
- }
2589
- getContainingNamespace(currentToken) {
2590
- return this.references.namespaceStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
2591
- }
2592
- getContainingFunctionExpression(currentToken) {
2593
- return this.getContainingFunctionExpressionByPosition(currentToken.range.start);
2594
- }
2595
- getContainingFunctionExpressionByPosition(position) {
2596
- return this.references.functionExpressions.find((fe) => util_1.util.rangeContains(fe.range, position));
2597
- }
2598
2422
  dispose() {
2599
2423
  }
2600
2424
  }
@@ -2604,154 +2428,9 @@ var ParseMode;
2604
2428
  ParseMode["BrightScript"] = "BrightScript";
2605
2429
  ParseMode["BrighterScript"] = "BrighterScript";
2606
2430
  })(ParseMode = exports.ParseMode || (exports.ParseMode = {}));
2607
- class References {
2608
- constructor() {
2609
- this.cache = new Cache_1.Cache();
2610
- this.assignmentStatements = [];
2611
- this.classStatements = [];
2612
- this.dottedSetStatements = [];
2613
- this.aaLiterals = [];
2614
- this.functionExpressions = [];
2615
- this.functionStatements = [];
2616
- this.interfaceStatements = [];
2617
- this.enumStatements = [];
2618
- this.constStatements = [];
2619
- /**
2620
- * A collection of full expressions. This excludes intermediary expressions.
2621
- *
2622
- * Example 1:
2623
- * `a.b.c` is composed of `a` (variableExpression) `.b` (DottedGetExpression) `.c` (DottedGetExpression)
2624
- * This will only contain the final `.c` DottedGetExpression because `.b` and `a` can both be derived by walking back from the `.c` DottedGetExpression.
2625
- *
2626
- * Example 2:
2627
- * `name.space.doSomething(a.b.c)` will result in 2 entries in this list. the `CallExpression` for `doSomething`, and the `.c` DottedGetExpression.
2628
- *
2629
- * Example 3:
2630
- * `value = SomeEnum.value > 2 or SomeEnum.otherValue < 10` will result in 4 entries. `SomeEnum.value`, `2`, `SomeEnum.otherValue`, `10`
2631
- */
2632
- this.expressions = new Set();
2633
- this.importStatements = [];
2634
- this.libraryStatements = [];
2635
- this.namespaceStatements = [];
2636
- this.newExpressions = [];
2637
- this.propertyHints = {};
2638
- }
2639
- get classStatementLookup() {
2640
- if (!this._classStatementLookup) {
2641
- this._classStatementLookup = new Map();
2642
- for (const stmt of this.classStatements) {
2643
- this._classStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2644
- }
2645
- }
2646
- return this._classStatementLookup;
2647
- }
2648
- /**
2649
- * A map of function statements, indexed by fully-namespaced lower function name.
2650
- */
2651
- get functionStatementLookup() {
2652
- if (!this._functionStatementLookup) {
2653
- this._functionStatementLookup = new Map();
2654
- for (const stmt of this.functionStatements) {
2655
- this._functionStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2656
- }
2657
- }
2658
- return this._functionStatementLookup;
2659
- }
2660
- get interfaceStatementLookup() {
2661
- if (!this._interfaceStatementLookup) {
2662
- this._interfaceStatementLookup = new Map();
2663
- for (const stmt of this.interfaceStatements) {
2664
- this._interfaceStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2665
- }
2666
- }
2667
- return this._interfaceStatementLookup;
2668
- }
2669
- get enumStatementLookup() {
2670
- return this.cache.getOrAdd('enums', () => {
2671
- const result = new Map();
2672
- for (const stmt of this.enumStatements) {
2673
- result.set(stmt.fullName.toLowerCase(), stmt);
2674
- }
2675
- return result;
2676
- });
2677
- }
2678
- get constStatementLookup() {
2679
- return this.cache.getOrAdd('consts', () => {
2680
- const result = new Map();
2681
- for (const stmt of this.constStatements) {
2682
- result.set(stmt.fullName.toLowerCase(), stmt);
2683
- }
2684
- return result;
2685
- });
2686
- }
2687
- }
2688
- exports.References = References;
2689
- var TokenUsage;
2690
- (function (TokenUsage) {
2691
- TokenUsage[TokenUsage["Direct"] = 1] = "Direct";
2692
- TokenUsage[TokenUsage["Call"] = 2] = "Call";
2693
- TokenUsage[TokenUsage["ArrayReference"] = 3] = "ArrayReference";
2694
- })(TokenUsage = exports.TokenUsage || (exports.TokenUsage = {}));
2695
2431
  class CancelStatementError extends Error {
2696
2432
  constructor() {
2697
2433
  super('CancelStatement');
2698
2434
  }
2699
2435
  }
2700
- /**
2701
- * Gets the type of an expression. If it can not be processed, will return DynamicType
2702
- *
2703
- * @param expression the Expression to process
2704
- * @param functionExpression the wrapping function expression
2705
- * @return the best guess type of that expression
2706
- */
2707
- function getBscTypeFromExpression(expression, functionExpression) {
2708
- try {
2709
- if ((0, reflection_1.isFunctionExpression)(expression)) {
2710
- return expression.getFunctionType();
2711
- //literal
2712
- }
2713
- else if ((0, reflection_1.isLiteralExpression)(expression)) {
2714
- return expression.type;
2715
- //Associative array literal
2716
- }
2717
- else if ((0, reflection_1.isAALiteralExpression)(expression)) {
2718
- return new ObjectType_1.ObjectType('object', expression.memberTable);
2719
- //Array literal
2720
- }
2721
- else if ((0, reflection_1.isArrayLiteralExpression)(expression)) {
2722
- const innerTypes = expression.elements.filter((element) => !(0, reflection_1.isCommentStatement)(element)).map((element) => {
2723
- return getBscTypeFromExpression(element, functionExpression);
2724
- });
2725
- return new ArrayType_1.ArrayType(...innerTypes);
2726
- //function call
2727
- }
2728
- else if (functionExpression) {
2729
- // These are more precise, and can't be determined without knowing the function expression you're in
2730
- if ((0, reflection_1.isNewExpression)(expression)) {
2731
- return (0, helpers_1.getTypeFromNewExpression)(expression, functionExpression);
2732
- }
2733
- else if ((0, reflection_1.isCallExpression)(expression)) {
2734
- return (0, helpers_1.getTypeFromCallExpression)(expression, functionExpression);
2735
- }
2736
- else if ((0, reflection_1.isVariableExpression)(expression)) {
2737
- return (0, helpers_1.getTypeFromVariableExpression)(expression, functionExpression);
2738
- }
2739
- else if ((0, reflection_1.isDottedGetExpression)(expression)) {
2740
- return (0, helpers_1.getTypeFromDottedGetExpression)(expression, functionExpression);
2741
- }
2742
- else if ((0, reflection_1.isIndexedGetExpression)(expression)) {
2743
- const source = getBscTypeFromExpression(expression.obj, functionExpression);
2744
- if ((0, reflection_1.isArrayType)(source)) {
2745
- return source.getDefaultType();
2746
- }
2747
- }
2748
- }
2749
- }
2750
- catch (e) {
2751
- //do nothing. Just return dynamic
2752
- }
2753
- //fallback to dynamic
2754
- return DynamicType_1.DynamicType.instance;
2755
- }
2756
- exports.getBscTypeFromExpression = getBscTypeFromExpression;
2757
2436
  //# sourceMappingURL=Parser.js.map