brighterscript 1.0.0-alpha.4 → 1.0.0-alpha.41

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 (620) hide show
  1. package/CHANGELOG.md +1393 -291
  2. package/README.md +72 -131
  3. package/bsconfig.schema.json +85 -1
  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 +42 -0
  8. package/dist/AstValidationSegmenter.js +237 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +56 -6
  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.d.ts +5 -6
  15. package/dist/Cache.js +12 -11
  16. package/dist/Cache.js.map +1 -1
  17. package/dist/CacheVerifier.d.ts +7 -0
  18. package/dist/CacheVerifier.js +20 -0
  19. package/dist/CacheVerifier.js.map +1 -0
  20. package/dist/CodeActionUtil.d.ts +6 -3
  21. package/dist/CodeActionUtil.js +19 -5
  22. package/dist/CodeActionUtil.js.map +1 -1
  23. package/dist/CommentFlagProcessor.d.ts +7 -6
  24. package/dist/CommentFlagProcessor.js +11 -8
  25. package/dist/CommentFlagProcessor.js.map +1 -1
  26. package/dist/CrossScopeValidator.d.ts +67 -0
  27. package/dist/CrossScopeValidator.js +617 -0
  28. package/dist/CrossScopeValidator.js.map +1 -0
  29. package/dist/DependencyGraph.d.ts +8 -3
  30. package/dist/DependencyGraph.js +49 -16
  31. package/dist/DependencyGraph.js.map +1 -1
  32. package/dist/DiagnosticCollection.d.ts +5 -3
  33. package/dist/DiagnosticCollection.js +21 -16
  34. package/dist/DiagnosticCollection.js.map +1 -1
  35. package/dist/DiagnosticFilterer.d.ts +8 -4
  36. package/dist/DiagnosticFilterer.js +90 -54
  37. package/dist/DiagnosticFilterer.js.map +1 -1
  38. package/dist/DiagnosticManager.d.ts +61 -0
  39. package/dist/DiagnosticManager.js +238 -0
  40. package/dist/DiagnosticManager.js.map +1 -0
  41. package/dist/DiagnosticMessages.d.ts +204 -24
  42. package/dist/DiagnosticMessages.js +266 -33
  43. package/dist/DiagnosticMessages.js.map +1 -1
  44. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  45. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  46. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  47. package/dist/FunctionScope.d.ts +28 -0
  48. package/dist/FunctionScope.js +52 -0
  49. package/dist/FunctionScope.js.map +1 -0
  50. package/dist/KeyedThrottler.d.ts +3 -3
  51. package/dist/KeyedThrottler.js +3 -3
  52. package/dist/KeyedThrottler.js.map +1 -1
  53. package/dist/LanguageServer.d.ts +72 -47
  54. package/dist/LanguageServer.js +545 -314
  55. package/dist/LanguageServer.js.map +1 -1
  56. package/dist/Logger.d.ts +9 -10
  57. package/dist/Logger.js +36 -30
  58. package/dist/Logger.js.map +1 -1
  59. package/dist/PluginInterface.d.ts +29 -7
  60. package/dist/PluginInterface.js +90 -7
  61. package/dist/PluginInterface.js.map +1 -1
  62. package/dist/Program.d.ts +201 -100
  63. package/dist/Program.js +1079 -700
  64. package/dist/Program.js.map +1 -1
  65. package/dist/ProgramBuilder.d.ts +29 -18
  66. package/dist/ProgramBuilder.js +178 -141
  67. package/dist/ProgramBuilder.js.map +1 -1
  68. package/dist/Scope.d.ts +144 -109
  69. package/dist/Scope.js +533 -552
  70. package/dist/Scope.js.map +1 -1
  71. package/dist/SemanticTokenUtils.d.ts +14 -0
  72. package/dist/SemanticTokenUtils.js +85 -0
  73. package/dist/SemanticTokenUtils.js.map +1 -0
  74. package/dist/Stopwatch.d.ts +4 -0
  75. package/dist/Stopwatch.js +8 -1
  76. package/dist/Stopwatch.js.map +1 -1
  77. package/dist/SymbolTable.d.ts +91 -24
  78. package/dist/SymbolTable.js +291 -64
  79. package/dist/SymbolTable.js.map +1 -1
  80. package/dist/SymbolTypeFlag.d.ts +9 -0
  81. package/dist/SymbolTypeFlag.js +14 -0
  82. package/dist/SymbolTypeFlag.js.map +1 -0
  83. package/dist/Throttler.d.ts +12 -0
  84. package/dist/Throttler.js +39 -0
  85. package/dist/Throttler.js.map +1 -1
  86. package/dist/Watcher.d.ts +0 -3
  87. package/dist/Watcher.js +0 -3
  88. package/dist/Watcher.js.map +1 -1
  89. package/dist/XmlScope.d.ts +5 -15
  90. package/dist/XmlScope.js +35 -87
  91. package/dist/XmlScope.js.map +1 -1
  92. package/dist/astUtils/CachedLookups.d.ts +50 -0
  93. package/dist/astUtils/CachedLookups.js +335 -0
  94. package/dist/astUtils/CachedLookups.js.map +1 -0
  95. package/dist/astUtils/CachedLookups.spec.js +39 -0
  96. package/dist/astUtils/CachedLookups.spec.js.map +1 -0
  97. package/dist/astUtils/Editor.d.ts +69 -0
  98. package/dist/astUtils/Editor.js +245 -0
  99. package/dist/astUtils/Editor.js.map +1 -0
  100. package/dist/astUtils/Editor.spec.js +258 -0
  101. package/dist/astUtils/Editor.spec.js.map +1 -0
  102. package/dist/astUtils/creators.d.ts +36 -19
  103. package/dist/astUtils/creators.js +222 -43
  104. package/dist/astUtils/creators.js.map +1 -1
  105. package/dist/astUtils/creators.spec.js +5 -5
  106. package/dist/astUtils/creators.spec.js.map +1 -1
  107. package/dist/astUtils/reflection.d.ts +148 -82
  108. package/dist/astUtils/reflection.js +324 -137
  109. package/dist/astUtils/reflection.js.map +1 -1
  110. package/dist/astUtils/reflection.spec.js +267 -167
  111. package/dist/astUtils/reflection.spec.js.map +1 -1
  112. package/dist/astUtils/stackedVisitor.js.map +1 -1
  113. package/dist/astUtils/stackedVisitor.spec.js +14 -14
  114. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  115. package/dist/astUtils/visitors.d.ts +114 -53
  116. package/dist/astUtils/visitors.js +70 -13
  117. package/dist/astUtils/visitors.js.map +1 -1
  118. package/dist/astUtils/visitors.spec.js +463 -51
  119. package/dist/astUtils/visitors.spec.js.map +1 -1
  120. package/dist/astUtils/xml.d.ts +9 -8
  121. package/dist/astUtils/xml.js +10 -5
  122. package/dist/astUtils/xml.js.map +1 -1
  123. package/dist/bscPlugin/BscPlugin.d.ts +22 -1
  124. package/dist/bscPlugin/BscPlugin.js +88 -0
  125. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  126. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  127. package/dist/bscPlugin/CallExpressionInfo.js +135 -0
  128. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  129. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  130. package/dist/bscPlugin/FileWriter.js +24 -0
  131. package/dist/bscPlugin/FileWriter.js.map +1 -0
  132. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  133. package/dist/bscPlugin/SignatureHelpUtil.js +137 -0
  134. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  135. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  136. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +30 -18
  137. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  138. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +94 -21
  139. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  140. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +64 -0
  141. package/dist/bscPlugin/completions/CompletionsProcessor.js +626 -0
  142. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  143. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +2188 -0
  144. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  145. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  146. package/dist/bscPlugin/definition/DefinitionProvider.js +212 -0
  147. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  148. package/dist/bscPlugin/definition/DefinitionProvider.spec.d.ts +1 -0
  149. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +87 -0
  150. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  151. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  152. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  153. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  154. package/dist/bscPlugin/hover/HoverProcessor.d.ts +18 -0
  155. package/dist/bscPlugin/hover/HoverProcessor.js +218 -0
  156. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  157. package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
  158. package/dist/bscPlugin/hover/HoverProcessor.spec.js +786 -0
  159. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  160. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  161. package/dist/bscPlugin/references/ReferencesProvider.js +57 -0
  162. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  163. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
  164. package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
  165. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
  166. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
  167. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +154 -0
  168. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  169. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
  170. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +530 -0
  171. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
  172. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  173. package/dist/bscPlugin/serialize/BslibInjector.spec.js +33 -0
  174. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  175. package/dist/bscPlugin/serialize/BslibManager.d.ts +12 -0
  176. package/dist/bscPlugin/serialize/BslibManager.js +46 -0
  177. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  178. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  179. package/dist/bscPlugin/serialize/FileSerializer.js +75 -0
  180. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  181. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.d.ts +7 -0
  182. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js +22 -0
  183. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js.map +1 -0
  184. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.d.ts +1 -0
  185. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js +291 -0
  186. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js.map +1 -0
  187. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.d.ts +7 -0
  188. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js +26 -0
  189. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js.map +1 -0
  190. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.d.ts +1 -0
  191. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js +245 -0
  192. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js.map +1 -0
  193. package/dist/bscPlugin/symbols/symbolUtils.d.ts +5 -0
  194. package/dist/bscPlugin/symbols/symbolUtils.js +141 -0
  195. package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
  196. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +21 -0
  197. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +201 -0
  198. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  199. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  200. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +75 -0
  201. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  202. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  203. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  204. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  205. package/dist/bscPlugin/validation/BrsFileAfterValidator.d.ts +7 -0
  206. package/dist/bscPlugin/validation/BrsFileAfterValidator.js +18 -0
  207. package/dist/bscPlugin/validation/BrsFileAfterValidator.js.map +1 -0
  208. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +36 -0
  209. package/dist/bscPlugin/validation/BrsFileValidator.js +534 -0
  210. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  211. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  212. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +1118 -0
  213. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  214. package/dist/bscPlugin/validation/ProgramValidator.d.ts +11 -0
  215. package/dist/bscPlugin/validation/ProgramValidator.js +33 -0
  216. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  217. package/dist/bscPlugin/validation/ScopeValidator.d.ts +128 -0
  218. package/dist/bscPlugin/validation/ScopeValidator.js +1045 -0
  219. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  220. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  221. package/dist/bscPlugin/validation/ScopeValidator.spec.js +3380 -0
  222. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  223. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  224. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  225. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  226. package/dist/cli.js +117 -11
  227. package/dist/cli.js.map +1 -1
  228. package/dist/deferred.d.ts +3 -3
  229. package/dist/deferred.js.map +1 -1
  230. package/dist/diagnosticUtils.d.ts +10 -3
  231. package/dist/diagnosticUtils.js +62 -24
  232. package/dist/diagnosticUtils.js.map +1 -1
  233. package/dist/examples/plugins/removePrint.js +8 -12
  234. package/dist/examples/plugins/removePrint.js.map +1 -1
  235. package/dist/files/AssetFile.d.ts +24 -0
  236. package/dist/files/AssetFile.js +25 -0
  237. package/dist/files/AssetFile.js.map +1 -0
  238. package/dist/files/BrsFile.Class.spec.js +912 -153
  239. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  240. package/dist/files/BrsFile.d.ts +142 -85
  241. package/dist/files/BrsFile.js +845 -935
  242. package/dist/files/BrsFile.js.map +1 -1
  243. package/dist/files/BrsFile.spec.js +3778 -862
  244. package/dist/files/BrsFile.spec.js.map +1 -1
  245. package/dist/files/BscFile.d.ts +101 -0
  246. package/dist/files/BscFile.js +15 -0
  247. package/dist/files/BscFile.js.map +1 -0
  248. package/dist/files/Factory.d.ts +25 -0
  249. package/dist/files/Factory.js +22 -0
  250. package/dist/files/Factory.js.map +1 -0
  251. package/dist/files/LazyFileData.d.ts +20 -0
  252. package/dist/files/LazyFileData.js +54 -0
  253. package/dist/files/LazyFileData.js.map +1 -0
  254. package/dist/files/LazyFileData.spec.d.ts +1 -0
  255. package/dist/files/LazyFileData.spec.js +27 -0
  256. package/dist/files/LazyFileData.spec.js.map +1 -0
  257. package/dist/files/XmlFile.d.ts +73 -41
  258. package/dist/files/XmlFile.js +128 -138
  259. package/dist/files/XmlFile.js.map +1 -1
  260. package/dist/files/XmlFile.spec.js +451 -324
  261. package/dist/files/XmlFile.spec.js.map +1 -1
  262. package/dist/files/tests/imports.spec.js +62 -52
  263. package/dist/files/tests/imports.spec.js.map +1 -1
  264. package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
  265. package/dist/files/tests/optionalChaning.spec.js +152 -0
  266. package/dist/files/tests/optionalChaning.spec.js.map +1 -0
  267. package/dist/globalCallables.d.ts +3 -1
  268. package/dist/globalCallables.js +417 -163
  269. package/dist/globalCallables.js.map +1 -1
  270. package/dist/index.d.ts +26 -3
  271. package/dist/index.js +44 -5
  272. package/dist/index.js.map +1 -1
  273. package/dist/interfaces.d.ts +783 -122
  274. package/dist/interfaces.js +21 -0
  275. package/dist/interfaces.js.map +1 -1
  276. package/dist/lexer/Character.spec.js +5 -5
  277. package/dist/lexer/Character.spec.js.map +1 -1
  278. package/dist/lexer/Lexer.d.ts +51 -12
  279. package/dist/lexer/Lexer.js +201 -57
  280. package/dist/lexer/Lexer.js.map +1 -1
  281. package/dist/lexer/Lexer.spec.js +781 -565
  282. package/dist/lexer/Lexer.spec.js.map +1 -1
  283. package/dist/lexer/Token.d.ts +27 -11
  284. package/dist/lexer/Token.js +10 -2
  285. package/dist/lexer/Token.js.map +1 -1
  286. package/dist/lexer/TokenKind.d.ts +31 -2
  287. package/dist/lexer/TokenKind.js +134 -10
  288. package/dist/lexer/TokenKind.js.map +1 -1
  289. package/dist/logging.d.ts +9 -0
  290. package/dist/logging.js +16 -0
  291. package/dist/logging.js.map +1 -0
  292. package/dist/parser/AstNode.d.ts +191 -0
  293. package/dist/parser/AstNode.js +269 -0
  294. package/dist/parser/AstNode.js.map +1 -0
  295. package/dist/parser/AstNode.spec.d.ts +1 -0
  296. package/dist/parser/AstNode.spec.js +1455 -0
  297. package/dist/parser/AstNode.spec.js.map +1 -0
  298. package/dist/parser/BrightScriptDocParser.d.ts +56 -0
  299. package/dist/parser/BrightScriptDocParser.js +294 -0
  300. package/dist/parser/BrightScriptDocParser.js.map +1 -0
  301. package/dist/parser/BrightScriptDocParser.spec.d.ts +1 -0
  302. package/dist/parser/BrightScriptDocParser.spec.js +310 -0
  303. package/dist/parser/BrightScriptDocParser.spec.js.map +1 -0
  304. package/dist/parser/BrsTranspileState.d.ts +22 -3
  305. package/dist/parser/BrsTranspileState.js +19 -0
  306. package/dist/parser/BrsTranspileState.js.map +1 -1
  307. package/dist/parser/Expression.d.ts +489 -221
  308. package/dist/parser/Expression.js +1206 -506
  309. package/dist/parser/Expression.js.map +1 -1
  310. package/dist/parser/Expression.spec.d.ts +1 -0
  311. package/dist/parser/Expression.spec.js +40 -0
  312. package/dist/parser/Expression.spec.js.map +1 -0
  313. package/dist/parser/Parser.Class.spec.js +230 -125
  314. package/dist/parser/Parser.Class.spec.js.map +1 -1
  315. package/dist/parser/Parser.d.ts +113 -124
  316. package/dist/parser/Parser.js +1510 -983
  317. package/dist/parser/Parser.js.map +1 -1
  318. package/dist/parser/Parser.spec.d.ts +3 -1
  319. package/dist/parser/Parser.spec.js +1533 -517
  320. package/dist/parser/Parser.spec.js.map +1 -1
  321. package/dist/parser/SGParser.d.ts +60 -7
  322. package/dist/parser/SGParser.js +225 -185
  323. package/dist/parser/SGParser.js.map +1 -1
  324. package/dist/parser/SGParser.spec.js +29 -32
  325. package/dist/parser/SGParser.spec.js.map +1 -1
  326. package/dist/parser/SGTypes.d.ts +295 -52
  327. package/dist/parser/SGTypes.js +540 -187
  328. package/dist/parser/SGTypes.js.map +1 -1
  329. package/dist/parser/Statement.d.ts +808 -261
  330. package/dist/parser/Statement.js +2232 -588
  331. package/dist/parser/Statement.js.map +1 -1
  332. package/dist/parser/Statement.spec.js +133 -36
  333. package/dist/parser/Statement.spec.js.map +1 -1
  334. package/dist/parser/TranspileState.d.ts +26 -12
  335. package/dist/parser/TranspileState.js +114 -15
  336. package/dist/parser/TranspileState.js.map +1 -1
  337. package/dist/parser/tests/Parser.spec.d.ts +3 -9
  338. package/dist/parser/tests/Parser.spec.js +7 -13
  339. package/dist/parser/tests/Parser.spec.js.map +1 -1
  340. package/dist/parser/tests/controlFlow/For.spec.js +83 -75
  341. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  342. package/dist/parser/tests/controlFlow/ForEach.spec.js +58 -51
  343. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  344. package/dist/parser/tests/controlFlow/If.spec.js +382 -239
  345. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  346. package/dist/parser/tests/controlFlow/While.spec.js +52 -45
  347. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  348. package/dist/parser/tests/expression/Additive.spec.js +51 -43
  349. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  350. package/dist/parser/tests/expression/ArrayLiterals.spec.js +192 -142
  351. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  352. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +236 -160
  353. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  354. package/dist/parser/tests/expression/Boolean.spec.js +41 -34
  355. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  356. package/dist/parser/tests/expression/Call.spec.js +173 -55
  357. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  358. package/dist/parser/tests/expression/Exponential.spec.js +20 -20
  359. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  360. package/dist/parser/tests/expression/Function.spec.js +291 -282
  361. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  362. package/dist/parser/tests/expression/Indexing.spec.js +193 -110
  363. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  364. package/dist/parser/tests/expression/Multiplicative.spec.js +42 -42
  365. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  366. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +213 -115
  367. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  368. package/dist/parser/tests/expression/PrefixUnary.spec.js +58 -52
  369. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  370. package/dist/parser/tests/expression/Primary.spec.js +76 -60
  371. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  372. package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
  373. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
  374. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
  375. package/dist/parser/tests/expression/Relational.spec.js +50 -50
  376. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  377. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +31 -31
  378. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  379. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +235 -94
  380. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  381. package/dist/parser/tests/expression/TernaryExpression.spec.js +403 -174
  382. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  383. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  384. package/dist/parser/tests/expression/TypeExpression.spec.js +126 -0
  385. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  386. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  387. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  388. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  389. package/dist/parser/tests/statement/AssignmentOperators.spec.js +44 -44
  390. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  391. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  392. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  393. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  394. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  395. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  396. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  397. package/dist/parser/tests/statement/Declaration.spec.js +61 -55
  398. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  399. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  400. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  401. package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
  402. package/dist/parser/tests/statement/Enum.spec.js +744 -0
  403. package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
  404. package/dist/parser/tests/statement/For.spec.d.ts +1 -0
  405. package/dist/parser/tests/statement/For.spec.js +45 -0
  406. package/dist/parser/tests/statement/For.spec.js.map +1 -0
  407. package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
  408. package/dist/parser/tests/statement/ForEach.spec.js +36 -0
  409. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
  410. package/dist/parser/tests/statement/Function.spec.js +226 -215
  411. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  412. package/dist/parser/tests/statement/Goto.spec.js +16 -15
  413. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  414. package/dist/parser/tests/statement/Increment.spec.js +64 -59
  415. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  416. package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
  417. package/dist/parser/tests/statement/InterfaceStatement.spec.js +110 -0
  418. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
  419. package/dist/parser/tests/statement/LibraryStatement.spec.js +22 -22
  420. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  421. package/dist/parser/tests/statement/Misc.spec.js +127 -168
  422. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  423. package/dist/parser/tests/statement/PrintStatement.spec.js +133 -114
  424. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  425. package/dist/parser/tests/statement/ReturnStatement.spec.js +57 -54
  426. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  427. package/dist/parser/tests/statement/Set.spec.js +131 -117
  428. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  429. package/dist/parser/tests/statement/Stop.spec.js +14 -13
  430. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  431. package/dist/parser/tests/statement/Throw.spec.js +11 -8
  432. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  433. package/dist/parser/tests/statement/TryCatch.spec.js +26 -15
  434. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  435. package/dist/preprocessor/Manifest.d.ts +6 -6
  436. package/dist/preprocessor/Manifest.js +17 -38
  437. package/dist/preprocessor/Manifest.js.map +1 -1
  438. package/dist/preprocessor/Manifest.spec.d.ts +1 -0
  439. package/dist/preprocessor/Manifest.spec.js +78 -103
  440. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  441. package/dist/roku-types/data.json +19452 -0
  442. package/dist/roku-types/index.d.ts +5533 -0
  443. package/dist/roku-types/index.js +11 -0
  444. package/dist/roku-types/index.js.map +1 -0
  445. package/dist/types/ArrayType.d.ts +9 -5
  446. package/dist/types/ArrayType.js +73 -24
  447. package/dist/types/ArrayType.js.map +1 -1
  448. package/dist/types/ArrayType.spec.js +39 -11
  449. package/dist/types/ArrayType.spec.js.map +1 -1
  450. package/dist/types/AssociativeArrayType.d.ts +14 -0
  451. package/dist/types/AssociativeArrayType.js +60 -0
  452. package/dist/types/AssociativeArrayType.js.map +1 -0
  453. package/dist/types/BaseFunctionType.d.ts +9 -0
  454. package/dist/types/BaseFunctionType.js +25 -0
  455. package/dist/types/BaseFunctionType.js.map +1 -0
  456. package/dist/types/BooleanType.d.ts +10 -5
  457. package/dist/types/BooleanType.js +21 -9
  458. package/dist/types/BooleanType.js.map +1 -1
  459. package/dist/types/BooleanType.spec.js +10 -4
  460. package/dist/types/BooleanType.spec.js.map +1 -1
  461. package/dist/types/BscType.d.ts +29 -3
  462. package/dist/types/BscType.js +121 -0
  463. package/dist/types/BscType.js.map +1 -1
  464. package/dist/types/BscTypeKind.d.ts +25 -0
  465. package/dist/types/BscTypeKind.js +30 -0
  466. package/dist/types/BscTypeKind.js.map +1 -0
  467. package/dist/types/BuiltInInterfaceAdder.d.ts +25 -0
  468. package/dist/types/BuiltInInterfaceAdder.js +201 -0
  469. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  470. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  471. package/dist/types/BuiltInInterfaceAdder.spec.js +115 -0
  472. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  473. package/dist/types/ClassType.d.ts +16 -0
  474. package/dist/types/ClassType.js +57 -0
  475. package/dist/types/ClassType.js.map +1 -0
  476. package/dist/types/ClassType.spec.d.ts +1 -0
  477. package/dist/types/ClassType.spec.js +76 -0
  478. package/dist/types/ClassType.spec.js.map +1 -0
  479. package/dist/types/ComponentType.d.ts +27 -0
  480. package/dist/types/ComponentType.js +83 -0
  481. package/dist/types/ComponentType.js.map +1 -0
  482. package/dist/types/DoubleType.d.ts +10 -5
  483. package/dist/types/DoubleType.js +25 -18
  484. package/dist/types/DoubleType.js.map +1 -1
  485. package/dist/types/DoubleType.spec.js +12 -4
  486. package/dist/types/DoubleType.spec.js.map +1 -1
  487. package/dist/types/DynamicType.d.ts +12 -5
  488. package/dist/types/DynamicType.js +22 -6
  489. package/dist/types/DynamicType.js.map +1 -1
  490. package/dist/types/DynamicType.spec.js +16 -5
  491. package/dist/types/DynamicType.spec.js.map +1 -1
  492. package/dist/types/EnumType.d.ts +40 -0
  493. package/dist/types/EnumType.js +80 -0
  494. package/dist/types/EnumType.js.map +1 -0
  495. package/dist/types/EnumType.spec.d.ts +1 -0
  496. package/dist/types/EnumType.spec.js +33 -0
  497. package/dist/types/EnumType.spec.js.map +1 -0
  498. package/dist/types/FloatType.d.ts +10 -5
  499. package/dist/types/FloatType.js +25 -18
  500. package/dist/types/FloatType.js.map +1 -1
  501. package/dist/types/FloatType.spec.js +4 -4
  502. package/dist/types/FloatType.spec.js.map +1 -1
  503. package/dist/types/FunctionType.d.ts +10 -22
  504. package/dist/types/FunctionType.js +26 -63
  505. package/dist/types/FunctionType.js.map +1 -1
  506. package/dist/types/InheritableType.d.ts +29 -0
  507. package/dist/types/InheritableType.js +162 -0
  508. package/dist/types/InheritableType.js.map +1 -0
  509. package/dist/types/IntegerType.d.ts +10 -5
  510. package/dist/types/IntegerType.js +25 -18
  511. package/dist/types/IntegerType.js.map +1 -1
  512. package/dist/types/IntegerType.spec.js +8 -4
  513. package/dist/types/IntegerType.spec.js.map +1 -1
  514. package/dist/types/InterfaceType.d.ts +14 -6
  515. package/dist/types/InterfaceType.js +26 -15
  516. package/dist/types/InterfaceType.js.map +1 -1
  517. package/dist/types/InterfaceType.spec.d.ts +1 -0
  518. package/dist/types/InterfaceType.spec.js +227 -0
  519. package/dist/types/InterfaceType.spec.js.map +1 -0
  520. package/dist/types/InvalidType.d.ts +9 -5
  521. package/dist/types/InvalidType.js +20 -9
  522. package/dist/types/InvalidType.js.map +1 -1
  523. package/dist/types/InvalidType.spec.js +8 -4
  524. package/dist/types/InvalidType.spec.js.map +1 -1
  525. package/dist/types/LongIntegerType.d.ts +10 -5
  526. package/dist/types/LongIntegerType.js +25 -18
  527. package/dist/types/LongIntegerType.js.map +1 -1
  528. package/dist/types/LongIntegerType.spec.js +10 -4
  529. package/dist/types/LongIntegerType.spec.js.map +1 -1
  530. package/dist/types/NamespaceType.d.ts +12 -0
  531. package/dist/types/NamespaceType.js +28 -0
  532. package/dist/types/NamespaceType.js.map +1 -0
  533. package/dist/types/ObjectType.d.ts +10 -5
  534. package/dist/types/ObjectType.js +23 -9
  535. package/dist/types/ObjectType.js.map +1 -1
  536. package/dist/types/ObjectType.spec.js +3 -3
  537. package/dist/types/ObjectType.spec.js.map +1 -1
  538. package/dist/types/ReferenceType.d.ts +79 -0
  539. package/dist/types/ReferenceType.js +522 -0
  540. package/dist/types/ReferenceType.js.map +1 -0
  541. package/dist/types/ReferenceType.spec.d.ts +1 -0
  542. package/dist/types/ReferenceType.spec.js +151 -0
  543. package/dist/types/ReferenceType.spec.js.map +1 -0
  544. package/dist/types/StringType.d.ts +13 -5
  545. package/dist/types/StringType.js +25 -9
  546. package/dist/types/StringType.js.map +1 -1
  547. package/dist/types/StringType.spec.js +3 -3
  548. package/dist/types/StringType.spec.js.map +1 -1
  549. package/dist/types/TypedFunctionType.d.ts +33 -0
  550. package/dist/types/TypedFunctionType.js +106 -0
  551. package/dist/types/TypedFunctionType.js.map +1 -0
  552. package/dist/types/TypedFunctionType.spec.d.ts +1 -0
  553. package/dist/types/TypedFunctionType.spec.js +122 -0
  554. package/dist/types/TypedFunctionType.spec.js.map +1 -0
  555. package/dist/types/UninitializedType.d.ts +8 -6
  556. package/dist/types/UninitializedType.js +15 -9
  557. package/dist/types/UninitializedType.js.map +1 -1
  558. package/dist/types/UnionType.d.ts +20 -0
  559. package/dist/types/UnionType.js +127 -0
  560. package/dist/types/UnionType.js.map +1 -0
  561. package/dist/types/UnionType.spec.d.ts +1 -0
  562. package/dist/types/UnionType.spec.js +129 -0
  563. package/dist/types/UnionType.spec.js.map +1 -0
  564. package/dist/types/VoidType.d.ts +10 -5
  565. package/dist/types/VoidType.js +20 -9
  566. package/dist/types/VoidType.js.map +1 -1
  567. package/dist/types/VoidType.spec.js +3 -3
  568. package/dist/types/VoidType.spec.js.map +1 -1
  569. package/dist/types/helper.spec.d.ts +1 -0
  570. package/dist/types/helper.spec.js +144 -0
  571. package/dist/types/helper.spec.js.map +1 -0
  572. package/dist/types/helpers.d.ts +26 -0
  573. package/dist/types/helpers.js +191 -0
  574. package/dist/types/helpers.js.map +1 -0
  575. package/dist/types/index.d.ts +22 -0
  576. package/dist/types/index.js +39 -0
  577. package/dist/types/index.js.map +1 -0
  578. package/dist/util.d.ts +272 -117
  579. package/dist/util.js +1583 -343
  580. package/dist/util.js.map +1 -1
  581. package/dist/validators/ClassValidator.d.ts +9 -15
  582. package/dist/validators/ClassValidator.js +85 -138
  583. package/dist/validators/ClassValidator.js.map +1 -1
  584. package/package.json +174 -138
  585. package/dist/astUtils/index.d.ts +0 -7
  586. package/dist/astUtils/index.js +0 -26
  587. package/dist/astUtils/index.js.map +0 -1
  588. package/dist/lexer/index.d.ts +0 -3
  589. package/dist/lexer/index.js +0 -17
  590. package/dist/lexer/index.js.map +0 -1
  591. package/dist/parser/index.d.ts +0 -3
  592. package/dist/parser/index.js +0 -16
  593. package/dist/parser/index.js.map +0 -1
  594. package/dist/preprocessor/Chunk.d.ts +0 -82
  595. package/dist/preprocessor/Chunk.js +0 -77
  596. package/dist/preprocessor/Chunk.js.map +0 -1
  597. package/dist/preprocessor/Preprocessor.d.ts +0 -60
  598. package/dist/preprocessor/Preprocessor.js +0 -156
  599. package/dist/preprocessor/Preprocessor.js.map +0 -1
  600. package/dist/preprocessor/Preprocessor.spec.js +0 -152
  601. package/dist/preprocessor/Preprocessor.spec.js.map +0 -1
  602. package/dist/preprocessor/PreprocessorParser.d.ts +0 -61
  603. package/dist/preprocessor/PreprocessorParser.js +0 -194
  604. package/dist/preprocessor/PreprocessorParser.js.map +0 -1
  605. package/dist/preprocessor/PreprocessorParser.spec.js +0 -116
  606. package/dist/preprocessor/PreprocessorParser.spec.js.map +0 -1
  607. package/dist/preprocessor/index.d.ts +0 -3
  608. package/dist/preprocessor/index.js +0 -16
  609. package/dist/preprocessor/index.js.map +0 -1
  610. package/dist/types/CustomType.d.ts +0 -10
  611. package/dist/types/CustomType.js +0 -35
  612. package/dist/types/CustomType.js.map +0 -1
  613. package/dist/types/FunctionType.spec.js +0 -29
  614. package/dist/types/FunctionType.spec.js.map +0 -1
  615. package/dist/types/LazyType.d.ts +0 -15
  616. package/dist/types/LazyType.js +0 -32
  617. package/dist/types/LazyType.js.map +0 -1
  618. /package/dist/{preprocessor/Preprocessor.spec.d.ts → astUtils/CachedLookups.spec.d.ts} +0 -0
  619. /package/dist/{preprocessor/PreprocessorParser.spec.d.ts → astUtils/Editor.spec.d.ts} +0 -0
  620. /package/dist/{types/FunctionType.spec.d.ts → bscPlugin/completions/CompletionsProcessor.spec.d.ts} +0 -0
