brighterscript 1.0.0-alpha.5 → 1.0.0-alpha.50

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