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