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