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