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