@@ -1,21 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTypeFromVariableExpression = exports.getTypeFromCallExpression = exports.getBscTypeFromExpression = exports.References = exports.ParseMode = exports.Parser = void 0;
4
- const lexer_1 = require("../lexer");
3
+ exports.ParseMode = exports.Parser = void 0;
4
+ const Token_1 = require("../lexer/Token");
5
+ const Lexer_1 = require("../lexer/Lexer");
6
+ const TokenKind_1 = require("../lexer/TokenKind");
5
7
  const Statement_1 = require("./Statement");
6
8
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
7
9
  const util_1 = require("../util");
8
10
  const Expression_1 = require("./Expression");
9
- const Logger_1 = require("../Logger");
11
+ const logging_1 = require("../logging");
10
12
  const reflection_1 = require("../astUtils/reflection");
11
- const visitors_1 = require("../astUtils/visitors");
12
13
  const creators_1 = require("../astUtils/creators");
13
- const DynamicType_1 = require("../types/DynamicType");
14
- const LazyType_1 = require("../types/LazyType");
15
- const SymbolTable_1 = require("../SymbolTable");
16
- const ObjectType_1 = require("../types/ObjectType");
17
- const CustomType_1 = require("../types/CustomType");
18
- const ArrayType_1 = require("../types/ArrayType");
19
14
  class Parser {
20
15
  constructor() {
21
16
  /**
@@ -25,60 +20,26 @@ class Parser {
25
20
  /**
26
21
  * The list of statements for the parsed file
27
22
  */
28
- this.ast = new Statement_1.Body([]);
29
- this.symbolTable = new SymbolTable_1.SymbolTable();
30
- this._references = new References();
23
+ this.ast = new Statement_1.Body({ statements: [] });
31
24
  this.globalTerminators = [];
32
25
  /**
33
26
  * An array of CallExpression for the current function body
34
27
  */
35
28
  this.callExpressions = [];
29
+ this.nestedInlineConditionalCount = 0;
36
30
  }
37
- get statements() {
38
- return this.ast.statements;
39
- }
40
- get currentSymbolTable() {
41
- var _a, _b;
42
- return (_b = (_a = this.currentFunctionExpression) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : this.symbolTable;
43
- }
44
- /**
45
- * References for significant statements/expressions in the parser.
46
- * These are initially extracted during parse-time to improve performance, but will also be dynamically regenerated if need be.
47
- *
48
- * If a plugin modifies the AST, then the plugin should call Parser#invalidateReferences() to force this object to refresh
49
- */
50
- get references() {
51
- //build the references object if it's missing.
52
- if (!this._references) {
53
- this.findReferences();
31
+ get eofToken() {
32
+ var _a;
33
+ const lastToken = (_a = this.tokens) === null || _a === void 0 ? void 0 : _a[this.tokens.length - 1];
34
+ if ((lastToken === null || lastToken === void 0 ? void 0 : lastToken.kind) === TokenKind_1.TokenKind.Eof) {
35
+ return lastToken;
54
36
  }
55
- return this._references;
56
37
  }
57
38
  /**
58
- * Invalidates (clears) the references collection. This should be called anytime the AST has been manipulated.
39
+ * The top-level symbol table for the body of this file.
59
40
  */
60
- invalidateReferences() {
61
- this._references = undefined;
62
- }
63
- addPropertyHints(item) {
64
- if (lexer_1.isToken(item)) {
65
- const name = item.text;
66
- this._references.propertyHints[name.toLowerCase()] = name;
67
- }
68
- else {
69
- for (const member of item.elements) {
70
- if (!reflection_1.isCommentStatement(member)) {
71
- const name = member.keyToken.text;
72
- if (!name.startsWith('"')) {
73
- this._references.propertyHints[name.toLowerCase()] = name;
74
- }
75
- }
76
- }
77
- }
78
- }
79
- get currentNamespaceName() {
80
- var _a;
81
- return (_a = this.currentNamespace) === null || _a === void 0 ? void 0 : _a.nameExpression;
41
+ get symbolTable() {
42
+ return this.ast.symbolTable;
82
43
  }
83
44
  /**
84
45
  * Get the currently active global terminators
@@ -87,41 +48,51 @@ class Parser {
87
48
  var _a;
88
49
  return (_a = this.globalTerminators[this.globalTerminators.length - 1]) !== null && _a !== void 0 ? _a : [];
89
50
  }
51
+ /**
52
+ * Static wrapper around creating a new parser and parsing a list of tokens
53
+ */
90
54
  static parse(toParse, options) {
91
- let tokens;
92
- if (typeof toParse === 'string') {
93
- tokens = lexer_1.Lexer.scan(toParse).tokens;
94
- }
95
- else {
96
- tokens = toParse;
97
- }
98
- return new Parser().parse(tokens, options);
55
+ return new Parser().parse(toParse, options);
99
56
  }
100
57
  /**
101
58
  * Parses an array of `Token`s into an abstract syntax tree
102
59
  * @param toParse the array of tokens to parse. May not contain any whitespace tokens
103
60
  * @returns the same instance of the parser which contains the diagnostics and statements
104
61
  */
105
- parse(tokens, options) {
62
+ parse(toParse, options) {
106
63
  var _a;
107
- this.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : new Logger_1.Logger();
64
+ this.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : (0, logging_1.createLogger)();
65
+ options = this.sanitizeParseOptions(options);
66
+ this.options = options;
67
+ let tokens;
68
+ if (typeof toParse === 'string') {
69
+ tokens = Lexer_1.Lexer.scan(toParse, {
70
+ trackLocations: options.trackLocations,
71
+ srcPath: options === null || options === void 0 ? void 0 : options.srcPath
72
+ }).tokens;
73
+ }
74
+ else {
75
+ tokens = toParse;
76
+ }
108
77
  this.tokens = tokens;
109
- this.options = this.sanitizeParseOptions(options);
110
78
  this.allowedLocalIdentifiers = [
111
- ...lexer_1.AllowedLocalIdentifiers,
79
+ ...TokenKind_1.AllowedLocalIdentifiers,
112
80
  //when in plain brightscript mode, the BrighterScript source literals can be used as regular variables
113
- ...(this.options.mode === ParseMode.BrightScript ? lexer_1.BrighterScriptSourceLiterals : [])
81
+ ...(this.options.mode === ParseMode.BrightScript ? TokenKind_1.BrighterScriptSourceLiterals : [])
114
82
  ];
115
83
  this.current = 0;
116
84
  this.diagnostics = [];
117
85
  this.namespaceAndFunctionDepth = 0;
118
86
  this.pendingAnnotations = [];
119
87
  this.ast = this.body();
88
+ this.ast.bsConsts = options.bsConsts;
89
+ //now that we've built the AST, link every node to its parent
90
+ this.ast.link();
120
91
  return this;
121
92
  }
122
93
  body() {
123
94
  const parentAnnotations = this.enterAnnotationBlock();
124
- let body = new Statement_1.Body([]);
95
+ let body = new Statement_1.Body({ statements: [] });
125
96
  if (this.tokens.length > 0) {
126
97
  this.consumeStatementSeparators(true);
127
98
  try {
@@ -132,7 +103,7 @@ class Parser {
132
103
  !this.checkAny(...this.peekGlobalTerminators())) {
133
104
  let dec = this.declaration();
134
105
  if (dec) {
135
- if (!reflection_1.isAnnotationExpression(dec)) {
106
+ if (!(0, reflection_1.isAnnotationExpression)(dec)) {
136
107
  this.consumePendingAnnotations(dec);
137
108
  body.statements.push(dec);
138
109
  //ensure statement separator
@@ -153,7 +124,13 @@ class Parser {
153
124
  return body;
154
125
  }
155
126
  sanitizeParseOptions(options) {
156
- return Object.assign({ mode: 'brightscript' }, (options || {}));
127
+ var _a, _b;
128
+ options !== null && options !== void 0 ? options : (options = {
129
+ srcPath: undefined
130
+ });
131
+ (_a = options.mode) !== null && _a !== void 0 ? _a : (options.mode = ParseMode.BrightScript);
132
+ (_b = options.trackLocations) !== null && _b !== void 0 ? _b : (options.trackLocations = true);
133
+ return options;
157
134
  }
158
135
  /**
159
136
  * Determine if the parser is currently parsing tokens at the root level.
@@ -166,7 +143,7 @@ class Parser {
166
143
  */
167
144
  warnIfNotBrighterScriptMode(featureName) {
168
145
  if (this.options.mode !== ParseMode.BrighterScript) {
169
- let diagnostic = Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.bsFeatureNotSupportedInBrsFiles(featureName)), { range: this.peek().range });
146
+ let diagnostic = Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.bsFeatureNotSupportedInBrsFiles(featureName)), { location: this.peek().location });
170
147
  this.diagnostics.push(diagnostic);
171
148
  }
172
149
  }
@@ -181,23 +158,29 @@ class Parser {
181
158
  }
182
159
  declaration() {
183
160
  try {
184
- if (this.check(lexer_1.TokenKind.Class)) {
185
- return this.classDeclaration();
161
+ if (this.checkAny(TokenKind_1.TokenKind.HashConst)) {
162
+ return this.conditionalCompileConstStatement();
186
163
  }
187
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
164
+ if (this.checkAny(TokenKind_1.TokenKind.HashIf)) {
165
+ return this.conditionalCompileStatement();
166
+ }
167
+ if (this.checkAny(TokenKind_1.TokenKind.HashError)) {
168
+ return this.conditionalCompileErrorStatement();
169
+ }
170
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
188
171
  return this.functionDeclaration(false);
189
172
  }
190
173
  if (this.checkLibrary()) {
191
174
  return this.libraryStatement();
192
175
  }
193
- if (this.check(lexer_1.TokenKind.Namespace)) {
194
- return this.namespaceStatement();
176
+ if (this.checkAlias()) {
177
+ return this.aliasStatement();
195
178
  }
196
- if (this.check(lexer_1.TokenKind.At) && this.checkNext(lexer_1.TokenKind.Identifier)) {
197
- return this.annotationExpression();
179
+ if (this.check(TokenKind_1.TokenKind.Const) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
180
+ return this.constDeclaration();
198
181
  }
199
- if (this.check(lexer_1.TokenKind.Comment)) {
200
- return this.commentStatement();
182
+ if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
183
+ return this.annotationExpression();
201
184
  }
202
185
  //catch certain global terminators to prevent unnecessary lookahead (i.e. like `end namespace`, no need to continue)
203
186
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -213,34 +196,262 @@ class Parser {
213
196
  this.synchronize();
214
197
  }
215
198
  }
199
+ /**
200
+ * Try to get an identifier. If not found, add diagnostic and return undefined
201
+ */
202
+ tryIdentifier(...additionalTokenKinds) {
203
+ const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
204
+ if (identifier) {
205
+ // force the name into an identifier so the AST makes some sense
206
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
207
+ return identifier;
208
+ }
209
+ }
210
+ identifier(...additionalTokenKinds) {
211
+ const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
212
+ // force the name into an identifier so the AST makes some sense
213
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
214
+ return identifier;
215
+ }
216
+ enumMemberStatement() {
217
+ const name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
218
+ let equalsToken;
219
+ let value;
220
+ //look for `= SOME_EXPRESSION`
221
+ if (this.check(TokenKind_1.TokenKind.Equal)) {
222
+ equalsToken = this.advance();
223
+ value = this.expression();
224
+ }
225
+ const statement = new Statement_1.EnumMemberStatement({ name: name, equals: equalsToken, value: value });
226
+ return statement;
227
+ }
228
+ /**
229
+ * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration`
230
+ */
231
+ interfaceFieldStatement(optionalKeyword) {
232
+ const name = this.identifier(...TokenKind_1.AllowedProperties);
233
+ let asToken;
234
+ let typeExpression;
235
+ if (this.check(TokenKind_1.TokenKind.As)) {
236
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
237
+ }
238
+ return new Statement_1.InterfaceFieldStatement({ name: name, as: asToken, typeExpression: typeExpression, optional: optionalKeyword });
239
+ }
240
+ consumeAsTokenAndTypeExpression(ignoreDiagnostics = false) {
241
+ let asToken = this.consumeToken(TokenKind_1.TokenKind.As);
242
+ let typeExpression;
243
+ if (asToken) {
244
+ //if there's nothing after the `as`, add a diagnostic and continue
245
+ if (this.checkEndOfStatement()) {
246
+ if (!ignoreDiagnostics) {
247
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(asToken.text)), { location: asToken.location }));
248
+ }
249
+ //consume the statement separator
250
+ this.consumeStatementSeparators();
251
+ }
252
+ else if (this.peek().kind !== TokenKind_1.TokenKind.Identifier && !this.checkAny(...TokenKind_1.DeclarableTypes, ...TokenKind_1.AllowedTypeIdentifiers)) {
253
+ if (!ignoreDiagnostics) {
254
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(asToken.text)), { location: asToken.location }));
255
+ }
256
+ }
257
+ else {
258
+ typeExpression = this.typeExpression();
259
+ }
260
+ }
261
+ return [asToken, typeExpression];
262
+ }
263
+ /**
264
+ * Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration()`
265
+ */
266
+ interfaceMethodStatement(optionalKeyword) {
267
+ const functionType = this.advance();
268
+ const name = this.identifier(...TokenKind_1.AllowedProperties);
269
+ const leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.LeftParen), TokenKind_1.TokenKind.LeftParen);
270
+ let params = [];
271
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
272
+ do {
273
+ if (params.length >= Expression_1.CallExpression.MaximumArguments) {
274
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { location: this.peek().location }));
275
+ }
276
+ params.push(this.functionParameter());
277
+ } while (this.match(TokenKind_1.TokenKind.Comma));
278
+ }
279
+ const rightParen = this.consumeToken(TokenKind_1.TokenKind.RightParen);
280
+ // let asToken = null as Token;
281
+ // let returnTypeExpression: TypeExpression;
282
+ let asToken;
283
+ let returnTypeExpression;
284
+ if (this.check(TokenKind_1.TokenKind.As)) {
285
+ [asToken, returnTypeExpression] = this.consumeAsTokenAndTypeExpression();
286
+ }
287
+ return new Statement_1.InterfaceMethodStatement({
288
+ functionType: functionType,
289
+ name: name,
290
+ leftParen: leftParen,
291
+ params: params,
292
+ rightParen: rightParen,
293
+ as: asToken,
294
+ returnTypeExpression: returnTypeExpression,
295
+ optional: optionalKeyword
296
+ });
297
+ }
298
+ interfaceDeclaration() {
299
+ this.warnIfNotBrighterScriptMode('interface declarations');
300
+ const parentAnnotations = this.enterAnnotationBlock();
301
+ const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
302
+ const nameToken = this.identifier(...this.allowedLocalIdentifiers);
303
+ let extendsToken;
304
+ let parentInterfaceName;
305
+ if (this.peek().text.toLowerCase() === 'extends') {
306
+ extendsToken = this.advance();
307
+ if (this.checkEndOfStatement()) {
308
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(extendsToken.text)), { location: extendsToken.location }));
309
+ }
310
+ else {
311
+ parentInterfaceName = this.typeExpression();
312
+ }
313
+ }
314
+ this.consumeStatementSeparators();
315
+ //gather up all interface members (Fields, Methods)
316
+ let body = [];
317
+ while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
318
+ try {
319
+ //break out of this loop if we encountered the `EndInterface` token not followed by `as`
320
+ if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
321
+ break;
322
+ }
323
+ let decl;
324
+ //collect leading annotations
325
+ if (this.check(TokenKind_1.TokenKind.At)) {
326
+ this.annotationExpression();
327
+ }
328
+ const optionalKeyword = this.consumeTokenIf(TokenKind_1.TokenKind.Optional);
329
+ //fields
330
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkAnyNext(TokenKind_1.TokenKind.As, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
331
+ decl = this.interfaceFieldStatement(optionalKeyword);
332
+ //field with name = 'optional'
333
+ }
334
+ else if (optionalKeyword && this.checkAny(TokenKind_1.TokenKind.As, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
335
+ //rewind one place, so that 'optional' is the field name
336
+ this.current--;
337
+ decl = this.interfaceFieldStatement();
338
+ //methods (function/sub keyword followed by opening paren)
339
+ }
340
+ else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
341
+ decl = this.interfaceMethodStatement(optionalKeyword);
342
+ }
343
+ if (decl) {
344
+ this.consumePendingAnnotations(decl);
345
+ body.push(decl);
346
+ }
347
+ else {
348
+ //we didn't find a declaration...flag tokens until next line
349
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
350
+ }
351
+ }
352
+ catch (e) {
353
+ //throw out any failed members and move on to the next line
354
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
355
+ }
356
+ //ensure statement separator
357
+ this.consumeStatementSeparators();
358
+ }
359
+ //consume the final `end interface` token
360
+ const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
361
+ const statement = new Statement_1.InterfaceStatement({
362
+ interface: interfaceToken,
363
+ name: nameToken,
364
+ extends: extendsToken,
365
+ parentInterfaceName: parentInterfaceName,
366
+ body: body,
367
+ endInterface: endInterfaceToken
368
+ });
369
+ this.exitAnnotationBlock(parentAnnotations);
370
+ return statement;
371
+ }
372
+ enumDeclaration() {
373
+ const enumToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
374
+ const nameToken = this.tryIdentifier(...this.allowedLocalIdentifiers);
375
+ this.warnIfNotBrighterScriptMode('enum declarations');
376
+ const parentAnnotations = this.enterAnnotationBlock();
377
+ this.consumeStatementSeparators();
378
+ const body = [];
379
+ //gather up all members
380
+ while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
381
+ try {
382
+ let decl;
383
+ //collect leading annotations
384
+ if (this.check(TokenKind_1.TokenKind.At)) {
385
+ this.annotationExpression();
386
+ }
387
+ //members
388
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
389
+ decl = this.enumMemberStatement();
390
+ }
391
+ if (decl) {
392
+ this.consumePendingAnnotations(decl);
393
+ body.push(decl);
394
+ }
395
+ else {
396
+ //we didn't find a declaration...flag tokens until next line
397
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
398
+ }
399
+ }
400
+ catch (e) {
401
+ //throw out any failed members and move on to the next line
402
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
403
+ }
404
+ //ensure statement separator
405
+ this.consumeStatementSeparators();
406
+ //break out of this loop if we encountered the `EndEnum` token
407
+ if (this.check(TokenKind_1.TokenKind.EndEnum)) {
408
+ break;
409
+ }
410
+ }
411
+ //consume the final `end interface` token
412
+ const endEnumToken = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
413
+ const result = new Statement_1.EnumStatement({
414
+ enum: enumToken,
415
+ name: nameToken,
416
+ body: body,
417
+ endEnum: endEnumToken
418
+ });
419
+ this.exitAnnotationBlock(parentAnnotations);
420
+ return result;
421
+ }
216
422
  /**
217
423
  * A BrighterScript class declaration
218
424
  */
