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