brighterscript 1.0.0-alpha.3 → 1.0.0-alpha.30

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