219
425
  classDeclaration() {
220
426
  this.warnIfNotBrighterScriptMode('class declarations');
221
427
  const parentAnnotations = this.enterAnnotationBlock();
222
- let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassKeyword(), lexer_1.TokenKind.Class);
428
+ let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Class), TokenKind_1.TokenKind.Class);
223
429
  let extendsKeyword;
224
430
  let parentClassName;
225
431
  //get the class name
226
- let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
432
+ let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
227
433
  //see if the class inherits from parent
228
434
  if (this.peek().text.toLowerCase() === 'extends') {
229
435
  extendsKeyword = this.advance();
230
- parentClassName = this.getNamespacedVariableNameExpression();
436
+ if (this.checkEndOfStatement()) {
437
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(extendsKeyword.text)), { location: extendsKeyword.location }));
438
+ }
439
+ else {
440
+ parentClassName = this.typeExpression();
441
+ }
231
442
  }
232
443
  //ensure statement separator
233
444
  this.consumeStatementSeparators();
234
445
  //gather up all class members (Fields, Methods)
235
446
  let body = [];
236
- while (this.checkAny(lexer_1.TokenKind.Public, lexer_1.TokenKind.Protected, lexer_1.TokenKind.Private, lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub, lexer_1.TokenKind.Comment, lexer_1.TokenKind.Identifier, lexer_1.TokenKind.At, ...lexer_1.AllowedProperties)) {
447
+ while (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private, TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
237
448
  try {
238
449
  let decl;
239
450
  let accessModifier;
240
- if (this.check(lexer_1.TokenKind.At)) {
451
+ if (this.check(TokenKind_1.TokenKind.At)) {
241
452
  this.annotationExpression();
242
453
  }
243
- if (this.checkAny(lexer_1.TokenKind.Public, lexer_1.TokenKind.Protected, lexer_1.TokenKind.Private)) {
454
+ if (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private)) {
244
455
  //use actual access modifier
245
456
  accessModifier = this.advance();
246
457
  }
@@ -249,29 +460,26 @@ class Parser {
249
460
  overrideKeyword = this.advance();
250
461
  }
251
462
  //methods (function/sub keyword OR identifier followed by opening paren)
252
- if (this.checkAny(lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub) || (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties) && this.checkNext(lexer_1.TokenKind.LeftParen))) {
463
+ 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))) {
253
464
  const funcDeclaration = this.functionDeclaration(false, false);
254
- //remove this function from the lists because it's not a callable
255
- const functionStatement = this._references.functionStatements.pop();
256
465
  //if we have an overrides keyword AND this method is called 'new', that's not allowed
257
- if (overrideKeyword && funcDeclaration.name.text.toLowerCase() === 'new') {
258
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { range: overrideKeyword.range }));
466
+ if (overrideKeyword && funcDeclaration.tokens.name.text.toLowerCase() === 'new') {
467
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { location: overrideKeyword.location }));
259
468
  }
260
- decl = new Statement_1.ClassMethodStatement(accessModifier, funcDeclaration.name, funcDeclaration.func, overrideKeyword);
261
- //refer to this statement as parent of the expression
262
- functionStatement.func.functionStatement = decl;
469
+ decl = new Statement_1.MethodStatement({
470
+ modifiers: accessModifier,
471
+ name: funcDeclaration.tokens.name,
472
+ func: funcDeclaration.func,
473
+ override: overrideKeyword
474
+ });
263
475
  //fields
264
476
  }
265
- else if (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties)) {
266
- decl = this.classFieldDeclaration(accessModifier);
477
+ else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
478
+ decl = this.fieldDeclaration(accessModifier);
267
479
  //class fields cannot be overridden
268
480
  if (overrideKeyword) {
269
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classFieldCannotBeOverridden()), { range: overrideKeyword.range }));
481
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classFieldCannotBeOverridden()), { location: overrideKeyword.location }));
270
482
  }
271
- //comments
272
- }
273
- else if (this.check(lexer_1.TokenKind.Comment)) {
274
- decl = this.commentStatement();
275
483
  }
276
484
  if (decl) {
277
485
  this.consumePendingAnnotations(decl);
@@ -280,166 +488,169 @@ class Parser {
280
488
  }
281
489
  catch (e) {
282
490
  //throw out any failed members and move on to the next line
283
- this.flagUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
491
+ this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
284
492
  }
285
493
  //ensure statement separator
286
494
  this.consumeStatementSeparators();
287
495
  }
288
496
  let endingKeyword = this.advance();
289
- if (endingKeyword.kind !== lexer_1.TokenKind.EndClass) {
290
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
291
- }
292
- const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName);
293
- this._references.classStatements.push(result);
497
+ if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
498
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { location: endingKeyword.location }));
499
+ }
500
+ const result = new Statement_1.ClassStatement({
501
+ class: classKeyword,
502
+ name: className,
503
+ body: body,
504
+ endClass: endingKeyword,
505
+ extends: extendsKeyword,
506
+ parentClassName: parentClassName
507
+ });
294
508
  this.exitAnnotationBlock(parentAnnotations);
295
509
  return result;
296
510
  }
297
- classFieldDeclaration(accessModifier) {
298
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
511
+ fieldDeclaration(accessModifier) {
512
+ let optionalKeyword = this.consumeTokenIf(TokenKind_1.TokenKind.Optional);
513
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
514
+ if (this.check(TokenKind_1.TokenKind.As)) {
515
+ if (this.checkAnyNext(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Newline)) {
516
+ // as <EOL>
517
+ // `as` is the field name
518
+ }
519
+ else if (this.checkNext(TokenKind_1.TokenKind.As)) {
520
+ // as as ____
521
+ // first `as` is the field name
522
+ }
523
+ else if (optionalKeyword) {
524
+ // optional as ____
525
+ // optional is the field name, `as` starts type
526
+ // rewind current token
527
+ optionalKeyword = null;
528
+ this.current--;
529
+ }
530
+ }
531
+ }
532
+ else {
533
+ // no name after `optional` ... optional is the name
534
+ // rewind current token
535
+ optionalKeyword = null;
536
+ this.current--;
537
+ }
538
+ let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
299
539
  let asToken;
300
- let fieldType;
540
+ let fieldTypeExpression;
301
541
  //look for `as SOME_TYPE`
302
- if (this.check(lexer_1.TokenKind.As)) {
303
- asToken = this.advance();
304
- fieldType = this.typeToken();
305
- //no field type specified
306
- if (!util_1.util.tokenToBscType(fieldType)) {
307
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedValidTypeToFollowAsKeyword()), { range: this.peek().range }));
308
- }
542
+ if (this.check(TokenKind_1.TokenKind.As)) {
543
+ [asToken, fieldTypeExpression] = this.consumeAsTokenAndTypeExpression();
309
544
  }
310
545
  let initialValue;
311
546
  let equal;
312
547
  //if there is a field initializer
313
- if (this.check(lexer_1.TokenKind.Equal)) {
548
+ if (this.check(TokenKind_1.TokenKind.Equal)) {
314
549
  equal = this.advance();
315
550
  initialValue = this.expression();
316
551
  }
317
- return new Statement_1.ClassFieldStatement(accessModifier, name, asToken, fieldType, equal, initialValue);
552
+ return new Statement_1.FieldStatement({
553
+ accessModifier: accessModifier,
554
+ name: name,
555
+ as: asToken,
556
+ typeExpression: fieldTypeExpression,
557
+ equals: equal,
558
+ initialValue: initialValue,
559
+ optional: optionalKeyword
560
+ });
318
561
  }
319
- functionDeclaration(isAnonymous, checkIdentifier = true) {
320
- var _a, _b, _c, _d;
562
+ functionDeclaration(isAnonymous, checkIdentifier = true, onlyCallableAsMember = false) {
321
563
  let previousCallExpressions = this.callExpressions;
322
564
  this.callExpressions = [];
323
565
  try {
324
566
  //track depth to help certain statements need to know if they are contained within a function body
325
567
  this.namespaceAndFunctionDepth++;
326
568
  let functionType;
327
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
569
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
328
570
  functionType = this.advance();
329
571
  }
330
572
  else {
331
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
573
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { location: this.peek().location }));
574
+ //TODO we should probably eliminate this entirely, since it's not present in the source code
332
575
  functionType = {
333
576
  isReserved: true,
334
- kind: lexer_1.TokenKind.Function,
577
+ kind: TokenKind_1.TokenKind.Function,
335
578
  text: 'function',
336
579
  //zero-length location means derived
337
- range: {
338
- start: this.peek().range.start,
339
- end: this.peek().range.start
340
- },
341
- leadingWhitespace: ''
580
+ location: this.peek().location,
581
+ leadingWhitespace: '',
582
+ leadingTrivia: []
342
583
  };
343
584
  }
344
- let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === lexer_1.TokenKind.Sub;
585
+ let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === TokenKind_1.TokenKind.Sub;
345
586
  let functionTypeText = isSub ? 'sub' : 'function';
346
587
  let name;
347
588
  let leftParen;
348
589
  if (isAnonymous) {
349
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), lexer_1.TokenKind.LeftParen);
590
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), TokenKind_1.TokenKind.LeftParen);
350
591
  }
351
592
  else {
352
- name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
353
- leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), lexer_1.TokenKind.LeftParen);
593
+ name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
594
+ leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), TokenKind_1.TokenKind.LeftParen);
354
595
  //prevent functions from ending with type designators
355
596
  let lastChar = name.text[name.text.length - 1];
356
597
  if (['$', '%', '!', '#', '&'].includes(lastChar)) {
357
598
  //don't throw this error; let the parser continue
358
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { range: name.range }));
599
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { location: name.location }));
359
600
  }
360
601
  //flag functions with keywords for names (only for standard functions)
361
- if (checkIdentifier && lexer_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
362
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
602
+ if (checkIdentifier && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
603
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { location: name.location }));
363
604
  }
364
605
  }
365
606
  let params = [];
366
607
  let asToken;
367
- let typeToken;
368
- if (!this.check(lexer_1.TokenKind.RightParen)) {
608
+ let typeExpression;
609
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
369
610
  do {
370
- if (params.length >= Expression_1.CallExpression.MaximumArguments) {
371
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
372
- }
373
611
  params.push(this.functionParameter());
374
- } while (this.match(lexer_1.TokenKind.Comma));
612
+ } while (this.match(TokenKind_1.TokenKind.Comma));
375
613
  }
376
614
  let rightParen = this.advance();
377
- if (this.check(lexer_1.TokenKind.As)) {
378
- asToken = this.advance();
379
- typeToken = this.typeToken();
380
- if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript)) {
381
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a = typeToken.text) !== null && _a !== void 0 ? _a : '')), { range: typeToken.range }));
382
- }
615
+ if (this.check(TokenKind_1.TokenKind.As)) {
616
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
383
617
  }
384
618
  params.reduce((haveFoundOptional, param) => {
385
619
  if (haveFoundOptional && !param.defaultValue) {
386
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(param.name.text)), { range: param.range }));
620
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(param.tokens.name.text)), { location: param.location }));
387
621
  }
388
622
  return haveFoundOptional || !!param.defaultValue;
389
623
  }, false);
390
624
  this.consumeStatementSeparators(true);
391
- let func = new Expression_1.FunctionExpression(params, undefined, //body
392
- functionType, undefined, //ending keyword
393
- leftParen, rightParen, asToken, typeToken, //return type
394
- this.currentFunctionExpression, this.currentNamespaceName, (_c = (_b = this.currentNamespace) === null || _b === void 0 ? void 0 : _b.symbolTable) !== null && _c !== void 0 ? _c : this.symbolTable);
395
- //if there is a parent function, register this function with the parent
396
- if (this.currentFunctionExpression) {
397
- this.currentFunctionExpression.childFunctionExpressions.push(func);
398
- }
399
- // add the function to the relevant symbol tables
400
- if (!isAnonymous) {
401
- const funcType = func.getFunctionType();
402
- funcType.setName(name.text);
403
- // add the function as declared to the current namespace's table
404
- (_d = this.currentNamespace) === null || _d === void 0 ? void 0 : _d.symbolTable.addSymbol(name.text, name.range, funcType);
405
- let fullyQualifiedName = name.text;
406
- if (this.currentNamespaceName) {
407
- // add the "namespaced" name of this function to the parent symbol table
408
- fullyQualifiedName = this.currentNamespaceName.getName(ParseMode.BrighterScript) + '.' + name.text;
409
- }
410
- this.currentSymbolTable.addSymbol(fullyQualifiedName, name.range, funcType);
411
- }
412
- this._references.functionExpressions.push(func);
413
- let previousFunctionExpression = this.currentFunctionExpression;
414
- this.currentFunctionExpression = func;
415
- //make sure to restore the currentFunctionExpression even if the body block fails to parse
416
- try {
417
- //support ending the function with `end sub` OR `end function`
418
- func.body = this.block();
419
- }
420
- finally {
421
- this.currentFunctionExpression = previousFunctionExpression;
422
- }
423
- if (!func.body) {
424
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionTypeText)), { range: this.peek().range }));
425
- throw this.lastDiagnosticAsError();
426
- }
625
+ //support ending the function with `end sub` OR `end function`
626
+ let body = this.block();
627
+ //if the parser was unable to produce a block, make an empty one so the AST makes some sense...
427
628
  // consume 'end sub' or 'end function'
428
- func.end = this.advance();
429
- let expectedEndKind = isSub ? lexer_1.TokenKind.EndSub : lexer_1.TokenKind.EndFunction;
629
+ const endFunctionType = this.advance();
630
+ let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
430
631
  //if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
431
632
  //add an error but don't hard-fail so the AST can continue more gracefully
432
- if (func.end.kind !== expectedEndKind) {
433
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, func.end.text)), { range: this.peek().range }));
633
+ if (endFunctionType.kind !== expectedEndKind) {
634
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionTypeText, endFunctionType.text)), { location: endFunctionType.location }));
434
635
  }
435
- func.callExpressions = this.callExpressions;
636
+ if (!body) {
637
+ body = new Statement_1.Block({ statements: [] });
638
+ }
639
+ let func = new Expression_1.FunctionExpression({
640
+ parameters: params,
641
+ body: body,
642
+ functionType: functionType,
643
+ endFunctionType: endFunctionType,
644
+ leftParen: leftParen,
645
+ rightParen: rightParen,
646
+ as: asToken,
647
+ returnTypeExpression: typeExpression
648
+ });
436
649
  if (isAnonymous) {
437
650
  return func;
438
651
  }
439
652
  else {
440
- let result = new Statement_1.FunctionStatement(name, func, this.currentNamespaceName);
441
- func.functionStatement = result;
442
- this._references.functionStatements.push(result);
653
+ let result = new Statement_1.FunctionStatement({ name: name, func: func });
443
654
  return result;
444
655
  }
445
656
  }
@@ -449,77 +660,74 @@ class Parser {
449
660
  this.callExpressions = previousCallExpressions;
450
661
  }
451
662
  }
452
- identifier() {
453
- const identifier = this.advance();
454
- // force the name into an identifier so the AST makes some sense
455
- identifier.kind = lexer_1.TokenKind.Identifier;
456
- return identifier;
457
- }
458
663
  functionParameter() {
459
- if (!this.checkAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
460
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { range: this.peek().range }));
664
+ if (!this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
665
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { location: this.peek().location }));
461
666
  throw this.lastDiagnosticAsError();
462
667
  }
463
- const name = this.identifier();
464
- let typeToken;
668
+ let name = this.advance();
669
+ // force the name into an identifier so the AST makes some sense
670
+ name.kind = TokenKind_1.TokenKind.Identifier;
671
+ let typeExpression;
465
672
  let defaultValue;
466
- let equalsToken;
673
+ let equalToken;
467
674
  // parse argument default value
468
- if (this.match(lexer_1.TokenKind.Equal)) {
469
- equalsToken = this.previous();
675
+ if ((equalToken = this.consumeTokenIf(TokenKind_1.TokenKind.Equal))) {
470
676
  // it seems any expression is allowed here -- including ones that operate on other arguments!
471
- defaultValue = this.expression();
677
+ defaultValue = this.expression(false);
472
678
  }
473
679
  let asToken = null;
474
- if (this.check(lexer_1.TokenKind.As)) {
475
- asToken = this.advance();
476
- typeToken = this.typeToken();
477
- if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript)) {
478
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text)), { range: typeToken.range }));
479
- throw this.lastDiagnosticAsError();
480
- }
481
- }
482
- let type;
483
- if (typeToken) {
484
- type = util_1.util.tokenToBscType(typeToken);
485
- }
486
- else if (defaultValue) {
487
- type = getBscTypeFromExpression(defaultValue, this.currentFunctionExpression);
488
- }
489
- else {
490
- type = new DynamicType_1.DynamicType();
491
- }
492
- return new Expression_1.FunctionParameterExpression(name, type, equalsToken, defaultValue, asToken, typeToken, this.currentNamespaceName);
680
+ if (this.check(TokenKind_1.TokenKind.As)) {
681
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
682
+ }
683
+ return new Expression_1.FunctionParameterExpression({
684
+ name: name,
685
+ equals: equalToken,
686
+ defaultValue: defaultValue,
687
+ as: asToken,
688
+ typeExpression: typeExpression
689
+ });
493
690
  }
494
- assignment() {
495
- let name = this.identifier();
691
+ assignment(allowTypedAssignment = false) {
692
+ let name = this.advance();
496
693
  //add diagnostic if name is a reserved word that cannot be used as an identifier
497
- if (lexer_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
498
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
499
- }
500
- let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(lexer_1.AssignmentOperators, name.text), ...lexer_1.AssignmentOperators);
501
- let value = this.expression();
502
- let result;
503
- if (operator.kind === lexer_1.TokenKind.Equal) {
504
- result = new Statement_1.AssignmentStatement(name, operator, value, this.currentFunctionExpression);
694
+ if (TokenKind_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
695
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { location: name.location }));
505
696
  }
506
- else {
507
- result = new Statement_1.AssignmentStatement(name, operator, new Expression_1.BinaryExpression(new Expression_1.VariableExpression(name, this.currentNamespaceName), operator, value), this.currentFunctionExpression);
697
+ let asToken;
698
+ let typeExpression;
699
+ if (allowTypedAssignment) {
700
+ //look for `as SOME_TYPE`
701
+ if (this.check(TokenKind_1.TokenKind.As)) {
702
+ this.warnIfNotBrighterScriptMode('typed assignment');
703
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
704
+ }
508
705
  }
509
- this._references.assignmentStatements.push(result);
510
- const assignmentType = getBscTypeFromExpression(result.value, this.currentFunctionExpression);
511
- this.currentSymbolTable.addSymbol(name.text, name.range, assignmentType);
706
+ let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier([TokenKind_1.TokenKind.Equal], name.text), ...[TokenKind_1.TokenKind.Equal]);
707
+ let value = this.expression();
708
+ let result = new Statement_1.AssignmentStatement({ equals: operator, name: name, value: value, as: asToken, typeExpression: typeExpression });
709
+ return result;
710
+ }
711
+ augmentedAssignment() {
712
+ let item = this.expression();
713
+ let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(...TokenKind_1.CompoundAssignmentOperators), ...TokenKind_1.CompoundAssignmentOperators);
714
+ let value = this.expression();
715
+ let result = new Statement_1.AugmentedAssignmentStatement({
716
+ item: item,
717
+ operator: operator,
718
+ value: value
719
+ });
512
720
  return result;
513
721
  }
