brighterscript 1.0.0-alpha.2 → 1.0.0-alpha.22
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 +643 -253
- package/README.md +33 -9
- package/bsconfig.schema.json +22 -2
- package/dist/BsConfig.d.ts +9 -0
- package/dist/Cache.d.ts +5 -6
- package/dist/Cache.js +12 -11
- package/dist/Cache.js.map +1 -1
- 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 +4 -4
- package/dist/CommentFlagProcessor.js +5 -3
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DependencyGraph.d.ts +2 -2
- package/dist/DependencyGraph.js +20 -7
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticCollection.d.ts +3 -3
- package/dist/DiagnosticCollection.js +11 -11
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.js +5 -4
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +59 -4
- package/dist/DiagnosticMessages.js +65 -7
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.d.ts +51 -39
- package/dist/LanguageServer.js +316 -232
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +2 -0
- package/dist/Logger.js +10 -8
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +7 -3
- package/dist/PluginInterface.js +9 -0
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +43 -25
- package/dist/Program.js +212 -95
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +4 -0
- package/dist/ProgramBuilder.js +36 -20
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +126 -29
- package/dist/Scope.js +433 -156
- 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/SymbolTable.d.ts +10 -4
- package/dist/SymbolTable.js +55 -13
- package/dist/SymbolTable.js.map +1 -1
- package/dist/XmlScope.d.ts +7 -2
- package/dist/XmlScope.js +65 -27
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/AstEditor.d.ts +65 -0
- package/dist/astUtils/AstEditor.js +239 -0
- package/dist/astUtils/AstEditor.js.map +1 -0
- package/dist/{types/FunctionType.spec.d.ts → astUtils/AstEditor.spec.d.ts} +0 -0
- package/dist/astUtils/AstEditor.spec.js +254 -0
- package/dist/astUtils/AstEditor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +28 -6
- package/dist/astUtils/creators.js +137 -19
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +14 -4
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +32 -10
- package/dist/astUtils/reflection.js +82 -7
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +130 -119
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/stackedVisitor.js.map +1 -1
- package/dist/astUtils/stackedVisitor.spec.js +13 -13
- package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +76 -51
- package/dist/astUtils/visitors.js +31 -11
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +126 -32
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +4 -3
- package/dist/astUtils/xml.js +8 -3
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +7 -1
- package/dist/bscPlugin/BscPlugin.js +28 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +4 -4
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +26 -26
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +9 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +108 -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 +130 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +52 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +32 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +29 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +183 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/cli.js +10 -3
- package/dist/cli.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +1 -0
- package/dist/diagnosticUtils.js +15 -8
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +12 -14
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +717 -147
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +70 -30
- package/dist/files/BrsFile.js +719 -353
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +1238 -449
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +6 -5
- package/dist/files/XmlFile.js +38 -30
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +302 -237
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +44 -42
- 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 +88 -0
- package/dist/files/tests/optionalChaning.spec.js.map +1 -0
- package/dist/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +424 -152
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +28 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +133 -16
- package/dist/lexer/Lexer.d.ts +19 -1
- package/dist/lexer/Lexer.js +127 -21
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +657 -536
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.d.ts +2 -2
- package/dist/lexer/TokenKind.d.ts +13 -1
- package/dist/lexer/TokenKind.js +60 -3
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/BrsTranspileState.d.ts +9 -0
- package/dist/parser/BrsTranspileState.js +14 -0
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +150 -34
- package/dist/parser/Expression.js +335 -165
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +189 -89
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +153 -30
- package/dist/parser/Parser.js +1100 -503
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +687 -266
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +41 -4
- package/dist/parser/SGParser.js +186 -175
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +35 -22
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +206 -38
- package/dist/parser/SGTypes.js +470 -161
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/SGTypes.spec.d.ts +1 -0
- package/dist/parser/SGTypes.spec.js +351 -0
- package/dist/parser/SGTypes.spec.js.map +1 -0
- package/dist/parser/Statement.d.ts +202 -48
- package/dist/parser/Statement.js +648 -193
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +11 -11
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +1 -1
- package/dist/parser/TranspileState.js +15 -7
- 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 +15 -11
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +60 -60
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +40 -39
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +213 -194
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +37 -37
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +30 -30
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +119 -119
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +162 -138
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +24 -24
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +41 -40
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +17 -17
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +256 -256
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +87 -87
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +37 -37
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +75 -63
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +41 -41
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +41 -41
- 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 +43 -43
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +9 -9
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +28 -28
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +102 -102
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +36 -36
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/Declaration.spec.js +44 -44
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Dim.spec.js +21 -21
- 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 +840 -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 +46 -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 +37 -0
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
- package/dist/parser/tests/statement/Function.spec.js +198 -197
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +15 -14
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +50 -50
- 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 +254 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/LibraryStatement.spec.js +17 -17
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +108 -106
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +40 -40
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +46 -46
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +83 -83
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +12 -11
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/parser/tests/statement/Throw.spec.js +5 -5
- package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +15 -13
- package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
- package/dist/preprocessor/Chunk.d.ts +1 -1
- package/dist/preprocessor/Chunk.js.map +1 -1
- package/dist/preprocessor/Manifest.d.ts +5 -5
- package/dist/preprocessor/Manifest.js +14 -35
- 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/preprocessor/Preprocessor.d.ts +1 -1
- package/dist/preprocessor/Preprocessor.js +8 -8
- package/dist/preprocessor/Preprocessor.js.map +1 -1
- package/dist/preprocessor/Preprocessor.spec.js +49 -49
- package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
- package/dist/preprocessor/PreprocessorParser.spec.js +72 -72
- package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
- package/dist/roku-types/data.json +21891 -0
- package/dist/roku-types/index.d.ts +6776 -0
- package/dist/roku-types/index.js +11 -0
- package/dist/roku-types/index.js.map +1 -0
- package/dist/types/ArrayType.d.ts +8 -5
- package/dist/types/ArrayType.js +52 -12
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +72 -11
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/BooleanType.d.ts +4 -2
- package/dist/types/BooleanType.js +9 -4
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BooleanType.spec.js +5 -3
- package/dist/types/BooleanType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +20 -5
- package/dist/types/BscType.js +24 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/CustomType.d.ts +8 -6
- package/dist/types/CustomType.js +20 -11
- package/dist/types/CustomType.js.map +1 -1
- package/dist/types/DoubleType.d.ts +2 -0
- package/dist/types/DoubleType.js +14 -9
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DoubleType.spec.js +5 -3
- package/dist/types/DoubleType.spec.js.map +1 -1
- package/dist/types/DynamicType.d.ts +2 -0
- package/dist/types/DynamicType.js +6 -2
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/DynamicType.spec.js +2 -2
- package/dist/types/DynamicType.spec.js.map +1 -1
- package/dist/types/EnumType.d.ts +22 -0
- package/dist/types/EnumType.js +55 -0
- package/dist/types/EnumType.js.map +1 -0
- package/dist/types/FloatType.d.ts +2 -0
- package/dist/types/FloatType.js +14 -9
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FloatType.spec.js +4 -2
- package/dist/types/FloatType.spec.js.map +1 -1
- package/dist/types/FunctionType.d.ts +7 -31
- package/dist/types/FunctionType.js +11 -57
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/IntegerType.d.ts +2 -0
- package/dist/types/IntegerType.js +14 -9
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/IntegerType.spec.js +5 -3
- package/dist/types/IntegerType.spec.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +13 -4
- package/dist/types/InterfaceType.js +48 -8
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.d.ts +1 -0
- package/dist/types/InterfaceType.spec.js +194 -0
- package/dist/types/InterfaceType.spec.js.map +1 -0
- package/dist/types/InvalidType.d.ts +4 -2
- package/dist/types/InvalidType.js +10 -5
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/InvalidType.spec.js +4 -2
- package/dist/types/InvalidType.spec.js.map +1 -1
- package/dist/types/LazyType.d.ts +8 -7
- package/dist/types/LazyType.js +22 -10
- package/dist/types/LazyType.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +2 -0
- package/dist/types/LongIntegerType.js +14 -9
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.spec.js +4 -2
- package/dist/types/LongIntegerType.spec.js.map +1 -1
- package/dist/types/ObjectType.d.ts +8 -4
- package/dist/types/ObjectType.js +9 -4
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ObjectType.spec.js +2 -2
- package/dist/types/ObjectType.spec.js.map +1 -1
- package/dist/types/StringType.d.ts +4 -2
- package/dist/types/StringType.js +9 -4
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/StringType.spec.js +4 -2
- package/dist/types/StringType.spec.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +28 -0
- package/dist/types/TypedFunctionType.js +88 -0
- package/dist/types/TypedFunctionType.js.map +1 -0
- package/dist/types/TypedFunctionType.spec.d.ts +1 -0
- package/dist/types/TypedFunctionType.spec.js +37 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -0
- package/dist/types/UninitializedType.js +3 -3
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/VoidType.d.ts +4 -2
- package/dist/types/VoidType.js +8 -4
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/VoidType.spec.js +2 -2
- package/dist/types/VoidType.spec.js.map +1 -1
- package/dist/types/helpers.d.ts +42 -0
- package/dist/types/helpers.js +118 -0
- package/dist/types/helpers.js.map +1 -0
- package/dist/util.d.ts +91 -21
- package/dist/util.js +364 -114
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +19 -2
- package/dist/validators/ClassValidator.js +164 -103
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +30 -19
- 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/index.d.ts +0 -3
- package/dist/preprocessor/index.js +0 -16
- package/dist/preprocessor/index.js.map +0 -1
- package/dist/types/FunctionType.spec.js +0 -23
- package/dist/types/FunctionType.spec.js.map +0 -1
package/dist/parser/Parser.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
3
|
+
exports.getBscTypeFromExpression = exports.TokenUsage = exports.References = 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");
|
|
@@ -10,12 +12,12 @@ const Logger_1 = require("../Logger");
|
|
|
10
12
|
const reflection_1 = require("../astUtils/reflection");
|
|
11
13
|
const visitors_1 = require("../astUtils/visitors");
|
|
12
14
|
const creators_1 = require("../astUtils/creators");
|
|
15
|
+
const Cache_1 = require("../Cache");
|
|
13
16
|
const DynamicType_1 = require("../types/DynamicType");
|
|
14
|
-
const
|
|
17
|
+
const ArrayType_1 = require("../types/ArrayType");
|
|
18
|
+
const helpers_1 = require("../types/helpers");
|
|
15
19
|
const SymbolTable_1 = require("../SymbolTable");
|
|
16
20
|
const ObjectType_1 = require("../types/ObjectType");
|
|
17
|
-
const CustomType_1 = require("../types/CustomType");
|
|
18
|
-
const ArrayType_1 = require("../types/ArrayType");
|
|
19
21
|
class Parser {
|
|
20
22
|
constructor() {
|
|
21
23
|
/**
|
|
@@ -61,13 +63,13 @@ class Parser {
|
|
|
61
63
|
this._references = undefined;
|
|
62
64
|
}
|
|
63
65
|
addPropertyHints(item) {
|
|
64
|
-
if (
|
|
66
|
+
if ((0, Token_1.isToken)(item)) {
|
|
65
67
|
const name = item.text;
|
|
66
68
|
this._references.propertyHints[name.toLowerCase()] = name;
|
|
67
69
|
}
|
|
68
70
|
else {
|
|
69
71
|
for (const member of item.elements) {
|
|
70
|
-
if (!reflection_1.isCommentStatement(member)) {
|
|
72
|
+
if (!(0, reflection_1.isCommentStatement)(member)) {
|
|
71
73
|
const name = member.keyToken.text;
|
|
72
74
|
if (!name.startsWith('"')) {
|
|
73
75
|
this._references.propertyHints[name.toLowerCase()] = name;
|
|
@@ -87,10 +89,13 @@ class Parser {
|
|
|
87
89
|
var _a;
|
|
88
90
|
return (_a = this.globalTerminators[this.globalTerminators.length - 1]) !== null && _a !== void 0 ? _a : [];
|
|
89
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Static wrapper around creating a new parser and parsing a list of tokens
|
|
94
|
+
*/
|
|
90
95
|
static parse(toParse, options) {
|
|
91
96
|
let tokens;
|
|
92
97
|
if (typeof toParse === 'string') {
|
|
93
|
-
tokens =
|
|
98
|
+
tokens = Lexer_1.Lexer.scan(toParse).tokens;
|
|
94
99
|
}
|
|
95
100
|
else {
|
|
96
101
|
tokens = toParse;
|
|
@@ -108,9 +113,9 @@ class Parser {
|
|
|
108
113
|
this.tokens = tokens;
|
|
109
114
|
this.options = this.sanitizeParseOptions(options);
|
|
110
115
|
this.allowedLocalIdentifiers = [
|
|
111
|
-
...
|
|
116
|
+
...TokenKind_1.AllowedLocalIdentifiers,
|
|
112
117
|
//when in plain brightscript mode, the BrighterScript source literals can be used as regular variables
|
|
113
|
-
...(this.options.mode === ParseMode.BrightScript ?
|
|
118
|
+
...(this.options.mode === ParseMode.BrightScript ? TokenKind_1.BrighterScriptSourceLiterals : [])
|
|
114
119
|
];
|
|
115
120
|
this.current = 0;
|
|
116
121
|
this.diagnostics = [];
|
|
@@ -132,7 +137,7 @@ class Parser {
|
|
|
132
137
|
!this.checkAny(...this.peekGlobalTerminators())) {
|
|
133
138
|
let dec = this.declaration();
|
|
134
139
|
if (dec) {
|
|
135
|
-
if (!reflection_1.isAnnotationExpression(dec)) {
|
|
140
|
+
if (!(0, reflection_1.isAnnotationExpression)(dec)) {
|
|
136
141
|
this.consumePendingAnnotations(dec);
|
|
137
142
|
body.statements.push(dec);
|
|
138
143
|
//ensure statement separator
|
|
@@ -181,22 +186,16 @@ class Parser {
|
|
|
181
186
|
}
|
|
182
187
|
declaration() {
|
|
183
188
|
try {
|
|
184
|
-
if (this.
|
|
185
|
-
return this.
|
|
186
|
-
}
|
|
187
|
-
if (this.checkAny(lexer_1.TokenKind.Sub, lexer_1.TokenKind.Function)) {
|
|
188
|
-
return this.functionDeclaration(false);
|
|
189
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
190
|
+
return this.functionStatement({ hasName: true, hasBody: true, hasEnd: true });
|
|
189
191
|
}
|
|
190
192
|
if (this.checkLibrary()) {
|
|
191
193
|
return this.libraryStatement();
|
|
192
194
|
}
|
|
193
|
-
if (this.check(
|
|
194
|
-
return this.namespaceStatement();
|
|
195
|
-
}
|
|
196
|
-
if (this.check(lexer_1.TokenKind.At) && this.checkNext(lexer_1.TokenKind.Identifier)) {
|
|
195
|
+
if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
|
|
197
196
|
return this.annotationExpression();
|
|
198
197
|
}
|
|
199
|
-
if (this.check(
|
|
198
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
200
199
|
return this.commentStatement();
|
|
201
200
|
}
|
|
202
201
|
//catch certain global terminators to prevent unnecessary lookahead (i.e. like `end namespace`, no need to continue)
|
|
@@ -213,17 +212,185 @@ class Parser {
|
|
|
213
212
|
this.synchronize();
|
|
214
213
|
}
|
|
215
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Try to get an identifier. If not found, add diagnostic and return undefined
|
|
217
|
+
*/
|
|
218
|
+
tryIdentifier(...additionalTokenKinds) {
|
|
219
|
+
const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
|
|
220
|
+
if (identifier) {
|
|
221
|
+
// force the name into an identifier so the AST makes some sense
|
|
222
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
223
|
+
return identifier;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
identifier(...additionalTokenKinds) {
|
|
227
|
+
const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
|
|
228
|
+
// force the name into an identifier so the AST makes some sense
|
|
229
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
230
|
+
return identifier;
|
|
231
|
+
}
|
|
232
|
+
enumMemberStatement() {
|
|
233
|
+
const tokens = {};
|
|
234
|
+
let value;
|
|
235
|
+
tokens.name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
236
|
+
//look for `= SOME_EXPRESSION`
|
|
237
|
+
if (this.check(TokenKind_1.TokenKind.Equal)) {
|
|
238
|
+
tokens.equal = this.advance();
|
|
239
|
+
value = this.expression();
|
|
240
|
+
}
|
|
241
|
+
return new Statement_1.EnumMemberStatement(tokens, value);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Create a new InterfaceFieldStatement. This should only be called from within `interfaceDeclaration`
|
|
245
|
+
*/
|
|
246
|
+
interfaceFieldStatement() {
|
|
247
|
+
const name = this.identifier(...TokenKind_1.AllowedProperties);
|
|
248
|
+
let asToken;
|
|
249
|
+
let typeExpr;
|
|
250
|
+
//look for `as SOME_TYPE`
|
|
251
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
252
|
+
asToken = this.consumeToken(TokenKind_1.TokenKind.As);
|
|
253
|
+
typeExpr = this.typeExpression();
|
|
254
|
+
//no field type specified
|
|
255
|
+
if (!typeExpr.isValidType()) {
|
|
256
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return new Statement_1.InterfaceFieldStatement(name, asToken, typeExpr, this.currentNamespaceName);
|
|
260
|
+
}
|
|
261
|
+
interfaceDeclaration() {
|
|
262
|
+
this.warnIfNotBrighterScriptMode('interface declarations');
|
|
263
|
+
const parentAnnotations = this.enterAnnotationBlock();
|
|
264
|
+
const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
|
|
265
|
+
//get the interface name
|
|
266
|
+
let nameToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('interface'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
267
|
+
let extendsToken;
|
|
268
|
+
let parentInterfaceName;
|
|
269
|
+
if (this.peek().text.toLowerCase() === 'extends') {
|
|
270
|
+
extendsToken = this.advance();
|
|
271
|
+
parentInterfaceName = this.getNamespacedVariableNameExpression();
|
|
272
|
+
}
|
|
273
|
+
this.consumeStatementSeparators();
|
|
274
|
+
//gather up all interface members (Fields, Methods)
|
|
275
|
+
let body = [];
|
|
276
|
+
while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
|
|
277
|
+
try {
|
|
278
|
+
//break out of this loop if we encountered the `EndInterface` token not followed by `as`
|
|
279
|
+
if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
let decl;
|
|
283
|
+
//collect leading annotations
|
|
284
|
+
if (this.check(TokenKind_1.TokenKind.At)) {
|
|
285
|
+
this.annotationExpression();
|
|
286
|
+
}
|
|
287
|
+
//fields
|
|
288
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.As)) {
|
|
289
|
+
decl = this.interfaceFieldStatement();
|
|
290
|
+
//methods (function/sub keyword followed by opening paren)
|
|
291
|
+
}
|
|
292
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
293
|
+
const functionStatement = this.functionStatement({
|
|
294
|
+
hasName: true,
|
|
295
|
+
hasBody: false,
|
|
296
|
+
hasEnd: false,
|
|
297
|
+
onlyCallableAsMember: true
|
|
298
|
+
});
|
|
299
|
+
decl = new Statement_1.InterfaceMethodStatement(functionStatement.name, functionStatement.func);
|
|
300
|
+
//refer to this statement as parent of the expression
|
|
301
|
+
functionStatement.func.functionStatement = decl;
|
|
302
|
+
//comments
|
|
303
|
+
}
|
|
304
|
+
else if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
305
|
+
decl = this.commentStatement();
|
|
306
|
+
}
|
|
307
|
+
if (decl) {
|
|
308
|
+
this.consumePendingAnnotations(decl);
|
|
309
|
+
body.push(decl);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch (e) {
|
|
313
|
+
//throw out any failed members and move on to the next line
|
|
314
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
315
|
+
}
|
|
316
|
+
//ensure statement separator
|
|
317
|
+
this.consumeStatementSeparators();
|
|
318
|
+
}
|
|
319
|
+
//consume the final `end interface` token
|
|
320
|
+
let endingKeyword = this.advance();
|
|
321
|
+
if (endingKeyword.kind !== TokenKind_1.TokenKind.EndInterface) {
|
|
322
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('interface')), { range: endingKeyword.range }));
|
|
323
|
+
}
|
|
324
|
+
const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endingKeyword, this.currentNamespaceName);
|
|
325
|
+
this._references.interfaceStatements.push(statement);
|
|
326
|
+
this.exitAnnotationBlock(parentAnnotations);
|
|
327
|
+
return statement;
|
|
328
|
+
}
|
|
329
|
+
enumDeclaration() {
|
|
330
|
+
this.warnIfNotBrighterScriptMode('enum declarations');
|
|
331
|
+
const parentAnnotations = this.enterAnnotationBlock();
|
|
332
|
+
const tokens = {};
|
|
333
|
+
const body = [];
|
|
334
|
+
tokens.enum = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Enum), TokenKind_1.TokenKind.Enum);
|
|
335
|
+
tokens.name = this.tryIdentifier();
|
|
336
|
+
this.consumeStatementSeparators();
|
|
337
|
+
//gather up all members
|
|
338
|
+
while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
|
|
339
|
+
try {
|
|
340
|
+
let decl;
|
|
341
|
+
//collect leading annotations
|
|
342
|
+
if (this.check(TokenKind_1.TokenKind.At)) {
|
|
343
|
+
this.annotationExpression();
|
|
344
|
+
}
|
|
345
|
+
//members
|
|
346
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
347
|
+
decl = this.enumMemberStatement();
|
|
348
|
+
//comments
|
|
349
|
+
}
|
|
350
|
+
else if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
351
|
+
decl = this.commentStatement();
|
|
352
|
+
}
|
|
353
|
+
if (decl) {
|
|
354
|
+
this.consumePendingAnnotations(decl);
|
|
355
|
+
body.push(decl);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
//we didn't find a declaration...flag tokens until next line
|
|
359
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (e) {
|
|
363
|
+
//throw out any failed members and move on to the next line
|
|
364
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
365
|
+
}
|
|
366
|
+
//ensure statement separator
|
|
367
|
+
this.consumeStatementSeparators();
|
|
368
|
+
//break out of this loop if we encountered the `EndEnum` token
|
|
369
|
+
if (this.check(TokenKind_1.TokenKind.EndEnum)) {
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
//consume the final `end interface` token
|
|
374
|
+
tokens.endEnum = this.consumeToken(TokenKind_1.TokenKind.EndEnum);
|
|
375
|
+
const result = new Statement_1.EnumStatement(tokens, body, this.currentNamespaceName);
|
|
376
|
+
if (tokens.name) {
|
|
377
|
+
this.currentSymbolTable.addSymbol(tokens.name.text, tokens.name.range, result.getThisBscType());
|
|
378
|
+
}
|
|
379
|
+
this._references.enumStatements.push(result);
|
|
380
|
+
this.exitAnnotationBlock(parentAnnotations);
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
216
383
|
/**
|
|
217
384
|
* A BrighterScript class declaration
|
|
218
385
|
*/
|
|
219
386
|
classDeclaration() {
|
|
220
387
|
this.warnIfNotBrighterScriptMode('class declarations');
|
|
221
388
|
const parentAnnotations = this.enterAnnotationBlock();
|
|
222
|
-
let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.
|
|
389
|
+
let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Class), TokenKind_1.TokenKind.Class);
|
|
223
390
|
let extendsKeyword;
|
|
224
391
|
let parentClassName;
|
|
225
392
|
//get the class name
|
|
226
|
-
let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'),
|
|
393
|
+
let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
227
394
|
//see if the class inherits from parent
|
|
228
395
|
if (this.peek().text.toLowerCase() === 'extends') {
|
|
229
396
|
extendsKeyword = this.advance();
|
|
@@ -233,14 +400,14 @@ class Parser {
|
|
|
233
400
|
this.consumeStatementSeparators();
|
|
234
401
|
//gather up all class members (Fields, Methods)
|
|
235
402
|
let body = [];
|
|
236
|
-
while (this.checkAny(
|
|
403
|
+
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
404
|
try {
|
|
238
405
|
let decl;
|
|
239
406
|
let accessModifier;
|
|
240
|
-
if (this.check(
|
|
407
|
+
if (this.check(TokenKind_1.TokenKind.At)) {
|
|
241
408
|
this.annotationExpression();
|
|
242
409
|
}
|
|
243
|
-
if (this.checkAny(
|
|
410
|
+
if (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private)) {
|
|
244
411
|
//use actual access modifier
|
|
245
412
|
accessModifier = this.advance();
|
|
246
413
|
}
|
|
@@ -249,28 +416,28 @@ class Parser {
|
|
|
249
416
|
overrideKeyword = this.advance();
|
|
250
417
|
}
|
|
251
418
|
//methods (function/sub keyword OR identifier followed by opening paren)
|
|
252
|
-
if (this.checkAny(
|
|
253
|
-
const
|
|
254
|
-
//remove this function from the lists because it's not a callable
|
|
255
|
-
const functionStatement = this._references.functionStatements.pop();
|
|
419
|
+
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))) {
|
|
420
|
+
const functionStatement = this.functionStatement({ hasName: true, hasBody: true, hasEnd: true, onlyCallableAsMember: true });
|
|
256
421
|
//if we have an overrides keyword AND this method is called 'new', that's not allowed
|
|
257
|
-
if (overrideKeyword &&
|
|
422
|
+
if (overrideKeyword && functionStatement.name.text.toLowerCase() === 'new') {
|
|
258
423
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseOverrideKeywordOnConstructorFunction()), { range: overrideKeyword.range }));
|
|
259
424
|
}
|
|
260
|
-
decl = new Statement_1.
|
|
425
|
+
decl = new Statement_1.MethodStatement(accessModifier, functionStatement.name, functionStatement.func, overrideKeyword);
|
|
261
426
|
//refer to this statement as parent of the expression
|
|
262
427
|
functionStatement.func.functionStatement = decl;
|
|
428
|
+
//cache the range property so that plugins can't affect it
|
|
429
|
+
decl.cacheRange();
|
|
263
430
|
//fields
|
|
264
431
|
}
|
|
265
|
-
else if (this.checkAny(
|
|
266
|
-
decl = this.
|
|
432
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
433
|
+
decl = this.fieldDeclaration(accessModifier);
|
|
267
434
|
//class fields cannot be overridden
|
|
268
435
|
if (overrideKeyword) {
|
|
269
436
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.classFieldCannotBeOverridden()), { range: overrideKeyword.range }));
|
|
270
437
|
}
|
|
271
438
|
//comments
|
|
272
439
|
}
|
|
273
|
-
else if (this.check(
|
|
440
|
+
else if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
274
441
|
decl = this.commentStatement();
|
|
275
442
|
}
|
|
276
443
|
if (decl) {
|
|
@@ -280,58 +447,73 @@ class Parser {
|
|
|
280
447
|
}
|
|
281
448
|
catch (e) {
|
|
282
449
|
//throw out any failed members and move on to the next line
|
|
283
|
-
this.flagUntil(
|
|
450
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
284
451
|
}
|
|
285
452
|
//ensure statement separator
|
|
286
453
|
this.consumeStatementSeparators();
|
|
287
454
|
}
|
|
288
455
|
let endingKeyword = this.advance();
|
|
289
|
-
if (endingKeyword.kind !==
|
|
456
|
+
if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
|
|
290
457
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
|
|
291
458
|
}
|
|
292
|
-
const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName);
|
|
459
|
+
const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName, this.currentSymbolTable);
|
|
460
|
+
if (className) {
|
|
461
|
+
this.currentSymbolTable.addSymbol(className.text, className.range, result.getConstructorFunctionType());
|
|
462
|
+
}
|
|
293
463
|
this._references.classStatements.push(result);
|
|
294
464
|
this.exitAnnotationBlock(parentAnnotations);
|
|
295
465
|
return result;
|
|
296
466
|
}
|
|
297
|
-
|
|
298
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(),
|
|
467
|
+
fieldDeclaration(accessModifier) {
|
|
468
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
299
469
|
let asToken;
|
|
300
|
-
let
|
|
470
|
+
let fieldTypeExpr;
|
|
301
471
|
//look for `as SOME_TYPE`
|
|
302
|
-
if (this.check(
|
|
472
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
303
473
|
asToken = this.advance();
|
|
304
|
-
|
|
474
|
+
fieldTypeExpr = this.typeExpression();
|
|
305
475
|
//no field type specified
|
|
306
|
-
if (!
|
|
476
|
+
if (!fieldTypeExpr.isValidType(this.options.mode)) {
|
|
307
477
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedValidTypeToFollowAsKeyword()), { range: this.peek().range }));
|
|
308
478
|
}
|
|
309
479
|
}
|
|
310
480
|
let initialValue;
|
|
311
481
|
let equal;
|
|
312
482
|
//if there is a field initializer
|
|
313
|
-
if (this.check(
|
|
483
|
+
if (this.check(TokenKind_1.TokenKind.Equal)) {
|
|
314
484
|
equal = this.advance();
|
|
315
485
|
initialValue = this.expression();
|
|
316
486
|
}
|
|
317
|
-
return new Statement_1.
|
|
487
|
+
return new Statement_1.FieldStatement(accessModifier, name, asToken, fieldTypeExpr, equal, initialValue, this.currentNamespaceName);
|
|
488
|
+
}
|
|
489
|
+
functionStatement(options) {
|
|
490
|
+
options.hasName = true;
|
|
491
|
+
const funcResult = this.functionDeclaration(options);
|
|
492
|
+
if (funcResult) {
|
|
493
|
+
let result = new Statement_1.FunctionStatement(funcResult.name, funcResult.functionExpression, this.currentNamespaceName);
|
|
494
|
+
funcResult.functionExpression.functionStatement = result;
|
|
495
|
+
if (!options.onlyCallableAsMember) {
|
|
496
|
+
this._references.functionStatements.push(result);
|
|
497
|
+
}
|
|
498
|
+
return result;
|
|
499
|
+
}
|
|
318
500
|
}
|
|
319
|
-
functionDeclaration(
|
|
501
|
+
functionDeclaration(options = {}) {
|
|
320
502
|
var _a, _b, _c, _d;
|
|
321
503
|
let previousCallExpressions = this.callExpressions;
|
|
322
504
|
this.callExpressions = [];
|
|
323
505
|
try {
|
|
324
506
|
//track depth to help certain statements need to know if they are contained within a function body
|
|
325
507
|
this.namespaceAndFunctionDepth++;
|
|
326
|
-
let
|
|
327
|
-
if (this.checkAny(
|
|
328
|
-
|
|
508
|
+
let functionKeyword;
|
|
509
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
510
|
+
functionKeyword = this.advance();
|
|
329
511
|
}
|
|
330
512
|
else {
|
|
331
513
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
|
|
332
|
-
|
|
514
|
+
functionKeyword = {
|
|
333
515
|
isReserved: true,
|
|
334
|
-
kind:
|
|
516
|
+
kind: TokenKind_1.TokenKind.Function,
|
|
335
517
|
text: 'function',
|
|
336
518
|
//zero-length location means derived
|
|
337
519
|
range: {
|
|
@@ -341,44 +523,44 @@ class Parser {
|
|
|
341
523
|
leadingWhitespace: ''
|
|
342
524
|
};
|
|
343
525
|
}
|
|
344
|
-
let isSub = (
|
|
345
|
-
let
|
|
526
|
+
let isSub = (functionKeyword === null || functionKeyword === void 0 ? void 0 : functionKeyword.kind) === TokenKind_1.TokenKind.Sub;
|
|
527
|
+
let functionKeywordText = isSub ? 'sub' : 'function';
|
|
346
528
|
let name;
|
|
347
529
|
let leftParen;
|
|
348
|
-
if (
|
|
349
|
-
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(
|
|
530
|
+
if (!options.hasName) {
|
|
531
|
+
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
|
|
350
532
|
}
|
|
351
533
|
else {
|
|
352
|
-
name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(
|
|
353
|
-
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(
|
|
534
|
+
name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionKeywordText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
535
|
+
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionKeywordText), TokenKind_1.TokenKind.LeftParen);
|
|
354
536
|
//prevent functions from ending with type designators
|
|
355
537
|
let lastChar = name.text[name.text.length - 1];
|
|
356
538
|
if (['$', '%', '!', '#', '&'].includes(lastChar)) {
|
|
357
539
|
//don't throw this error; let the parser continue
|
|
358
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(
|
|
540
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionKeywordText, name.text, lastChar)), { range: name.range }));
|
|
359
541
|
}
|
|
360
|
-
//flag functions with keywords for names (only for standard functions)
|
|
361
|
-
if (
|
|
542
|
+
//flag functions with keywords for names (only for standard functions - not for class methods)
|
|
543
|
+
if (!options.onlyCallableAsMember && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
|
|
362
544
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
|
|
363
545
|
}
|
|
364
546
|
}
|
|
365
547
|
let params = [];
|
|
366
548
|
let asToken;
|
|
367
|
-
let
|
|
368
|
-
if (!this.check(
|
|
549
|
+
let typeExpr;
|
|
550
|
+
if (!this.check(TokenKind_1.TokenKind.RightParen)) {
|
|
369
551
|
do {
|
|
370
552
|
if (params.length >= Expression_1.CallExpression.MaximumArguments) {
|
|
371
553
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
|
|
372
554
|
}
|
|
373
555
|
params.push(this.functionParameter());
|
|
374
|
-
} while (this.match(
|
|
556
|
+
} while (this.match(TokenKind_1.TokenKind.Comma));
|
|
375
557
|
}
|
|
376
558
|
let rightParen = this.advance();
|
|
377
|
-
if (this.check(
|
|
559
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
378
560
|
asToken = this.advance();
|
|
379
|
-
|
|
380
|
-
if (!
|
|
381
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a =
|
|
561
|
+
typeExpr = this.typeExpression();
|
|
562
|
+
if (!typeExpr.isValidType(this.options.mode)) {
|
|
563
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.invalidFunctionReturnType((_a = typeExpr.getText()) !== null && _a !== void 0 ? _a : '')), { range: typeExpr.range }));
|
|
382
564
|
}
|
|
383
565
|
}
|
|
384
566
|
params.reduce((haveFoundOptional, param) => {
|
|
@@ -387,17 +569,20 @@ class Parser {
|
|
|
387
569
|
}
|
|
388
570
|
return haveFoundOptional || !!param.defaultValue;
|
|
389
571
|
}, false);
|
|
390
|
-
|
|
572
|
+
if (options.hasEnd && options.hasBody) {
|
|
573
|
+
// do not go to next statement - we don't care about any other statement
|
|
574
|
+
this.consumeStatementSeparators(true);
|
|
575
|
+
}
|
|
391
576
|
let func = new Expression_1.FunctionExpression(params, undefined, //body
|
|
392
|
-
|
|
393
|
-
leftParen, rightParen, asToken,
|
|
577
|
+
functionKeyword, undefined, //ending keyword
|
|
578
|
+
leftParen, rightParen, asToken, typeExpr, //return type
|
|
394
579
|
this.currentFunctionExpression, this.currentNamespaceName, (_c = (_b = this.currentNamespace) === null || _b === void 0 ? void 0 : _b.symbolTable) !== null && _c !== void 0 ? _c : this.symbolTable);
|
|
395
580
|
//if there is a parent function, register this function with the parent
|
|
396
581
|
if (this.currentFunctionExpression) {
|
|
397
582
|
this.currentFunctionExpression.childFunctionExpressions.push(func);
|
|
398
583
|
}
|
|
399
584
|
// add the function to the relevant symbol tables
|
|
400
|
-
if (!
|
|
585
|
+
if (!options.onlyCallableAsMember && name) {
|
|
401
586
|
const funcType = func.getFunctionType();
|
|
402
587
|
funcType.setName(name.text);
|
|
403
588
|
// add the function as declared to the current namespace's table
|
|
@@ -410,38 +595,35 @@ class Parser {
|
|
|
410
595
|
this.currentSymbolTable.addSymbol(fullyQualifiedName, name.range, funcType);
|
|
411
596
|
}
|
|
412
597
|
this._references.functionExpressions.push(func);
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
598
|
+
if (options.hasBody) {
|
|
599
|
+
let previousFunctionExpression = this.currentFunctionExpression;
|
|
600
|
+
this.currentFunctionExpression = func;
|
|
601
|
+
//make sure to restore the currentFunctionExpression even if the body block fails to parse
|
|
602
|
+
try {
|
|
603
|
+
//support ending the function with `end sub` OR `end function`
|
|
604
|
+
func.body = this.block();
|
|
605
|
+
}
|
|
606
|
+
finally {
|
|
607
|
+
this.currentFunctionExpression = previousFunctionExpression;
|
|
608
|
+
}
|
|
609
|
+
if (!func.body) {
|
|
610
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.callableBlockMissingEndKeyword(functionKeywordText)), { range: this.peek().range }));
|
|
611
|
+
throw this.lastDiagnosticAsError();
|
|
612
|
+
}
|
|
426
613
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
614
|
+
if (options.hasEnd) {
|
|
615
|
+
// consume 'end sub' or 'end function'
|
|
616
|
+
func.end = this.advance();
|
|
617
|
+
let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
|
|
618
|
+
//if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
|
|
619
|
+
//add an error but don't hard-fail so the AST can continue more gracefully
|
|
620
|
+
if (func.end.kind !== expectedEndKind) {
|
|
621
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword(functionKeywordText, func.end.text)), { range: this.peek().range }));
|
|
622
|
+
}
|
|
434
623
|
}
|
|
435
624
|
func.callExpressions = this.callExpressions;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
let result = new Statement_1.FunctionStatement(name, func, this.currentNamespaceName);
|
|
441
|
-
func.functionStatement = result;
|
|
442
|
-
this._references.functionStatements.push(result);
|
|
443
|
-
return result;
|
|
444
|
-
}
|
|
625
|
+
func.cacheRange();
|
|
626
|
+
return { name: name, functionExpression: func };
|
|
445
627
|
}
|
|
446
628
|
finally {
|
|
447
629
|
this.namespaceAndFunctionDepth--;
|
|
@@ -449,62 +631,62 @@ class Parser {
|
|
|
449
631
|
this.callExpressions = previousCallExpressions;
|
|
450
632
|
}
|
|
451
633
|
}
|
|
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
634
|
functionParameter() {
|
|
459
|
-
if (!this.checkAny(
|
|
635
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
|
|
460
636
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { range: this.peek().range }));
|
|
461
637
|
throw this.lastDiagnosticAsError();
|
|
462
638
|
}
|
|
463
|
-
const name = this.identifier();
|
|
464
|
-
let
|
|
639
|
+
const name = this.identifier(...TokenKind_1.AllowedLocalIdentifiers);
|
|
640
|
+
let typeExpr;
|
|
465
641
|
let defaultValue;
|
|
466
642
|
let equalsToken;
|
|
467
643
|
// parse argument default value
|
|
468
|
-
if (this.match(
|
|
644
|
+
if (this.match(TokenKind_1.TokenKind.Equal)) {
|
|
469
645
|
equalsToken = this.previous();
|
|
470
646
|
// it seems any expression is allowed here -- including ones that operate on other arguments!
|
|
471
647
|
defaultValue = this.expression();
|
|
472
648
|
}
|
|
473
649
|
let asToken = null;
|
|
474
|
-
if (this.check(
|
|
650
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
475
651
|
asToken = this.advance();
|
|
476
|
-
|
|
477
|
-
if (!
|
|
478
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text,
|
|
652
|
+
typeExpr = this.typeExpression();
|
|
653
|
+
if (!typeExpr.isValidType(this.options.mode)) {
|
|
654
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeExpr.getText())), { range: typeExpr.range }));
|
|
479
655
|
throw this.lastDiagnosticAsError();
|
|
480
656
|
}
|
|
481
657
|
}
|
|
482
|
-
let
|
|
483
|
-
if (
|
|
484
|
-
|
|
658
|
+
let typeInContext;
|
|
659
|
+
if (typeExpr) {
|
|
660
|
+
typeInContext = typeExpr.type;
|
|
485
661
|
}
|
|
486
662
|
else if (defaultValue) {
|
|
487
|
-
|
|
663
|
+
typeInContext = getBscTypeFromExpression(defaultValue, this.currentFunctionExpression);
|
|
664
|
+
if ((0, reflection_1.isInvalidType)(typeInContext)) {
|
|
665
|
+
typeInContext = new DynamicType_1.DynamicType();
|
|
666
|
+
}
|
|
488
667
|
}
|
|
489
668
|
else {
|
|
490
|
-
|
|
669
|
+
typeInContext = new DynamicType_1.DynamicType();
|
|
491
670
|
}
|
|
492
|
-
return new Expression_1.FunctionParameterExpression(name,
|
|
671
|
+
return new Expression_1.FunctionParameterExpression(name, typeInContext, equalsToken, defaultValue, asToken, typeExpr, this.currentNamespaceName);
|
|
493
672
|
}
|
|
494
673
|
assignment() {
|
|
495
|
-
let name = this.identifier();
|
|
674
|
+
let name = this.identifier(...this.allowedLocalIdentifiers);
|
|
496
675
|
//add diagnostic if name is a reserved word that cannot be used as an identifier
|
|
497
|
-
if (
|
|
676
|
+
if (TokenKind_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
|
|
498
677
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
|
|
499
678
|
}
|
|
500
|
-
let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(
|
|
679
|
+
let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(TokenKind_1.AssignmentOperators, name.text), ...TokenKind_1.AssignmentOperators);
|
|
501
680
|
let value = this.expression();
|
|
502
681
|
let result;
|
|
503
|
-
if (operator.kind ===
|
|
682
|
+
if (operator.kind === TokenKind_1.TokenKind.Equal) {
|
|
504
683
|
result = new Statement_1.AssignmentStatement(name, operator, value, this.currentFunctionExpression);
|
|
505
684
|
}
|
|
506
685
|
else {
|
|
507
686
|
result = new Statement_1.AssignmentStatement(name, operator, new Expression_1.BinaryExpression(new Expression_1.VariableExpression(name, this.currentNamespaceName), operator, value), this.currentFunctionExpression);
|
|
687
|
+
//remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
|
|
688
|
+
this._references.expressions.delete(value);
|
|
689
|
+
this._references.expressions.add(result);
|
|
508
690
|
}
|
|
509
691
|
this._references.assignmentStatements.push(result);
|
|
510
692
|
const assignmentType = getBscTypeFromExpression(result.value, this.currentFunctionExpression);
|
|
@@ -512,14 +694,14 @@ class Parser {
|
|
|
512
694
|
return result;
|
|
513
695
|
}
|
|
514
696
|
checkLibrary() {
|
|
515
|
-
let isLibraryToken = this.check(
|
|
697
|
+
let isLibraryToken = this.check(TokenKind_1.TokenKind.Library);
|
|
516
698
|
//if we are at the top level, any line that starts with "library" should be considered a library statement
|
|
517
699
|
if (this.isAtRootLevel() && isLibraryToken) {
|
|
518
700
|
return true;
|
|
519
701
|
//not at root level, library statements are all invalid here, but try to detect if the tokens look
|
|
520
702
|
//like a library statement (and let the libraryStatement function handle emitting the diagnostics)
|
|
521
703
|
}
|
|
522
|
-
else if (isLibraryToken && this.checkNext(
|
|
704
|
+
else if (isLibraryToken && this.checkNext(TokenKind_1.TokenKind.StringLiteral)) {
|
|
523
705
|
return true;
|
|
524
706
|
//definitely not a library statement
|
|
525
707
|
}
|
|
@@ -531,54 +713,54 @@ class Parser {
|
|
|
531
713
|
if (this.checkLibrary()) {
|
|
532
714
|
return this.libraryStatement();
|
|
533
715
|
}
|
|
534
|
-
if (this.check(
|
|
716
|
+
if (this.check(TokenKind_1.TokenKind.Import)) {
|
|
535
717
|
return this.importStatement();
|
|
536
718
|
}
|
|
537
|
-
if (this.check(
|
|
719
|
+
if (this.check(TokenKind_1.TokenKind.Stop)) {
|
|
538
720
|
return this.stopStatement();
|
|
539
721
|
}
|
|
540
|
-
if (this.check(
|
|
722
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
541
723
|
return this.ifStatement();
|
|
542
724
|
}
|
|
543
725
|
//`try` must be followed by a block, otherwise it could be a local variable
|
|
544
|
-
if (this.check(
|
|
726
|
+
if (this.check(TokenKind_1.TokenKind.Try) && this.checkAnyNext(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
|
|
545
727
|
return this.tryCatchStatement();
|
|
546
728
|
}
|
|
547
|
-
if (this.check(
|
|
729
|
+
if (this.check(TokenKind_1.TokenKind.Throw)) {
|
|
548
730
|
return this.throwStatement();
|
|
549
731
|
}
|
|
550
|
-
if (this.checkAny(
|
|
732
|
+
if (this.checkAny(TokenKind_1.TokenKind.Print, TokenKind_1.TokenKind.Question)) {
|
|
551
733
|
return this.printStatement();
|
|
552
734
|
}
|
|
553
|
-
if (this.check(
|
|
735
|
+
if (this.check(TokenKind_1.TokenKind.Dim)) {
|
|
554
736
|
return this.dimStatement();
|
|
555
737
|
}
|
|
556
|
-
if (this.check(
|
|
738
|
+
if (this.check(TokenKind_1.TokenKind.While)) {
|
|
557
739
|
return this.whileStatement();
|
|
558
740
|
}
|
|
559
|
-
if (this.check(
|
|
741
|
+
if (this.check(TokenKind_1.TokenKind.ExitWhile)) {
|
|
560
742
|
return this.exitWhile();
|
|
561
743
|
}
|
|
562
|
-
if (this.check(
|
|
744
|
+
if (this.check(TokenKind_1.TokenKind.For)) {
|
|
563
745
|
return this.forStatement();
|
|
564
746
|
}
|
|
565
|
-
if (this.check(
|
|
747
|
+
if (this.check(TokenKind_1.TokenKind.ForEach)) {
|
|
566
748
|
return this.forEachStatement();
|
|
567
749
|
}
|
|
568
|
-
if (this.check(
|
|
750
|
+
if (this.check(TokenKind_1.TokenKind.ExitFor)) {
|
|
569
751
|
return this.exitFor();
|
|
570
752
|
}
|
|
571
|
-
if (this.check(
|
|
753
|
+
if (this.check(TokenKind_1.TokenKind.End)) {
|
|
572
754
|
return this.endStatement();
|
|
573
755
|
}
|
|
574
|
-
if (this.match(
|
|
756
|
+
if (this.match(TokenKind_1.TokenKind.Return)) {
|
|
575
757
|
return this.returnStatement();
|
|
576
758
|
}
|
|
577
|
-
if (this.check(
|
|
759
|
+
if (this.check(TokenKind_1.TokenKind.Goto)) {
|
|
578
760
|
return this.gotoStatement();
|
|
579
761
|
}
|
|
580
762
|
//does this line look like a label? (i.e. `someIdentifier:` )
|
|
581
|
-
if (this.check(
|
|
763
|
+
if (this.check(TokenKind_1.TokenKind.Identifier) && this.checkNext(TokenKind_1.TokenKind.Colon) && this.checkPrevious(TokenKind_1.TokenKind.Newline)) {
|
|
582
764
|
try {
|
|
583
765
|
return this.labelStatement();
|
|
584
766
|
}
|
|
@@ -592,10 +774,23 @@ class Parser {
|
|
|
592
774
|
// BrightScript is like python, in that variables can be declared without a `var`,
|
|
593
775
|
// `let`, (...) keyword. As such, we must check the token *after* an identifier to figure
|
|
594
776
|
// out what to do with it.
|
|
595
|
-
if (this.checkAny(
|
|
596
|
-
this.checkAnyNext(...
|
|
777
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
|
|
778
|
+
this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
|
|
597
779
|
return this.assignment();
|
|
598
780
|
}
|
|
781
|
+
//some BrighterScript keywords are allowed as a local identifiers, so we need to check for them AFTER the assignment check
|
|
782
|
+
if (this.check(TokenKind_1.TokenKind.Interface)) {
|
|
783
|
+
return this.interfaceDeclaration();
|
|
784
|
+
}
|
|
785
|
+
if (this.check(TokenKind_1.TokenKind.Class)) {
|
|
786
|
+
return this.classDeclaration();
|
|
787
|
+
}
|
|
788
|
+
if (this.check(TokenKind_1.TokenKind.Namespace)) {
|
|
789
|
+
return this.namespaceStatement();
|
|
790
|
+
}
|
|
791
|
+
if (this.check(TokenKind_1.TokenKind.Enum)) {
|
|
792
|
+
return this.enumDeclaration();
|
|
793
|
+
}
|
|
599
794
|
// TODO: support multi-statements
|
|
600
795
|
return this.setStatement();
|
|
601
796
|
}
|
|
@@ -603,9 +798,9 @@ class Parser {
|
|
|
603
798
|
const whileKeyword = this.advance();
|
|
604
799
|
const condition = this.expression();
|
|
605
800
|
this.consumeStatementSeparators();
|
|
606
|
-
const whileBlock = this.block(
|
|
801
|
+
const whileBlock = this.block(TokenKind_1.TokenKind.EndWhile);
|
|
607
802
|
let endWhile;
|
|
608
|
-
if (!whileBlock || this.peek().kind !==
|
|
803
|
+
if (!whileBlock || this.peek().kind !== TokenKind_1.TokenKind.EndWhile) {
|
|
609
804
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('while')), { range: this.peek().range }));
|
|
610
805
|
if (!whileBlock) {
|
|
611
806
|
throw this.lastDiagnosticAsError();
|
|
@@ -628,7 +823,7 @@ class Parser {
|
|
|
628
823
|
const finalValue = this.expression();
|
|
629
824
|
let incrementExpression;
|
|
630
825
|
let stepToken;
|
|
631
|
-
if (this.check(
|
|
826
|
+
if (this.check(TokenKind_1.TokenKind.Step)) {
|
|
632
827
|
stepToken = this.advance();
|
|
633
828
|
incrementExpression = this.expression();
|
|
634
829
|
}
|
|
@@ -636,9 +831,9 @@ class Parser {
|
|
|
636
831
|
// BrightScript for/to/step loops default to a step of 1 if no `step` is provided
|
|
637
832
|
}
|
|
638
833
|
this.consumeStatementSeparators();
|
|
639
|
-
let body = this.block(
|
|
834
|
+
let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
|
|
640
835
|
let endForToken;
|
|
641
|
-
if (!body || !this.checkAny(
|
|
836
|
+
if (!body || !this.checkAny(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next)) {
|
|
642
837
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
|
|
643
838
|
if (!body) {
|
|
644
839
|
throw this.lastDiagnosticAsError();
|
|
@@ -653,9 +848,9 @@ class Parser {
|
|
|
653
848
|
}
|
|
654
849
|
forEachStatement() {
|
|
655
850
|
let forEach = this.advance();
|
|
656
|
-
let name = this.identifier();
|
|
851
|
+
let name = this.identifier(...this.allowedLocalIdentifiers);
|
|
657
852
|
let maybeIn = this.peek();
|
|
658
|
-
if (this.check(
|
|
853
|
+
if (this.check(TokenKind_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
|
|
659
854
|
this.advance();
|
|
660
855
|
}
|
|
661
856
|
else {
|
|
@@ -667,16 +862,19 @@ class Parser {
|
|
|
667
862
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedExpressionAfterForEachIn()), { range: this.peek().range }));
|
|
668
863
|
throw this.lastDiagnosticAsError();
|
|
669
864
|
}
|
|
865
|
+
let itemType = new DynamicType_1.DynamicType();
|
|
866
|
+
const targetType = getBscTypeFromExpression(target, this.currentFunctionExpression);
|
|
867
|
+
if ((0, reflection_1.isArrayType)(targetType)) {
|
|
868
|
+
itemType = targetType.getDefaultType();
|
|
869
|
+
}
|
|
870
|
+
this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
|
|
670
871
|
this.consumeStatementSeparators();
|
|
671
|
-
let body = this.block(
|
|
872
|
+
let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
|
|
672
873
|
if (!body) {
|
|
673
874
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
|
|
674
875
|
throw this.lastDiagnosticAsError();
|
|
675
876
|
}
|
|
676
877
|
let endFor = this.advance();
|
|
677
|
-
//TODO infer type from `target`
|
|
678
|
-
const itemType = new DynamicType_1.DynamicType();
|
|
679
|
-
this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
|
|
680
878
|
return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
|
|
681
879
|
}
|
|
682
880
|
exitFor() {
|
|
@@ -692,7 +890,7 @@ class Parser {
|
|
|
692
890
|
}
|
|
693
891
|
else {
|
|
694
892
|
let comments = [this.advance()];
|
|
695
|
-
while (this.check(
|
|
893
|
+
while (this.check(TokenKind_1.TokenKind.Newline) && this.checkNext(TokenKind_1.TokenKind.Comment)) {
|
|
696
894
|
this.advance();
|
|
697
895
|
comments.push(this.advance());
|
|
698
896
|
}
|
|
@@ -710,13 +908,13 @@ class Parser {
|
|
|
710
908
|
//set the current namespace name
|
|
711
909
|
let result = new Statement_1.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
|
|
712
910
|
this.currentNamespace = result;
|
|
713
|
-
this.globalTerminators.push([
|
|
911
|
+
this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
|
|
714
912
|
let body = this.body();
|
|
715
913
|
this.globalTerminators.pop();
|
|
716
914
|
//unset the current namespace name
|
|
717
915
|
this.currentNamespace = undefined;
|
|
718
916
|
let endKeyword;
|
|
719
|
-
if (this.check(
|
|
917
|
+
if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
|
|
720
918
|
endKeyword = this.advance();
|
|
721
919
|
}
|
|
722
920
|
else {
|
|
@@ -727,30 +925,33 @@ class Parser {
|
|
|
727
925
|
result.body = body;
|
|
728
926
|
result.endKeyword = endKeyword;
|
|
729
927
|
this._references.namespaceStatements.push(result);
|
|
928
|
+
//cache the range property so that plugins can't affect it
|
|
929
|
+
result.cacheRange();
|
|
730
930
|
return result;
|
|
731
931
|
}
|
|
732
932
|
/**
|
|
733
933
|
* Get an expression with identifiers separated by periods. Useful for namespaces and class extends
|
|
734
934
|
*/
|
|
735
935
|
getNamespacedVariableNameExpression() {
|
|
736
|
-
let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text),
|
|
936
|
+
let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
737
937
|
let expr;
|
|
738
938
|
if (firstIdentifier) {
|
|
739
939
|
// force it into an identifier so the AST makes some sense
|
|
740
|
-
firstIdentifier.kind =
|
|
741
|
-
|
|
940
|
+
firstIdentifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
941
|
+
const varExpr = new Expression_1.VariableExpression(firstIdentifier, null);
|
|
942
|
+
expr = varExpr;
|
|
742
943
|
//consume multiple dot identifiers (i.e. `Name.Space.Can.Have.Many.Parts`)
|
|
743
|
-
while (this.check(
|
|
744
|
-
let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.
|
|
944
|
+
while (this.check(TokenKind_1.TokenKind.Dot)) {
|
|
945
|
+
let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.Dot);
|
|
745
946
|
if (!dot) {
|
|
746
947
|
break;
|
|
747
948
|
}
|
|
748
|
-
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
949
|
+
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...TokenKind_1.AllowedProperties);
|
|
749
950
|
if (!identifier) {
|
|
750
951
|
break;
|
|
751
952
|
}
|
|
752
953
|
// force it into an identifier so the AST makes some sense
|
|
753
|
-
identifier.kind =
|
|
954
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
754
955
|
expr = new Expression_1.DottedGetExpression(expr, identifier, dot);
|
|
755
956
|
}
|
|
756
957
|
}
|
|
@@ -762,7 +963,7 @@ class Parser {
|
|
|
762
963
|
flagUntil(...stopTokens) {
|
|
763
964
|
while (!this.checkAny(...stopTokens) && !this.isAtEnd()) {
|
|
764
965
|
let token = this.advance();
|
|
765
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.
|
|
966
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(token.text)), { range: token.range }));
|
|
766
967
|
}
|
|
767
968
|
}
|
|
768
969
|
/**
|
|
@@ -782,7 +983,7 @@ class Parser {
|
|
|
782
983
|
let libStatement = new Statement_1.LibraryStatement({
|
|
783
984
|
library: this.advance(),
|
|
784
985
|
//grab the next token only if it's a string
|
|
785
|
-
filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'),
|
|
986
|
+
filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
|
|
786
987
|
});
|
|
787
988
|
this._references.libraryStatements.push(libStatement);
|
|
788
989
|
return libStatement;
|
|
@@ -791,23 +992,25 @@ class Parser {
|
|
|
791
992
|
this.warnIfNotBrighterScriptMode('import statements');
|
|
792
993
|
let importStatement = new Statement_1.ImportStatement(this.advance(),
|
|
793
994
|
//grab the next token only if it's a string
|
|
794
|
-
this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'),
|
|
995
|
+
this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
|
|
795
996
|
this._references.importStatements.push(importStatement);
|
|
796
997
|
return importStatement;
|
|
797
998
|
}
|
|
798
999
|
annotationExpression() {
|
|
799
1000
|
const atToken = this.advance();
|
|
800
|
-
const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
1001
|
+
const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
801
1002
|
if (identifier) {
|
|
802
|
-
identifier.kind =
|
|
1003
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
803
1004
|
}
|
|
804
1005
|
let annotation = new Expression_1.AnnotationExpression(atToken, identifier);
|
|
805
1006
|
this.pendingAnnotations.push(annotation);
|
|
806
1007
|
//optional arguments
|
|
807
|
-
if (this.check(
|
|
1008
|
+
if (this.check(TokenKind_1.TokenKind.LeftParen)) {
|
|
808
1009
|
let leftParen = this.advance();
|
|
809
1010
|
annotation.call = this.finishCall(leftParen, annotation, false);
|
|
810
1011
|
}
|
|
1012
|
+
//cache the range property so that plugins can't affect it
|
|
1013
|
+
annotation.cacheRange();
|
|
811
1014
|
return annotation;
|
|
812
1015
|
}
|
|
813
1016
|
ternaryExpression(test) {
|
|
@@ -817,7 +1020,7 @@ class Parser {
|
|
|
817
1020
|
}
|
|
818
1021
|
const questionMarkToken = this.advance();
|
|
819
1022
|
//consume newlines or comments
|
|
820
|
-
while (this.checkAny(
|
|
1023
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
821
1024
|
this.advance();
|
|
822
1025
|
}
|
|
823
1026
|
let consequent;
|
|
@@ -826,12 +1029,12 @@ class Parser {
|
|
|
826
1029
|
}
|
|
827
1030
|
catch (_a) { }
|
|
828
1031
|
//consume newlines or comments
|
|
829
|
-
while (this.checkAny(
|
|
1032
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
830
1033
|
this.advance();
|
|
831
1034
|
}
|
|
832
|
-
const colonToken = this.
|
|
1035
|
+
const colonToken = this.tryConsumeToken(TokenKind_1.TokenKind.Colon);
|
|
833
1036
|
//consume newlines
|
|
834
|
-
while (this.checkAny(
|
|
1037
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
835
1038
|
this.advance();
|
|
836
1039
|
}
|
|
837
1040
|
let alternate;
|
|
@@ -847,28 +1050,34 @@ class Parser {
|
|
|
847
1050
|
const alternate = this.expression();
|
|
848
1051
|
return new Expression_1.NullCoalescingExpression(test, questionQuestionToken, alternate);
|
|
849
1052
|
}
|
|
1053
|
+
regexLiteralExpression() {
|
|
1054
|
+
this.warnIfNotBrighterScriptMode('regular expression literal');
|
|
1055
|
+
return new Expression_1.RegexLiteralExpression({
|
|
1056
|
+
regexLiteral: this.advance()
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
850
1059
|
templateString(isTagged) {
|
|
851
1060
|
this.warnIfNotBrighterScriptMode('template string');
|
|
852
1061
|
//get the tag name
|
|
853
1062
|
let tagName;
|
|
854
1063
|
if (isTagged) {
|
|
855
|
-
tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
1064
|
+
tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
856
1065
|
// force it into an identifier so the AST makes some sense
|
|
857
|
-
tagName.kind =
|
|
1066
|
+
tagName.kind = TokenKind_1.TokenKind.Identifier;
|
|
858
1067
|
}
|
|
859
1068
|
let quasis = [];
|
|
860
1069
|
let expressions = [];
|
|
861
1070
|
let openingBacktick = this.peek();
|
|
862
1071
|
this.advance();
|
|
863
1072
|
let currentQuasiExpressionParts = [];
|
|
864
|
-
while (!this.isAtEnd() && !this.check(
|
|
1073
|
+
while (!this.isAtEnd() && !this.check(TokenKind_1.TokenKind.BackTick)) {
|
|
865
1074
|
let next = this.peek();
|
|
866
|
-
if (next.kind ===
|
|
1075
|
+
if (next.kind === TokenKind_1.TokenKind.TemplateStringQuasi) {
|
|
867
1076
|
//a quasi can actually be made up of multiple quasis when it includes char literals
|
|
868
1077
|
currentQuasiExpressionParts.push(new Expression_1.LiteralExpression(next));
|
|
869
1078
|
this.advance();
|
|
870
1079
|
}
|
|
871
|
-
else if (next.kind ===
|
|
1080
|
+
else if (next.kind === TokenKind_1.TokenKind.EscapedCharCodeLiteral) {
|
|
872
1081
|
currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression(next));
|
|
873
1082
|
this.advance();
|
|
874
1083
|
}
|
|
@@ -876,12 +1085,12 @@ class Parser {
|
|
|
876
1085
|
//finish up the current quasi
|
|
877
1086
|
quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
|
|
878
1087
|
currentQuasiExpressionParts = [];
|
|
879
|
-
if (next.kind ===
|
|
1088
|
+
if (next.kind === TokenKind_1.TokenKind.TemplateStringExpressionBegin) {
|
|
880
1089
|
this.advance();
|
|
881
1090
|
}
|
|
882
1091
|
//now keep this expression
|
|
883
1092
|
expressions.push(this.expression());
|
|
884
|
-
if (!this.isAtEnd() && this.check(
|
|
1093
|
+
if (!this.isAtEnd() && this.check(TokenKind_1.TokenKind.TemplateStringExpressionEnd)) {
|
|
885
1094
|
//TODO is it an error if this is not present?
|
|
886
1095
|
this.advance();
|
|
887
1096
|
}
|
|
@@ -910,43 +1119,42 @@ class Parser {
|
|
|
910
1119
|
}
|
|
911
1120
|
tryCatchStatement() {
|
|
912
1121
|
const tryToken = this.advance();
|
|
913
|
-
const statement = new Statement_1.TryCatchStatement(tryToken);
|
|
1122
|
+
const statement = new Statement_1.TryCatchStatement({ try: tryToken });
|
|
914
1123
|
//ensure statement separator
|
|
915
1124
|
this.consumeStatementSeparators();
|
|
916
|
-
statement.tryBranch = this.block(
|
|
1125
|
+
statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
|
|
917
1126
|
const peek = this.peek();
|
|
918
|
-
if (peek.kind !==
|
|
1127
|
+
if (peek.kind !== TokenKind_1.TokenKind.Catch) {
|
|
919
1128
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
|
|
920
1129
|
//gracefully handle end-try
|
|
921
|
-
if (peek.kind ===
|
|
922
|
-
statement.
|
|
1130
|
+
if (peek.kind === TokenKind_1.TokenKind.EndTry) {
|
|
1131
|
+
statement.tokens.endTry = this.advance();
|
|
923
1132
|
}
|
|
924
1133
|
return statement;
|
|
925
1134
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), lexer_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
1135
|
+
const catchStmt = new Statement_1.CatchStatement({ catch: this.advance() });
|
|
1136
|
+
statement.catchStatement = catchStmt;
|
|
1137
|
+
const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
930
1138
|
if (exceptionVarToken) {
|
|
931
1139
|
// force it into an identifier so the AST makes some sense
|
|
932
|
-
exceptionVarToken.kind =
|
|
933
|
-
|
|
1140
|
+
exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
|
|
1141
|
+
catchStmt.exceptionVariable = exceptionVarToken;
|
|
934
1142
|
}
|
|
935
1143
|
//ensure statement sepatator
|
|
936
1144
|
this.consumeStatementSeparators();
|
|
937
|
-
|
|
938
|
-
if (this.peek().kind !==
|
|
1145
|
+
catchStmt.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
|
|
1146
|
+
if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
|
|
939
1147
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
|
|
940
1148
|
}
|
|
941
1149
|
else {
|
|
942
|
-
statement.
|
|
1150
|
+
statement.tokens.endTry = this.advance();
|
|
943
1151
|
}
|
|
944
1152
|
return statement;
|
|
945
1153
|
}
|
|
946
1154
|
throwStatement() {
|
|
947
1155
|
const throwToken = this.advance();
|
|
948
1156
|
let expression;
|
|
949
|
-
if (this.checkAny(
|
|
1157
|
+
if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
950
1158
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword()), { range: throwToken.range }));
|
|
951
1159
|
}
|
|
952
1160
|
else {
|
|
@@ -956,19 +1164,19 @@ class Parser {
|
|
|
956
1164
|
}
|
|
957
1165
|
dimStatement() {
|
|
958
1166
|
const dim = this.advance();
|
|
959
|
-
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'),
|
|
1167
|
+
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
960
1168
|
// force to an identifier so the AST makes some sense
|
|
961
1169
|
if (identifier) {
|
|
962
|
-
identifier.kind =
|
|
1170
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
963
1171
|
}
|
|
964
|
-
let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(),
|
|
1172
|
+
let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.LeftSquareBracket);
|
|
965
1173
|
let expressions = [];
|
|
966
1174
|
let expression;
|
|
967
1175
|
do {
|
|
968
1176
|
try {
|
|
969
1177
|
expression = this.expression();
|
|
970
1178
|
expressions.push(expression);
|
|
971
|
-
if (this.check(
|
|
1179
|
+
if (this.check(TokenKind_1.TokenKind.Comma)) {
|
|
972
1180
|
this.advance();
|
|
973
1181
|
}
|
|
974
1182
|
else {
|
|
@@ -982,15 +1190,15 @@ class Parser {
|
|
|
982
1190
|
if (expressions.length === 0) {
|
|
983
1191
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
|
|
984
1192
|
}
|
|
985
|
-
let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(),
|
|
1193
|
+
let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
986
1194
|
return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
|
|
987
1195
|
}
|
|
988
1196
|
ifStatement() {
|
|
989
1197
|
// colon before `if` is usually not allowed, unless it's after `then`
|
|
990
1198
|
if (this.current > 0) {
|
|
991
1199
|
const prev = this.previous();
|
|
992
|
-
if (prev.kind ===
|
|
993
|
-
if (this.current > 1 && this.tokens[this.current - 2].kind !==
|
|
1200
|
+
if (prev.kind === TokenKind_1.TokenKind.Colon) {
|
|
1201
|
+
if (this.current > 1 && this.tokens[this.current - 2].kind !== TokenKind_1.TokenKind.Then) {
|
|
994
1202
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedColonBeforeIfStatement()), { range: prev.range }));
|
|
995
1203
|
}
|
|
996
1204
|
}
|
|
@@ -1004,14 +1212,14 @@ class Parser {
|
|
|
1004
1212
|
let endIfToken;
|
|
1005
1213
|
let elseToken;
|
|
1006
1214
|
//optional `then`
|
|
1007
|
-
if (this.check(
|
|
1215
|
+
if (this.check(TokenKind_1.TokenKind.Then)) {
|
|
1008
1216
|
thenToken = this.advance();
|
|
1009
1217
|
}
|
|
1010
1218
|
//is it inline or multi-line if?
|
|
1011
|
-
const isInlineIfThen = !this.checkAny(
|
|
1219
|
+
const isInlineIfThen = !this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment);
|
|
1012
1220
|
if (isInlineIfThen) {
|
|
1013
1221
|
/*** PARSE INLINE IF STATEMENT ***/
|
|
1014
|
-
thenBranch = this.inlineConditionalBranch(
|
|
1222
|
+
thenBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
|
|
1015
1223
|
if (!thenBranch) {
|
|
1016
1224
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowConditionalCondition(ifToken.text)), { range: this.peek().range }));
|
|
1017
1225
|
throw this.lastDiagnosticAsError();
|
|
@@ -1020,9 +1228,9 @@ class Parser {
|
|
|
1020
1228
|
this.ensureInline(thenBranch.statements);
|
|
1021
1229
|
}
|
|
1022
1230
|
//else branch
|
|
1023
|
-
if (this.check(
|
|
1231
|
+
if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1024
1232
|
elseToken = this.advance();
|
|
1025
|
-
if (this.check(
|
|
1233
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
1026
1234
|
// recurse-read `else if`
|
|
1027
1235
|
elseBranch = this.ifStatement();
|
|
1028
1236
|
//no multi-line if chained with an inline if
|
|
@@ -1030,13 +1238,13 @@ class Parser {
|
|
|
1030
1238
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: elseBranch.range }));
|
|
1031
1239
|
}
|
|
1032
1240
|
}
|
|
1033
|
-
else if (this.checkAny(
|
|
1241
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
1034
1242
|
//expecting inline else branch
|
|
1035
1243
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: this.peek().range }));
|
|
1036
1244
|
throw this.lastDiagnosticAsError();
|
|
1037
1245
|
}
|
|
1038
1246
|
else {
|
|
1039
|
-
elseBranch = this.inlineConditionalBranch(
|
|
1247
|
+
elseBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
|
|
1040
1248
|
if (elseBranch) {
|
|
1041
1249
|
this.ensureInline(elseBranch.statements);
|
|
1042
1250
|
}
|
|
@@ -1047,12 +1255,12 @@ class Parser {
|
|
|
1047
1255
|
throw this.lastDiagnosticAsError();
|
|
1048
1256
|
}
|
|
1049
1257
|
}
|
|
1050
|
-
if (!elseBranch || !reflection_1.isIfStatement(elseBranch)) {
|
|
1258
|
+
if (!elseBranch || !(0, reflection_1.isIfStatement)(elseBranch)) {
|
|
1051
1259
|
//enforce newline at the end of the inline if statement
|
|
1052
1260
|
const peek = this.peek();
|
|
1053
|
-
if (peek.kind !==
|
|
1261
|
+
if (peek.kind !== TokenKind_1.TokenKind.Newline && peek.kind !== TokenKind_1.TokenKind.Comment && !this.isAtEnd()) {
|
|
1054
1262
|
//ignore last error if it was about a colon
|
|
1055
|
-
if (this.previous().kind ===
|
|
1263
|
+
if (this.previous().kind === TokenKind_1.TokenKind.Colon) {
|
|
1056
1264
|
this.diagnostics.pop();
|
|
1057
1265
|
this.current--;
|
|
1058
1266
|
}
|
|
@@ -1067,9 +1275,9 @@ class Parser {
|
|
|
1067
1275
|
//ensure newline/colon before next keyword
|
|
1068
1276
|
this.ensureNewLineOrColon();
|
|
1069
1277
|
//else branch
|
|
1070
|
-
if (this.check(
|
|
1278
|
+
if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1071
1279
|
elseToken = this.advance();
|
|
1072
|
-
if (this.check(
|
|
1280
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
1073
1281
|
// recurse-read `else if`
|
|
1074
1282
|
elseBranch = this.ifStatement();
|
|
1075
1283
|
}
|
|
@@ -1079,8 +1287,8 @@ class Parser {
|
|
|
1079
1287
|
this.ensureNewLineOrColon();
|
|
1080
1288
|
}
|
|
1081
1289
|
}
|
|
1082
|
-
if (!reflection_1.isIfStatement(elseBranch)) {
|
|
1083
|
-
if (this.check(
|
|
1290
|
+
if (!(0, reflection_1.isIfStatement)(elseBranch)) {
|
|
1291
|
+
if (this.check(TokenKind_1.TokenKind.EndIf)) {
|
|
1084
1292
|
endIfToken = this.advance();
|
|
1085
1293
|
}
|
|
1086
1294
|
else {
|
|
@@ -1103,7 +1311,7 @@ class Parser {
|
|
|
1103
1311
|
let diagnosticsLengthBeforeBlock = this.diagnostics.length;
|
|
1104
1312
|
// we're parsing a multi-line ("block") form of the BrightScript if/then and must find
|
|
1105
1313
|
// a trailing "end if" or "else if"
|
|
1106
|
-
let branch = this.block(
|
|
1314
|
+
let branch = this.block(TokenKind_1.TokenKind.EndIf, TokenKind_1.TokenKind.Else);
|
|
1107
1315
|
if (!branch) {
|
|
1108
1316
|
//throw out any new diagnostics created as a result of a `then` block parse failure.
|
|
1109
1317
|
//the block() function will discard the current line, so any discarded diagnostics will
|
|
@@ -1117,7 +1325,7 @@ class Parser {
|
|
|
1117
1325
|
}
|
|
1118
1326
|
ensureNewLineOrColon(silent = false) {
|
|
1119
1327
|
const prev = this.previous().kind;
|
|
1120
|
-
if (prev !==
|
|
1328
|
+
if (prev !== TokenKind_1.TokenKind.Newline && prev !== TokenKind_1.TokenKind.Colon) {
|
|
1121
1329
|
if (!silent) {
|
|
1122
1330
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { range: this.peek().range }));
|
|
1123
1331
|
}
|
|
@@ -1128,7 +1336,7 @@ class Parser {
|
|
|
1128
1336
|
//ensure each statement of an inline block is single-line
|
|
1129
1337
|
ensureInline(statements) {
|
|
1130
1338
|
for (const stat of statements) {
|
|
1131
|
-
if (reflection_1.isIfStatement(stat) && !stat.isInline) {
|
|
1339
|
+
if ((0, reflection_1.isIfStatement)(stat) && !stat.isInline) {
|
|
1132
1340
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: stat.range }));
|
|
1133
1341
|
}
|
|
1134
1342
|
}
|
|
@@ -1143,14 +1351,15 @@ class Parser {
|
|
|
1143
1351
|
return undefined;
|
|
1144
1352
|
}
|
|
1145
1353
|
statements.push(statement);
|
|
1354
|
+
const startingRange = statement.range;
|
|
1146
1355
|
//look for colon statement separator
|
|
1147
1356
|
let foundColon = false;
|
|
1148
|
-
while (this.match(
|
|
1357
|
+
while (this.match(TokenKind_1.TokenKind.Colon)) {
|
|
1149
1358
|
foundColon = true;
|
|
1150
1359
|
}
|
|
1151
1360
|
//if a colon was found, add the next statement or err if unexpected
|
|
1152
1361
|
if (foundColon) {
|
|
1153
|
-
if (!this.checkAny(
|
|
1362
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Newline, ...additionalTerminators)) {
|
|
1154
1363
|
//if not an ending keyword, add next statement
|
|
1155
1364
|
let extra = this.inlineConditionalBranch(...additionalTerminators);
|
|
1156
1365
|
if (!extra) {
|
|
@@ -1161,26 +1370,28 @@ class Parser {
|
|
|
1161
1370
|
else {
|
|
1162
1371
|
//error: colon before next keyword
|
|
1163
1372
|
const colon = this.previous();
|
|
1164
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.
|
|
1373
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(colon.text)), { range: colon.range }));
|
|
1165
1374
|
}
|
|
1166
1375
|
}
|
|
1167
|
-
return new Statement_1.Block(statements,
|
|
1376
|
+
return new Statement_1.Block(statements, startingRange);
|
|
1168
1377
|
}
|
|
1169
1378
|
expressionStatement(expr) {
|
|
1170
1379
|
let expressionStart = this.peek();
|
|
1171
|
-
if (this.checkAny(
|
|
1380
|
+
if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
|
|
1172
1381
|
let operator = this.advance();
|
|
1173
|
-
if (this.checkAny(
|
|
1382
|
+
if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
|
|
1174
1383
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.consecutiveIncrementDecrementOperatorsAreNotAllowed()), { range: this.peek().range }));
|
|
1175
1384
|
throw this.lastDiagnosticAsError();
|
|
1176
1385
|
}
|
|
1177
|
-
else if (reflection_1.isCallExpression(expr)) {
|
|
1386
|
+
else if ((0, reflection_1.isCallExpression)(expr)) {
|
|
1178
1387
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
|
|
1179
1388
|
throw this.lastDiagnosticAsError();
|
|
1180
1389
|
}
|
|
1181
|
-
|
|
1390
|
+
const result = new Statement_1.IncrementStatement(expr, operator);
|
|
1391
|
+
this._references.expressions.add(result);
|
|
1392
|
+
return result;
|
|
1182
1393
|
}
|
|
1183
|
-
if (reflection_1.isCallExpression(expr) || reflection_1.isCallfuncExpression(expr)) {
|
|
1394
|
+
if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
|
|
1184
1395
|
return new Statement_1.ExpressionStatement(expr);
|
|
1185
1396
|
}
|
|
1186
1397
|
//at this point, it's probably an error. However, we recover a little more gracefully by creating an assignment
|
|
@@ -1195,20 +1406,20 @@ class Parser {
|
|
|
1195
1406
|
* priority as standalone function calls though, so we can parse them in the same way.
|
|
1196
1407
|
*/
|
|
1197
1408
|
let expr = this.call();
|
|
1198
|
-
if (this.checkAny(...
|
|
1409
|
+
if (this.checkAny(...TokenKind_1.AssignmentOperators) && !((0, reflection_1.isCallExpression)(expr))) {
|
|
1199
1410
|
let left = expr;
|
|
1200
1411
|
let operator = this.advance();
|
|
1201
1412
|
let right = this.expression();
|
|
1202
1413
|
// Create a dotted or indexed "set" based on the left-hand side's type
|
|
1203
|
-
if (reflection_1.isIndexedGetExpression(left)) {
|
|
1204
|
-
return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind ===
|
|
1414
|
+
if ((0, reflection_1.isIndexedGetExpression)(left)) {
|
|
1415
|
+
return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
|
|
1205
1416
|
? right
|
|
1206
|
-
: new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
|
|
1417
|
+
: new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare, operator);
|
|
1207
1418
|
}
|
|
1208
|
-
else if (reflection_1.isDottedGetExpression(left)) {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1419
|
+
else if ((0, reflection_1.isDottedGetExpression)(left)) {
|
|
1420
|
+
const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal ? right : new Expression_1.BinaryExpression(left, operator, right), left.dot, operator);
|
|
1421
|
+
this._references.dottedSetStatements.push(dottedSetStmt);
|
|
1422
|
+
return dottedSetStmt;
|
|
1212
1423
|
}
|
|
1213
1424
|
}
|
|
1214
1425
|
return this.expressionStatement(expr);
|
|
@@ -1217,13 +1428,13 @@ class Parser {
|
|
|
1217
1428
|
let printKeyword = this.advance();
|
|
1218
1429
|
let values = [];
|
|
1219
1430
|
while (!this.checkEndOfStatement()) {
|
|
1220
|
-
if (this.check(
|
|
1431
|
+
if (this.check(TokenKind_1.TokenKind.Semicolon)) {
|
|
1221
1432
|
values.push(this.advance());
|
|
1222
1433
|
}
|
|
1223
|
-
else if (this.check(
|
|
1434
|
+
else if (this.check(TokenKind_1.TokenKind.Comma)) {
|
|
1224
1435
|
values.push(this.advance());
|
|
1225
1436
|
}
|
|
1226
|
-
else if (this.check(
|
|
1437
|
+
else if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1227
1438
|
break; // inline branch
|
|
1228
1439
|
}
|
|
1229
1440
|
else {
|
|
@@ -1232,11 +1443,11 @@ class Parser {
|
|
|
1232
1443
|
}
|
|
1233
1444
|
//print statements can be empty, so look for empty print conditions
|
|
1234
1445
|
if (!values.length) {
|
|
1235
|
-
let emptyStringLiteral = creators_1.createStringLiteral('');
|
|
1446
|
+
let emptyStringLiteral = (0, creators_1.createStringLiteral)('');
|
|
1236
1447
|
values.push(emptyStringLiteral);
|
|
1237
1448
|
}
|
|
1238
1449
|
let last = values[values.length - 1];
|
|
1239
|
-
if (
|
|
1450
|
+
if ((0, Token_1.isToken)(last)) {
|
|
1240
1451
|
// TODO: error, expected value
|
|
1241
1452
|
}
|
|
1242
1453
|
return new Statement_1.PrintStatement({ print: printKeyword }, values);
|
|
@@ -1250,7 +1461,7 @@ class Parser {
|
|
|
1250
1461
|
if (this.checkEndOfStatement()) {
|
|
1251
1462
|
return new Statement_1.ReturnStatement(tokens);
|
|
1252
1463
|
}
|
|
1253
|
-
let toReturn = this.check(
|
|
1464
|
+
let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
|
|
1254
1465
|
return new Statement_1.ReturnStatement(tokens, toReturn);
|
|
1255
1466
|
}
|
|
1256
1467
|
/**
|
|
@@ -1263,7 +1474,7 @@ class Parser {
|
|
|
1263
1474
|
colon: this.advance()
|
|
1264
1475
|
};
|
|
1265
1476
|
//label must be alone on its line, this is probably not a label
|
|
1266
|
-
if (!this.checkAny(
|
|
1477
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
1267
1478
|
//rewind and cancel
|
|
1268
1479
|
this.current -= 2;
|
|
1269
1480
|
throw new CancelStatementError();
|
|
@@ -1279,7 +1490,7 @@ class Parser {
|
|
|
1279
1490
|
gotoStatement() {
|
|
1280
1491
|
let tokens = {
|
|
1281
1492
|
goto: this.advance(),
|
|
1282
|
-
label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(),
|
|
1493
|
+
label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
|
|
1283
1494
|
};
|
|
1284
1495
|
return new Statement_1.GotoStatement(tokens);
|
|
1285
1496
|
}
|
|
@@ -1310,12 +1521,12 @@ class Parser {
|
|
|
1310
1521
|
this.consumeStatementSeparators(true);
|
|
1311
1522
|
let startingToken = this.peek();
|
|
1312
1523
|
const statements = [];
|
|
1313
|
-
while (!this.isAtEnd() && !this.checkAny(
|
|
1524
|
+
while (!this.isAtEnd() && !this.checkAny(TokenKind_1.TokenKind.EndSub, TokenKind_1.TokenKind.EndFunction, ...terminators)) {
|
|
1314
1525
|
//grab the location of the current token
|
|
1315
1526
|
let loopCurrent = this.current;
|
|
1316
1527
|
let dec = this.declaration();
|
|
1317
1528
|
if (dec) {
|
|
1318
|
-
if (!reflection_1.isAnnotationExpression(dec)) {
|
|
1529
|
+
if (!(0, reflection_1.isAnnotationExpression)(dec)) {
|
|
1319
1530
|
this.consumePendingAnnotations(dec);
|
|
1320
1531
|
statements.push(dec);
|
|
1321
1532
|
}
|
|
@@ -1326,7 +1537,7 @@ class Parser {
|
|
|
1326
1537
|
//something went wrong. reset to the top of the loop
|
|
1327
1538
|
this.current = loopCurrent;
|
|
1328
1539
|
//scrap the entire line (hopefully whatever failed has added a diagnostic)
|
|
1329
|
-
this.consumeUntil(
|
|
1540
|
+
this.consumeUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
1330
1541
|
//trash the next token. this prevents an infinite loop. not exactly sure why we need this,
|
|
1331
1542
|
//but there's already an error in the file being parsed, so just leave this line here
|
|
1332
1543
|
this.advance();
|
|
@@ -1343,8 +1554,8 @@ class Parser {
|
|
|
1343
1554
|
//if so, we need to restore the statement separator
|
|
1344
1555
|
let prev = this.previous().kind;
|
|
1345
1556
|
let peek = this.peek().kind;
|
|
1346
|
-
if ((peek ===
|
|
1347
|
-
(prev ===
|
|
1557
|
+
if ((peek === TokenKind_1.TokenKind.EndSub || peek === TokenKind_1.TokenKind.EndFunction) &&
|
|
1558
|
+
(prev === TokenKind_1.TokenKind.Newline || prev === TokenKind_1.TokenKind.Colon)) {
|
|
1348
1559
|
this.current--;
|
|
1349
1560
|
}
|
|
1350
1561
|
}
|
|
@@ -1376,13 +1587,15 @@ class Parser {
|
|
|
1376
1587
|
this.pendingAnnotations = parentAnnotations;
|
|
1377
1588
|
}
|
|
1378
1589
|
expression() {
|
|
1379
|
-
|
|
1590
|
+
const expression = this.anonymousFunction();
|
|
1591
|
+
this._references.expressions.add(expression);
|
|
1592
|
+
return expression;
|
|
1380
1593
|
}
|
|
1381
1594
|
anonymousFunction() {
|
|
1382
|
-
if (this.checkAny(
|
|
1383
|
-
const func = this.functionDeclaration(true);
|
|
1595
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
1596
|
+
const func = this.functionDeclaration({ hasName: false, hasBody: true, hasEnd: true }).functionExpression;
|
|
1384
1597
|
//if there's an open paren after this, this is an IIFE
|
|
1385
|
-
if (this.check(
|
|
1598
|
+
if (this.check(TokenKind_1.TokenKind.LeftParen)) {
|
|
1386
1599
|
return this.finishCall(this.advance(), func);
|
|
1387
1600
|
}
|
|
1388
1601
|
else {
|
|
@@ -1390,10 +1603,10 @@ class Parser {
|
|
|
1390
1603
|
}
|
|
1391
1604
|
}
|
|
1392
1605
|
let expr = this.boolean();
|
|
1393
|
-
if (this.check(
|
|
1606
|
+
if (this.check(TokenKind_1.TokenKind.Question)) {
|
|
1394
1607
|
return this.ternaryExpression(expr);
|
|
1395
1608
|
}
|
|
1396
|
-
else if (this.check(
|
|
1609
|
+
else if (this.check(TokenKind_1.TokenKind.QuestionQuestion)) {
|
|
1397
1610
|
return this.nullCoalescingExpression(expr);
|
|
1398
1611
|
}
|
|
1399
1612
|
else {
|
|
@@ -1402,7 +1615,7 @@ class Parser {
|
|
|
1402
1615
|
}
|
|
1403
1616
|
boolean() {
|
|
1404
1617
|
let expr = this.relational();
|
|
1405
|
-
while (this.matchAny(
|
|
1618
|
+
while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
|
|
1406
1619
|
let operator = this.previous();
|
|
1407
1620
|
let right = this.relational();
|
|
1408
1621
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1411,7 +1624,7 @@ class Parser {
|
|
|
1411
1624
|
}
|
|
1412
1625
|
relational() {
|
|
1413
1626
|
let expr = this.additive();
|
|
1414
|
-
while (this.matchAny(
|
|
1627
|
+
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
1628
|
let operator = this.previous();
|
|
1416
1629
|
let right = this.additive();
|
|
1417
1630
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1421,7 +1634,7 @@ class Parser {
|
|
|
1421
1634
|
// TODO: bitshift
|
|
1422
1635
|
additive() {
|
|
1423
1636
|
let expr = this.multiplicative();
|
|
1424
|
-
while (this.matchAny(
|
|
1637
|
+
while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
|
|
1425
1638
|
let operator = this.previous();
|
|
1426
1639
|
let right = this.multiplicative();
|
|
1427
1640
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1430,7 +1643,7 @@ class Parser {
|
|
|
1430
1643
|
}
|
|
1431
1644
|
multiplicative() {
|
|
1432
1645
|
let expr = this.exponential();
|
|
1433
|
-
while (this.matchAny(
|
|
1646
|
+
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
1647
|
let operator = this.previous();
|
|
1435
1648
|
let right = this.exponential();
|
|
1436
1649
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1439,7 +1652,7 @@ class Parser {
|
|
|
1439
1652
|
}
|
|
1440
1653
|
exponential() {
|
|
1441
1654
|
let expr = this.prefixUnary();
|
|
1442
|
-
while (this.match(
|
|
1655
|
+
while (this.match(TokenKind_1.TokenKind.Caret)) {
|
|
1443
1656
|
let operator = this.previous();
|
|
1444
1657
|
let right = this.prefixUnary();
|
|
1445
1658
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1448,7 +1661,7 @@ class Parser {
|
|
|
1448
1661
|
}
|
|
1449
1662
|
prefixUnary() {
|
|
1450
1663
|
const nextKind = this.peek().kind;
|
|
1451
|
-
if (nextKind ===
|
|
1664
|
+
if (nextKind === TokenKind_1.TokenKind.Not || nextKind === TokenKind_1.TokenKind.Minus) {
|
|
1452
1665
|
this.current++; //advance
|
|
1453
1666
|
let operator = this.previous();
|
|
1454
1667
|
let right = this.prefixUnary();
|
|
@@ -1458,17 +1671,18 @@ class Parser {
|
|
|
1458
1671
|
}
|
|
1459
1672
|
indexedGet(expr) {
|
|
1460
1673
|
let openingSquare = this.previous();
|
|
1461
|
-
|
|
1674
|
+
let questionDotToken = this.getMatchingTokenAtOffset(-2, TokenKind_1.TokenKind.QuestionDot);
|
|
1675
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1462
1676
|
let index = this.expression();
|
|
1463
|
-
while (this.match(
|
|
1464
|
-
let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(),
|
|
1465
|
-
return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare);
|
|
1677
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1678
|
+
let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
1679
|
+
return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare, questionDotToken);
|
|
1466
1680
|
}
|
|
1467
1681
|
newExpression() {
|
|
1468
1682
|
this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
|
|
1469
1683
|
let newToken = this.advance();
|
|
1470
1684
|
let nameExpr = this.getNamespacedVariableNameExpression();
|
|
1471
|
-
let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.
|
|
1685
|
+
let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen);
|
|
1472
1686
|
let call = this.finishCall(leftParen, nameExpr);
|
|
1473
1687
|
//pop the call from the callExpressions list because this is technically something else
|
|
1474
1688
|
this.callExpressions.pop();
|
|
@@ -1482,46 +1696,52 @@ class Parser {
|
|
|
1482
1696
|
callfunc(callee) {
|
|
1483
1697
|
this.warnIfNotBrighterScriptMode('callfunc operator');
|
|
1484
1698
|
let operator = this.previous();
|
|
1485
|
-
let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
1699
|
+
let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1486
1700
|
// force it into an identifier so the AST makes some sense
|
|
1487
|
-
methodName.kind =
|
|
1488
|
-
let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(),
|
|
1701
|
+
methodName.kind = TokenKind_1.TokenKind.Identifier;
|
|
1702
|
+
let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), TokenKind_1.TokenKind.LeftParen);
|
|
1489
1703
|
let call = this.finishCall(openParen, callee, false);
|
|
1490
1704
|
return new Expression_1.CallfuncExpression(callee, operator, methodName, openParen, call.args, call.closingParen);
|
|
1491
1705
|
}
|
|
1492
1706
|
call() {
|
|
1493
|
-
if (this.check(
|
|
1707
|
+
if (this.check(TokenKind_1.TokenKind.New) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
|
|
1494
1708
|
return this.newExpression();
|
|
1495
1709
|
}
|
|
1496
1710
|
let expr = this.primary();
|
|
1711
|
+
//an expression to keep for _references
|
|
1712
|
+
let referenceCallExpression;
|
|
1497
1713
|
while (true) {
|
|
1498
|
-
if (this.
|
|
1714
|
+
if (this.matchAny(TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.QuestionLeftParen)) {
|
|
1499
1715
|
expr = this.finishCall(this.previous(), expr);
|
|
1716
|
+
//store this call expression in references
|
|
1717
|
+
referenceCallExpression = expr;
|
|
1500
1718
|
}
|
|
1501
|
-
else if (this.
|
|
1719
|
+
else if (this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.QuestionLeftSquare) || this.matchSequence(TokenKind_1.TokenKind.QuestionDot, TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1502
1720
|
expr = this.indexedGet(expr);
|
|
1503
1721
|
}
|
|
1504
|
-
else if (this.match(
|
|
1722
|
+
else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
|
|
1505
1723
|
expr = this.callfunc(expr);
|
|
1724
|
+
//store this callfunc expression in references
|
|
1725
|
+
referenceCallExpression = expr;
|
|
1506
1726
|
}
|
|
1507
|
-
else if (this.
|
|
1508
|
-
if (this.match(
|
|
1727
|
+
else if (this.matchAny(TokenKind_1.TokenKind.Dot, TokenKind_1.TokenKind.QuestionDot)) {
|
|
1728
|
+
if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1509
1729
|
expr = this.indexedGet(expr);
|
|
1510
1730
|
}
|
|
1511
1731
|
else {
|
|
1512
1732
|
let dot = this.previous();
|
|
1513
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(),
|
|
1733
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1514
1734
|
// force it into an identifier so the AST makes some sense
|
|
1515
|
-
name.kind =
|
|
1735
|
+
name.kind = TokenKind_1.TokenKind.Identifier;
|
|
1516
1736
|
expr = new Expression_1.DottedGetExpression(expr, name, dot);
|
|
1517
1737
|
this.addPropertyHints(name);
|
|
1518
1738
|
}
|
|
1519
1739
|
}
|
|
1520
|
-
else if (this.
|
|
1740
|
+
else if (this.checkAny(TokenKind_1.TokenKind.At, TokenKind_1.TokenKind.QuestionAt)) {
|
|
1521
1741
|
let dot = this.advance();
|
|
1522
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(),
|
|
1742
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1523
1743
|
// force it into an identifier so the AST makes some sense
|
|
1524
|
-
name.kind =
|
|
1744
|
+
name.kind = TokenKind_1.TokenKind.Identifier;
|
|
1525
1745
|
expr = new Expression_1.XmlAttributeGetExpression(expr, name, dot);
|
|
1526
1746
|
//only allow a single `@` expression
|
|
1527
1747
|
break;
|
|
@@ -1530,27 +1750,27 @@ class Parser {
|
|
|
1530
1750
|
break;
|
|
1531
1751
|
}
|
|
1532
1752
|
}
|
|
1753
|
+
//if we found a callExpression, add it to `expressions` in references
|
|
1754
|
+
if (referenceCallExpression) {
|
|
1755
|
+
this._references.expressions.add(referenceCallExpression);
|
|
1756
|
+
}
|
|
1533
1757
|
return expr;
|
|
1534
1758
|
}
|
|
1535
1759
|
finishCall(openingParen, callee, addToCallExpressionList = true) {
|
|
1536
1760
|
let args = [];
|
|
1537
|
-
while (this.match(
|
|
1538
|
-
|
|
1539
|
-
if (!this.check(lexer_1.TokenKind.RightParen)) {
|
|
1761
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1762
|
+
if (!this.check(TokenKind_1.TokenKind.RightParen)) {
|
|
1540
1763
|
do {
|
|
1541
|
-
while (this.match(
|
|
1764
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1542
1765
|
if (args.length >= Expression_1.CallExpression.MaximumArguments) {
|
|
1543
1766
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
|
|
1544
1767
|
throw this.lastDiagnosticAsError();
|
|
1545
1768
|
}
|
|
1546
1769
|
args.push(this.expression());
|
|
1547
|
-
} while (this.match(
|
|
1548
|
-
}
|
|
1549
|
-
while (this.match(lexer_1.TokenKind.Newline)) { }
|
|
1550
|
-
const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), lexer_1.TokenKind.RightParen);
|
|
1551
|
-
if (reflection_1.isVariableExpression(callee)) {
|
|
1552
|
-
callee.isCalled = true;
|
|
1770
|
+
} while (this.match(TokenKind_1.TokenKind.Comma));
|
|
1553
1771
|
}
|
|
1772
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1773
|
+
const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
|
|
1554
1774
|
let expression = new Expression_1.CallExpression(callee, openingParen, closingParen, args, this.currentNamespaceName);
|
|
1555
1775
|
if (addToCallExpressionList) {
|
|
1556
1776
|
this.callExpressions.push(expression);
|
|
@@ -1560,19 +1780,19 @@ class Parser {
|
|
|
1560
1780
|
/**
|
|
1561
1781
|
* Tries to get the next token as a type
|
|
1562
1782
|
* Allows for built-in types (double, string, etc.) or namespaced custom types in Brighterscript mode
|
|
1563
|
-
* Will
|
|
1783
|
+
* Will return a token of whatever is next to be parsed (unless `advanceIfUnknown` is false, in which case undefined will be returned instead
|
|
1564
1784
|
*/
|
|
1565
|
-
|
|
1785
|
+
typeExpression() {
|
|
1566
1786
|
let typeToken;
|
|
1567
|
-
if (this.checkAny(...
|
|
1787
|
+
if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
|
|
1568
1788
|
// Token is a built in type
|
|
1569
1789
|
typeToken = this.advance();
|
|
1570
1790
|
}
|
|
1571
1791
|
else if (this.options.mode === ParseMode.BrighterScript) {
|
|
1572
1792
|
try {
|
|
1573
|
-
// see if we can get a namespaced
|
|
1793
|
+
// see if we can get a namespaced identifier
|
|
1574
1794
|
const qualifiedType = this.getNamespacedVariableNameExpression();
|
|
1575
|
-
typeToken = creators_1.createToken(
|
|
1795
|
+
typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
|
|
1576
1796
|
}
|
|
1577
1797
|
catch (_a) {
|
|
1578
1798
|
//could not get an identifier - just get whatever's next
|
|
@@ -1583,127 +1803,58 @@ class Parser {
|
|
|
1583
1803
|
// just get whatever's next
|
|
1584
1804
|
typeToken = this.advance();
|
|
1585
1805
|
}
|
|
1586
|
-
|
|
1806
|
+
//TODO: to support InterfaceTypeLiterals - (eg. `{name as string; age as integer}`), check if "typeToken" is a curly bracket, and do something else
|
|
1807
|
+
let typeExpr = new Expression_1.TypeExpression({ type: typeToken }, this.currentNamespaceName);
|
|
1808
|
+
if (this.options.mode === ParseMode.BrighterScript) {
|
|
1809
|
+
// Check if it is an array - that is, if it has `[]` after the type
|
|
1810
|
+
// eg. `string[]` or `SomeKlass[]` or `float[][][]`
|
|
1811
|
+
while (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1812
|
+
const leftBracket = this.advance();
|
|
1813
|
+
if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1814
|
+
const rightBracket = this.advance();
|
|
1815
|
+
typeExpr = new Expression_1.ArrayTypeExpression([typeExpr], { leftBracket: leftBracket, rightBracket: rightBracket }, this.currentNamespaceName);
|
|
1816
|
+
}
|
|
1817
|
+
else {
|
|
1818
|
+
break;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return typeExpr;
|
|
1587
1823
|
}
|
|
1588
1824
|
primary() {
|
|
1589
1825
|
switch (true) {
|
|
1590
|
-
case this.matchAny(
|
|
1826
|
+
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):
|
|
1591
1827
|
return new Expression_1.LiteralExpression(this.previous());
|
|
1592
1828
|
//capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript)
|
|
1593
|
-
case this.matchAny(
|
|
1829
|
+
case this.matchAny(TokenKind_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : TokenKind_1.BrighterScriptSourceLiterals)):
|
|
1594
1830
|
return new Expression_1.SourceLiteralExpression(this.previous());
|
|
1595
1831
|
//template string
|
|
1596
|
-
case this.check(
|
|
1832
|
+
case this.check(TokenKind_1.TokenKind.BackTick):
|
|
1597
1833
|
return this.templateString(false);
|
|
1598
1834
|
//tagged template string (currently we do not support spaces between the identifier and the backtick)
|
|
1599
|
-
case this.checkAny(
|
|
1835
|
+
case this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers) && this.checkNext(TokenKind_1.TokenKind.BackTick):
|
|
1600
1836
|
return this.templateString(true);
|
|
1601
|
-
case this.matchAny(
|
|
1837
|
+
case this.matchAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
|
|
1602
1838
|
return new Expression_1.VariableExpression(this.previous(), this.currentNamespaceName);
|
|
1603
|
-
case this.match(
|
|
1839
|
+
case this.match(TokenKind_1.TokenKind.LeftParen):
|
|
1604
1840
|
let left = this.previous();
|
|
1605
1841
|
let expr = this.expression();
|
|
1606
|
-
let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(),
|
|
1842
|
+
let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
|
|
1607
1843
|
return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
|
|
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):
|
|
1844
|
+
case this.matchAny(TokenKind_1.TokenKind.LeftSquareBracket):
|
|
1845
|
+
return this.arrayLiteral();
|
|
1846
|
+
case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
|
|
1847
|
+
return this.aaLiteral();
|
|
1848
|
+
case this.matchAny(TokenKind_1.TokenKind.Pos, TokenKind_1.TokenKind.Tab):
|
|
1700
1849
|
let token = Object.assign(this.previous(), {
|
|
1701
|
-
kind:
|
|
1850
|
+
kind: TokenKind_1.TokenKind.Identifier
|
|
1702
1851
|
});
|
|
1703
1852
|
return new Expression_1.VariableExpression(token, this.currentNamespaceName);
|
|
1704
|
-
case this.checkAny(
|
|
1853
|
+
case this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub):
|
|
1705
1854
|
return this.anonymousFunction();
|
|
1706
|
-
case this.check(
|
|
1855
|
+
case this.check(TokenKind_1.TokenKind.RegexLiteral):
|
|
1856
|
+
return this.regexLiteralExpression();
|
|
1857
|
+
case this.check(TokenKind_1.TokenKind.Comment):
|
|
1707
1858
|
return new Statement_1.CommentStatement([this.advance()]);
|
|
1708
1859
|
default:
|
|
1709
1860
|
//if we found an expected terminator, don't throw a diagnostic...just return undefined
|
|
@@ -1712,11 +1863,111 @@ class Parser {
|
|
|
1712
1863
|
//something went wrong...throw an error so the upstream processor can scrap this line and move on
|
|
1713
1864
|
}
|
|
1714
1865
|
else {
|
|
1715
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.
|
|
1866
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text)), { range: this.peek().range }));
|
|
1716
1867
|
throw this.lastDiagnosticAsError();
|
|
1717
1868
|
}
|
|
1718
1869
|
}
|
|
1719
1870
|
}
|
|
1871
|
+
arrayLiteral() {
|
|
1872
|
+
let elements = [];
|
|
1873
|
+
let openingSquare = this.previous();
|
|
1874
|
+
//add any comment found right after the opening square
|
|
1875
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1876
|
+
elements.push(new Statement_1.CommentStatement([this.advance()]));
|
|
1877
|
+
}
|
|
1878
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1879
|
+
}
|
|
1880
|
+
if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1881
|
+
elements.push(this.expression());
|
|
1882
|
+
while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
1883
|
+
if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1884
|
+
let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
|
|
1885
|
+
elements.push(new Statement_1.CommentStatement([comment]));
|
|
1886
|
+
}
|
|
1887
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1888
|
+
}
|
|
1889
|
+
if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1890
|
+
break;
|
|
1891
|
+
}
|
|
1892
|
+
elements.push(this.expression());
|
|
1893
|
+
}
|
|
1894
|
+
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
1895
|
+
}
|
|
1896
|
+
let closingSquare = this.previous();
|
|
1897
|
+
//this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
|
|
1898
|
+
return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
|
|
1899
|
+
}
|
|
1900
|
+
aaLiteral() {
|
|
1901
|
+
let openingBrace = this.previous();
|
|
1902
|
+
let members = [];
|
|
1903
|
+
let key = () => {
|
|
1904
|
+
let result = {
|
|
1905
|
+
colonToken: null,
|
|
1906
|
+
keyToken: null,
|
|
1907
|
+
range: null
|
|
1908
|
+
};
|
|
1909
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
1910
|
+
result.keyToken = this.advance();
|
|
1911
|
+
}
|
|
1912
|
+
else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
|
|
1913
|
+
result.keyToken = this.advance();
|
|
1914
|
+
}
|
|
1915
|
+
else {
|
|
1916
|
+
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
|
|
1917
|
+
throw this.lastDiagnosticAsError();
|
|
1918
|
+
}
|
|
1919
|
+
result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
|
|
1920
|
+
result.range = util_1.util.getRange(result.keyToken, result.colonToken);
|
|
1921
|
+
return result;
|
|
1922
|
+
};
|
|
1923
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1924
|
+
if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
|
|
1925
|
+
let lastAAMember;
|
|
1926
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1927
|
+
lastAAMember = null;
|
|
1928
|
+
members.push(new Statement_1.CommentStatement([this.advance()]));
|
|
1929
|
+
}
|
|
1930
|
+
else {
|
|
1931
|
+
let k = key();
|
|
1932
|
+
let expr = this.expression();
|
|
1933
|
+
lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
|
|
1934
|
+
members.push(lastAAMember);
|
|
1935
|
+
}
|
|
1936
|
+
while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
|
|
1937
|
+
// collect comma at end of expression
|
|
1938
|
+
if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
|
|
1939
|
+
lastAAMember.commaToken = this.previous();
|
|
1940
|
+
}
|
|
1941
|
+
//check for comment at the end of the current line
|
|
1942
|
+
if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
|
|
1943
|
+
let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
|
|
1944
|
+
members.push(new Statement_1.CommentStatement([token]));
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
this.consumeStatementSeparators(true);
|
|
1948
|
+
//check for a comment on its own line
|
|
1949
|
+
if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
|
|
1950
|
+
let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
|
|
1951
|
+
lastAAMember = null;
|
|
1952
|
+
members.push(new Statement_1.CommentStatement([token]));
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
|
|
1956
|
+
break;
|
|
1957
|
+
}
|
|
1958
|
+
let k = key();
|
|
1959
|
+
let expr = this.expression();
|
|
1960
|
+
lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
|
|
1961
|
+
members.push(lastAAMember);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
|
|
1965
|
+
}
|
|
1966
|
+
let closingBrace = this.previous();
|
|
1967
|
+
const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
|
|
1968
|
+
this.addPropertyHints(aaExpr);
|
|
1969
|
+
return aaExpr;
|
|
1970
|
+
}
|
|
1720
1971
|
/**
|
|
1721
1972
|
* Pop token if we encounter specified token
|
|
1722
1973
|
*/
|
|
@@ -1740,6 +1991,21 @@ class Parser {
|
|
|
1740
1991
|
}
|
|
1741
1992
|
return false;
|
|
1742
1993
|
}
|
|
1994
|
+
/**
|
|
1995
|
+
* If the next series of tokens matches the given set of tokens, pop them all
|
|
1996
|
+
* @param tokenKinds
|
|
1997
|
+
*/
|
|
1998
|
+
matchSequence(...tokenKinds) {
|
|
1999
|
+
var _a;
|
|
2000
|
+
const endIndex = this.current + tokenKinds.length;
|
|
2001
|
+
for (let i = 0; i < tokenKinds.length; i++) {
|
|
2002
|
+
if (tokenKinds[i] !== ((_a = this.tokens[this.current + i]) === null || _a === void 0 ? void 0 : _a.kind)) {
|
|
2003
|
+
return false;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
this.current = endIndex;
|
|
2007
|
+
return true;
|
|
2008
|
+
}
|
|
1743
2009
|
/**
|
|
1744
2010
|
* Get next token matching a specified list, or fail with an error
|
|
1745
2011
|
*/
|
|
@@ -1754,6 +2020,9 @@ class Parser {
|
|
|
1754
2020
|
throw error;
|
|
1755
2021
|
}
|
|
1756
2022
|
}
|
|
2023
|
+
consumeToken(tokenKind) {
|
|
2024
|
+
return this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(tokenKind), tokenKind);
|
|
2025
|
+
}
|
|
1757
2026
|
/**
|
|
1758
2027
|
* Consume, or add a message if not found. But then continue and return undefined
|
|
1759
2028
|
*/
|
|
@@ -1765,14 +2034,17 @@ class Parser {
|
|
|
1765
2034
|
}
|
|
1766
2035
|
this.diagnostics.push(Object.assign(Object.assign({}, diagnostic), { range: this.peek().range }));
|
|
1767
2036
|
}
|
|
2037
|
+
tryConsumeToken(tokenKind) {
|
|
2038
|
+
return this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedToken(tokenKind), tokenKind);
|
|
2039
|
+
}
|
|
1768
2040
|
consumeStatementSeparators(optional = false) {
|
|
1769
2041
|
//a comment or EOF mark the end of the statement
|
|
1770
|
-
if (this.isAtEnd() || this.check(
|
|
2042
|
+
if (this.isAtEnd() || this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1771
2043
|
return true;
|
|
1772
2044
|
}
|
|
1773
2045
|
let consumed = false;
|
|
1774
2046
|
//consume any newlines and colons
|
|
1775
|
-
while (this.matchAny(
|
|
2047
|
+
while (this.matchAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
1776
2048
|
consumed = true;
|
|
1777
2049
|
}
|
|
1778
2050
|
if (!optional && !consumed) {
|
|
@@ -1788,7 +2060,7 @@ class Parser {
|
|
|
1788
2060
|
}
|
|
1789
2061
|
checkEndOfStatement() {
|
|
1790
2062
|
const nextKind = this.peek().kind;
|
|
1791
|
-
return [
|
|
2063
|
+
return [TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Eof].includes(nextKind);
|
|
1792
2064
|
}
|
|
1793
2065
|
checkPrevious(tokenKind) {
|
|
1794
2066
|
var _a;
|
|
@@ -1796,14 +2068,14 @@ class Parser {
|
|
|
1796
2068
|
}
|
|
1797
2069
|
check(tokenKind) {
|
|
1798
2070
|
const nextKind = this.peek().kind;
|
|
1799
|
-
if (nextKind ===
|
|
2071
|
+
if (nextKind === TokenKind_1.TokenKind.Eof) {
|
|
1800
2072
|
return false;
|
|
1801
2073
|
}
|
|
1802
2074
|
return nextKind === tokenKind;
|
|
1803
2075
|
}
|
|
1804
2076
|
checkAny(...tokenKinds) {
|
|
1805
2077
|
const nextKind = this.peek().kind;
|
|
1806
|
-
if (nextKind ===
|
|
2078
|
+
if (nextKind === TokenKind_1.TokenKind.Eof) {
|
|
1807
2079
|
return false;
|
|
1808
2080
|
}
|
|
1809
2081
|
return tokenKinds.includes(nextKind);
|
|
@@ -1822,7 +2094,7 @@ class Parser {
|
|
|
1822
2094
|
return tokenKinds.includes(nextKind);
|
|
1823
2095
|
}
|
|
1824
2096
|
isAtEnd() {
|
|
1825
|
-
return this.peek().kind ===
|
|
2097
|
+
return this.peek().kind === TokenKind_1.TokenKind.Eof;
|
|
1826
2098
|
}
|
|
1827
2099
|
peekNext() {
|
|
1828
2100
|
if (this.isAtEnd()) {
|
|
@@ -1836,6 +2108,21 @@ class Parser {
|
|
|
1836
2108
|
previous() {
|
|
1837
2109
|
return this.tokens[this.current - 1];
|
|
1838
2110
|
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Get the token that is {offset} indexes away from {this.current}
|
|
2113
|
+
* @param offset the number of index steps away from current index to fetch
|
|
2114
|
+
* @param tokenKinds the desired token must match one of these
|
|
2115
|
+
* @example
|
|
2116
|
+
* getToken(-1); //returns the previous token.
|
|
2117
|
+
* getToken(0); //returns current token.
|
|
2118
|
+
* getToken(1); //returns next token
|
|
2119
|
+
*/
|
|
2120
|
+
getMatchingTokenAtOffset(offset, ...tokenKinds) {
|
|
2121
|
+
const token = this.tokens[this.current + offset];
|
|
2122
|
+
if (tokenKinds.includes(token.kind)) {
|
|
2123
|
+
return token;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
1839
2126
|
synchronize() {
|
|
1840
2127
|
this.advance(); // skip the erroneous token
|
|
1841
2128
|
while (!this.isAtEnd()) {
|
|
@@ -1844,16 +2131,16 @@ class Parser {
|
|
|
1844
2131
|
return;
|
|
1845
2132
|
}
|
|
1846
2133
|
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
|
|
2134
|
+
case TokenKind_1.TokenKind.Namespace:
|
|
2135
|
+
case TokenKind_1.TokenKind.Class:
|
|
2136
|
+
case TokenKind_1.TokenKind.Function:
|
|
2137
|
+
case TokenKind_1.TokenKind.Sub:
|
|
2138
|
+
case TokenKind_1.TokenKind.If:
|
|
2139
|
+
case TokenKind_1.TokenKind.For:
|
|
2140
|
+
case TokenKind_1.TokenKind.ForEach:
|
|
2141
|
+
case TokenKind_1.TokenKind.While:
|
|
2142
|
+
case TokenKind_1.TokenKind.Print:
|
|
2143
|
+
case TokenKind_1.TokenKind.Return:
|
|
1857
2144
|
// start parsing again from the next block starter or obvious
|
|
1858
2145
|
// expression start
|
|
1859
2146
|
return;
|
|
@@ -1861,6 +2148,235 @@ class Parser {
|
|
|
1861
2148
|
this.advance();
|
|
1862
2149
|
}
|
|
1863
2150
|
}
|
|
2151
|
+
/**
|
|
2152
|
+
* Get the token at the specified position
|
|
2153
|
+
* @param position
|
|
2154
|
+
*/
|
|
2155
|
+
getTokenAt(position) {
|
|
2156
|
+
for (let token of this.tokens) {
|
|
2157
|
+
if (util_1.util.rangeContains(token.range, position)) {
|
|
2158
|
+
return token;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Get the token closest to the position. if no token is found, the previous token is returned
|
|
2164
|
+
* @param position
|
|
2165
|
+
* @param tokens
|
|
2166
|
+
*/
|
|
2167
|
+
getClosestToken(position) {
|
|
2168
|
+
let tokens = this.tokens;
|
|
2169
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
2170
|
+
let token = tokens[i];
|
|
2171
|
+
if (util_1.util.rangeContains(token.range, position)) {
|
|
2172
|
+
return token;
|
|
2173
|
+
}
|
|
2174
|
+
//if the position less than this token range, then this position touches no token,
|
|
2175
|
+
if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
|
|
2176
|
+
let t = tokens[i - 1];
|
|
2177
|
+
//return the token or the first token
|
|
2178
|
+
return t ? t : tokens[0];
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
//return the last token
|
|
2182
|
+
return tokens[tokens.length - 1];
|
|
2183
|
+
}
|
|
2184
|
+
isPositionNextToTokenKind(position, tokenKind) {
|
|
2185
|
+
const closestToken = this.getClosestToken(position);
|
|
2186
|
+
const previousToken = this.getPreviousToken(closestToken);
|
|
2187
|
+
const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
|
|
2188
|
+
//next to matched token
|
|
2189
|
+
if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
|
|
2190
|
+
return false;
|
|
2191
|
+
}
|
|
2192
|
+
else if (closestToken.kind === tokenKind) {
|
|
2193
|
+
return true;
|
|
2194
|
+
}
|
|
2195
|
+
else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
|
|
2196
|
+
return false;
|
|
2197
|
+
//next to an identifier, which is next to token kind
|
|
2198
|
+
}
|
|
2199
|
+
else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
|
|
2200
|
+
return true;
|
|
2201
|
+
}
|
|
2202
|
+
else {
|
|
2203
|
+
return false;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
getTokenBefore(currentToken, tokenKind) {
|
|
2207
|
+
const index = this.tokens.indexOf(currentToken);
|
|
2208
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
2209
|
+
currentToken = this.tokens[i];
|
|
2210
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
|
|
2211
|
+
break;
|
|
2212
|
+
}
|
|
2213
|
+
else if (currentToken.kind === tokenKind) {
|
|
2214
|
+
return currentToken;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
return undefined;
|
|
2218
|
+
}
|
|
2219
|
+
tokenFollows(currentToken, tokenKind) {
|
|
2220
|
+
const index = this.tokens.indexOf(currentToken);
|
|
2221
|
+
if (index > 0) {
|
|
2222
|
+
return this.tokens[index - 1].kind === tokenKind;
|
|
2223
|
+
}
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
getTokensUntil(currentToken, tokenKind, direction = -1) {
|
|
2227
|
+
let tokens = [];
|
|
2228
|
+
for (let i = this.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.tokens.length; i += direction) {
|
|
2229
|
+
currentToken = this.tokens[i];
|
|
2230
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
|
|
2231
|
+
break;
|
|
2232
|
+
}
|
|
2233
|
+
tokens.push(currentToken);
|
|
2234
|
+
}
|
|
2235
|
+
return tokens;
|
|
2236
|
+
}
|
|
2237
|
+
getPreviousToken(token) {
|
|
2238
|
+
let idx = this.tokens.indexOf(token);
|
|
2239
|
+
return this.tokens[idx - 1];
|
|
2240
|
+
}
|
|
2241
|
+
getPreviousTokenFromIndex(idx) {
|
|
2242
|
+
return { token: this.tokens[idx - 1], index: idx - 1 };
|
|
2243
|
+
}
|
|
2244
|
+
getPreviousTokenIgnoreNests(currentTokenIndex, leftBracketType, rightBracketType) {
|
|
2245
|
+
let currentToken = this.tokens[currentTokenIndex];
|
|
2246
|
+
let previousTokenResult;
|
|
2247
|
+
function isRightBracket(token) {
|
|
2248
|
+
return (token === null || token === void 0 ? void 0 : token.kind) === rightBracketType;
|
|
2249
|
+
}
|
|
2250
|
+
function isLeftBracket(token) {
|
|
2251
|
+
return (token === null || token === void 0 ? void 0 : token.kind) === leftBracketType;
|
|
2252
|
+
}
|
|
2253
|
+
let lastTokenHadLeadingWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
|
|
2254
|
+
let lastTokenWasLeftBracket = false;
|
|
2255
|
+
let bracketNestCount = 0;
|
|
2256
|
+
let hasBrackets = false;
|
|
2257
|
+
// check for nested function call
|
|
2258
|
+
if (isRightBracket(currentToken)) {
|
|
2259
|
+
bracketNestCount++;
|
|
2260
|
+
hasBrackets = true;
|
|
2261
|
+
}
|
|
2262
|
+
while (currentToken && bracketNestCount > 0) {
|
|
2263
|
+
previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
|
|
2264
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2265
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2266
|
+
lastTokenWasLeftBracket = false;
|
|
2267
|
+
if (isRightBracket(currentToken)) {
|
|
2268
|
+
bracketNestCount++;
|
|
2269
|
+
}
|
|
2270
|
+
while (isLeftBracket(currentToken)) {
|
|
2271
|
+
bracketNestCount--;
|
|
2272
|
+
lastTokenWasLeftBracket = true;
|
|
2273
|
+
lastTokenHadLeadingWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
|
|
2274
|
+
previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
|
|
2275
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2276
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
// We will not be able to decipher the token type if it was in brackets
|
|
2280
|
+
// e.g (someVar+otherVar).toStr() -- we don't bother trying to decipher what "(someVar+otherVar)" is
|
|
2281
|
+
let isUnknown = (lastTokenWasLeftBracket && (lastTokenHadLeadingWhitespace || !this.isAcceptableChainToken(currentToken)));
|
|
2282
|
+
const tokenWithIndex = { token: currentToken, index: currentTokenIndex, tokenTypeIsNotKnowable: isUnknown, hasBrackets: hasBrackets };
|
|
2283
|
+
return tokenWithIndex;
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Finds the previous token in a chain (e.g. 'm.obj.func(someFunc()).value'), skipping over any arguments of function calls
|
|
2287
|
+
* If this function was called with the token at 'value' above, the previous identifier in the chain is 'func'
|
|
2288
|
+
* @param currentTokenIndex token index to start from
|
|
2289
|
+
* @param allowCurrent can the current token be the token that's the identifier?
|
|
2290
|
+
* @returns the previous identifer
|
|
2291
|
+
*/
|
|
2292
|
+
getPreviousTokenInChain(currentTokenIndex, allowCurrent = false) {
|
|
2293
|
+
let currentToken = this.tokens[currentTokenIndex];
|
|
2294
|
+
let previousTokenResult;
|
|
2295
|
+
let usage = TokenUsage.Direct;
|
|
2296
|
+
if (!allowCurrent) {
|
|
2297
|
+
previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
|
|
2298
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2299
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2300
|
+
}
|
|
2301
|
+
if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.Dot) {
|
|
2302
|
+
previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
|
|
2303
|
+
currentToken = previousTokenResult.token;
|
|
2304
|
+
currentTokenIndex = previousTokenResult.index;
|
|
2305
|
+
}
|
|
2306
|
+
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.RightParen);
|
|
2307
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2308
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2309
|
+
if (previousTokenResult.hasBrackets) {
|
|
2310
|
+
usage = TokenUsage.Call;
|
|
2311
|
+
}
|
|
2312
|
+
let tokenTypeIsNotKnowable = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable;
|
|
2313
|
+
if (currentTokenIndex) {
|
|
2314
|
+
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.RightSquareBracket);
|
|
2315
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2316
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2317
|
+
if (previousTokenResult.hasBrackets) {
|
|
2318
|
+
usage = TokenUsage.ArrayReference;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
tokenTypeIsNotKnowable = tokenTypeIsNotKnowable || (previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
|
|
2322
|
+
if (tokenTypeIsNotKnowable || this.isAcceptableChainToken(currentToken)) {
|
|
2323
|
+
// either we have a valid chain token, or we can't know what the token type is
|
|
2324
|
+
return { token: currentToken, index: currentTokenIndex, tokenTypeIsNotKnowable: tokenTypeIsNotKnowable, usage: usage };
|
|
2325
|
+
}
|
|
2326
|
+
return undefined;
|
|
2327
|
+
}
|
|
2328
|
+
isAcceptableChainToken(currentToken, lastTokenHasWhitespace = false) {
|
|
2329
|
+
if (!currentToken || lastTokenHasWhitespace) {
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Identifier) {
|
|
2333
|
+
return true;
|
|
2334
|
+
}
|
|
2335
|
+
if (currentToken.leadingWhitespace.length === 0) {
|
|
2336
|
+
// start of the chain
|
|
2337
|
+
return TokenKind_1.AllowedLocalIdentifiers.includes(currentToken.kind);
|
|
2338
|
+
}
|
|
2339
|
+
// not the start of the chain
|
|
2340
|
+
return TokenKind_1.AllowedProperties.includes(currentToken.kind);
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Builds up a chain of tokens, starting with the first in the chain, and ending with currentToken
|
|
2344
|
+
* e.g. m.prop.method().field (with 'field' as currentToken) -> ["m", "prop", "method", "field"], with each element as a token
|
|
2345
|
+
* @param currentToken the token that is the end of the chain
|
|
2346
|
+
* @returns array of tokens
|
|
2347
|
+
*/
|
|
2348
|
+
getTokenChain(currentToken) {
|
|
2349
|
+
const tokenChain = [];
|
|
2350
|
+
let currentTokenIndex = this.tokens.indexOf(currentToken);
|
|
2351
|
+
let previousTokenResult;
|
|
2352
|
+
let lastTokenHasWhitespace = false;
|
|
2353
|
+
let includesUnknown = false;
|
|
2354
|
+
previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex, true);
|
|
2355
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2356
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2357
|
+
if (this.isAcceptableChainToken(currentToken)) {
|
|
2358
|
+
tokenChain.push(previousTokenResult);
|
|
2359
|
+
lastTokenHasWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
|
|
2360
|
+
}
|
|
2361
|
+
if (!lastTokenHasWhitespace) {
|
|
2362
|
+
previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex);
|
|
2363
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2364
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2365
|
+
includesUnknown = !!(previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
|
|
2366
|
+
while (!includesUnknown && this.isAcceptableChainToken(currentToken, lastTokenHasWhitespace)) {
|
|
2367
|
+
tokenChain.push(previousTokenResult);
|
|
2368
|
+
lastTokenHasWhitespace = (currentToken === null || currentToken === void 0 ? void 0 : currentToken.leadingWhitespace.length) > 0;
|
|
2369
|
+
if (!lastTokenHasWhitespace) {
|
|
2370
|
+
previousTokenResult = this.getPreviousTokenInChain(currentTokenIndex);
|
|
2371
|
+
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2372
|
+
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2373
|
+
includesUnknown = includesUnknown || (previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
tokenChain.reverse();
|
|
2378
|
+
return { chain: tokenChain, includesUnknowableTokenType: !!includesUnknown };
|
|
2379
|
+
}
|
|
1864
2380
|
/**
|
|
1865
2381
|
* References are found during the initial parse.
|
|
1866
2382
|
* However, sometimes plugins can modify the AST, requiring a full walk to re-compute all references.
|
|
@@ -1868,59 +2384,141 @@ class Parser {
|
|
|
1868
2384
|
*/
|
|
1869
2385
|
findReferences() {
|
|
1870
2386
|
this._references = new References();
|
|
2387
|
+
const excludedExpressions = new Set();
|
|
2388
|
+
const visitCallExpression = (e) => {
|
|
2389
|
+
for (const p of e.args) {
|
|
2390
|
+
this._references.expressions.add(p);
|
|
2391
|
+
}
|
|
2392
|
+
//add calls that were not excluded (from loop below)
|
|
2393
|
+
if (!excludedExpressions.has(e)) {
|
|
2394
|
+
this._references.expressions.add(e);
|
|
2395
|
+
}
|
|
2396
|
+
//if this call is part of a longer expression that includes a call higher up, find that higher one and remove it
|
|
2397
|
+
if (e.callee) {
|
|
2398
|
+
let node = e.callee;
|
|
2399
|
+
while (node) {
|
|
2400
|
+
//the primary goal for this loop. If we found a parent call expression, remove it from `references`
|
|
2401
|
+
if ((0, reflection_1.isCallExpression)(node)) {
|
|
2402
|
+
this.references.expressions.delete(node);
|
|
2403
|
+
excludedExpressions.add(node);
|
|
2404
|
+
//stop here. even if there are multiple calls in the chain, each child will find and remove its closest parent, so that reduces excess walking.
|
|
2405
|
+
break;
|
|
2406
|
+
//when we hit a variable expression, we're definitely at the leftmost expression so stop
|
|
2407
|
+
}
|
|
2408
|
+
else if ((0, reflection_1.isVariableExpression)(node)) {
|
|
2409
|
+
break;
|
|
2410
|
+
//if
|
|
2411
|
+
}
|
|
2412
|
+
else if ((0, reflection_1.isDottedGetExpression)(node) || (0, reflection_1.isIndexedGetExpression)(node)) {
|
|
2413
|
+
node = node.obj;
|
|
2414
|
+
}
|
|
2415
|
+
else {
|
|
2416
|
+
//some expression we don't understand. log it and quit the loop
|
|
2417
|
+
this.logger.info('Encountered unknown expression while calculating function expression chain', node);
|
|
2418
|
+
break;
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
1871
2423
|
//gather up all the top-level statements
|
|
1872
|
-
this.ast.walk(visitors_1.createVisitor({
|
|
2424
|
+
this.ast.walk((0, visitors_1.createVisitor)({
|
|
2425
|
+
AssignmentStatement: s => {
|
|
2426
|
+
this._references.assignmentStatements.push(s);
|
|
2427
|
+
this.references.expressions.add(s.value);
|
|
2428
|
+
},
|
|
1873
2429
|
ClassStatement: s => {
|
|
1874
2430
|
this._references.classStatements.push(s);
|
|
1875
2431
|
},
|
|
2432
|
+
FieldStatement: s => {
|
|
2433
|
+
if (s.initialValue) {
|
|
2434
|
+
this._references.expressions.add(s.initialValue);
|
|
2435
|
+
}
|
|
2436
|
+
},
|
|
2437
|
+
InterfaceStatement: s => {
|
|
2438
|
+
this._references.interfaceStatements.push(s);
|
|
2439
|
+
},
|
|
1876
2440
|
NamespaceStatement: s => {
|
|
1877
2441
|
this._references.namespaceStatements.push(s);
|
|
1878
2442
|
},
|
|
1879
2443
|
FunctionStatement: s => {
|
|
1880
2444
|
this._references.functionStatements.push(s);
|
|
1881
|
-
//add the initial set of function expressions for function statements
|
|
1882
|
-
this._references.functionExpressions.push(s.func);
|
|
1883
2445
|
},
|
|
1884
2446
|
ImportStatement: s => {
|
|
1885
2447
|
this._references.importStatements.push(s);
|
|
1886
2448
|
},
|
|
1887
2449
|
LibraryStatement: s => {
|
|
1888
2450
|
this._references.libraryStatements.push(s);
|
|
1889
|
-
}
|
|
1890
|
-
}), {
|
|
1891
|
-
walkMode: visitors_1.WalkMode.visitStatements
|
|
1892
|
-
});
|
|
1893
|
-
let func;
|
|
1894
|
-
let visitor = visitors_1.createVisitor({
|
|
1895
|
-
AssignmentStatement: s => {
|
|
1896
|
-
this._references.assignmentStatements.push(s);
|
|
1897
2451
|
},
|
|
1898
2452
|
FunctionExpression: (expression, parent) => {
|
|
1899
|
-
if (!reflection_1.
|
|
2453
|
+
if (!(0, reflection_1.isMethodStatement)(parent) && !(0, reflection_1.isInterfaceMethodStatement)(parent)) {
|
|
1900
2454
|
this._references.functionExpressions.push(expression);
|
|
1901
2455
|
}
|
|
1902
2456
|
},
|
|
1903
2457
|
NewExpression: e => {
|
|
1904
2458
|
this._references.newExpressions.push(e);
|
|
2459
|
+
for (const p of e.call.args) {
|
|
2460
|
+
this._references.expressions.add(p);
|
|
2461
|
+
}
|
|
2462
|
+
},
|
|
2463
|
+
ExpressionStatement: s => {
|
|
2464
|
+
this._references.expressions.add(s.expression);
|
|
2465
|
+
},
|
|
2466
|
+
CallfuncExpression: e => {
|
|
2467
|
+
visitCallExpression(e);
|
|
2468
|
+
},
|
|
2469
|
+
CallExpression: e => {
|
|
2470
|
+
visitCallExpression(e);
|
|
1905
2471
|
},
|
|
1906
2472
|
AALiteralExpression: e => {
|
|
1907
2473
|
this.addPropertyHints(e);
|
|
2474
|
+
this._references.expressions.add(e);
|
|
2475
|
+
for (const member of e.elements) {
|
|
2476
|
+
if ((0, reflection_1.isAAMemberExpression)(member)) {
|
|
2477
|
+
this._references.expressions.add(member.value);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
},
|
|
2481
|
+
ArrayLiteralExpression: e => {
|
|
2482
|
+
for (const element of e.elements) {
|
|
2483
|
+
//keep everything except comments
|
|
2484
|
+
if (!(0, reflection_1.isCommentStatement)(element)) {
|
|
2485
|
+
this._references.expressions.add(element);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
1908
2488
|
},
|
|
1909
2489
|
DottedGetExpression: e => {
|
|
1910
2490
|
this.addPropertyHints(e.name);
|
|
1911
2491
|
},
|
|
1912
2492
|
DottedSetStatement: e => {
|
|
1913
2493
|
this.addPropertyHints(e.name);
|
|
2494
|
+
},
|
|
2495
|
+
EnumStatement: e => {
|
|
2496
|
+
this._references.enumStatements.push(e);
|
|
2497
|
+
},
|
|
2498
|
+
UnaryExpression: e => {
|
|
2499
|
+
this._references.expressions.add(e);
|
|
2500
|
+
},
|
|
2501
|
+
IncrementStatement: e => {
|
|
2502
|
+
this._references.expressions.add(e);
|
|
1914
2503
|
}
|
|
2504
|
+
}), {
|
|
2505
|
+
walkMode: visitors_1.WalkMode.visitAllRecursive
|
|
1915
2506
|
});
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2507
|
+
}
|
|
2508
|
+
getContainingClass(currentToken) {
|
|
2509
|
+
return this.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
|
|
2510
|
+
}
|
|
2511
|
+
getContainingAA(currentToken) {
|
|
2512
|
+
return this.references.aaLiterals.find((aa) => util_1.util.rangeContains(aa.range, currentToken.range.start));
|
|
2513
|
+
}
|
|
2514
|
+
getContainingNamespace(currentToken) {
|
|
2515
|
+
return this.references.namespaceStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
|
|
2516
|
+
}
|
|
2517
|
+
getContainingFunctionExpression(currentToken) {
|
|
2518
|
+
return this.getContainingFunctionExpressionByPosition(currentToken.range.start);
|
|
2519
|
+
}
|
|
2520
|
+
getContainingFunctionExpressionByPosition(position) {
|
|
2521
|
+
return this.references.functionExpressions.find((fe) => util_1.util.rangeContains(fe.range, position));
|
|
1924
2522
|
}
|
|
1925
2523
|
dispose() {
|
|
1926
2524
|
}
|
|
@@ -1933,10 +2531,26 @@ var ParseMode;
|
|
|
1933
2531
|
})(ParseMode = exports.ParseMode || (exports.ParseMode = {}));
|
|
1934
2532
|
class References {
|
|
1935
2533
|
constructor() {
|
|
2534
|
+
this.cache = new Cache_1.Cache();
|
|
1936
2535
|
this.assignmentStatements = [];
|
|
1937
2536
|
this.classStatements = [];
|
|
2537
|
+
this.dottedSetStatements = [];
|
|
2538
|
+
this.aaLiterals = [];
|
|
1938
2539
|
this.functionExpressions = [];
|
|
1939
2540
|
this.functionStatements = [];
|
|
2541
|
+
this.interfaceStatements = [];
|
|
2542
|
+
this.enumStatements = [];
|
|
2543
|
+
/**
|
|
2544
|
+
* A collection of full expressions. This excludes intermediary expressions.
|
|
2545
|
+
*
|
|
2546
|
+
* Example 1:
|
|
2547
|
+
* `a.b.c` is composed of `a` (variableExpression) `.b` (DottedGetExpression) `.c` (DottedGetExpression)
|
|
2548
|
+
* This will only contain the final `.c` DottedGetExpression because `.b` and `a` can both be derived by walking back from the `.c` DottedGetExpression.
|
|
2549
|
+
*
|
|
2550
|
+
* Example 2:
|
|
2551
|
+
* `name.space.doSomething(a.b.c)` will result in 2 entries in this list. the `CallExpression` for `doSomething`, and the `.c` DottedGetExpression.
|
|
2552
|
+
*/
|
|
2553
|
+
this.expressions = new Set();
|
|
1940
2554
|
this.importStatements = [];
|
|
1941
2555
|
this.libraryStatements = [];
|
|
1942
2556
|
this.namespaceStatements = [];
|
|
@@ -1964,8 +2578,32 @@ class References {
|
|
|
1964
2578
|
}
|
|
1965
2579
|
return this._functionStatementLookup;
|
|
1966
2580
|
}
|
|
2581
|
+
get interfaceStatementLookup() {
|
|
2582
|
+
if (!this._interfaceStatementLookup) {
|
|
2583
|
+
this._interfaceStatementLookup = new Map();
|
|
2584
|
+
for (const stmt of this.interfaceStatements) {
|
|
2585
|
+
this._interfaceStatementLookup.set(stmt.getName(ParseMode.BrighterScript).toLowerCase(), stmt);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
return this._interfaceStatementLookup;
|
|
2589
|
+
}
|
|
2590
|
+
get enumStatementLookup() {
|
|
2591
|
+
return this.cache.getOrAdd('enums', () => {
|
|
2592
|
+
const result = new Map();
|
|
2593
|
+
for (const stmt of this.enumStatements) {
|
|
2594
|
+
result.set(stmt.fullName.toLowerCase(), stmt);
|
|
2595
|
+
}
|
|
2596
|
+
return result;
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
1967
2599
|
}
|
|
1968
2600
|
exports.References = References;
|
|
2601
|
+
var TokenUsage;
|
|
2602
|
+
(function (TokenUsage) {
|
|
2603
|
+
TokenUsage[TokenUsage["Direct"] = 1] = "Direct";
|
|
2604
|
+
TokenUsage[TokenUsage["Call"] = 2] = "Call";
|
|
2605
|
+
TokenUsage[TokenUsage["ArrayReference"] = 3] = "ArrayReference";
|
|
2606
|
+
})(TokenUsage = exports.TokenUsage || (exports.TokenUsage = {}));
|
|
1969
2607
|
class CancelStatementError extends Error {
|
|
1970
2608
|
constructor() {
|
|
1971
2609
|
super('CancelStatement');
|
|
@@ -1980,32 +2618,43 @@ class CancelStatementError extends Error {
|
|
|
1980
2618
|
*/
|
|
1981
2619
|
function getBscTypeFromExpression(expression, functionExpression) {
|
|
1982
2620
|
try {
|
|
1983
|
-
|
|
1984
|
-
if (reflection_1.isFunctionExpression(expression)) {
|
|
2621
|
+
if ((0, reflection_1.isFunctionExpression)(expression)) {
|
|
1985
2622
|
return expression.getFunctionType();
|
|
1986
2623
|
//literal
|
|
1987
2624
|
}
|
|
1988
|
-
else if (reflection_1.isLiteralExpression(expression)) {
|
|
2625
|
+
else if ((0, reflection_1.isLiteralExpression)(expression)) {
|
|
1989
2626
|
return expression.type;
|
|
1990
2627
|
//Associative array literal
|
|
1991
2628
|
}
|
|
1992
|
-
else if (reflection_1.isAALiteralExpression(expression)) {
|
|
1993
|
-
return new ObjectType_1.ObjectType();
|
|
2629
|
+
else if ((0, reflection_1.isAALiteralExpression)(expression)) {
|
|
2630
|
+
return new ObjectType_1.ObjectType('object', expression.memberTable);
|
|
1994
2631
|
//Array literal
|
|
1995
2632
|
}
|
|
1996
|
-
else if (reflection_1.isArrayLiteralExpression(expression)) {
|
|
1997
|
-
|
|
2633
|
+
else if ((0, reflection_1.isArrayLiteralExpression)(expression)) {
|
|
2634
|
+
const innerTypes = expression.elements.filter((element) => !(0, reflection_1.isCommentStatement)(element)).map((element) => {
|
|
2635
|
+
return getBscTypeFromExpression(element, functionExpression);
|
|
2636
|
+
});
|
|
2637
|
+
return new ArrayType_1.ArrayType(...innerTypes);
|
|
1998
2638
|
//function call
|
|
1999
2639
|
}
|
|
2000
|
-
else if (reflection_1.isNewExpression(expression)) {
|
|
2001
|
-
return
|
|
2640
|
+
else if ((0, reflection_1.isNewExpression)(expression)) {
|
|
2641
|
+
return (0, helpers_1.getTypeFromNewExpression)(expression, functionExpression);
|
|
2002
2642
|
//Function call
|
|
2003
2643
|
}
|
|
2004
|
-
else if (reflection_1.isCallExpression(expression)) {
|
|
2005
|
-
return getTypeFromCallExpression(expression, functionExpression);
|
|
2644
|
+
else if ((0, reflection_1.isCallExpression)(expression)) {
|
|
2645
|
+
return (0, helpers_1.getTypeFromCallExpression)(expression, functionExpression);
|
|
2646
|
+
}
|
|
2647
|
+
else if ((0, reflection_1.isVariableExpression)(expression)) {
|
|
2648
|
+
return (0, helpers_1.getTypeFromVariableExpression)(expression, functionExpression);
|
|
2006
2649
|
}
|
|
2007
|
-
else if (reflection_1.
|
|
2008
|
-
return
|
|
2650
|
+
else if ((0, reflection_1.isDottedGetExpression)(expression)) {
|
|
2651
|
+
return (0, helpers_1.getTypeFromDottedGetExpression)(expression, functionExpression);
|
|
2652
|
+
}
|
|
2653
|
+
else if ((0, reflection_1.isIndexedGetExpression)(expression)) {
|
|
2654
|
+
const source = getBscTypeFromExpression(expression.obj, functionExpression);
|
|
2655
|
+
if ((0, reflection_1.isArrayType)(source)) {
|
|
2656
|
+
return source.getDefaultType();
|
|
2657
|
+
}
|
|
2009
2658
|
}
|
|
2010
2659
|
}
|
|
2011
2660
|
catch (e) {
|
|
@@ -2015,56 +2664,4 @@ function getBscTypeFromExpression(expression, functionExpression) {
|
|
|
2015
2664
|
return new DynamicType_1.DynamicType();
|
|
2016
2665
|
}
|
|
2017
2666
|
exports.getBscTypeFromExpression = getBscTypeFromExpression;
|
|
2018
|
-
/**
|
|
2019
|
-
* Gets the return type of a function, taking into account that the function may not have been declared yet
|
|
2020
|
-
* If the callee already exists in symbol table, use that return type
|
|
2021
|
-
* otherwise, make a lazy type which will not compute its type until the file is done parsing
|
|
2022
|
-
*
|
|
2023
|
-
* @param call the Expression to process
|
|
2024
|
-
* @param functionExpression the wrapping function expression
|
|
2025
|
-
* @return the best guess type of that expression
|
|
2026
|
-
*/
|
|
2027
|
-
function getTypeFromCallExpression(call, functionExpression) {
|
|
2028
|
-
var _a;
|
|
2029
|
-
let calleeName = (_a = call.callee.name.text) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
2030
|
-
if (calleeName) {
|
|
2031
|
-
// i
|
|
2032
|
-
const currentKnownType = functionExpression.symbolTable.getSymbolType(calleeName);
|
|
2033
|
-
if (reflection_1.isFunctionType(currentKnownType)) {
|
|
2034
|
-
return currentKnownType.returnType;
|
|
2035
|
-
}
|
|
2036
|
-
if (!reflection_1.isUninitializedType(currentKnownType)) {
|
|
2037
|
-
// this will probably only happen if a functionName has been assigned to something else previously?
|
|
2038
|
-
return currentKnownType;
|
|
2039
|
-
}
|
|
2040
|
-
return new LazyType_1.LazyType(() => {
|
|
2041
|
-
const futureType = functionExpression.symbolTable.getSymbolType(calleeName);
|
|
2042
|
-
if (reflection_1.isFunctionType(futureType)) {
|
|
2043
|
-
return futureType.returnType;
|
|
2044
|
-
}
|
|
2045
|
-
return futureType;
|
|
2046
|
-
});
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
exports.getTypeFromCallExpression = getTypeFromCallExpression;
|
|
2050
|
-
/**
|
|
2051
|
-
* Gets the type of a variable
|
|
2052
|
-
* if it already exists in symbol table, use that type
|
|
2053
|
-
* 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)
|
|
2054
|
-
*
|
|
2055
|
-
* @param variable the Expression to process
|
|
2056
|
-
* @param functionExpression the wrapping function expression
|
|
2057
|
-
* @return the best guess type of that expression
|
|
2058
|
-
*/
|
|
2059
|
-
function getTypeFromVariableExpression(variable, functionExpression) {
|
|
2060
|
-
let variableName = variable.name.text.toLowerCase();
|
|
2061
|
-
const currentKnownType = functionExpression.symbolTable.getSymbolType(variableName);
|
|
2062
|
-
if (!reflection_1.isUninitializedType(currentKnownType)) {
|
|
2063
|
-
return currentKnownType;
|
|
2064
|
-
}
|
|
2065
|
-
return new LazyType_1.LazyType(() => {
|
|
2066
|
-
return functionExpression.symbolTable.getSymbolType(variableName);
|
|
2067
|
-
});
|
|
2068
|
-
}
|
|
2069
|
-
exports.getTypeFromVariableExpression = getTypeFromVariableExpression;
|
|
2070
2667
|
//# sourceMappingURL=Parser.js.map
|