514
722
  checkLibrary() {
515
- let isLibraryToken = this.check(lexer_1.TokenKind.Library);
723
+ let isLibraryToken = this.check(TokenKind_1.TokenKind.Library);
516
724
  //if we are at the top level, any line that starts with "library" should be considered a library statement
517
725
  if (this.isAtRootLevel() && isLibraryToken) {
518
726
  return true;
519
727
  //not at root level, library statements are all invalid here, but try to detect if the tokens look
520
728
  //like a library statement (and let the libraryStatement function handle emitting the diagnostics)
521
729
  }
522
- else if (isLibraryToken && this.checkNext(lexer_1.TokenKind.StringLiteral)) {
730
+ else if (isLibraryToken && this.checkNext(TokenKind_1.TokenKind.StringLiteral)) {
523
731
  return true;
524
732
  //definitely not a library statement
525
733
  }
@@ -527,58 +735,81 @@ class Parser {
527
735
  return false;
528
736
  }
529
737
  }
738
+ checkAlias() {
739
+ let isAliasToken = this.check(TokenKind_1.TokenKind.Alias);
740
+ //if we are at the top level, any line that starts with "alias" should be considered a alias statement
741
+ if (this.isAtRootLevel() && isAliasToken) {
742
+ return true;
743
+ //not at root level, alias statements are all invalid here, but try to detect if the tokens look
744
+ //like a alias statement (and let the alias function handle emitting the diagnostics)
745
+ }
746
+ else if (isAliasToken && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
747
+ return true;
748
+ //definitely not a alias statement
749
+ }
750
+ else {
751
+ return false;
752
+ }
753
+ }
530
754
  statement() {
531
755
  if (this.checkLibrary()) {
532
756
  return this.libraryStatement();
533
757
  }
534
- if (this.check(lexer_1.TokenKind.Import)) {
758
+ if (this.check(TokenKind_1.TokenKind.Import)) {
535
759
  return this.importStatement();
536
760
  }
537
- if (this.check(lexer_1.TokenKind.Stop)) {
761
+ if (this.check(TokenKind_1.TokenKind.Typecast) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
762
+ return this.typecastStatement();
763
+ }
764
+ if (this.checkAlias()) {
765
+ return this.aliasStatement();
766
+ }
767
+ if (this.check(TokenKind_1.TokenKind.Stop)) {
538
768
  return this.stopStatement();
539
769
  }
540
- if (this.check(lexer_1.TokenKind.If)) {
770
+ if (this.check(TokenKind_1.TokenKind.If)) {
541
771
  return this.ifStatement();
542
772
  }
543
773
  //`try` must be followed by a block, otherwise it could be a local variable
544
- if (this.check(lexer_1.TokenKind.Try) && this.checkAnyNext(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment)) {
774
+ if (this.check(TokenKind_1.TokenKind.Try) && this.checkAnyNext(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
545
775
  return this.tryCatchStatement();
546
776
  }
547
- if (this.check(lexer_1.TokenKind.Throw)) {
777
+ if (this.check(TokenKind_1.TokenKind.Throw)) {
548
778
  return this.throwStatement();
549
779
  }
550
- if (this.checkAny(lexer_1.TokenKind.Print, lexer_1.TokenKind.Question)) {
780
+ if (this.checkAny(TokenKind_1.TokenKind.Print, TokenKind_1.TokenKind.Question)) {
551
781
  return this.printStatement();
552
782
  }
553
- if (this.check(lexer_1.TokenKind.Dim)) {
783
+ if (this.check(TokenKind_1.TokenKind.Dim)) {
554
784
  return this.dimStatement();
555
785
  }
556
- if (this.check(lexer_1.TokenKind.While)) {
786
+ if (this.check(TokenKind_1.TokenKind.While)) {
557
787
  return this.whileStatement();
558
788
  }
559
- if (this.check(lexer_1.TokenKind.ExitWhile)) {
560
- return this.exitWhile();
789
+ if (this.checkAny(TokenKind_1.TokenKind.Exit, TokenKind_1.TokenKind.ExitWhile)) {
790
+ return this.exitStatement();
561
791
  }
562
- if (this.check(lexer_1.TokenKind.For)) {
792
+ if (this.check(TokenKind_1.TokenKind.For)) {
563
793
  return this.forStatement();
564
794
  }
565
- if (this.check(lexer_1.TokenKind.ForEach)) {
795
+ if (this.check(TokenKind_1.TokenKind.ForEach)) {
566
796
  return this.forEachStatement();
567
797
  }
568
- if (this.check(lexer_1.TokenKind.ExitFor)) {
569
- return this.exitFor();
570
- }
571
- if (this.check(lexer_1.TokenKind.End)) {
798
+ if (this.check(TokenKind_1.TokenKind.End)) {
572
799
  return this.endStatement();
573
800
  }
574
- if (this.match(lexer_1.TokenKind.Return)) {
801
+ if (this.match(TokenKind_1.TokenKind.Return)) {
575
802
  return this.returnStatement();
576
803
  }
577
- if (this.check(lexer_1.TokenKind.Goto)) {
804
+ if (this.check(TokenKind_1.TokenKind.Goto)) {
578
805
  return this.gotoStatement();
579
806
  }
807
+ //the continue keyword (followed by `for`, `while`, or a statement separator)
808
+ 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)) {
809
+ return this.continueStatement();
810
+ }
580
811
  //does this line look like a label? (i.e. `someIdentifier:` )
581
- if (this.check(lexer_1.TokenKind.Identifier) && this.checkNext(lexer_1.TokenKind.Colon) && this.checkPrevious(lexer_1.TokenKind.Newline)) {
812
+ if (this.check(TokenKind_1.TokenKind.Identifier) && this.checkNext(TokenKind_1.TokenKind.Colon) && this.checkPrevious(TokenKind_1.TokenKind.Newline)) {
582
813
  try {
583
814
  return this.labelStatement();
584
815
  }
@@ -592,9 +823,47 @@ class Parser {
592
823
  // BrightScript is like python, in that variables can be declared without a `var`,
593
824
  // `let`, (...) keyword. As such, we must check the token *after* an identifier to figure
594
825
  // out what to do with it.
595
- if (this.checkAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
596
- this.checkAnyNext(...lexer_1.AssignmentOperators)) {
597
- return this.assignment();
826
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
827
+ if (this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
828
+ if (this.checkAnyNext(...TokenKind_1.CompoundAssignmentOperators)) {
829
+ return this.augmentedAssignment();
830
+ }
831
+ return this.assignment();
832
+ }
833
+ else if (this.checkNext(TokenKind_1.TokenKind.As)) {
834
+ // may be a typed assignment
835
+ const backtrack = this.current;
836
+ let validTypeExpression = false;
837
+ try {
838
+ // skip the identifier, and check for valid type expression
839
+ this.advance();
840
+ const parts = this.consumeAsTokenAndTypeExpression(true);
841
+ validTypeExpression = !!((parts === null || parts === void 0 ? void 0 : parts[0]) && (parts === null || parts === void 0 ? void 0 : parts[1]));
842
+ }
843
+ catch (e) {
844
+ // ignore any errors
845
+ }
846
+ finally {
847
+ this.current = backtrack;
848
+ }
849
+ if (validTypeExpression) {
850
+ // there is a valid 'as' and type expression
851
+ return this.assignment(true);
852
+ }
853
+ }
854
+ }
855
+ //some BrighterScript keywords are allowed as a local identifiers, so we need to check for them AFTER the assignment check
856
+ if (this.check(TokenKind_1.TokenKind.Interface)) {
857
+ return this.interfaceDeclaration();
858
+ }
859
+ if (this.check(TokenKind_1.TokenKind.Class)) {
860
+ return this.classDeclaration();
861
+ }
862
+ if (this.check(TokenKind_1.TokenKind.Namespace)) {
863
+ return this.namespaceStatement();
864
+ }
865
+ if (this.check(TokenKind_1.TokenKind.Enum)) {
866
+ return this.enumDeclaration();
598
867
  }
599
868
  // TODO: support multi-statements
600
869
  return this.setStatement();
@@ -603,10 +872,10 @@ class Parser {
603
872
  const whileKeyword = this.advance();
604
873
  const condition = this.expression();
605
874
  this.consumeStatementSeparators();
606
- const whileBlock = this.block(lexer_1.TokenKind.EndWhile);
875
+ const whileBlock = this.block(TokenKind_1.TokenKind.EndWhile);
607
876
  let endWhile;
608
- if (!whileBlock || this.peek().kind !== lexer_1.TokenKind.EndWhile) {
609
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('while')), { range: this.peek().range }));
877
+ if (!whileBlock || this.peek().kind !== TokenKind_1.TokenKind.EndWhile) {
878
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('while')), { location: this.peek().location }));
610
879
  if (!whileBlock) {
611
880
  throw this.lastDiagnosticAsError();
612
881
  }
@@ -614,11 +883,34 @@ class Parser {
614
883
  else {
615
884
  endWhile = this.advance();
616
885
  }
617
- return new Statement_1.WhileStatement({ while: whileKeyword, endWhile: endWhile }, condition, whileBlock);
886
+ return new Statement_1.WhileStatement({
887
+ while: whileKeyword,
888
+ endWhile: endWhile,
889
+ condition: condition,
890
+ body: whileBlock
891
+ });
618
892
  }
619
- exitWhile() {
620
- let keyword = this.advance();
621
- return new Statement_1.ExitWhileStatement({ exitWhile: keyword });
893
+ exitStatement() {
894
+ let exitToken = this.advance();
895
+ if (exitToken.kind === TokenKind_1.TokenKind.ExitWhile) {
896
+ // `exitwhile` is allowed in code, and means `exit while`
897
+ // use an ExitStatement that is nicer to work with by breaking the `exit` and `while` tokens apart
898
+ const exitText = exitToken.text.substring(0, 4);
899
+ const whileText = exitToken.text.substring(4);
900
+ const originalRange = exitToken.location.range;
901
+ const originalStart = originalRange.start;
902
+ const exitRange = util_1.util.createRange(originalStart.line, originalStart.character, originalStart.line, originalStart.character + 4);
903
+ const whileRange = util_1.util.createRange(originalStart.line, originalStart.character + 4, originalStart.line, originalStart.character + exitToken.text.length);
904
+ exitToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Exit, exitText, util_1.util.createLocationFromRange(exitToken.location.uri, exitRange));
905
+ this.tokens[this.current - 1] = exitToken;
906
+ const newLoopToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.While, whileText, util_1.util.createLocationFromRange(exitToken.location.uri, whileRange));
907
+ this.tokens.splice(this.current, 0, newLoopToken);
908
+ }
909
+ const loopTypeToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For), TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For);
910
+ return new Statement_1.ExitStatement({
911
+ exit: exitToken,
912
+ loopType: loopTypeToken
913
+ });
622
914
  }
623
915
  forStatement() {
624
916
  const forToken = this.advance();
@@ -628,7 +920,7 @@ class Parser {
628
920
  const finalValue = this.expression();
629
921
  let incrementExpression;
630
922
  let stepToken;
631
- if (this.check(lexer_1.TokenKind.Step)) {
923
+ if (this.check(TokenKind_1.TokenKind.Step)) {
632
924
  stepToken = this.advance();
633
925
  incrementExpression = this.expression();
634
926
  }
@@ -636,10 +928,10 @@ class Parser {
636
928
  // BrightScript for/to/step loops default to a step of 1 if no `step` is provided
637
929
  }
638
930
  this.consumeStatementSeparators();
639
- let body = this.block(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next);
931
+ let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
640
932
  let endForToken;
641
- if (!body || !this.checkAny(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next)) {
642
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
933
+ if (!body || !this.checkAny(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next)) {
934
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { location: this.peek().location }));
643
935
  if (!body) {
644
936
  throw this.lastDiagnosticAsError();
645
937
  }
@@ -649,112 +941,107 @@ class Parser {
649
941
  }
650
942
  // WARNING: BrightScript doesn't delete the loop initial value after a for/to loop! It just
651
943
  // stays around in scope with whatever value it was when the loop exited.
652
- return new Statement_1.ForStatement(forToken, initializer, toToken, finalValue, body, endForToken, stepToken, incrementExpression);
944
+ return new Statement_1.ForStatement({
945
+ for: forToken,
946
+ counterDeclaration: initializer,
947
+ to: toToken,
948
+ finalValue: finalValue,
949
+ body: body,
950
+ endFor: endForToken,
951
+ step: stepToken,
952
+ increment: incrementExpression
953
+ });
653
954
  }
654
955
  forEachStatement() {
655
956
  let forEach = this.advance();
656
- let name = this.identifier();
957
+ let name = this.advance();
657
958
  let maybeIn = this.peek();
658
- if (this.check(lexer_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
959
+ if (this.check(TokenKind_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
659
960
  this.advance();
660
961
  }
661
962
  else {
662
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInAfterForEach(name.text)), { range: this.peek().range }));
963
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInAfterForEach(name.text)), { location: this.peek().location }));
663
964
  throw this.lastDiagnosticAsError();
664
965
  }
966
+ maybeIn.kind = TokenKind_1.TokenKind.In;
665
967
  let target = this.expression();
666
968
  if (!target) {
667
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
969
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { location: this.peek().location }));
668
970
  throw this.lastDiagnosticAsError();
669
971
  }
670
972
  this.consumeStatementSeparators();
671
- let body = this.block(lexer_1.TokenKind.EndFor, lexer_1.TokenKind.Next);
973
+ let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
672
974
  if (!body) {
673
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
975
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { location: this.peek().location }));
674
976
  throw this.lastDiagnosticAsError();
675
977
  }
676
978
  let endFor = this.advance();
677
- //TODO infer type from `target`
678
- const itemType = new DynamicType_1.DynamicType();
679
- this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
680
- return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
681
- }
682
- exitFor() {
683
- let keyword = this.advance();
684
- return new Statement_1.ExitForStatement({ exitFor: keyword });
685
- }
686
- commentStatement() {
687
- //if this comment is on the same line as the previous statement,
688
- //then this comment should be treated as a single-line comment
689
- let prev = this.previous();
690
- if ((prev === null || prev === void 0 ? void 0 : prev.range.end.line) === this.peek().range.start.line) {
691
- return new Statement_1.CommentStatement([this.advance()]);
692
- }
693
- else {
694
- let comments = [this.advance()];
695
- while (this.check(lexer_1.TokenKind.Newline) && this.checkNext(lexer_1.TokenKind.Comment)) {
696
- this.advance();
697
- comments.push(this.advance());
698
- }
699
- return new Statement_1.CommentStatement(comments);
700
- }
979
+ return new Statement_1.ForEachStatement({
980
+ forEach: forEach,
981
+ in: maybeIn,
982
+ endFor: endFor,
983
+ item: name,
984
+ target: target,
985
+ body: body
986
+ });
701
987
  }
702
988
  namespaceStatement() {
703
989
  this.warnIfNotBrighterScriptMode('namespace');
704
990
  let keyword = this.advance();
705
- if (!this.isAtRootLevel()) {
706
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.keywordMustBeDeclaredAtRootLevel('namespace')), { range: keyword.range }));
707
- }
708
991
  this.namespaceAndFunctionDepth++;
709
- let name = this.getNamespacedVariableNameExpression();
992
+ let name = this.identifyingExpression();
710
993
  //set the current namespace name
711
- let result = new Statement_1.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
712
- this.currentNamespace = result;
713
- this.globalTerminators.push([lexer_1.TokenKind.EndNamespace]);
994
+ this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
714
995
  let body = this.body();
715
996
  this.globalTerminators.pop();
716
- //unset the current namespace name
717
- this.currentNamespace = undefined;
718
997
  let endKeyword;
719
- if (this.check(lexer_1.TokenKind.EndNamespace)) {
998
+ if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
720
999
  endKeyword = this.advance();
721
1000
  }
722
1001
  else {
723
1002
  //the `end namespace` keyword is missing. add a diagnostic, but keep parsing
724
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('namespace')), { range: keyword.range }));
1003
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('namespace')), { location: keyword.location }));
725
1004
  }
726
1005
  this.namespaceAndFunctionDepth--;
727
- result.body = body;
728
- result.endKeyword = endKeyword;
729
- this._references.namespaceStatements.push(result);
1006
+ let result = new Statement_1.NamespaceStatement({
1007
+ namespace: keyword,
1008
+ nameExpression: name,
1009
+ body: body,
1010
+ endNamespace: endKeyword
1011
+ });
1012
+ //cache the range property so that plugins can't affect it
1013
+ result.cacheLocation();
1014
+ result.body.symbolTable.name += `: namespace '${result.name}'`;
730
1015
  return result;
731
1016
  }
732
1017
  /**
733
1018
  * Get an expression with identifiers separated by periods. Useful for namespaces and class extends
734
1019
  */
735
- getNamespacedVariableNameExpression() {
736
- let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1020
+ identifyingExpression(allowedTokenKinds) {
1021
+ allowedTokenKinds = allowedTokenKinds !== null && allowedTokenKinds !== void 0 ? allowedTokenKinds : this.allowedLocalIdentifiers;
1022
+ let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...allowedTokenKinds);
737
1023
  let expr;
738
1024
  if (firstIdentifier) {
739
1025
  // force it into an identifier so the AST makes some sense
740
- firstIdentifier.kind = lexer_1.TokenKind.Identifier;
741
- expr = new Expression_1.VariableExpression(firstIdentifier, null);
1026
+ firstIdentifier.kind = TokenKind_1.TokenKind.Identifier;
1027
+ const varExpr = new Expression_1.VariableExpression({ name: firstIdentifier });
1028
+ expr = varExpr;
742
1029
  //consume multiple dot identifiers (i.e. `Name.Space.Can.Have.Many.Parts`)
743
- while (this.check(lexer_1.TokenKind.Dot)) {
744
- let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.foundUnexpectedToken(this.peek().text), lexer_1.TokenKind.Dot);
1030
+ while (this.check(TokenKind_1.TokenKind.Dot)) {
1031
+ let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.Dot);
745
1032
  if (!dot) {
746
1033
  break;
747
1034
  }
748
- let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...lexer_1.AllowedProperties);
1035
+ let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...allowedTokenKinds, ...TokenKind_1.AllowedProperties);
749
1036
  if (!identifier) {
750
1037
  break;
751
1038
  }
752
1039
  // force it into an identifier so the AST makes some sense
753
- identifier.kind = lexer_1.TokenKind.Identifier;
754
- expr = new Expression_1.DottedGetExpression(expr, identifier, dot);
1040
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
1041
+ expr = new Expression_1.DottedGetExpression({ obj: expr, name: identifier, dot: dot });
755
1042
  }
756
1043
  }
757
- return new Expression_1.NamespacedVariableNameExpression(expr);
1044
+ return expr;
758
1045
  }
759
1046
  /**
760
1047
  * Add an 'unexpected token' diagnostic for any token found between current and the first stopToken found.
@@ -762,13 +1049,13 @@ class Parser {
762
1049
  flagUntil(...stopTokens) {
763
1050
  while (!this.checkAny(...stopTokens) && !this.isAtEnd()) {
764
1051
  let token = this.advance();
765
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.foundUnexpectedToken(token.text)), { range: token.range }));
1052
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(token.text)), { location: token.location }));
766
1053
  }
767
1054
  }
768
1055
  /**
769
1056
  * Consume tokens until one of the `stopTokenKinds` is encountered
770
- * @param tokenKinds
771
- * @return - the list of tokens consumed, EXCLUDING the `stopTokenKind` (you can use `this.peek()` to see which one it was)
1057
+ * @param stopTokenKinds a list of tokenKinds where any tokenKind in this list will result in a match
1058
+ * @returns - the list of tokens consumed, EXCLUDING the `stopTokenKind` (you can use `this.peek()` to see which one it was)
772
1059
  */
773
1060
  consumeUntil(...stopTokenKinds) {
774
1061
  let result = [];
@@ -778,33 +1065,77 @@ class Parser {
778
1065
  }
779
1066
  return result;
780
1067
  }
1068
+ constDeclaration() {
1069
+ this.warnIfNotBrighterScriptMode('const declaration');
1070
+ const constToken = this.advance();
1071
+ const nameToken = this.identifier(...this.allowedLocalIdentifiers);
1072
+ const equalToken = this.consumeToken(TokenKind_1.TokenKind.Equal);
1073
+ const expression = this.expression();
1074
+ const statement = new Statement_1.ConstStatement({
1075
+ const: constToken,
1076
+ name: nameToken,
1077
+ equals: equalToken,
1078
+ value: expression
1079
+ });
1080
+ return statement;
1081
+ }
781
1082
  libraryStatement() {
782
1083
  let libStatement = new Statement_1.LibraryStatement({
783
1084
  library: this.advance(),
784
1085
  //grab the next token only if it's a string
785
- filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), lexer_1.TokenKind.StringLiteral)
1086
+ filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
786
1087
  });
787
- this._references.libraryStatements.push(libStatement);
788
1088
  return libStatement;
789
1089
  }
790
1090
  importStatement() {
791
1091
  this.warnIfNotBrighterScriptMode('import statements');
792
- let importStatement = new Statement_1.ImportStatement(this.advance(),
793
- //grab the next token only if it's a string
794
- this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), lexer_1.TokenKind.StringLiteral));
795
- this._references.importStatements.push(importStatement);
1092
+ let importStatement = new Statement_1.ImportStatement({
1093
+ import: this.advance(),
1094
+ //grab the next token only if it's a string
1095
+ path: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral)
1096
+ });
796
1097
  return importStatement;
797
1098
  }
1099
+ typecastStatement() {
1100
+ this.warnIfNotBrighterScriptMode('typecast statements');
1101
+ const typecastToken = this.advance();
1102
+ const typecastExpr = this.expression();
1103
+ if ((0, reflection_1.isTypecastExpression)(typecastExpr)) {
1104
+ return new Statement_1.TypecastStatement({
1105
+ typecast: typecastToken,
1106
+ typecastExpression: typecastExpr
1107
+ });
1108
+ }
1109
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('typecast')), { location: {
1110
+ uri: typecastToken.location.uri,
1111
+ range: util_1.util.createBoundingRange(typecastToken, this.peek())
1112
+ } }));
1113
+ throw this.lastDiagnosticAsError();
1114
+ }
1115
+ aliasStatement() {
1116
+ this.warnIfNotBrighterScriptMode('alias statements');
1117
+ const aliasToken = this.advance();
1118
+ const name = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('alias'), TokenKind_1.TokenKind.Identifier);
1119
+ const equals = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.Equal), TokenKind_1.TokenKind.Equal);
1120
+ let value = this.identifyingExpression();
1121
+ let aliasStmt = new Statement_1.AliasStatement({
1122
+ alias: aliasToken,
1123
+ name: name,
1124
+ equals: equals,
1125
+ value: value
1126
+ });
1127
+ return aliasStmt;
1128
+ }
798
1129
  annotationExpression() {
799
1130
  const atToken = this.advance();
800
- const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1131
+ const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
801
1132
  if (identifier) {
802
- identifier.kind = lexer_1.TokenKind.Identifier;
1133
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
803
1134
  }
804
- let annotation = new Expression_1.AnnotationExpression(atToken, identifier);
1135
+ let annotation = new Expression_1.AnnotationExpression({ at: atToken, name: identifier });
805
1136
  this.pendingAnnotations.push(annotation);
806
1137
  //optional arguments
807
- if (this.check(lexer_1.TokenKind.LeftParen)) {
1138
+ if (this.check(TokenKind_1.TokenKind.LeftParen)) {
808
1139
  let leftParen = this.advance();
809
1140
  annotation.call = this.finishCall(leftParen, annotation, false);
810
1141
  }
@@ -817,7 +1148,7 @@ class Parser {
817
1148
  }
818
1149
  const questionMarkToken = this.advance();
819
1150
  //consume newlines or comments
820
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1151
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
821
1152
  this.advance();
822
1153
  }
823
1154
  let consequent;
@@ -826,12 +1157,12 @@ class Parser {
826
1157
  }
827
1158
  catch (_a) { }
828
1159
  //consume newlines or comments
829
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1160
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
830
1161
  this.advance();
831
1162
  }
832
- const colonToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedTokenAButFoundTokenB(lexer_1.TokenKind.Colon, this.peek().text), lexer_1.TokenKind.Colon);
1163
+ const colonToken = this.tryConsumeToken(TokenKind_1.TokenKind.Colon);
833
1164
  //consume newlines
834
- while (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1165
+ while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
835
1166
  this.advance();
836
1167
  }
837
1168
  let alternate;
@@ -839,136 +1170,179 @@ class Parser {
839
1170
  alternate = this.expression();
840
1171
  }
841
1172
  catch (_b) { }
842
- return new Expression_1.TernaryExpression(test, questionMarkToken, consequent, colonToken, alternate);
1173
+ return new Expression_1.TernaryExpression({
1174
+ test: test,
1175
+ questionMark: questionMarkToken,
1176
+ consequent: consequent,
1177
+ colon: colonToken,
1178
+ alternate: alternate
1179
+ });
843
1180
  }
844
1181
  nullCoalescingExpression(test) {
845
1182
  this.warnIfNotBrighterScriptMode('null coalescing operator');
846
1183
  const questionQuestionToken = this.advance();
847
1184
  const alternate = this.expression();
848
- return new Expression_1.NullCoalescingExpression(test, questionQuestionToken, alternate);
1185
+ return new Expression_1.NullCoalescingExpression({
1186
+ consequent: test,
1187
+ questionQuestion: questionQuestionToken,
1188
+ alternate: alternate
1189
+ });
1190
+ }
1191
+ regexLiteralExpression() {
1192
+ this.warnIfNotBrighterScriptMode('regular expression literal');
1193
+ return new Expression_1.RegexLiteralExpression({
1194
+ regexLiteral: this.advance()
1195
+ });
849
1196
  }
850
1197
  templateString(isTagged) {
851
1198
  this.warnIfNotBrighterScriptMode('template string');
852
1199
  //get the tag name
853
1200
  let tagName;
854
1201
  if (isTagged) {
855
- tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
1202
+ tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
856
1203
  // force it into an identifier so the AST makes some sense
857
- tagName.kind = lexer_1.TokenKind.Identifier;
1204
+ tagName.kind = TokenKind_1.TokenKind.Identifier;
858
1205
  }
859
1206
  let quasis = [];
860
1207
  let expressions = [];
861
1208
  let openingBacktick = this.peek();
862
1209
  this.advance();
863
1210
  let currentQuasiExpressionParts = [];
864
- while (!this.isAtEnd() && !this.check(lexer_1.TokenKind.BackTick)) {
1211
+ while (!this.isAtEnd() && !this.check(TokenKind_1.TokenKind.BackTick)) {
865
1212
  let next = this.peek();
866
- if (next.kind === lexer_1.TokenKind.TemplateStringQuasi) {
1213
+ if (next.kind === TokenKind_1.TokenKind.TemplateStringQuasi) {
867
1214
  //a quasi can actually be made up of multiple quasis when it includes char literals
868
- currentQuasiExpressionParts.push(new Expression_1.LiteralExpression(next));
1215
+ currentQuasiExpressionParts.push(new Expression_1.LiteralExpression({ value: next }));
869
1216
  this.advance();
870
1217
  }
871
- else if (next.kind === lexer_1.TokenKind.EscapedCharCodeLiteral) {
872
- currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression(next));
1218
+ else if (next.kind === TokenKind_1.TokenKind.EscapedCharCodeLiteral) {
1219
+ currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression({ value: next }));
873
1220
  this.advance();
874
1221
  }
875
1222
  else {
876
1223
  //finish up the current quasi
877
- quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
1224
+ quasis.push(new Expression_1.TemplateStringQuasiExpression({ expressions: currentQuasiExpressionParts }));
878
1225
  currentQuasiExpressionParts = [];
879
- if (next.kind === lexer_1.TokenKind.TemplateStringExpressionBegin) {
1226
+ if (next.kind === TokenKind_1.TokenKind.TemplateStringExpressionBegin) {
880
1227
  this.advance();
881
1228
  }
882
1229
  //now keep this expression
883
1230
  expressions.push(this.expression());
884
- if (!this.isAtEnd() && this.check(lexer_1.TokenKind.TemplateStringExpressionEnd)) {
1231
+ if (!this.isAtEnd() && this.check(TokenKind_1.TokenKind.TemplateStringExpressionEnd)) {
885
1232
  //TODO is it an error if this is not present?
886
1233
  this.advance();
887
1234
  }
888
1235
  else {
889
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unterminatedTemplateExpression()), { range: util_1.util.getRange(openingBacktick, this.peek()) }));
1236
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unterminatedTemplateExpression()), { location: {
1237
+ uri: openingBacktick.location.uri,
1238
+ range: util_1.util.createBoundingRange(openingBacktick, this.peek())
1239
+ } }));
890
1240
  throw this.lastDiagnosticAsError();
891
1241
  }
892
1242
  }
893
1243
  }
894
1244
  //store the final set of quasis
895
- quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
1245
+ quasis.push(new Expression_1.TemplateStringQuasiExpression({ expressions: currentQuasiExpressionParts }));
896
1246
  if (this.isAtEnd()) {
897
1247
  //error - missing backtick
898
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unterminatedTemplateStringAtEndOfFile()), { range: util_1.util.getRange(openingBacktick, this.peek()) }));
1248
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unterminatedTemplateStringAtEndOfFile()), { location: {
1249
+ uri: openingBacktick.location.uri,
1250
+ range: util_1.util.createBoundingRange(openingBacktick, this.peek())
1251
+ } }));
899
1252
  throw this.lastDiagnosticAsError();
900
1253
  }
901
1254
  else {
902
1255
  let closingBacktick = this.advance();
903
1256
  if (isTagged) {
904
- return new Expression_1.TaggedTemplateStringExpression(tagName, openingBacktick, quasis, expressions, closingBacktick);
1257
+ return new Expression_1.TaggedTemplateStringExpression({
1258
+ tagName: tagName,
1259
+ openingBacktick: openingBacktick,
1260
+ quasis: quasis,
1261
+ expressions: expressions,
1262
+ closingBacktick: closingBacktick
1263
+ });
905
1264
  }
906
1265
  else {
907
- return new Expression_1.TemplateStringExpression(openingBacktick, quasis, expressions, closingBacktick);
1266
+ return new Expression_1.TemplateStringExpression({
1267
+ openingBacktick: openingBacktick,
1268
+ quasis: quasis,
1269
+ expressions: expressions,
1270
+ closingBacktick: closingBacktick
1271
+ });
908
1272
  }
909
1273
  }
910
1274
  }
911
1275
  tryCatchStatement() {
1276
+ var _a;
912
1277
  const tryToken = this.advance();
913
- const statement = new Statement_1.TryCatchStatement(tryToken);
1278
+ let endTryToken;
1279
+ let catchStmt;
914
1280
  //ensure statement separator
915
1281
  this.consumeStatementSeparators();
916
- statement.tryBranch = this.block(lexer_1.TokenKind.Catch, lexer_1.TokenKind.EndTry);
1282
+ let tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
917
1283
  const peek = this.peek();
918
- if (peek.kind !== lexer_1.TokenKind.Catch) {
919
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
920
- //gracefully handle end-try
921
- if (peek.kind === lexer_1.TokenKind.EndTry) {
922
- statement.endTryToken = this.advance();
923
- }
924
- return statement;
1284
+ if (peek.kind !== TokenKind_1.TokenKind.Catch) {
1285
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
925
1286
  }
926
1287
  else {
927
- statement.catchToken = this.advance();
928
- }
929
- const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
930
- if (exceptionVarToken) {
931
- // force it into an identifier so the AST makes some sense
932
- exceptionVarToken.kind = lexer_1.TokenKind.Identifier;
933
- statement.exceptionVariable = exceptionVarToken;
1288
+ const catchToken = this.advance();
1289
+ //get the exception variable as an expression
1290
+ let exceptionVariableExpression;
1291
+ //if we consumed any statement separators, that means we don't have an exception variable
1292
+ if (this.consumeStatementSeparators(true)) {
1293
+ //no exception variable. That's fine in BrighterScript but not in brightscript. But that'll get caught by the validator later...
1294
+ }
1295
+ else {
1296
+ exceptionVariableExpression = this.expression(true);
1297
+ this.consumeStatementSeparators();
1298
+ }
1299
+ const catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
1300
+ catchStmt = new Statement_1.CatchStatement({
1301
+ catch: catchToken,
1302
+ exceptionVariableExpression: exceptionVariableExpression,
1303
+ catchBranch: catchBranch
1304
+ });
934
1305
  }
935
- //ensure statement sepatator
936
- this.consumeStatementSeparators();
937
- statement.catchBranch = this.block(lexer_1.TokenKind.EndTry);
938
- if (this.peek().kind !== lexer_1.TokenKind.EndTry) {
939
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
1306
+ if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
1307
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { location: this.peek().location }));
940
1308
  }
941
1309
  else {
942
- statement.endTryToken = this.advance();
1310
+ endTryToken = this.advance();
943
1311
  }
1312
+ const statement = new Statement_1.TryCatchStatement({
1313
+ try: tryToken,
1314
+ tryBranch: tryBranch,
1315
+ catchStatement: catchStmt,
1316
+ endTry: endTryToken
1317
+ });
944
1318
  return statement;
945
1319
  }
946
1320
  throwStatement() {
947
1321
  const throwToken = this.advance();
948
1322
  let expression;
949
- if (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
950
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword()), { range: throwToken.range }));
1323
+ if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1324
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword()), { location: throwToken.location }));
951
1325
  }
952
1326
  else {
953
1327
  expression = this.expression();
954
1328
  }
955
- return new Statement_1.ThrowStatement(throwToken, expression);
1329
+ return new Statement_1.ThrowStatement({ throw: throwToken, expression: expression });
956
1330
  }
957
1331
  dimStatement() {
958
1332
  const dim = this.advance();
959
- let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
1333
+ let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
960
1334
  // force to an identifier so the AST makes some sense
961
1335
  if (identifier) {
962
- identifier.kind = lexer_1.TokenKind.Identifier;
1336
+ identifier.kind = TokenKind_1.TokenKind.Identifier;
963
1337
  }
964
- let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), lexer_1.TokenKind.LeftSquareBracket);
1338
+ let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.LeftSquareBracket);
965
1339
  let expressions = [];
966
1340
  let expression;
967
1341
  do {
968
1342
  try {
969
1343
  expression = this.expression();
970
1344
  expressions.push(expression);
971
- if (this.check(lexer_1.TokenKind.Comma)) {
1345
+ if (this.check(TokenKind_1.TokenKind.Comma)) {
972
1346
  this.advance();
973
1347
  }
974
1348
  else {
@@ -980,23 +1354,29 @@ class Parser {
980
1354
  }
981
1355
  } while (expression);
982
1356
  if (expressions.length === 0) {
983
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
984
- }
985
- let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), lexer_1.TokenKind.RightSquareBracket);
986
- return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
1357
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { location: this.peek().location }));
1358
+ }
1359
+ let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
1360
+ return new Statement_1.DimStatement({
1361
+ dim: dim,
1362
+ name: identifier,
1363
+ openingSquare: leftSquareBracket,
1364
+ dimensions: expressions,
1365
+ closingSquare: rightSquareBracket
1366
+ });
987
1367
  }
988
- ifStatement() {
1368
+ ifStatement(incrementNestedCount = true) {
1369
+ var _a;
989
1370
  // colon before `if` is usually not allowed, unless it's after `then`
990
1371
  if (this.current > 0) {
991
1372
  const prev = this.previous();
992
- if (prev.kind === lexer_1.TokenKind.Colon) {
993
- if (this.current > 1 && this.tokens[this.current - 2].kind !== lexer_1.TokenKind.Then) {
994
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedColonBeforeIfStatement()), { range: prev.range }));
1373
+ if (prev.kind === TokenKind_1.TokenKind.Colon) {
1374
+ if (this.current > 1 && this.tokens[this.current - 2].kind !== TokenKind_1.TokenKind.Then && this.nestedInlineConditionalCount === 0) {
1375
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedColonBeforeIfStatement()), { location: prev.location }));
995
1376
  }
996
1377
  }
997
1378
  }
998
1379
  const ifToken = this.advance();
999
- const startingRange = ifToken.range;
1000
1380
  const condition = this.expression();
1001
1381
  let thenBranch;
1002
1382
  let elseBranch;
@@ -1004,62 +1384,66 @@ class Parser {
1004
1384
  let endIfToken;
1005
1385
  let elseToken;
1006
1386
  //optional `then`
1007
- if (this.check(lexer_1.TokenKind.Then)) {
1387
+ if (this.check(TokenKind_1.TokenKind.Then)) {
1008
1388
  thenToken = this.advance();
1009
1389
  }
1010
1390
  //is it inline or multi-line if?
1011
- const isInlineIfThen = !this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment);
1391
+ const isInlineIfThen = !this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment);
1012
1392
  if (isInlineIfThen) {
1013
1393
  /*** PARSE INLINE IF STATEMENT ***/
1014
- thenBranch = this.inlineConditionalBranch(lexer_1.TokenKind.Else, lexer_1.TokenKind.EndIf);
1394
+ if (!incrementNestedCount) {
1395
+ this.nestedInlineConditionalCount++;
1396
+ }
1397
+ thenBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
1015
1398
  if (!thenBranch) {
1016
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowConditionalCondition(ifToken.text)), { range: this.peek().range }));
1399
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowConditionalCondition(ifToken.text)), { location: this.peek().location }));
1017
1400
  throw this.lastDiagnosticAsError();
1018
1401
  }
1019
1402
  else {
1020
1403
  this.ensureInline(thenBranch.statements);
1021
1404
  }
1022
1405
  //else branch
1023
- if (this.check(lexer_1.TokenKind.Else)) {
1406
+ if (this.check(TokenKind_1.TokenKind.Else)) {
1024
1407
  elseToken = this.advance();
1025
- if (this.check(lexer_1.TokenKind.If)) {
1408
+ if (this.check(TokenKind_1.TokenKind.If)) {
1026
1409
  // recurse-read `else if`
1027
- elseBranch = this.ifStatement();
1410
+ elseBranch = this.ifStatement(false);
1028
1411
  //no multi-line if chained with an inline if
1029
1412
  if (!elseBranch.isInline) {
1030
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: elseBranch.range }));
1413
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { location: elseBranch.location }));
1031
1414
  }
1032
1415
  }
1033
- else if (this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
1416
+ else if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1034
1417
  //expecting inline else branch
1035
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: this.peek().range }));
1418
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { location: this.peek().location }));
1036
1419
  throw this.lastDiagnosticAsError();
1037
1420
  }
1038
1421
  else {
1039
- elseBranch = this.inlineConditionalBranch(lexer_1.TokenKind.Else, lexer_1.TokenKind.EndIf);
1422
+ elseBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
1040
1423
  if (elseBranch) {
1041
1424
  this.ensureInline(elseBranch.statements);
1042
1425
  }
1043
1426
  }
1044
1427
  if (!elseBranch) {
1045
1428
  //missing `else` branch
1046
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowElse()), { range: this.peek().range }));
1429
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowElse()), { location: this.peek().location }));
1047
1430
  throw this.lastDiagnosticAsError();
1048
1431
  }
1049
1432
  }
1050
- if (!elseBranch || !reflection_1.isIfStatement(elseBranch)) {
1433
+ if (!elseBranch || !(0, reflection_1.isIfStatement)(elseBranch)) {
1051
1434
  //enforce newline at the end of the inline if statement
1052
1435
  const peek = this.peek();
1053
- if (peek.kind !== lexer_1.TokenKind.Newline && peek.kind !== lexer_1.TokenKind.Comment && !this.isAtEnd()) {
1436
+ if (peek.kind !== TokenKind_1.TokenKind.Newline && peek.kind !== TokenKind_1.TokenKind.Comment && peek.kind !== TokenKind_1.TokenKind.Else && !this.isAtEnd()) {
1054
1437
  //ignore last error if it was about a colon
1055
- if (this.previous().kind === lexer_1.TokenKind.Colon) {
1438
+ if (this.previous().kind === TokenKind_1.TokenKind.Colon) {
1056
1439
  this.diagnostics.pop();
1057
1440
  this.current--;
1058
1441
  }
1059
1442
  //newline is required
1060
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedFinalNewline()), { range: this.peek().range }));
1443
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedFinalNewline()), { location: this.peek().location }));
1061
1444
  }
1062
1445
  }
1446
+ this.nestedInlineConditionalCount--;
1063
1447
  }
1064
1448
  else {
1065
1449
  /*** PARSE MULTI-LINE IF STATEMENT ***/
@@ -1067,9 +1451,9 @@ class Parser {
1067
1451
  //ensure newline/colon before next keyword
1068
1452
  this.ensureNewLineOrColon();
1069
1453
  //else branch
1070
- if (this.check(lexer_1.TokenKind.Else)) {
1454
+ if (this.check(TokenKind_1.TokenKind.Else)) {
1071
1455
  elseToken = this.advance();
1072
- if (this.check(lexer_1.TokenKind.If)) {
1456
+ if (this.check(TokenKind_1.TokenKind.If)) {
1073
1457
  // recurse-read `else if`
1074
1458
  elseBranch = this.ifStatement();
1075
1459
  }
@@ -1079,13 +1463,13 @@ class Parser {
1079
1463
  this.ensureNewLineOrColon();
1080
1464
  }
1081
1465
  }
1082
- if (!reflection_1.isIfStatement(elseBranch)) {
1083
- if (this.check(lexer_1.TokenKind.EndIf)) {
1466
+ if (!(0, reflection_1.isIfStatement)(elseBranch)) {
1467
+ if (this.check(TokenKind_1.TokenKind.EndIf)) {
1084
1468
  endIfToken = this.advance();
1085
1469
  }
1086
1470
  else {
1087
1471
  //missing endif
1088
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndIfToCloseIfStatement(startingRange.start)), { range: ifToken.range }));
1472
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndIfToCloseIfStatement((_a = ifToken.location) === null || _a === void 0 ? void 0 : _a.range.start)), { location: ifToken.location }));
1089
1473
  }
1090
1474
  }
1091
1475
  }
@@ -1093,8 +1477,11 @@ class Parser {
1093
1477
  if: ifToken,
1094
1478
  then: thenToken,
1095
1479
  endIf: endIfToken,
1096
- else: elseToken
1097
- }, condition, thenBranch, elseBranch, isInlineIfThen);
1480
+ else: elseToken,
1481
+ condition: condition,
1482
+ thenBranch: thenBranch,
1483
+ elseBranch: elseBranch
1484
+ });
1098
1485
  }
1099
1486
  //consume a `then` or `else` branch block of an `if` statement
1100
1487
  blockConditionalBranch(ifToken) {
@@ -1103,33 +1490,230 @@ class Parser {
1103
1490
  let diagnosticsLengthBeforeBlock = this.diagnostics.length;
1104
1491
  // we're parsing a multi-line ("block") form of the BrightScript if/then and must find
1105
1492
  // a trailing "end if" or "else if"
1106
- let branch = this.block(lexer_1.TokenKind.EndIf, lexer_1.TokenKind.Else);
1493
+ let branch = this.block(TokenKind_1.TokenKind.EndIf, TokenKind_1.TokenKind.Else);
1107
1494
  if (!branch) {
1108
1495
  //throw out any new diagnostics created as a result of a `then` block parse failure.
1109
1496
  //the block() function will discard the current line, so any discarded diagnostics will
1110
1497
  //resurface if they are legitimate, and not a result of a malformed if statement
1111
1498
  this.diagnostics.splice(diagnosticsLengthBeforeBlock, this.diagnostics.length - diagnosticsLengthBeforeBlock);
1112
1499
  //this whole if statement is bogus...add error to the if token and hard-fail
1113
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndIfElseIfOrElseToTerminateThenBlock()), { range: ifToken.range }));
1500
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndIfElseIfOrElseToTerminateThenBlock()), { location: ifToken.location }));
1114
1501
  throw this.lastDiagnosticAsError();
1115
1502
  }
1116
1503
  return branch;
1117
1504
  }
1118
- ensureNewLineOrColon(silent = false) {
1119
- const prev = this.previous().kind;
1120
- if (prev !== lexer_1.TokenKind.Newline && prev !== lexer_1.TokenKind.Colon) {
1121
- if (!silent) {
1122
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { range: this.peek().range }));
1123
- }
1124
- return false;
1505
+ conditionalCompileStatement() {
1506
+ var _a, _b, _c;
1507
+ const hashIfToken = this.advance();
1508
+ let notToken;
1509
+ if (this.check(TokenKind_1.TokenKind.Not)) {
1510
+ notToken = this.advance();
1125
1511
  }
1126
- return true;
1127
- }
1128
- //ensure each statement of an inline block is single-line
1512
+ if (!this.checkAny(TokenKind_1.TokenKind.True, TokenKind_1.TokenKind.False, TokenKind_1.TokenKind.Identifier)) {
1513
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidHashIfValue()), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
1514
+ }
1515
+ const condition = this.advance();
1516
+ let thenBranch;
1517
+ let elseBranch;
1518
+ let hashEndIfToken;
1519
+ let hashElseToken;
1520
+ //keep track of the current error count
1521
+ //if this is `#if false` remove all diagnostics.
1522
+ let diagnosticsLengthBeforeBlock = this.diagnostics.length;
1523
+ thenBranch = this.blockConditionalCompileBranch(hashIfToken);
1524
+ const conditionTextLower = condition.text.toLowerCase();
1525
+ if (!((_b = this.options.bsConsts) === null || _b === void 0 ? void 0 : _b.get(conditionTextLower)) || conditionTextLower === 'false') {
1526
+ //throw out any new diagnostics created as a result of a false block
1527
+ this.diagnostics.splice(diagnosticsLengthBeforeBlock, this.diagnostics.length - diagnosticsLengthBeforeBlock);
1528
+ }
1529
+ this.ensureNewLine();
1530
+ this.advance();
1531
+ //else branch
1532
+ if (this.check(TokenKind_1.TokenKind.HashElseIf)) {
1533
+ // recurse-read `#else if`
1534
+ elseBranch = this.conditionalCompileStatement();
1535
+ this.ensureNewLine();
1536
+ }
1537
+ else if (this.check(TokenKind_1.TokenKind.HashElse)) {
1538
+ hashElseToken = this.advance();
1539
+ let diagnosticsLengthBeforeBlock = this.diagnostics.length;
1540
+ elseBranch = this.blockConditionalCompileBranch(hashIfToken);
1541
+ if (condition.text.toLowerCase() === 'true') {
1542
+ //throw out any new diagnostics created as a result of a false block
1543
+ this.diagnostics.splice(diagnosticsLengthBeforeBlock, this.diagnostics.length - diagnosticsLengthBeforeBlock);
1544
+ }
1545
+ this.ensureNewLine();
1546
+ this.advance();
1547
+ }
1548
+ if (!(0, reflection_1.isConditionalCompileStatement)(elseBranch)) {
1549
+ if (this.check(TokenKind_1.TokenKind.HashEndIf)) {
1550
+ hashEndIfToken = this.advance();
1551
+ }
1552
+ else {
1553
+ //missing #endif
1554
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedHashEndIfToCloseHashIf((_c = hashIfToken.location) === null || _c === void 0 ? void 0 : _c.range.start.line)), { location: hashIfToken.location }));
1555
+ }
1556
+ }
1557
+ return new Statement_1.ConditionalCompileStatement({
1558
+ hashIf: hashIfToken,
1559
+ hashElse: hashElseToken,
1560
+ hashEndIf: hashEndIfToken,
1561
+ not: notToken,
1562
+ condition: condition,
1563
+ thenBranch: thenBranch,
1564
+ elseBranch: elseBranch
1565
+ });
1566
+ }
1567
+ //consume a conditional compile branch block of an `#if` statement
1568
+ blockConditionalCompileBranch(hashIfToken) {
1569
+ //keep track of the current error count, because if the then branch fails,
1570
+ //we will trash them in favor of a single error on if
1571
+ let diagnosticsLengthBeforeBlock = this.diagnostics.length;
1572
+ //parsing until trailing "#end if", "#else", "#else if"
1573
+ let branch = this.conditionalCompileBlock();
1574
+ if (!branch) {
1575
+ //throw out any new diagnostics created as a result of a `then` block parse failure.
1576
+ //the block() function will discard the current line, so any discarded diagnostics will
1577
+ //resurface if they are legitimate, and not a result of a malformed if statement
1578
+ this.diagnostics.splice(diagnosticsLengthBeforeBlock, this.diagnostics.length - diagnosticsLengthBeforeBlock);
1579
+ //this whole if statement is bogus...add error to the if token and hard-fail
1580
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedTerminatorOnConditionalCompileBlock()), { location: hashIfToken.location }));
1581
+ throw this.lastDiagnosticAsError();
1582
+ }
1583
+ return branch;
1584
+ }
1585
+ /**
1586
+ * Parses a block, looking for a specific terminating TokenKind to denote completion.
1587
+ * Always looks for `#end if` or `#else`
1588
+ */
1589
+ conditionalCompileBlock() {
1590
+ const parentAnnotations = this.enterAnnotationBlock();
1591
+ this.consumeStatementSeparators(true);
1592
+ const unsafeTerminators = TokenKind_1.BlockTerminators;
1593
+ const conditionalEndTokens = [TokenKind_1.TokenKind.HashElse, TokenKind_1.TokenKind.HashElseIf, TokenKind_1.TokenKind.HashEndIf];
1594
+ const terminators = [...conditionalEndTokens, ...unsafeTerminators];
1595
+ this.globalTerminators.push(conditionalEndTokens);
1596
+ const statements = [];
1597
+ while (!this.isAtEnd() && !this.checkAny(...terminators)) {
1598
+ //grab the location of the current token
1599
+ let loopCurrent = this.current;
1600
+ let dec = this.declaration();
1601
+ if (dec) {
1602
+ if (!(0, reflection_1.isAnnotationExpression)(dec)) {
1603
+ this.consumePendingAnnotations(dec);
1604
+ statements.push(dec);
1605
+ }
1606
+ const peekKind = this.peek().kind;
1607
+ if (conditionalEndTokens.includes(peekKind)) {
1608
+ // current conditional compile branch was closed by other statement, rewind to preceding newline
1609
+ this.current--;
1610
+ }
1611
+ //ensure statement separator
1612
+ this.consumeStatementSeparators();
1613
+ }
1614
+ else {
1615
+ //something went wrong. reset to the top of the loop
1616
+ this.current = loopCurrent;
1617
+ //scrap the entire line (hopefully whatever failed has added a diagnostic)
1618
+ this.consumeUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
1619
+ //trash the next token. this prevents an infinite loop. not exactly sure why we need this,
1620
+ //but there's already an error in the file being parsed, so just leave this line here
1621
+ this.advance();
1622
+ //consume potential separators
1623
+ this.consumeStatementSeparators(true);
1624
+ }
1625
+ }
1626
+ this.globalTerminators.pop();
1627
+ if (this.isAtEnd()) {
1628
+ return undefined;
1629
+ // TODO: Figure out how to handle unterminated blocks well
1630
+ }
1631
+ else {
1632
+ //did we hit an unsafe terminator?
1633
+ //if so, we need to restore the statement separator
1634
+ let prev = this.previous();
1635
+ let prevKind = prev.kind;
1636
+ let peek = this.peek();
1637
+ let peekKind = this.peek().kind;
1638
+ if ((peekKind === TokenKind_1.TokenKind.HashEndIf || peekKind === TokenKind_1.TokenKind.HashElse || peekKind === TokenKind_1.TokenKind.HashElseIf) &&
1639
+ (prevKind === TokenKind_1.TokenKind.Newline)) {
1640
+ this.current--;
1641
+ }
1642
+ else if (unsafeTerminators.includes(peekKind) &&
1643
+ (prevKind === TokenKind_1.TokenKind.Newline || prevKind === TokenKind_1.TokenKind.Colon)) {
1644
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unsafeUnmatchedTerminatorInConditionalCompileBlock(peek.text)), { location: peek.location }));
1645
+ throw this.lastDiagnosticAsError();
1646
+ }
1647
+ else {
1648
+ return undefined;
1649
+ }
1650
+ }
1651
+ this.exitAnnotationBlock(parentAnnotations);
1652
+ return new Statement_1.Block({ statements: statements });
1653
+ }
1654
+ conditionalCompileConstStatement() {
1655
+ var _a, _b, _c, _d, _e;
1656
+ const hashConstToken = this.advance();
1657
+ const constName = this.peek();
1658
+ //disallow using keywords for const names
1659
+ if (TokenKind_1.ReservedWords.has(constName === null || constName === void 0 ? void 0 : constName.text.toLowerCase())) {
1660
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.constNameCannotBeReservedWord()), { location: constName === null || constName === void 0 ? void 0 : constName.location }));
1661
+ this.lastDiagnosticAsError();
1662
+ return;
1663
+ }
1664
+ const assignment = this.assignment();
1665
+ if (assignment) {
1666
+ // check for something other than #const <name> = <otherName|true|false>
1667
+ if (assignment.tokens.as || assignment.typeExpression) {
1668
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(((_a = assignment.tokens.as) === null || _a === void 0 ? void 0 : _a.text) || ((_b = assignment.typeExpression) === null || _b === void 0 ? void 0 : _b.getName(ParseMode.BrighterScript)))), { location: (_d = (_c = assignment.tokens.as) === null || _c === void 0 ? void 0 : _c.location) !== null && _d !== void 0 ? _d : (_e = assignment.typeExpression) === null || _e === void 0 ? void 0 : _e.location }));
1669
+ this.lastDiagnosticAsError();
1670
+ }
1671
+ if ((0, reflection_1.isVariableExpression)(assignment.value) || (0, reflection_1.isLiteralBoolean)(assignment.value)) {
1672
+ //value is an identifier or a boolean
1673
+ //check for valid identifiers will happen in program validation
1674
+ }
1675
+ else {
1676
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidHashConstValue()), { location: assignment.value.location }));
1677
+ this.lastDiagnosticAsError();
1678
+ }
1679
+ }
1680
+ else {
1681
+ return undefined;
1682
+ }
1683
+ if (!this.check(TokenKind_1.TokenKind.Newline)) {
1684
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineInConditionalCompile()), { location: this.peek().location }));
1685
+ throw this.lastDiagnosticAsError();
1686
+ }
1687
+ return new Statement_1.ConditionalCompileConstStatement({ hashConst: hashConstToken, assignment: assignment });
1688
+ }
1689
+ conditionalCompileErrorStatement() {
1690
+ const hashErrorToken = this.advance();
1691
+ const tokensUntilEndOfLine = this.consumeUntil(TokenKind_1.TokenKind.Newline);
1692
+ const message = (0, creators_1.createToken)(TokenKind_1.TokenKind.HashErrorMessage, tokensUntilEndOfLine.map(t => t.text).join(' '));
1693
+ return new Statement_1.ConditionalCompileErrorStatement({ hashError: hashErrorToken, message: message });
1694
+ }
1695
+ ensureNewLine() {
1696
+ //ensure newline before next keyword
1697
+ if (!this.check(TokenKind_1.TokenKind.Newline)) {
1698
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineInConditionalCompile()), { location: this.peek().location }));
1699
+ throw this.lastDiagnosticAsError();
1700
+ }
1701
+ }
1702
+ ensureNewLineOrColon(silent = false) {
1703
+ const prev = this.previous().kind;
1704
+ if (prev !== TokenKind_1.TokenKind.Newline && prev !== TokenKind_1.TokenKind.Colon) {
1705
+ if (!silent) {
1706
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { location: this.peek().location }));
1707
+ }
1708
+ return false;
1709
+ }
1710
+ return true;
1711
+ }
1712
+ //ensure each statement of an inline block is single-line
1129
1713
  ensureInline(statements) {
1130
1714
  for (const stat of statements) {
1131
- if (reflection_1.isIfStatement(stat) && !stat.isInline) {
1132
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: stat.range }));
1715
+ if ((0, reflection_1.isIfStatement)(stat) && !stat.isInline) {
1716
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { location: stat.location }));
1133
1717
  }
1134
1718
  }
1135
1719
  }
@@ -1145,12 +1729,12 @@ class Parser {
1145
1729
  statements.push(statement);
1146
1730
  //look for colon statement separator
1147
1731
  let foundColon = false;
1148
- while (this.match(lexer_1.TokenKind.Colon)) {
1732
+ while (this.match(TokenKind_1.TokenKind.Colon)) {
1149
1733
  foundColon = true;
1150
1734
  }
1151
1735
  //if a colon was found, add the next statement or err if unexpected
1152
1736
  if (foundColon) {
1153
- if (!this.checkAny(lexer_1.TokenKind.Newline, ...additionalTerminators)) {
1737
+ if (!this.checkAny(TokenKind_1.TokenKind.Newline, ...additionalTerminators)) {
1154
1738
  //if not an ending keyword, add next statement
1155
1739
  let extra = this.inlineConditionalBranch(...additionalTerminators);
1156
1740
  if (!extra) {
@@ -1161,31 +1745,35 @@ class Parser {
1161
1745
  else {
1162
1746
  //error: colon before next keyword
1163
1747
  const colon = this.previous();
1164
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.foundUnexpectedToken(colon.text)), { range: colon.range }));
1748
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(colon.text)), { location: colon.location }));
1165
1749
  }
1166
1750
  }
1167
- return new Statement_1.Block(statements, this.peek().range);
1751
+ return new Statement_1.Block({ statements: statements });
1168
1752
  }
1169
1753
  expressionStatement(expr) {
1170
1754
  let expressionStart = this.peek();
1171
- if (this.checkAny(lexer_1.TokenKind.PlusPlus, lexer_1.TokenKind.MinusMinus)) {
1755
+ if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
1172
1756
  let operator = this.advance();
1173
- if (this.checkAny(lexer_1.TokenKind.PlusPlus, lexer_1.TokenKind.MinusMinus)) {
1174
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.consecutiveIncrementDecrementOperatorsAreNotAllowed()), { range: this.peek().range }));
1757
+ if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
1758
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.consecutiveIncrementDecrementOperatorsAreNotAllowed()), { location: this.peek().location }));
1175
1759
  throw this.lastDiagnosticAsError();
1176
1760
  }
1177
- else if (reflection_1.isCallExpression(expr)) {
1178
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
1761
+ else if ((0, reflection_1.isCallExpression)(expr)) {
1762
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { location: expressionStart.location }));
1179
1763
  throw this.lastDiagnosticAsError();
1180
1764
  }
1181
- return new Statement_1.IncrementStatement(expr, operator);
1765
+ const result = new Statement_1.IncrementStatement({ value: expr, operator: operator });
1766
+ return result;
1182
1767
  }
1183
- if (reflection_1.isCallExpression(expr) || reflection_1.isCallfuncExpression(expr)) {
1184
- return new Statement_1.ExpressionStatement(expr);
1768
+ if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
1769
+ return new Statement_1.ExpressionStatement({ expression: expr });
1185
1770
  }
1186
- //at this point, it's probably an error. However, we recover a little more gracefully by creating an assignment
1187
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementOrFunctionCallButReceivedExpression()), { range: expressionStart.range }));
1188
- throw this.lastDiagnosticAsError();
1771
+ if (this.checkAny(...TokenKind_1.BinaryExpressionOperatorTokens)) {
1772
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: this.advance(), right: this.expression() });
1773
+ }
1774
+ //at this point, it's probably an error. However, we recover a little more gracefully by creating an inclosing ExpressionStatement
1775
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementOrFunctionCallButReceivedExpression()), { location: expressionStart.location }));
1776
+ return new Statement_1.ExpressionStatement({ expression: expr });
1189
1777
  }
1190
1778
  setStatement() {
1191
1779
  /**
@@ -1195,35 +1783,54 @@ class Parser {
1195
1783
  * priority as standalone function calls though, so we can parse them in the same way.
1196
1784
  */
1197
1785
  let expr = this.call();
1198
- if (this.checkAny(...lexer_1.AssignmentOperators) && !(reflection_1.isCallExpression(expr))) {
1786
+ if (this.check(TokenKind_1.TokenKind.Equal) && !((0, reflection_1.isCallExpression)(expr))) {
1199
1787
  let left = expr;
1200
1788
  let operator = this.advance();
1201
1789
  let right = this.expression();
1202
1790
  // Create a dotted or indexed "set" based on the left-hand side's type
1203
- if (reflection_1.isIndexedGetExpression(left)) {
1204
- return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === lexer_1.TokenKind.Equal
1205
- ? right
1206
- : new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
1791
+ if ((0, reflection_1.isIndexedGetExpression)(left)) {
1792
+ return new Statement_1.IndexedSetStatement({
1793
+ obj: left.obj,
1794
+ indexes: left.indexes,
1795
+ value: right,
1796
+ openingSquare: left.tokens.openingSquare,
1797
+ closingSquare: left.tokens.closingSquare,
1798
+ equals: operator
1799
+ });
1207
1800
  }
1208
- else if (reflection_1.isDottedGetExpression(left)) {
1209
- return new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === lexer_1.TokenKind.Equal
1210
- ? right
1211
- : new Expression_1.BinaryExpression(left, operator, right));
1801
+ else if ((0, reflection_1.isDottedGetExpression)(left)) {
1802
+ return new Statement_1.DottedSetStatement({
1803
+ obj: left.obj,
1804
+ name: left.tokens.name,
1805
+ value: right,
1806
+ dot: left.tokens.dot,
1807
+ equals: operator
1808
+ });
1212
1809
  }
1213
1810
  }
1811
+ else if (this.checkAny(...TokenKind_1.CompoundAssignmentOperators) && !((0, reflection_1.isCallExpression)(expr))) {
1812
+ let left = expr;
1813
+ let operator = this.advance();
1814
+ let right = this.expression();
1815
+ return new Statement_1.AugmentedAssignmentStatement({
1816
+ item: left,
1817
+ operator: operator,
1818
+ value: right
1819
+ });
1820
+ }
1214
1821
  return this.expressionStatement(expr);
1215
1822
  }
1216
1823
  printStatement() {
1217
1824
  let printKeyword = this.advance();
1218
1825
  let values = [];
1219
1826
  while (!this.checkEndOfStatement()) {
1220
- if (this.check(lexer_1.TokenKind.Semicolon)) {
1827
+ if (this.check(TokenKind_1.TokenKind.Semicolon)) {
1221
1828
  values.push(this.advance());
1222
1829
  }
1223
- else if (this.check(lexer_1.TokenKind.Comma)) {
1830
+ else if (this.check(TokenKind_1.TokenKind.Comma)) {
1224
1831
  values.push(this.advance());
1225
1832
  }
1226
- else if (this.check(lexer_1.TokenKind.Else)) {
1833
+ else if (this.check(TokenKind_1.TokenKind.Else)) {
1227
1834
  break; // inline branch
1228
1835
  }
1229
1836
  else {
@@ -1232,45 +1839,53 @@ class Parser {
1232
1839
  }
1233
1840
  //print statements can be empty, so look for empty print conditions
1234
1841
  if (!values.length) {
1235
- let emptyStringLiteral = creators_1.createStringLiteral('');
1842
+ const endOfStatementLocation = util_1.util.createBoundingLocation(printKeyword, this.peek());
1843
+ let emptyStringLiteral = (0, creators_1.createStringLiteral)('', endOfStatementLocation);
1236
1844
  values.push(emptyStringLiteral);
1237
1845
  }
1238
1846
  let last = values[values.length - 1];
1239
- if (lexer_1.isToken(last)) {
1847
+ if ((0, Token_1.isToken)(last)) {
1240
1848
  // TODO: error, expected value
1241
1849
  }
1242
- return new Statement_1.PrintStatement({ print: printKeyword }, values);
1850
+ return new Statement_1.PrintStatement({ print: printKeyword, expressions: values });
1243
1851
  }
1244
1852
  /**
1245
1853
  * Parses a return statement with an optional return value.
1246
1854
  * @returns an AST representation of a return statement.
1247
1855
  */
1248
1856
  returnStatement() {
1249
- let tokens = { return: this.previous() };
1857
+ let options = { return: this.previous() };
1250
1858
  if (this.checkEndOfStatement()) {
1251
- return new Statement_1.ReturnStatement(tokens);
1859
+ return new Statement_1.ReturnStatement(options);
1252
1860
  }
1253
- let toReturn = this.check(lexer_1.TokenKind.Else) ? undefined : this.expression();
1254
- return new Statement_1.ReturnStatement(tokens, toReturn);
1861
+ let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
1862
+ return new Statement_1.ReturnStatement(Object.assign(Object.assign({}, options), { value: toReturn }));
1255
1863
  }
1256
1864
  /**
1257
1865
  * Parses a `label` statement
1258
1866
  * @returns an AST representation of an `label` statement.
1259
1867
  */
1260
1868
  labelStatement() {
1261
- let tokens = {
1262
- identifier: this.advance(),
1869
+ let options = {
1870
+ name: this.advance(),
1263
1871
  colon: this.advance()
1264
1872
  };
1265
1873
  //label must be alone on its line, this is probably not a label
1266
- if (!this.checkAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1874
+ if (!this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
1267
1875
  //rewind and cancel
1268
1876
  this.current -= 2;
1269
1877
  throw new CancelStatementError();
1270
1878
  }
1271
- const stmt = new Statement_1.LabelStatement(tokens);
1272
- this.currentFunctionExpression.labelStatements.push(stmt);
1273
- return stmt;
1879
+ return new Statement_1.LabelStatement(options);
1880
+ }
1881
+ /**
1882
+ * Parses a `continue` statement
1883
+ */
1884
+ continueStatement() {
1885
+ return new Statement_1.ContinueStatement({
1886
+ continue: this.advance(),
1887
+ loopType: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For), TokenKind_1.TokenKind.While, TokenKind_1.TokenKind.For)
1888
+ });
1274
1889
  }
1275
1890
  /**
1276
1891
  * Parses a `goto` statement
@@ -1279,7 +1894,7 @@ class Parser {
1279
1894
  gotoStatement() {
1280
1895
  let tokens = {
1281
1896
  goto: this.advance(),
1282
- label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), lexer_1.TokenKind.Identifier)
1897
+ label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
1283
1898
  };
1284
1899
  return new Statement_1.GotoStatement(tokens);
1285
1900
  }
@@ -1288,16 +1903,16 @@ class Parser {
1288
1903
  * @returns an AST representation of an `end` statement.
1289
1904
  */
1290
1905
  endStatement() {
1291
- let endTokens = { end: this.advance() };
1292
- return new Statement_1.EndStatement(endTokens);
1906
+ let options = { end: this.advance() };
1907
+ return new Statement_1.EndStatement(options);
1293
1908
  }
1294
1909
  /**
1295
1910
  * Parses a `stop` statement
1296
1911
  * @returns an AST representation of a `stop` statement
1297
1912
  */
1298
1913
  stopStatement() {
1299
- let tokens = { stop: this.advance() };
1300
- return new Statement_1.StopStatement(tokens);
1914
+ let options = { stop: this.advance() };
1915
+ return new Statement_1.StopStatement(options);
1301
1916
  }
1302
1917
  /**
1303
1918
  * Parses a block, looking for a specific terminating TokenKind to denote completion.
@@ -1308,14 +1923,14 @@ class Parser {
1308
1923
  block(...terminators) {
1309
1924
  const parentAnnotations = this.enterAnnotationBlock();
1310
1925
  this.consumeStatementSeparators(true);
1311
- let startingToken = this.peek();
1312
1926
  const statements = [];
1313
- while (!this.isAtEnd() && !this.checkAny(lexer_1.TokenKind.EndSub, lexer_1.TokenKind.EndFunction, ...terminators)) {
1927
+ const flatGlobalTerminators = this.globalTerminators.flat().flat();
1928
+ while (!this.isAtEnd() && !this.checkAny(TokenKind_1.TokenKind.EndSub, TokenKind_1.TokenKind.EndFunction, ...terminators, ...flatGlobalTerminators)) {
1314
1929
  //grab the location of the current token
1315
1930
  let loopCurrent = this.current;
1316
1931
  let dec = this.declaration();
1317
1932
  if (dec) {
1318
- if (!reflection_1.isAnnotationExpression(dec)) {
1933
+ if (!(0, reflection_1.isAnnotationExpression)(dec)) {
1319
1934
  this.consumePendingAnnotations(dec);
1320
1935
  statements.push(dec);
1321
1936
  }
@@ -1326,7 +1941,7 @@ class Parser {
1326
1941
  //something went wrong. reset to the top of the loop
1327
1942
  this.current = loopCurrent;
1328
1943
  //scrap the entire line (hopefully whatever failed has added a diagnostic)
1329
- this.consumeUntil(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Eof);
1944
+ this.consumeUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
1330
1945
  //trash the next token. this prevents an infinite loop. not exactly sure why we need this,
1331
1946
  //but there's already an error in the file being parsed, so just leave this line here
1332
1947
  this.advance();
@@ -1343,13 +1958,13 @@ class Parser {
1343
1958
  //if so, we need to restore the statement separator
1344
1959
  let prev = this.previous().kind;
1345
1960
  let peek = this.peek().kind;
1346
- if ((peek === lexer_1.TokenKind.EndSub || peek === lexer_1.TokenKind.EndFunction) &&
1347
- (prev === lexer_1.TokenKind.Newline || prev === lexer_1.TokenKind.Colon)) {
1961
+ if ((peek === TokenKind_1.TokenKind.EndSub || peek === TokenKind_1.TokenKind.EndFunction) &&
1962
+ (prev === TokenKind_1.TokenKind.Newline || prev === TokenKind_1.TokenKind.Colon)) {
1348
1963
  this.current--;
1349
1964
  }
1350
1965
  }
1351
1966
  this.exitAnnotationBlock(parentAnnotations);
1352
- return new Statement_1.Block(statements, startingToken.range);
1967
+ return new Statement_1.Block({ statements: statements });
1353
1968
  }
1354
1969
  /**
1355
1970
  * Attach pending annotations to the provided statement,
@@ -1370,19 +1985,39 @@ class Parser {
1370
1985
  // non consumed annotations are an error
1371
1986
  if (this.pendingAnnotations.length) {
1372
1987
  for (const annotation of this.pendingAnnotations) {
1373
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unusedAnnotation()), { range: annotation.range }));
1988
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unusedAnnotation()), { location: annotation.location }));
1374
1989
  }
1375
1990
  }
1376
1991
  this.pendingAnnotations = parentAnnotations;
1377
1992
  }
1378
- expression() {
1379
- return this.anonymousFunction();
1993
+ expression(findTypecast = true) {
1994
+ let expression = this.anonymousFunction();
1995
+ let asToken;
1996
+ let typeExpression;
1997
+ if (findTypecast) {
1998
+ do {
1999
+ if (this.check(TokenKind_1.TokenKind.As)) {
2000
+ this.warnIfNotBrighterScriptMode('type cast');
2001
+ // Check if this expression is wrapped in any type casts
2002
+ // allows for multiple casts:
2003
+ // myVal = foo() as dynamic as string
2004
+ [asToken, typeExpression] = this.consumeAsTokenAndTypeExpression();
2005
+ if (asToken && typeExpression) {
2006
+ expression = new Expression_1.TypecastExpression({ obj: expression, as: asToken, typeExpression: typeExpression });
2007
+ }
2008
+ }
2009
+ else {
2010
+ break;
2011
+ }
2012
+ } while (asToken && typeExpression);
2013
+ }
2014
+ return expression;
1380
2015
  }
1381
2016
  anonymousFunction() {
1382
- if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
2017
+ if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
1383
2018
  const func = this.functionDeclaration(true);
1384
2019
  //if there's an open paren after this, this is an IIFE
1385
- if (this.check(lexer_1.TokenKind.LeftParen)) {
2020
+ if (this.check(TokenKind_1.TokenKind.LeftParen)) {
1386
2021
  return this.finishCall(this.advance(), func);
1387
2022
  }
1388
2023
  else {
@@ -1390,10 +2025,10 @@ class Parser {
1390
2025
  }
1391
2026
  }
1392
2027
  let expr = this.boolean();
1393
- if (this.check(lexer_1.TokenKind.Question)) {
2028
+ if (this.check(TokenKind_1.TokenKind.Question)) {
1394
2029
  return this.ternaryExpression(expr);
1395
2030
  }
1396
- else if (this.check(lexer_1.TokenKind.QuestionQuestion)) {
2031
+ else if (this.check(TokenKind_1.TokenKind.QuestionQuestion)) {
1397
2032
  return this.nullCoalescingExpression(expr);
1398
2033
  }
1399
2034
  else {
@@ -1402,78 +2037,113 @@ class Parser {
1402
2037
  }
1403
2038
  boolean() {
1404
2039
  let expr = this.relational();
1405
- while (this.matchAny(lexer_1.TokenKind.And, lexer_1.TokenKind.Or)) {
2040
+ while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
1406
2041
  let operator = this.previous();
1407
2042
  let right = this.relational();
1408
- expr = new Expression_1.BinaryExpression(expr, operator, right);
2043
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1409
2044
  }
1410
2045
  return expr;
1411
2046
  }
1412
2047
  relational() {
1413
2048
  let expr = this.additive();
1414
- while (this.matchAny(lexer_1.TokenKind.Equal, lexer_1.TokenKind.LessGreater, lexer_1.TokenKind.Greater, lexer_1.TokenKind.GreaterEqual, lexer_1.TokenKind.Less, lexer_1.TokenKind.LessEqual)) {
2049
+ 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)) {
1415
2050
  let operator = this.previous();
1416
2051
  let right = this.additive();
1417
- expr = new Expression_1.BinaryExpression(expr, operator, right);
2052
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1418
2053
  }
1419
2054
  return expr;
1420
2055
  }
1421
2056
  // TODO: bitshift
1422
2057
  additive() {
1423
2058
  let expr = this.multiplicative();
1424
- while (this.matchAny(lexer_1.TokenKind.Plus, lexer_1.TokenKind.Minus)) {
2059
+ while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
1425
2060
  let operator = this.previous();
1426
2061
  let right = this.multiplicative();
1427
- expr = new Expression_1.BinaryExpression(expr, operator, right);
2062
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1428
2063
  }
1429
2064
  return expr;
1430
2065
  }
1431
2066
  multiplicative() {
1432
2067
  let expr = this.exponential();
1433
- while (this.matchAny(lexer_1.TokenKind.Forwardslash, lexer_1.TokenKind.Backslash, lexer_1.TokenKind.Star, lexer_1.TokenKind.Mod, lexer_1.TokenKind.LeftShift, lexer_1.TokenKind.RightShift)) {
2068
+ 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)) {
1434
2069
  let operator = this.previous();
1435
2070
  let right = this.exponential();
1436
- expr = new Expression_1.BinaryExpression(expr, operator, right);
2071
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1437
2072
  }
1438
2073
  return expr;
1439
2074
  }
1440
2075
  exponential() {
1441
2076
  let expr = this.prefixUnary();
1442
- while (this.match(lexer_1.TokenKind.Caret)) {
2077
+ while (this.match(TokenKind_1.TokenKind.Caret)) {
1443
2078
  let operator = this.previous();
1444
2079
  let right = this.prefixUnary();
1445
- expr = new Expression_1.BinaryExpression(expr, operator, right);
2080
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
1446
2081
  }
1447
2082
  return expr;
1448
2083
  }
1449
2084
  prefixUnary() {
1450
2085
  const nextKind = this.peek().kind;
1451
- if (nextKind === lexer_1.TokenKind.Not || nextKind === lexer_1.TokenKind.Minus) {
2086
+ if (nextKind === TokenKind_1.TokenKind.Not) {
1452
2087
  this.current++; //advance
1453
2088
  let operator = this.previous();
1454
- let right = this.prefixUnary();
1455
- return new Expression_1.UnaryExpression(operator, right);
2089
+ let right = this.relational();
2090
+ return new Expression_1.UnaryExpression({ operator: operator, right: right });
2091
+ }
2092
+ else if (nextKind === TokenKind_1.TokenKind.Minus || nextKind === TokenKind_1.TokenKind.Plus) {
2093
+ this.current++; //advance
2094
+ let operator = this.previous();
2095
+ let right = nextKind === TokenKind_1.TokenKind.Not
2096
+ ? this.boolean()
2097
+ : this.prefixUnary();
2098
+ return new Expression_1.UnaryExpression({ operator: operator, right: right });
1456
2099
  }
1457
2100
  return this.call();
1458
2101
  }
1459
2102
  indexedGet(expr) {
1460
2103
  let openingSquare = this.previous();
1461
- while (this.match(lexer_1.TokenKind.Newline)) { }
1462
- let index = this.expression();
1463
- while (this.match(lexer_1.TokenKind.Newline)) { }
1464
- let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), lexer_1.TokenKind.RightSquareBracket);
1465
- return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare);
2104
+ let questionDotToken = this.getMatchingTokenAtOffset(-2, TokenKind_1.TokenKind.QuestionDot);
2105
+ let indexes = [];
2106
+ //consume leading newlines
2107
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
2108
+ try {
2109
+ indexes.push(this.expression());
2110
+ //consume additional indexes separated by commas
2111
+ while (this.check(TokenKind_1.TokenKind.Comma)) {
2112
+ //discard the comma
2113
+ this.advance();
2114
+ indexes.push(this.expression());
2115
+ }
2116
+ }
2117
+ catch (error) {
2118
+ this.rethrowNonDiagnosticError(error);
2119
+ }
2120
+ //consume trailing newlines
2121
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
2122
+ const closingSquare = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
2123
+ return new Expression_1.IndexedGetExpression({
2124
+ obj: expr,
2125
+ indexes: indexes,
2126
+ openingSquare: openingSquare,
2127
+ closingSquare: closingSquare,
2128
+ questionDot: questionDotToken
2129
+ });
1466
2130
  }
1467
2131
  newExpression() {
1468
2132
  this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
1469
2133
  let newToken = this.advance();
1470
- let nameExpr = this.getNamespacedVariableNameExpression();
1471
- let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.foundUnexpectedToken(this.peek().text), lexer_1.TokenKind.LeftParen);
2134
+ let nameExpr = this.identifyingExpression();
2135
+ let leftParen = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen);
2136
+ if (!leftParen) {
2137
+ // new expression without a following call expression
2138
+ // wrap the name in an expression
2139
+ const endOfStatementLocation = util_1.util.createBoundingLocation(newToken, this.peek());
2140
+ const exprStmt = nameExpr !== null && nameExpr !== void 0 ? nameExpr : (0, creators_1.createStringLiteral)('', endOfStatementLocation);
2141
+ return new Statement_1.ExpressionStatement({ expression: exprStmt });
2142
+ }
1472
2143
  let call = this.finishCall(leftParen, nameExpr);
1473
2144
  //pop the call from the callExpressions list because this is technically something else
1474
2145
  this.callExpressions.pop();
1475
- let result = new Expression_1.NewExpression(newToken, call);
1476
- this._references.newExpressions.push(result);
2146
+ let result = new Expression_1.NewExpression({ new: newToken, call: call });
1477
2147
  return result;
1478
2148
  }
1479
2149
  /**
@@ -1482,47 +2152,59 @@ class Parser {
1482
2152
  callfunc(callee) {
1483
2153
  this.warnIfNotBrighterScriptMode('callfunc operator');
1484
2154
  let operator = this.previous();
1485
- let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
2155
+ let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1486
2156
  // force it into an identifier so the AST makes some sense
1487
- methodName.kind = lexer_1.TokenKind.Identifier;
1488
- let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), lexer_1.TokenKind.LeftParen);
2157
+ methodName.kind = TokenKind_1.TokenKind.Identifier;
2158
+ let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), TokenKind_1.TokenKind.LeftParen);
1489
2159
  let call = this.finishCall(openParen, callee, false);
1490
- return new Expression_1.CallfuncExpression(callee, operator, methodName, openParen, call.args, call.closingParen);
2160
+ return new Expression_1.CallfuncExpression({
2161
+ callee: callee,
2162
+ operator: operator,
2163
+ methodName: methodName,
2164
+ openingParen: openParen,
2165
+ args: call.args,
2166
+ closingParen: call.tokens.closingParen
2167
+ });
1491
2168
  }
1492
2169
  call() {
1493
- if (this.check(lexer_1.TokenKind.New) && this.checkAnyNext(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
2170
+ if (this.check(TokenKind_1.TokenKind.New) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
1494
2171
  return this.newExpression();
1495
2172
  }
1496
2173
  let expr = this.primary();
1497
2174
  while (true) {
1498
- if (this.match(lexer_1.TokenKind.LeftParen)) {
2175
+ if (this.matchAny(TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen)) {
1499
2176
  expr = this.finishCall(this.previous(), expr);
1500
2177
  }
1501
- else if (this.match(lexer_1.TokenKind.LeftSquareBracket)) {
2178
+ else if (this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.QuestionLeftSquare) || this.matchSequence(TokenKind_1.TokenKind.QuestionDot, TokenKind_1.TokenKind.LeftSquareBracket)) {
1502
2179
  expr = this.indexedGet(expr);
1503
2180
  }
1504
- else if (this.match(lexer_1.TokenKind.Callfunc)) {
2181
+ else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
1505
2182
  expr = this.callfunc(expr);
1506
2183
  }
1507
- else if (this.match(lexer_1.TokenKind.Dot)) {
1508
- if (this.match(lexer_1.TokenKind.LeftSquareBracket)) {
2184
+ else if (this.matchAny(TokenKind_1.TokenKind.Dot, TokenKind_1.TokenKind.QuestionDot)) {
2185
+ if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
1509
2186
  expr = this.indexedGet(expr);
1510
2187
  }
1511
2188
  else {
1512
2189
  let dot = this.previous();
1513
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
2190
+ let name = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
2191
+ if (!name) {
2192
+ break;
2193
+ }
1514
2194
  // force it into an identifier so the AST makes some sense
1515
- name.kind = lexer_1.TokenKind.Identifier;
1516
- expr = new Expression_1.DottedGetExpression(expr, name, dot);
1517
- this.addPropertyHints(name);
2195
+ name.kind = TokenKind_1.TokenKind.Identifier;
2196
+ expr = new Expression_1.DottedGetExpression({ obj: expr, name: name, dot: dot });
1518
2197
  }
1519
2198
  }
1520
- else if (this.check(lexer_1.TokenKind.At)) {
2199
+ else if (this.checkAny(TokenKind_1.TokenKind.At, TokenKind_1.TokenKind.QuestionAt)) {
1521
2200
  let dot = this.advance();
1522
- let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties);
2201
+ let name = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
1523
2202
  // force it into an identifier so the AST makes some sense
1524
- name.kind = lexer_1.TokenKind.Identifier;
1525
- expr = new Expression_1.XmlAttributeGetExpression(expr, name, dot);
2203
+ name.kind = TokenKind_1.TokenKind.Identifier;
2204
+ if (!name) {
2205
+ break;
2206
+ }
2207
+ expr = new Expression_1.XmlAttributeGetExpression({ obj: expr, name: name, at: dot });
1526
2208
  //only allow a single `@` expression
1527
2209
  break;
1528
2210
  }
@@ -1533,178 +2215,146 @@ class Parser {
1533
2215
  return expr;
1534
2216
  }
1535
2217
  finishCall(openingParen, callee, addToCallExpressionList = true) {
2218
+ var _a;
1536
2219
  let args = [];
1537
- while (this.match(lexer_1.TokenKind.Newline)) {
1538
- }
1539
- if (!this.check(lexer_1.TokenKind.RightParen)) {
2220
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
2221
+ if (!this.check(TokenKind_1.TokenKind.RightParen)) {
1540
2222
  do {
1541
- while (this.match(lexer_1.TokenKind.Newline)) { }
2223
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
1542
2224
  if (args.length >= Expression_1.CallExpression.MaximumArguments) {
1543
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
2225
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
1544
2226
  throw this.lastDiagnosticAsError();
1545
2227
  }
1546
- args.push(this.expression());
1547
- } while (this.match(lexer_1.TokenKind.Comma));
1548
- }
1549
- while (this.match(lexer_1.TokenKind.Newline)) { }
1550
- const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), lexer_1.TokenKind.RightParen);
1551
- if (reflection_1.isVariableExpression(callee)) {
1552
- callee.isCalled = true;
1553
- }
1554
- let expression = new Expression_1.CallExpression(callee, openingParen, closingParen, args, this.currentNamespaceName);
2228
+ try {
2229
+ args.push(this.expression());
2230
+ }
2231
+ catch (error) {
2232
+ this.rethrowNonDiagnosticError(error);
2233
+ // we were unable to get an expression, so don't continue
2234
+ break;
2235
+ }
2236
+ } while (this.match(TokenKind_1.TokenKind.Comma));
2237
+ }
2238
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
2239
+ const closingParen = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
2240
+ let expression = new Expression_1.CallExpression({
2241
+ callee: callee,
2242
+ openingParen: openingParen,
2243
+ args: args,
2244
+ closingParen: closingParen
2245
+ });
1555
2246
  if (addToCallExpressionList) {
1556
2247
  this.callExpressions.push(expression);
1557
2248
  }
1558
2249
  return expression;
1559
2250
  }
1560
2251
  /**
1561
- * Tries to get the next token as a type
1562
- * Allows for built-in types (double, string, etc.) or namespaced custom types in Brighterscript mode
1563
- * Will always return a token of whatever is next to be parsed
2252
+ * Creates a TypeExpression, which wraps standard ASTNodes that represent a BscType
1564
2253
  */
1565
- typeToken() {
1566
- let typeToken;
1567
- if (this.checkAny(...lexer_1.DeclarableTypes)) {
1568
- // Token is a built in type
1569
- typeToken = this.advance();
1570
- }
1571
- else if (this.options.mode === ParseMode.BrighterScript) {
1572
- try {
1573
- // see if we can get a namespaced identifer
1574
- const qualifiedType = this.getNamespacedVariableNameExpression();
1575
- typeToken = creators_1.createToken(lexer_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
2254
+ typeExpression() {
2255
+ const changedTokens = [];
2256
+ try {
2257
+ let expr = this.getTypeExpressionPart(changedTokens);
2258
+ while (this.options.mode === ParseMode.BrighterScript && this.matchAny(TokenKind_1.TokenKind.Or)) {
2259
+ // If we're in Brighterscript mode, allow union types with "or" between types
2260
+ // TODO: Handle Union types in parens? eg. "(string or integer)"
2261
+ let operator = this.previous();
2262
+ let right = this.getTypeExpressionPart(changedTokens);
2263
+ if (right) {
2264
+ expr = new Expression_1.BinaryExpression({ left: expr, operator: operator, right: right });
2265
+ }
2266
+ else {
2267
+ break;
2268
+ }
1576
2269
  }
1577
- catch (_a) {
1578
- //could not get an identifier - just get whatever's next
1579
- typeToken = this.advance();
2270
+ if (expr) {
2271
+ return new Expression_1.TypeExpression({ expression: expr });
1580
2272
  }
1581
2273
  }
2274
+ catch (error) {
2275
+ // Something went wrong - reset the kind to what it was previously
2276
+ for (const changedToken of changedTokens) {
2277
+ changedToken.token.kind = changedToken.oldKind;
2278
+ }
2279
+ throw error;
2280
+ }
2281
+ }
2282
+ /**
2283
+ * Gets a single "part" of a type of a potential Union type
2284
+ * Note: this does not NEED to be part of a union type, but the logic is the same
2285
+ *
2286
+ * @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
2287
+ * @returns an expression that was successfully parsed
2288
+ */
2289
+ getTypeExpressionPart(changedTokens) {
2290
+ let expr;
2291
+ if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
2292
+ // if this is just a type, just use directly
2293
+ expr = new Expression_1.VariableExpression({ name: this.advance() });
2294
+ }
1582
2295
  else {
1583
- // just get whatever's next
1584
- typeToken = this.advance();
2296
+ if (this.checkAny(...TokenKind_1.AllowedTypeIdentifiers)) {
2297
+ // Since the next token is allowed as a type identifier, change the kind
2298
+ let nextToken = this.peek();
2299
+ changedTokens.push({ token: nextToken, oldKind: nextToken.kind });
2300
+ nextToken.kind = TokenKind_1.TokenKind.Identifier;
2301
+ }
2302
+ expr = this.identifyingExpression(TokenKind_1.AllowedTypeIdentifiers);
2303
+ }
2304
+ //Check if it has square brackets, thus making it an array
2305
+ if (expr && this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
2306
+ if (this.options.mode === ParseMode.BrightScript) {
2307
+ // typed arrays not allowed in Brightscript
2308
+ this.warnIfNotBrighterScriptMode('typed arrays');
2309
+ return expr;
2310
+ }
2311
+ // Check if it is an array - that is, if it has `[]` after the type
2312
+ // eg. `string[]` or `SomeKlass[]`
2313
+ // This is while loop, so it supports multidimensional arrays (eg. integer[][])
2314
+ while (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
2315
+ const leftBracket = this.advance();
2316
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
2317
+ const rightBracket = this.advance();
2318
+ expr = new Expression_1.TypedArrayExpression({ innerType: expr, leftBracket: leftBracket, rightBracket: rightBracket });
2319
+ }
2320
+ }
1585
2321
  }
1586
- return typeToken;
2322
+ return expr;
1587
2323
  }
1588
2324
  primary() {
2325
+ var _a;
1589
2326
  switch (true) {
1590
- case this.matchAny(lexer_1.TokenKind.False, lexer_1.TokenKind.True, lexer_1.TokenKind.Invalid, lexer_1.TokenKind.IntegerLiteral, lexer_1.TokenKind.LongIntegerLiteral, lexer_1.TokenKind.FloatLiteral, lexer_1.TokenKind.DoubleLiteral, lexer_1.TokenKind.StringLiteral):
1591
- return new Expression_1.LiteralExpression(this.previous());
2327
+ 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):
2328
+ return new Expression_1.LiteralExpression({ value: this.previous() });
1592
2329
  //capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript)
1593
- case this.matchAny(lexer_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : lexer_1.BrighterScriptSourceLiterals)):
1594
- return new Expression_1.SourceLiteralExpression(this.previous());
2330
+ case this.matchAny(TokenKind_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : TokenKind_1.BrighterScriptSourceLiterals)):
2331
+ return new Expression_1.SourceLiteralExpression({ value: this.previous() });
1595
2332
  //template string
1596
- case this.check(lexer_1.TokenKind.BackTick):
2333
+ case this.check(TokenKind_1.TokenKind.BackTick):
1597
2334
  return this.templateString(false);
1598
2335
  //tagged template string (currently we do not support spaces between the identifier and the backtick)
1599
- case this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedLocalIdentifiers) && this.checkNext(lexer_1.TokenKind.BackTick):
2336
+ case this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers) && this.checkNext(TokenKind_1.TokenKind.BackTick):
1600
2337
  return this.templateString(true);
1601
- case this.matchAny(lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
1602
- return new Expression_1.VariableExpression(this.previous(), this.currentNamespaceName);
1603
- case this.match(lexer_1.TokenKind.LeftParen):
2338
+ case this.matchAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
2339
+ return new Expression_1.VariableExpression({ name: this.previous() });
2340
+ case this.match(TokenKind_1.TokenKind.LeftParen):
1604
2341
  let left = this.previous();
1605
2342
  let expr = this.expression();
1606
- let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), lexer_1.TokenKind.RightParen);
1607
- return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
1608
- case this.match(lexer_1.TokenKind.LeftSquareBracket):
1609
- let elements = [];
1610
- let openingSquare = this.previous();
1611
- //add any comment found right after the opening square
1612
- if (this.check(lexer_1.TokenKind.Comment)) {
1613
- elements.push(new Statement_1.CommentStatement([this.advance()]));
1614
- }
1615
- while (this.match(lexer_1.TokenKind.Newline)) {
1616
- }
1617
- if (!this.match(lexer_1.TokenKind.RightSquareBracket)) {
1618
- elements.push(this.expression());
1619
- while (this.matchAny(lexer_1.TokenKind.Comma, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment)) {
1620
- if (this.checkPrevious(lexer_1.TokenKind.Comment) || this.check(lexer_1.TokenKind.Comment)) {
1621
- let comment = this.check(lexer_1.TokenKind.Comment) ? this.advance() : this.previous();
1622
- elements.push(new Statement_1.CommentStatement([comment]));
1623
- }
1624
- while (this.match(lexer_1.TokenKind.Newline)) {
1625
- }
1626
- if (this.check(lexer_1.TokenKind.RightSquareBracket)) {
1627
- break;
1628
- }
1629
- elements.push(this.expression());
1630
- }
1631
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), lexer_1.TokenKind.RightSquareBracket);
1632
- }
1633
- let closingSquare = this.previous();
1634
- //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
1635
- return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
1636
- case this.match(lexer_1.TokenKind.LeftCurlyBrace):
1637
- let openingBrace = this.previous();
1638
- let members = [];
1639
- let key = () => {
1640
- let result = {
1641
- colonToken: null,
1642
- keyToken: null,
1643
- range: null
1644
- };
1645
- if (this.checkAny(lexer_1.TokenKind.Identifier, ...lexer_1.AllowedProperties)) {
1646
- result.keyToken = this.advance();
1647
- }
1648
- else if (this.check(lexer_1.TokenKind.StringLiteral)) {
1649
- result.keyToken = this.advance();
1650
- }
1651
- else {
1652
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
1653
- throw this.lastDiagnosticAsError();
1654
- }
1655
- result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), lexer_1.TokenKind.Colon);
1656
- result.range = util_1.util.getRange(result.keyToken, result.colonToken);
1657
- return result;
1658
- };
1659
- while (this.match(lexer_1.TokenKind.Newline)) {
1660
- }
1661
- if (!this.match(lexer_1.TokenKind.RightCurlyBrace)) {
1662
- if (this.check(lexer_1.TokenKind.Comment)) {
1663
- members.push(new Statement_1.CommentStatement([this.advance()]));
1664
- }
1665
- else {
1666
- let k = key();
1667
- let expr = this.expression();
1668
- members.push(new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr));
1669
- }
1670
- while (this.matchAny(lexer_1.TokenKind.Comma, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon, lexer_1.TokenKind.Comment)) {
1671
- //check for comment at the end of the current line
1672
- if (this.check(lexer_1.TokenKind.Comment) || this.checkPrevious(lexer_1.TokenKind.Comment)) {
1673
- let token = this.checkPrevious(lexer_1.TokenKind.Comment) ? this.previous() : this.advance();
1674
- members.push(new Statement_1.CommentStatement([token]));
1675
- }
1676
- else {
1677
- while (this.matchAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
1678
- }
1679
- //check for a comment on its own line
1680
- if (this.check(lexer_1.TokenKind.Comment) || this.checkPrevious(lexer_1.TokenKind.Comment)) {
1681
- let token = this.checkPrevious(lexer_1.TokenKind.Comment) ? this.previous() : this.advance();
1682
- members.push(new Statement_1.CommentStatement([token]));
1683
- continue;
1684
- }
1685
- if (this.check(lexer_1.TokenKind.RightCurlyBrace)) {
1686
- break;
1687
- }
1688
- let k = key();
1689
- let expr = this.expression();
1690
- members.push(new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr));
1691
- }
1692
- }
1693
- this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), lexer_1.TokenKind.RightCurlyBrace);
1694
- }
1695
- let closingBrace = this.previous();
1696
- const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace);
1697
- this.addPropertyHints(aaExpr);
1698
- return aaExpr;
1699
- case this.matchAny(lexer_1.TokenKind.Pos, lexer_1.TokenKind.Tab):
2343
+ let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
2344
+ return new Expression_1.GroupingExpression({ leftParen: left, rightParen: right, expression: expr });
2345
+ case this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket):
2346
+ return this.arrayLiteral();
2347
+ case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
2348
+ return this.aaLiteral();
2349
+ case this.matchAny(TokenKind_1.TokenKind.Pos, TokenKind_1.TokenKind.Tab):
1700
2350
  let token = Object.assign(this.previous(), {
1701
- kind: lexer_1.TokenKind.Identifier
2351
+ kind: TokenKind_1.TokenKind.Identifier
1702
2352
  });
1703
- return new Expression_1.VariableExpression(token, this.currentNamespaceName);
1704
- case this.checkAny(lexer_1.TokenKind.Function, lexer_1.TokenKind.Sub):
2353
+ return new Expression_1.VariableExpression({ name: token });
2354
+ case this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub):
1705
2355
  return this.anonymousFunction();
1706
- case this.check(lexer_1.TokenKind.Comment):
1707
- return new Statement_1.CommentStatement([this.advance()]);
2356
+ case this.check(TokenKind_1.TokenKind.RegexLiteral):
2357
+ return this.regexLiteralExpression();
1708
2358
  default:
1709
2359
  //if we found an expected terminator, don't throw a diagnostic...just return undefined
1710
2360
  if (this.checkAny(...this.peekGlobalTerminators())) {
@@ -1712,11 +2362,106 @@ class Parser {
1712
2362
  //something went wrong...throw an error so the upstream processor can scrap this line and move on
1713
2363
  }
1714
2364
  else {
1715
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.foundUnexpectedToken(this.peek().text)), { range: this.peek().range }));
2365
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text)), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
1716
2366
  throw this.lastDiagnosticAsError();
1717
2367
  }
1718
2368
  }
1719
2369
  }
2370
+ arrayLiteral() {
2371
+ let elements = [];
2372
+ let openingSquare = this.previous();
2373
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
2374
+ }
2375
+ let closingSquare;
2376
+ if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
2377
+ try {
2378
+ elements.push(this.expression());
2379
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
2380
+ while (this.match(TokenKind_1.TokenKind.Newline)) {
2381
+ }
2382
+ if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
2383
+ break;
2384
+ }
2385
+ elements.push(this.expression());
2386
+ }
2387
+ }
2388
+ catch (error) {
2389
+ this.rethrowNonDiagnosticError(error);
2390
+ }
2391
+ closingSquare = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
2392
+ }
2393
+ else {
2394
+ closingSquare = this.previous();
2395
+ }
2396
+ //this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
2397
+ return new Expression_1.ArrayLiteralExpression({ elements: elements, open: openingSquare, close: closingSquare });
2398
+ }
2399
+ aaLiteral() {
2400
+ let openingBrace = this.previous();
2401
+ let members = [];
2402
+ let key = () => {
2403
+ let result = {
2404
+ colonToken: null,
2405
+ keyToken: null,
2406
+ range: null
2407
+ };
2408
+ if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
2409
+ result.keyToken = this.identifier(...TokenKind_1.AllowedProperties);
2410
+ }
2411
+ else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
2412
+ result.keyToken = this.advance();
2413
+ }
2414
+ else {
2415
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { location: this.peek().location }));
2416
+ throw this.lastDiagnosticAsError();
2417
+ }
2418
+ result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
2419
+ result.range = util_1.util.createBoundingRange(result.keyToken, result.colonToken);
2420
+ return result;
2421
+ };
2422
+ while (this.match(TokenKind_1.TokenKind.Newline)) { }
2423
+ let closingBrace;
2424
+ if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
2425
+ let lastAAMember;
2426
+ try {
2427
+ let k = key();
2428
+ let expr = this.expression();
2429
+ lastAAMember = new Expression_1.AAMemberExpression({
2430
+ key: k.keyToken,
2431
+ colon: k.colonToken,
2432
+ value: expr
2433
+ });
2434
+ members.push(lastAAMember);
2435
+ while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
2436
+ // collect comma at end of expression
2437
+ if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
2438
+ lastAAMember.tokens.comma = this.previous();
2439
+ }
2440
+ this.consumeStatementSeparators(true);
2441
+ if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
2442
+ break;
2443
+ }
2444
+ let k = key();
2445
+ let expr = this.expression();
2446
+ lastAAMember = new Expression_1.AAMemberExpression({
2447
+ key: k.keyToken,
2448
+ colon: k.colonToken,
2449
+ value: expr
2450
+ });
2451
+ members.push(lastAAMember);
2452
+ }
2453
+ }
2454
+ catch (error) {
2455
+ this.rethrowNonDiagnosticError(error);
2456
+ }
2457
+ closingBrace = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
2458
+ }
2459
+ else {
2460
+ closingBrace = this.previous();
2461
+ }
2462
+ const aaExpr = new Expression_1.AALiteralExpression({ elements: members, open: openingBrace, close: closingBrace });
2463
+ return aaExpr;
2464
+ }
1720
2465
  /**
1721
2466
  * Pop token if we encounter specified token
1722
2467
  */
@@ -1729,7 +2474,7 @@ class Parser {
1729
2474
  }
1730
2475
  /**
1731
2476
  * Pop token if we encounter a token in the specified list
1732
- * @param tokenKinds
2477
+ * @param tokenKinds a list of tokenKinds where any tokenKind in this list will result in a match
1733
2478
  */
1734
2479
  matchAny(...tokenKinds) {
1735
2480
  for (let tokenKind of tokenKinds) {
@@ -1740,6 +2485,21 @@ class Parser {
1740
2485
  }
1741
2486
  return false;
1742
2487
  }
2488
+ /**
2489
+ * If the next series of tokens matches the given set of tokens, pop them all
2490
+ * @param tokenKinds a list of tokenKinds used to match the next set of tokens
2491
+ */
2492
+ matchSequence(...tokenKinds) {
2493
+ var _a;
2494
+ const endIndex = this.current + tokenKinds.length;
2495
+ for (let i = 0; i < tokenKinds.length; i++) {
2496
+ if (tokenKinds[i] !== ((_a = this.tokens[this.current + i]) === null || _a === void 0 ? void 0 : _a.kind)) {
2497
+ return false;
2498
+ }
2499
+ }
2500
+ this.current = endIndex;
2501
+ return true;
2502
+ }
1743
2503
  /**
1744
2504
  * Get next token matching a specified list, or fail with an error
1745
2505
  */
@@ -1754,29 +2514,45 @@ class Parser {
1754
2514
  throw error;
1755
2515
  }
1756
2516
  }
2517
+ /**
2518
+ * Consume next token IF it matches the specified kind. Otherwise, do nothing and return undefined
2519
+ */
2520
+ consumeTokenIf(tokenKind) {
2521
+ if (this.match(tokenKind)) {
2522
+ return this.previous();
2523
+ }
2524
+ }
2525
+ consumeToken(tokenKind) {
2526
+ return this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(tokenKind), tokenKind);
2527
+ }
1757
2528
  /**
1758
2529
  * Consume, or add a message if not found. But then continue and return undefined
1759
2530
  */
1760
2531
  tryConsume(diagnostic, ...tokenKinds) {
2532
+ var _a;
1761
2533
  const nextKind = this.peek().kind;
1762
2534
  let foundTokenKind = tokenKinds.some(tokenKind => nextKind === tokenKind);
1763
2535
  if (foundTokenKind) {
1764
2536
  return this.advance();
1765
2537
  }
1766
- this.diagnostics.push(Object.assign(Object.assign({}, diagnostic), { range: this.peek().range }));
2538
+ this.diagnostics.push(Object.assign(Object.assign({}, diagnostic), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
2539
+ }
2540
+ tryConsumeToken(tokenKind) {
2541
+ return this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(tokenKind), tokenKind);
1767
2542
  }
1768
2543
  consumeStatementSeparators(optional = false) {
2544
+ var _a;
1769
2545
  //a comment or EOF mark the end of the statement
1770
- if (this.isAtEnd() || this.check(lexer_1.TokenKind.Comment)) {
2546
+ if (this.isAtEnd() || this.check(TokenKind_1.TokenKind.Comment)) {
1771
2547
  return true;
1772
2548
  }
1773
2549
  let consumed = false;
1774
2550
  //consume any newlines and colons
1775
- while (this.matchAny(lexer_1.TokenKind.Newline, lexer_1.TokenKind.Colon)) {
2551
+ while (this.matchAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
1776
2552
  consumed = true;
1777
2553
  }
1778
2554
  if (!optional && !consumed) {
1779
- this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { range: this.peek().range }));
2555
+ this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { location: (_a = this.peek()) === null || _a === void 0 ? void 0 : _a.location }));
1780
2556
  }
1781
2557
  return consumed;
1782
2558
  }
@@ -1788,22 +2564,27 @@ class Parser {
1788
2564
  }
1789
2565
  checkEndOfStatement() {
1790
2566
  const nextKind = this.peek().kind;
1791
- return [lexer_1.TokenKind.Colon, lexer_1.TokenKind.Newline, lexer_1.TokenKind.Comment, lexer_1.TokenKind.Eof].includes(nextKind);
2567
+ return [TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Eof].includes(nextKind);
1792
2568
  }
1793
2569
  checkPrevious(tokenKind) {
1794
2570
  var _a;
1795
2571
  return ((_a = this.previous()) === null || _a === void 0 ? void 0 : _a.kind) === tokenKind;
1796
2572
  }
2573
+ /**
2574
+ * Check that the next token kind is the expected kind
2575
+ * @param tokenKind the expected next kind
2576
+ * @returns true if the next tokenKind is the expected value
2577
+ */
1797
2578
  check(tokenKind) {
1798
2579
  const nextKind = this.peek().kind;
1799
- if (nextKind === lexer_1.TokenKind.Eof) {
2580
+ if (nextKind === TokenKind_1.TokenKind.Eof) {
1800
2581
  return false;
1801
2582
  }
1802
2583
  return nextKind === tokenKind;
1803
2584
  }
1804
2585
  checkAny(...tokenKinds) {
1805
2586
  const nextKind = this.peek().kind;
1806
- if (nextKind === lexer_1.TokenKind.Eof) {
2587
+ if (nextKind === TokenKind_1.TokenKind.Eof) {
1807
2588
  return false;
1808
2589
  }
1809
2590
  return tokenKinds.includes(nextKind);
@@ -1822,7 +2603,8 @@ class Parser {
1822
2603
  return tokenKinds.includes(nextKind);
1823
2604
  }
1824
2605
  isAtEnd() {
1825
- return this.peek().kind === lexer_1.TokenKind.Eof;
2606
+ const peekToken = this.peek();
2607
+ return !peekToken || peekToken.kind === TokenKind_1.TokenKind.Eof;
1826
2608
  }
1827
2609
  peekNext() {
1828
2610
  if (this.isAtEnd()) {
@@ -1836,6 +2618,33 @@ class Parser {
1836
2618
  previous() {
1837
2619
  return this.tokens[this.current - 1];
1838
2620
  }
2621
+ /**
2622
+ * Sometimes we catch an error that is a diagnostic.
2623
+ * If that's the case, we want to continue parsing.
2624
+ * Otherwise, re-throw the error
2625
+ *
2626
+ * @param error error caught in a try/catch
2627
+ */
2628
+ rethrowNonDiagnosticError(error) {
2629
+ if (!error.isDiagnostic) {
2630
+ throw error;
2631
+ }
2632
+ }
2633
+ /**
2634
+ * Get the token that is {offset} indexes away from {this.current}
2635
+ * @param offset the number of index steps away from current index to fetch
2636
+ * @param tokenKinds the desired token must match one of these
2637
+ * @example
2638
+ * getToken(-1); //returns the previous token.
2639
+ * getToken(0); //returns current token.
2640
+ * getToken(1); //returns next token
2641
+ */
2642
+ getMatchingTokenAtOffset(offset, ...tokenKinds) {
2643
+ const token = this.tokens[this.current + offset];
2644
+ if (tokenKinds.includes(token.kind)) {
2645
+ return token;
2646
+ }
2647
+ }
1839
2648
  synchronize() {
1840
2649
  this.advance(); // skip the erroneous token
1841
2650
  while (!this.isAtEnd()) {
@@ -1844,16 +2653,16 @@ class Parser {
1844
2653
  return;
1845
2654
  }
1846
2655
  switch (this.peek().kind) { //eslint-disable-line @typescript-eslint/switch-exhaustiveness-check
1847
- case lexer_1.TokenKind.Namespace:
1848
- case lexer_1.TokenKind.Class:
1849
- case lexer_1.TokenKind.Function:
1850
- case lexer_1.TokenKind.Sub:
1851
- case lexer_1.TokenKind.If:
1852
- case lexer_1.TokenKind.For:
1853
- case lexer_1.TokenKind.ForEach:
1854
- case lexer_1.TokenKind.While:
1855
- case lexer_1.TokenKind.Print:
1856
- case lexer_1.TokenKind.Return:
2656
+ case TokenKind_1.TokenKind.Namespace:
2657
+ case TokenKind_1.TokenKind.Class:
2658
+ case TokenKind_1.TokenKind.Function:
2659
+ case TokenKind_1.TokenKind.Sub:
2660
+ case TokenKind_1.TokenKind.If:
2661
+ case TokenKind_1.TokenKind.For:
2662
+ case TokenKind_1.TokenKind.ForEach:
2663
+ case TokenKind_1.TokenKind.While:
2664
+ case TokenKind_1.TokenKind.Print:
2665
+ case TokenKind_1.TokenKind.Return:
1857
2666
  // start parsing again from the next block starter or obvious
1858
2667
  // expression start
1859
2668
  return;
@@ -1861,157 +2670,6 @@ class Parser {
1861
2670
  this.advance();
1862
2671
  }
1863
2672
  }
1864
- /**
1865
- * Get the token at the specified position
1866
- * @param position
1867
- */
1868
- getTokenAt(position) {
1869
- for (let token of this.tokens) {
1870
- if (util_1.util.rangeContains(token.range, position)) {
1871
- return token;
1872
- }
1873
- }
1874
- }
1875
- /**
1876
- * Get the token closest to the position. if no token is found, the previous token is returned
1877
- * @param position
1878
- * @param tokens
1879
- */
1880
- getClosestToken(position) {
1881
- let tokens = this.tokens;
1882
- for (let i = 0; i < tokens.length; i++) {
1883
- let token = tokens[i];
1884
- if (util_1.util.rangeContains(token.range, position)) {
1885
- return token;
1886
- }
1887
- //if the position less than this token range, then this position touches no token,
1888
- if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
1889
- let t = tokens[i - 1];
1890
- //return the token or the first token
1891
- return t ? t : tokens[0];
1892
- }
1893
- }
1894
- //return the last token
1895
- return tokens[tokens.length - 1];
1896
- }
1897
- isPositionNextToTokenKind(position, tokenKind) {
1898
- const closestToken = this.getClosestToken(position);
1899
- const previousToken = this.getPreviousToken(closestToken);
1900
- const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
1901
- //next to matched token
1902
- if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
1903
- return false;
1904
- }
1905
- else if (closestToken.kind === tokenKind) {
1906
- return true;
1907
- }
1908
- else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
1909
- return false;
1910
- //next to an identifier, which is next to token kind
1911
- }
1912
- else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
1913
- return true;
1914
- }
1915
- else {
1916
- return false;
1917
- }
1918
- }
1919
- getTokenBefore(currentToken, tokenKind) {
1920
- const index = this.tokens.indexOf(currentToken);
1921
- for (let i = index - 1; i >= 0; i--) {
1922
- currentToken = this.tokens[i];
1923
- if (currentToken.kind === lexer_1.TokenKind.Newline) {
1924
- break;
1925
- }
1926
- else if (currentToken.kind === tokenKind) {
1927
- return currentToken;
1928
- }
1929
- }
1930
- return undefined;
1931
- }
1932
- tokenFollows(currentToken, tokenKind) {
1933
- const index = this.tokens.indexOf(currentToken);
1934
- if (index > 0) {
1935
- return this.tokens[index - 1].kind === tokenKind;
1936
- }
1937
- return false;
1938
- }
1939
- getTokensUntil(currentToken, tokenKind, direction = -1) {
1940
- let tokens = [];
1941
- for (let i = this.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.tokens.length; i += direction) {
1942
- currentToken = this.tokens[i];
1943
- if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
1944
- break;
1945
- }
1946
- tokens.push(currentToken);
1947
- }
1948
- return tokens;
1949
- }
1950
- getPreviousToken(token) {
1951
- let idx = this.tokens.indexOf(token);
1952
- return this.tokens[idx - 1];
1953
- }
1954
- /**
1955
- * References are found during the initial parse.
1956
- * However, sometimes plugins can modify the AST, requiring a full walk to re-compute all references.
1957
- * This does that walk.
1958
- */
1959
- findReferences() {
1960
- this._references = new References();
1961
- //gather up all the top-level statements
1962
- this.ast.walk(visitors_1.createVisitor({
1963
- ClassStatement: s => {
1964
- this._references.classStatements.push(s);
1965
- },
1966
- NamespaceStatement: s => {
1967
- this._references.namespaceStatements.push(s);
1968
- },
1969
- FunctionStatement: s => {
1970
- this._references.functionStatements.push(s);
1971
- //add the initial set of function expressions for function statements
1972
- this._references.functionExpressions.push(s.func);
1973
- },
1974
- ImportStatement: s => {
1975
- this._references.importStatements.push(s);
1976
- },
1977
- LibraryStatement: s => {
1978
- this._references.libraryStatements.push(s);
1979
- }
1980
- }), {
1981
- walkMode: visitors_1.WalkMode.visitStatements
1982
- });
1983
- let func;
1984
- let visitor = visitors_1.createVisitor({
1985
- AssignmentStatement: s => {
1986
- this._references.assignmentStatements.push(s);
1987
- },
1988
- FunctionExpression: (expression, parent) => {
1989
- if (!reflection_1.isClassMethodStatement(parent)) {
1990
- this._references.functionExpressions.push(expression);
1991
- }
1992
- },
1993
- NewExpression: e => {
1994
- this._references.newExpressions.push(e);
1995
- },
1996
- AALiteralExpression: e => {
1997
- this.addPropertyHints(e);
1998
- },
1999
- DottedGetExpression: e => {
2000
- this.addPropertyHints(e.name);
2001
- },
2002
- DottedSetStatement: e => {
2003
- this.addPropertyHints(e.name);
2004
- }
2005
- });
2006
- //walk all function expressions (we'll add new ones as we move along too)
2007
- for (let i = 0; i < this._references.functionExpressions.length; i++) {
2008
- func = this._references.functionExpressions[i];
2009
- //walk this function expression
2010
- func.body.walk(visitor, {
2011
- walkMode: visitors_1.WalkMode.visitAll
2012
- });
2013
- }
2014
- }
2015
2673
  dispose() {
2016
2674
  }
2017
2675
  }
@@ -2021,140 +2679,9 @@ var ParseMode;
2021
2679
  ParseMode["BrightScript"] = "BrightScript";
2022
2680
  ParseMode["BrighterScript"] = "BrighterScript";
2023
2681
  })(ParseMode = exports.ParseMode || (exports.ParseMode = {}));
2024
- class References {
2025
- constructor() {
2026
- this.assignmentStatements = [];
2027
- this.classStatements = [];
2028
- this.functionExpressions = [];
2029
- this.functionStatements = [];
2030
- this.importStatements = [];
2031
- this.libraryStatements = [];
2032
- this.namespaceStatements = [];
2033
- this.newExpressions = [];
2034
- this.propertyHints = {};
2035
- }
2036
- get classStatementLookup() {
2037
- if (!this._classStatementLookup) {
2038
- this._classStatementLookup = new Map();
2039
- for (const stmt of this.classStatements) {
2040
- this._classStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2041
- }
2042
- }
2043
- return this._classStatementLookup;
2044
- }
2045
- /**
2046
- * A map of function statements, indexed by fully-namespaced lower function name.
2047
- */
2048
- get functionStatementLookup() {
2049
- if (!this._functionStatementLookup) {
2050
- this._functionStatementLookup = new Map();
2051
- for (const stmt of this.functionStatements) {
2052
- this._functionStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
2053
- }
2054
- }
2055
- return this._functionStatementLookup;
2056
- }
2057
- }
2058
- exports.References = References;
2059
2682
  class CancelStatementError extends Error {
2060
2683
  constructor() {
2061
2684
  super('CancelStatement');
2062
2685
  }
2063
2686
  }
2064
- /**
2065
- * Gets the type of an expression. If it can not be processed, will return DynamicType
2066
- *
2067
- * @param expression the Expression to process
2068
- * @param functionExpression the wrapping function expression
2069
- * @return the best guess type of that expression
2070
- */
2071
- function getBscTypeFromExpression(expression, functionExpression) {
2072
- try {
2073
- //function
2074
- if (reflection_1.isFunctionExpression(expression)) {
2075
- return expression.getFunctionType();
2076
- //literal
2077
- }
2078
- else if (reflection_1.isLiteralExpression(expression)) {
2079
- return expression.type;
2080
- //Associative array literal
2081
- }
2082
- else if (reflection_1.isAALiteralExpression(expression)) {
2083
- return new ObjectType_1.ObjectType();
2084
- //Array literal
2085
- }
2086
- else if (reflection_1.isArrayLiteralExpression(expression)) {
2087
- return new ArrayType_1.ArrayType();
2088
- //function call
2089
- }
2090
- else if (reflection_1.isNewExpression(expression)) {
2091
- return new CustomType_1.CustomType(expression.className.getName(ParseMode.BrighterScript));
2092
- //Function call
2093
- }
2094
- else if (reflection_1.isCallExpression(expression)) {
2095
- return getTypeFromCallExpression(expression, functionExpression);
2096
- }
2097
- else if (reflection_1.isVariableExpression(expression)) {
2098
- return getTypeFromVariableExpression(expression, functionExpression);
2099
- }
2100
- }
2101
- catch (e) {
2102
- //do nothing. Just return dynamic
2103
- }
2104
- //fallback to dynamic
2105
- return new DynamicType_1.DynamicType();
2106
- }
2107
- exports.getBscTypeFromExpression = getBscTypeFromExpression;
2108
- /**
2109
- * Gets the return type of a function, taking into account that the function may not have been declared yet
2110
- * If the callee already exists in symbol table, use that return type
2111
- * otherwise, make a lazy type which will not compute its type until the file is done parsing
2112
- *
2113
- * @param call the Expression to process
2114
- * @param functionExpression the wrapping function expression
2115
- * @return the best guess type of that expression
2116
- */
2117
- function getTypeFromCallExpression(call, functionExpression) {
2118
- var _a;
2119
- let calleeName = (_a = call.callee.name.text) === null || _a === void 0 ? void 0 : _a.toLowerCase();
2120
- if (calleeName) {
2121
- // i
2122
- const currentKnownType = functionExpression.symbolTable.getSymbolType(calleeName);
2123
- if (reflection_1.isFunctionType(currentKnownType)) {
2124
- return currentKnownType.returnType;
2125
- }
2126
- if (!reflection_1.isUninitializedType(currentKnownType)) {
2127
- // this will probably only happen if a functionName has been assigned to something else previously?
2128
- return currentKnownType;
2129
- }
2130
- return new LazyType_1.LazyType(() => {
2131
- const futureType = functionExpression.symbolTable.getSymbolType(calleeName);
2132
- if (reflection_1.isFunctionType(futureType)) {
2133
- return futureType.returnType;
2134
- }
2135
- return futureType;
2136
- });
2137
- }
2138
- }
2139
- exports.getTypeFromCallExpression = getTypeFromCallExpression;
2140
- /**
2141
- * Gets the type of a variable
2142
- * if it already exists in symbol table, use that type
2143
- * otherwise defer the type until first read, which will allow us to derive types from variables defined after this one (like from a loop perhaps)
2144
- *
2145
- * @param variable the Expression to process
2146
- * @param functionExpression the wrapping function expression
2147
- * @return the best guess type of that expression
2148
- */
2149
- function getTypeFromVariableExpression(variable, functionExpression) {
2150
- let variableName = variable.name.text.toLowerCase();
2151
- const currentKnownType = functionExpression.symbolTable.getSymbolType(variableName);
2152
- if (!reflection_1.isUninitializedType(currentKnownType)) {
2153
- return currentKnownType;
2154
- }
2155
- return new LazyType_1.LazyType(() => {
2156
- return functionExpression.symbolTable.getSymbolType(variableName);
2157
- });
2158
- }
2159
- exports.getTypeFromVariableExpression = getTypeFromVariableExpression;
2160
2687
  //# sourceMappingURL=Parser.js.map