brighterscript 1.0.0-alpha.2 → 1.0.0-alpha.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +643 -253
- package/README.md +33 -9
- package/bsconfig.schema.json +22 -2
- package/dist/BsConfig.d.ts +9 -0
- package/dist/Cache.d.ts +5 -6
- package/dist/Cache.js +12 -11
- package/dist/Cache.js.map +1 -1
- package/dist/CodeActionUtil.d.ts +11 -2
- package/dist/CodeActionUtil.js +17 -3
- package/dist/CodeActionUtil.js.map +1 -1
- package/dist/CommentFlagProcessor.d.ts +4 -4
- package/dist/CommentFlagProcessor.js +5 -3
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DependencyGraph.d.ts +2 -2
- package/dist/DependencyGraph.js +20 -7
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticCollection.d.ts +3 -3
- package/dist/DiagnosticCollection.js +11 -11
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.js +5 -4
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +59 -4
- package/dist/DiagnosticMessages.js +65 -7
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.d.ts +51 -39
- package/dist/LanguageServer.js +316 -232
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +2 -0
- package/dist/Logger.js +10 -8
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +7 -3
- package/dist/PluginInterface.js +9 -0
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +43 -25
- package/dist/Program.js +212 -95
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +4 -0
- package/dist/ProgramBuilder.js +36 -20
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +126 -29
- package/dist/Scope.js +433 -156
- package/dist/Scope.js.map +1 -1
- package/dist/SemanticTokenUtils.d.ts +14 -0
- package/dist/SemanticTokenUtils.js +81 -0
- package/dist/SemanticTokenUtils.js.map +1 -0
- package/dist/SymbolTable.d.ts +10 -4
- package/dist/SymbolTable.js +55 -13
- package/dist/SymbolTable.js.map +1 -1
- package/dist/XmlScope.d.ts +7 -2
- package/dist/XmlScope.js +65 -27
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/AstEditor.d.ts +65 -0
- package/dist/astUtils/AstEditor.js +239 -0
- package/dist/astUtils/AstEditor.js.map +1 -0
- package/dist/{types/FunctionType.spec.d.ts → astUtils/AstEditor.spec.d.ts} +0 -0
- package/dist/astUtils/AstEditor.spec.js +254 -0
- package/dist/astUtils/AstEditor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +28 -6
- package/dist/astUtils/creators.js +137 -19
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +14 -4
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +32 -10
- package/dist/astUtils/reflection.js +82 -7
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +130 -119
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/stackedVisitor.js.map +1 -1
- package/dist/astUtils/stackedVisitor.spec.js +13 -13
- package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +76 -51
- package/dist/astUtils/visitors.js +31 -11
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +126 -32
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +4 -3
- package/dist/astUtils/xml.js +8 -3
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +7 -1
- package/dist/bscPlugin/BscPlugin.js +28 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +4 -4
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +26 -26
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +9 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +108 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +130 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +52 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +32 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +29 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +183 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/cli.js +10 -3
- package/dist/cli.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +1 -0
- package/dist/diagnosticUtils.js +15 -8
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +12 -14
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +717 -147
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +70 -30
- package/dist/files/BrsFile.js +719 -353
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +1238 -449
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +6 -5
- package/dist/files/XmlFile.js +38 -30
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +302 -237
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +44 -42
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
- package/dist/files/tests/optionalChaning.spec.js +88 -0
- package/dist/files/tests/optionalChaning.spec.js.map +1 -0
- package/dist/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +424 -152
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +28 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +133 -16
- package/dist/lexer/Lexer.d.ts +19 -1
- package/dist/lexer/Lexer.js +127 -21
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +657 -536
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.d.ts +2 -2
- package/dist/lexer/TokenKind.d.ts +13 -1
- package/dist/lexer/TokenKind.js +60 -3
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/BrsTranspileState.d.ts +9 -0
- package/dist/parser/BrsTranspileState.js +14 -0
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +150 -34
- package/dist/parser/Expression.js +335 -165
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +189 -89
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +153 -30
- package/dist/parser/Parser.js +1100 -503
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +687 -266
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +41 -4
- package/dist/parser/SGParser.js +186 -175
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +35 -22
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +206 -38
- package/dist/parser/SGTypes.js +470 -161
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/SGTypes.spec.d.ts +1 -0
- package/dist/parser/SGTypes.spec.js +351 -0
- package/dist/parser/SGTypes.spec.js.map +1 -0
- package/dist/parser/Statement.d.ts +202 -48
- package/dist/parser/Statement.js +648 -193
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +11 -11
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +1 -1
- package/dist/parser/TranspileState.js +15 -7
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +10 -9
- package/dist/parser/tests/Parser.spec.js +15 -11
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +60 -60
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +40 -39
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +213 -194
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +37 -37
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +30 -30
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +119 -119
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +162 -138
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +24 -24
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +41 -40
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +17 -17
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +256 -256
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +87 -87
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +37 -37
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +75 -63
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +41 -41
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +41 -41
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/Relational.spec.js +43 -43
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +9 -9
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +28 -28
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +102 -102
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +36 -36
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/Declaration.spec.js +44 -44
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Dim.spec.js +21 -21
- package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Enum.spec.js +840 -0
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
- package/dist/parser/tests/statement/For.spec.d.ts +1 -0
- package/dist/parser/tests/statement/For.spec.js +46 -0
- package/dist/parser/tests/statement/For.spec.js.map +1 -0
- package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ForEach.spec.js +37 -0
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
- package/dist/parser/tests/statement/Function.spec.js +198 -197
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +15 -14
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +50 -50
- package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +254 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/LibraryStatement.spec.js +17 -17
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +108 -106
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +40 -40
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +46 -46
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +83 -83
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +12 -11
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/parser/tests/statement/Throw.spec.js +5 -5
- package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +15 -13
- package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
- package/dist/preprocessor/Chunk.d.ts +1 -1
- package/dist/preprocessor/Chunk.js.map +1 -1
- package/dist/preprocessor/Manifest.d.ts +5 -5
- package/dist/preprocessor/Manifest.js +14 -35
- package/dist/preprocessor/Manifest.js.map +1 -1
- package/dist/preprocessor/Manifest.spec.d.ts +1 -0
- package/dist/preprocessor/Manifest.spec.js +78 -103
- package/dist/preprocessor/Manifest.spec.js.map +1 -1
- package/dist/preprocessor/Preprocessor.d.ts +1 -1
- package/dist/preprocessor/Preprocessor.js +8 -8
- package/dist/preprocessor/Preprocessor.js.map +1 -1
- package/dist/preprocessor/Preprocessor.spec.js +49 -49
- package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
- package/dist/preprocessor/PreprocessorParser.spec.js +72 -72
- package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
- package/dist/roku-types/data.json +21891 -0
- package/dist/roku-types/index.d.ts +6776 -0
- package/dist/roku-types/index.js +11 -0
- package/dist/roku-types/index.js.map +1 -0
- package/dist/types/ArrayType.d.ts +8 -5
- package/dist/types/ArrayType.js +52 -12
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +72 -11
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/BooleanType.d.ts +4 -2
- package/dist/types/BooleanType.js +9 -4
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BooleanType.spec.js +5 -3
- package/dist/types/BooleanType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +20 -5
- package/dist/types/BscType.js +24 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/CustomType.d.ts +8 -6
- package/dist/types/CustomType.js +20 -11
- package/dist/types/CustomType.js.map +1 -1
- package/dist/types/DoubleType.d.ts +2 -0
- package/dist/types/DoubleType.js +14 -9
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DoubleType.spec.js +5 -3
- package/dist/types/DoubleType.spec.js.map +1 -1
- package/dist/types/DynamicType.d.ts +2 -0
- package/dist/types/DynamicType.js +6 -2
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/DynamicType.spec.js +2 -2
- package/dist/types/DynamicType.spec.js.map +1 -1
- package/dist/types/EnumType.d.ts +22 -0
- package/dist/types/EnumType.js +55 -0
- package/dist/types/EnumType.js.map +1 -0
- package/dist/types/FloatType.d.ts +2 -0
- package/dist/types/FloatType.js +14 -9
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FloatType.spec.js +4 -2
- package/dist/types/FloatType.spec.js.map +1 -1
- package/dist/types/FunctionType.d.ts +7 -31
- package/dist/types/FunctionType.js +11 -57
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/IntegerType.d.ts +2 -0
- package/dist/types/IntegerType.js +14 -9
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/IntegerType.spec.js +5 -3
- package/dist/types/IntegerType.spec.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +13 -4
- package/dist/types/InterfaceType.js +48 -8
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.d.ts +1 -0
- package/dist/types/InterfaceType.spec.js +194 -0
- package/dist/types/InterfaceType.spec.js.map +1 -0
- package/dist/types/InvalidType.d.ts +4 -2
- package/dist/types/InvalidType.js +10 -5
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/InvalidType.spec.js +4 -2
- package/dist/types/InvalidType.spec.js.map +1 -1
- package/dist/types/LazyType.d.ts +8 -7
- package/dist/types/LazyType.js +22 -10
- package/dist/types/LazyType.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +2 -0
- package/dist/types/LongIntegerType.js +14 -9
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.spec.js +4 -2
- package/dist/types/LongIntegerType.spec.js.map +1 -1
- package/dist/types/ObjectType.d.ts +8 -4
- package/dist/types/ObjectType.js +9 -4
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ObjectType.spec.js +2 -2
- package/dist/types/ObjectType.spec.js.map +1 -1
- package/dist/types/StringType.d.ts +4 -2
- package/dist/types/StringType.js +9 -4
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/StringType.spec.js +4 -2
- package/dist/types/StringType.spec.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +28 -0
- package/dist/types/TypedFunctionType.js +88 -0
- package/dist/types/TypedFunctionType.js.map +1 -0
- package/dist/types/TypedFunctionType.spec.d.ts +1 -0
- package/dist/types/TypedFunctionType.spec.js +37 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -0
- package/dist/types/UninitializedType.js +3 -3
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/VoidType.d.ts +4 -2
- package/dist/types/VoidType.js +8 -4
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/VoidType.spec.js +2 -2
- package/dist/types/VoidType.spec.js.map +1 -1
- package/dist/types/helpers.d.ts +42 -0
- package/dist/types/helpers.js +118 -0
- package/dist/types/helpers.js.map +1 -0
- package/dist/util.d.ts +91 -21
- package/dist/util.js +364 -114
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +19 -2
- package/dist/validators/ClassValidator.js +164 -103
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +30 -19
- package/dist/astUtils/index.d.ts +0 -7
- package/dist/astUtils/index.js +0 -26
- package/dist/astUtils/index.js.map +0 -1
- package/dist/lexer/index.d.ts +0 -3
- package/dist/lexer/index.js +0 -17
- package/dist/lexer/index.js.map +0 -1
- package/dist/parser/index.d.ts +0 -3
- package/dist/parser/index.js +0 -16
- package/dist/parser/index.js.map +0 -1
- package/dist/preprocessor/index.d.ts +0 -3
- package/dist/preprocessor/index.js +0 -16
- package/dist/preprocessor/index.js.map +0 -1
- package/dist/types/FunctionType.spec.js +0 -23
- package/dist/types/FunctionType.spec.js.map +0 -1
package/dist/files/BrsFile.js
CHANGED
|
@@ -6,10 +6,11 @@ const vscode_languageserver_1 = require("vscode-languageserver");
|
|
|
6
6
|
const chalk_1 = require("chalk");
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const DiagnosticMessages_1 = require("../DiagnosticMessages");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
9
|
+
const Token_1 = require("../lexer/Token");
|
|
10
|
+
const Lexer_1 = require("../lexer/Lexer");
|
|
11
|
+
const TokenKind_1 = require("../lexer/TokenKind");
|
|
12
|
+
const Parser_1 = require("../parser/Parser");
|
|
13
|
+
const DynamicType_1 = require("../types/DynamicType");
|
|
13
14
|
const util_1 = require("../util");
|
|
14
15
|
const BrsTranspileState_1 = require("../parser/BrsTranspileState");
|
|
15
16
|
const Preprocessor_1 = require("../preprocessor/Preprocessor");
|
|
@@ -18,6 +19,9 @@ const serialize_error_1 = require("serialize-error");
|
|
|
18
19
|
const reflection_1 = require("../astUtils/reflection");
|
|
19
20
|
const visitors_1 = require("../astUtils/visitors");
|
|
20
21
|
const CommentFlagProcessor_1 = require("../CommentFlagProcessor");
|
|
22
|
+
const BscType_1 = require("../types/BscType");
|
|
23
|
+
const UninitializedType_1 = require("../types/UninitializedType");
|
|
24
|
+
const InvalidType_1 = require("../types/InvalidType");
|
|
21
25
|
/**
|
|
22
26
|
* Holds all details about this file within the scope of the whole program
|
|
23
27
|
*/
|
|
@@ -31,37 +35,34 @@ class BrsFile {
|
|
|
31
35
|
* The full pkg path (i.e. `pkg:/path/to/file.brs`)
|
|
32
36
|
*/
|
|
33
37
|
pkgPath, program) {
|
|
34
|
-
var _a;
|
|
38
|
+
var _a, _b;
|
|
35
39
|
this.srcPath = srcPath;
|
|
36
40
|
this.pkgPath = pkgPath;
|
|
37
41
|
this.program = program;
|
|
38
42
|
/**
|
|
39
43
|
* The parseMode used for the parser for this file
|
|
40
44
|
*/
|
|
41
|
-
this.parseMode =
|
|
45
|
+
this.parseMode = Parser_1.ParseMode.BrightScript;
|
|
42
46
|
/**
|
|
43
47
|
* Indicates whether this file needs to be validated.
|
|
48
|
+
* Files are only ever validated a single time
|
|
44
49
|
*/
|
|
45
50
|
this.isValidated = false;
|
|
46
51
|
this.diagnostics = [];
|
|
47
52
|
this.commentFlags = [];
|
|
48
53
|
this.callables = [];
|
|
49
54
|
this.functionCalls = [];
|
|
50
|
-
/**
|
|
51
|
-
* files referenced by import statements
|
|
52
|
-
*/
|
|
53
|
-
this.ownScriptImports = [];
|
|
54
55
|
/**
|
|
55
56
|
* Does this file need to be transpiled?
|
|
56
57
|
*/
|
|
57
58
|
this.needsTranspiled = false;
|
|
58
|
-
this.srcPath = util_1.standardizePath `${this.srcPath}`;
|
|
59
|
+
this.srcPath = (0, util_1.standardizePath) `${this.srcPath}`;
|
|
59
60
|
this.dependencyGraphKey = this.pkgPath.toLowerCase();
|
|
60
61
|
this.extension = util_1.util.getExtension(this.srcPath);
|
|
61
62
|
//all BrighterScript files need to be transpiled
|
|
62
|
-
if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
|
|
63
|
+
if (((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) || ((_b = program === null || program === void 0 ? void 0 : program.options) === null || _b === void 0 ? void 0 : _b.allowBrighterScriptInBrightScript)) {
|
|
63
64
|
this.needsTranspiled = true;
|
|
64
|
-
this.parseMode =
|
|
65
|
+
this.parseMode = Parser_1.ParseMode.BrighterScript;
|
|
65
66
|
}
|
|
66
67
|
this.isTypedef = this.extension === '.d.bs';
|
|
67
68
|
if (!this.isTypedef) {
|
|
@@ -72,6 +73,16 @@ class BrsFile {
|
|
|
72
73
|
this.resolveTypedef();
|
|
73
74
|
}
|
|
74
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The absolute path to the source location for this file
|
|
78
|
+
* @deprecated use `srcPath` instead
|
|
79
|
+
*/
|
|
80
|
+
get pathAbsolute() {
|
|
81
|
+
return this.srcPath;
|
|
82
|
+
}
|
|
83
|
+
set pathAbsolute(value) {
|
|
84
|
+
this.srcPath = value;
|
|
85
|
+
}
|
|
75
86
|
getDiagnostics() {
|
|
76
87
|
return [...this.diagnostics];
|
|
77
88
|
}
|
|
@@ -79,21 +90,34 @@ class BrsFile {
|
|
|
79
90
|
this.diagnostics.push(...diagnostics);
|
|
80
91
|
}
|
|
81
92
|
/**
|
|
82
|
-
*
|
|
93
|
+
* files referenced by import statements
|
|
83
94
|
*/
|
|
84
|
-
get
|
|
85
|
-
|
|
95
|
+
get ownScriptImports() {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
98
|
+
const result = (_b = (_a = this._parser) === null || _a === void 0 ? void 0 : _a.references['cache'].getOrAdd('BrsFile_ownScriptImports', () => {
|
|
99
|
+
var _a, _b, _c, _d;
|
|
100
|
+
const result = [];
|
|
101
|
+
for (const statement of (_c = (_b = (_a = this.parser) === null || _a === void 0 ? void 0 : _a.references) === null || _b === void 0 ? void 0 : _b.importStatements) !== null && _c !== void 0 ? _c : []) {
|
|
102
|
+
//register import statements
|
|
103
|
+
if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
|
|
104
|
+
result.push({
|
|
105
|
+
filePathRange: statement.filePathToken.range,
|
|
106
|
+
pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
|
|
107
|
+
sourceFile: this,
|
|
108
|
+
text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
})) !== null && _b !== void 0 ? _b : [];
|
|
114
|
+
return result;
|
|
86
115
|
}
|
|
87
116
|
/**
|
|
88
|
-
*
|
|
89
|
-
* @param position
|
|
117
|
+
* The AST for this file
|
|
90
118
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (util_1.util.rangeContains(token.range, position)) {
|
|
94
|
-
return token;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
119
|
+
get ast() {
|
|
120
|
+
return this.parser.ast;
|
|
97
121
|
}
|
|
98
122
|
get parser() {
|
|
99
123
|
if (!this._parser) {
|
|
@@ -119,9 +143,8 @@ class BrsFile {
|
|
|
119
143
|
* Also notify the dependency graph of our current dependencies so other dependents can be notified.
|
|
120
144
|
*/
|
|
121
145
|
attachDependencyGraph(dependencyGraph) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
146
|
+
var _a;
|
|
147
|
+
(_a = this.unsubscribeFromDependencyGraph) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
125
148
|
//event that fires anytime a dependency changes
|
|
126
149
|
this.unsubscribeFromDependencyGraph = dependencyGraph.onchange(this.dependencyGraphKey, () => {
|
|
127
150
|
this.resolveTypedef();
|
|
@@ -133,6 +156,14 @@ class BrsFile {
|
|
|
133
156
|
}
|
|
134
157
|
dependencyGraph.addOrReplace(this.dependencyGraphKey, dependencies);
|
|
135
158
|
}
|
|
159
|
+
get logger() {
|
|
160
|
+
var _a;
|
|
161
|
+
const logger = (_a = this.program) === null || _a === void 0 ? void 0 : _a.logger;
|
|
162
|
+
if (!logger && !this._logger) {
|
|
163
|
+
this._logger = new Logger_1.Logger();
|
|
164
|
+
}
|
|
165
|
+
return logger !== null && logger !== void 0 ? logger : this._logger;
|
|
166
|
+
}
|
|
136
167
|
/**
|
|
137
168
|
* Calculate the AST for this file
|
|
138
169
|
* @param fileContents
|
|
@@ -143,11 +174,13 @@ class BrsFile {
|
|
|
143
174
|
this.diagnostics = [];
|
|
144
175
|
//if we have a typedef file, skip parsing this file
|
|
145
176
|
if (this.hasTypedef) {
|
|
177
|
+
//skip validation since the typedef is shadowing this file
|
|
178
|
+
this.isValidated = true;
|
|
146
179
|
return;
|
|
147
180
|
}
|
|
148
181
|
//tokenize the input file
|
|
149
|
-
let lexer = this.
|
|
150
|
-
return
|
|
182
|
+
let lexer = this.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
|
|
183
|
+
return Lexer_1.Lexer.scan(fileContents, {
|
|
151
184
|
includeWhitespace: false
|
|
152
185
|
});
|
|
153
186
|
});
|
|
@@ -157,7 +190,7 @@ class BrsFile {
|
|
|
157
190
|
//TODO preprocessor should go away in favor of the AST handling this internally (because it affects transpile)
|
|
158
191
|
//currently the preprocessor throws exceptions on syntax errors...so we need to catch it
|
|
159
192
|
try {
|
|
160
|
-
this.
|
|
193
|
+
this.logger.time(Logger_1.LogLevel.debug, ['preprocessor.process', chalk_1.default.green(this.srcPath)], () => {
|
|
161
194
|
preprocessor.process(lexer.tokens, this.program.getManifest());
|
|
162
195
|
});
|
|
163
196
|
}
|
|
@@ -169,10 +202,10 @@ class BrsFile {
|
|
|
169
202
|
}
|
|
170
203
|
//if the preprocessor generated tokens, use them.
|
|
171
204
|
let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
|
|
172
|
-
this.
|
|
173
|
-
this._parser =
|
|
205
|
+
this.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
|
|
206
|
+
this._parser = Parser_1.Parser.parse(tokens, {
|
|
174
207
|
mode: this.parseMode,
|
|
175
|
-
logger: this.
|
|
208
|
+
logger: this.logger
|
|
176
209
|
});
|
|
177
210
|
});
|
|
178
211
|
//absorb all lexing/preprocessing/parsing diagnostics
|
|
@@ -181,28 +214,31 @@ class BrsFile {
|
|
|
181
214
|
this.findCallables();
|
|
182
215
|
//find all places where a sub/function is being called
|
|
183
216
|
this.findFunctionCalls();
|
|
184
|
-
this.findAndValidateImportAndImportStatements();
|
|
185
217
|
//attach this file to every diagnostic
|
|
186
218
|
for (let diagnostic of this.diagnostics) {
|
|
187
219
|
diagnostic.file = this;
|
|
188
220
|
}
|
|
189
221
|
}
|
|
190
222
|
catch (e) {
|
|
191
|
-
this._parser = new
|
|
192
|
-
this.diagnostics.push(Object.assign({ file: this, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }, DiagnosticMessages_1.DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify(serialize_error_1.serializeError(e)))));
|
|
223
|
+
this._parser = new Parser_1.Parser();
|
|
224
|
+
this.diagnostics.push(Object.assign({ file: this, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }, DiagnosticMessages_1.DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify((0, serialize_error_1.serializeError)(e)))));
|
|
193
225
|
}
|
|
194
226
|
}
|
|
195
|
-
validate() {
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
validate() {
|
|
228
|
+
//only validate the file if it was actually parsed (skip files containing typedefs)
|
|
229
|
+
if (!this.hasTypedef) {
|
|
230
|
+
this.validateImportStatements();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
validateImportStatements() {
|
|
198
234
|
let topOfFileIncludeStatements = [];
|
|
199
235
|
for (let stmt of this.ast.statements) {
|
|
200
236
|
//skip comments
|
|
201
|
-
if (reflection_1.isCommentStatement(stmt)) {
|
|
237
|
+
if ((0, reflection_1.isCommentStatement)(stmt)) {
|
|
202
238
|
continue;
|
|
203
239
|
}
|
|
204
240
|
//if we found a non-library statement, this statement is not at the top of the file
|
|
205
|
-
if (reflection_1.isLibraryStatement(stmt) || reflection_1.isImportStatement(stmt)) {
|
|
241
|
+
if ((0, reflection_1.isLibraryStatement)(stmt) || (0, reflection_1.isImportStatement)(stmt)) {
|
|
206
242
|
topOfFileIncludeStatements.push(stmt);
|
|
207
243
|
}
|
|
208
244
|
else {
|
|
@@ -215,22 +251,13 @@ class BrsFile {
|
|
|
215
251
|
...this._parser.references.importStatements
|
|
216
252
|
];
|
|
217
253
|
for (let result of statements) {
|
|
218
|
-
//register import statements
|
|
219
|
-
if (reflection_1.isImportStatement(result) && result.filePathToken) {
|
|
220
|
-
this.ownScriptImports.push({
|
|
221
|
-
filePathRange: result.filePathToken.range,
|
|
222
|
-
pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, result.filePath),
|
|
223
|
-
sourceFile: this,
|
|
224
|
-
text: (_a = result.filePathToken) === null || _a === void 0 ? void 0 : _a.text
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
254
|
//if this statement is not one of the top-of-file statements,
|
|
228
255
|
//then add a diagnostic explaining that it is invalid
|
|
229
256
|
if (!topOfFileIncludeStatements.includes(result)) {
|
|
230
|
-
if (reflection_1.isLibraryStatement(result)) {
|
|
257
|
+
if ((0, reflection_1.isLibraryStatement)(result)) {
|
|
231
258
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.libraryStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
|
|
232
259
|
}
|
|
233
|
-
else if (reflection_1.isImportStatement(result)) {
|
|
260
|
+
else if ((0, reflection_1.isImportStatement)(result)) {
|
|
234
261
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()), { range: result.range, file: this }));
|
|
235
262
|
}
|
|
236
263
|
}
|
|
@@ -281,7 +308,7 @@ class BrsFile {
|
|
|
281
308
|
const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
|
|
282
309
|
this.commentFlags = [];
|
|
283
310
|
for (let token of tokens) {
|
|
284
|
-
if (token.kind ===
|
|
311
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
285
312
|
processor.tryAdd(token.text, token.range);
|
|
286
313
|
}
|
|
287
314
|
}
|
|
@@ -291,31 +318,14 @@ class BrsFile {
|
|
|
291
318
|
findCallables() {
|
|
292
319
|
var _a;
|
|
293
320
|
for (let statement of (_a = this.parser.references.functionStatements) !== null && _a !== void 0 ? _a : []) {
|
|
294
|
-
let functionType =
|
|
321
|
+
let functionType = statement.func.getFunctionType();
|
|
295
322
|
functionType.setName(statement.name.text);
|
|
296
|
-
functionType.isSub = statement.func.functionType.text.toLowerCase() === 'sub';
|
|
297
|
-
if (functionType.isSub) {
|
|
298
|
-
functionType.returnType = new VoidType_1.VoidType();
|
|
299
|
-
}
|
|
300
|
-
//extract the parameters
|
|
301
|
-
let params = [];
|
|
302
|
-
for (let param of statement.func.parameters) {
|
|
303
|
-
let callableParam = {
|
|
304
|
-
name: param.name.text,
|
|
305
|
-
type: param.type,
|
|
306
|
-
isOptional: !!param.defaultValue,
|
|
307
|
-
isRestArgument: false
|
|
308
|
-
};
|
|
309
|
-
params.push(callableParam);
|
|
310
|
-
let isRequired = !param.defaultValue;
|
|
311
|
-
functionType.addParameter(callableParam.name, callableParam.type, isRequired);
|
|
312
|
-
}
|
|
313
323
|
this.callables.push({
|
|
314
324
|
isSub: statement.func.functionType.text.toLowerCase() === 'sub',
|
|
315
325
|
name: statement.name.text,
|
|
316
326
|
nameRange: statement.name.range,
|
|
317
327
|
file: this,
|
|
318
|
-
params: params,
|
|
328
|
+
params: functionType.params,
|
|
319
329
|
range: statement.func.range,
|
|
320
330
|
type: functionType,
|
|
321
331
|
getName: statement.getName.bind(statement),
|
|
@@ -325,21 +335,24 @@ class BrsFile {
|
|
|
325
335
|
}
|
|
326
336
|
}
|
|
327
337
|
findFunctionCalls() {
|
|
338
|
+
var _a;
|
|
328
339
|
this.functionCalls = [];
|
|
329
340
|
//for every function in the file
|
|
330
341
|
for (let func of this._parser.references.functionExpressions) {
|
|
331
342
|
//for all function calls in this function
|
|
332
343
|
for (let expression of func.callExpressions) {
|
|
333
344
|
if (
|
|
334
|
-
//filter out
|
|
335
|
-
expression.callee.
|
|
336
|
-
//filter out method calls on
|
|
337
|
-
expression.callee.
|
|
345
|
+
//filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
|
|
346
|
+
expression.callee.callee ||
|
|
347
|
+
//filter out method calls on regexp literals for now
|
|
348
|
+
(0, reflection_1.isRegexLiteralExpression)((_a = expression.callee) === null || _a === void 0 ? void 0 : _a.obj) ||
|
|
338
349
|
//filter out callees without a name (immediately-invoked function expressions)
|
|
339
350
|
!expression.callee.name) {
|
|
340
351
|
continue;
|
|
341
352
|
}
|
|
342
|
-
|
|
353
|
+
//Flag dotted function invocations (i.e. object.doSomething())
|
|
354
|
+
const dottedInvocation = expression.callee.obj;
|
|
355
|
+
let functionName = expression.callee.name;
|
|
343
356
|
//callee is the name of the function being called
|
|
344
357
|
let callee = expression.callee;
|
|
345
358
|
let columnIndexBegin = callee.range.start.character;
|
|
@@ -347,7 +360,7 @@ class BrsFile {
|
|
|
347
360
|
let args = [];
|
|
348
361
|
//TODO convert if stmts to use instanceof instead
|
|
349
362
|
for (let arg of expression.args) {
|
|
350
|
-
let
|
|
363
|
+
let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
|
|
351
364
|
let argText = '';
|
|
352
365
|
// Get the text to display for the arg
|
|
353
366
|
if (arg.token) {
|
|
@@ -355,24 +368,28 @@ class BrsFile {
|
|
|
355
368
|
//is a function call being passed into argument
|
|
356
369
|
}
|
|
357
370
|
else if (arg.name) {
|
|
358
|
-
if (
|
|
371
|
+
if ((0, Token_1.isToken)(arg.name)) {
|
|
359
372
|
argText = arg.name.text;
|
|
360
373
|
}
|
|
361
374
|
}
|
|
362
375
|
else if (arg.value) {
|
|
363
376
|
/* istanbul ignore next: TODO figure out why value is undefined sometimes */
|
|
364
377
|
if (arg.value.value) {
|
|
365
|
-
|
|
378
|
+
if (arg.value.value.toString) {
|
|
379
|
+
argText = arg.value.value.toString();
|
|
380
|
+
}
|
|
366
381
|
}
|
|
367
382
|
//wrap the value in quotes because that's how it appears in the code
|
|
368
|
-
if (reflection_1.isStringType(
|
|
383
|
+
if (argText && (0, reflection_1.isStringType)(inferredType)) {
|
|
369
384
|
argText = '"' + argText + '"';
|
|
370
385
|
}
|
|
371
386
|
}
|
|
372
387
|
args.push({
|
|
373
388
|
range: arg.range,
|
|
374
|
-
type:
|
|
375
|
-
text: argText
|
|
389
|
+
type: inferredType,
|
|
390
|
+
text: argText,
|
|
391
|
+
expression: arg,
|
|
392
|
+
typeToken: undefined
|
|
376
393
|
});
|
|
377
394
|
}
|
|
378
395
|
let functionCall = {
|
|
@@ -381,8 +398,8 @@ class BrsFile {
|
|
|
381
398
|
file: this,
|
|
382
399
|
name: functionName,
|
|
383
400
|
nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
|
|
384
|
-
|
|
385
|
-
|
|
401
|
+
args: args,
|
|
402
|
+
isDottedInvocation: dottedInvocation
|
|
386
403
|
};
|
|
387
404
|
this.functionCalls.push(functionCall);
|
|
388
405
|
}
|
|
@@ -408,10 +425,25 @@ class BrsFile {
|
|
|
408
425
|
}
|
|
409
426
|
}
|
|
410
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Find the NamespaceStatement enclosing the given position
|
|
430
|
+
* @param position
|
|
431
|
+
* @param functionScopes
|
|
432
|
+
*/
|
|
433
|
+
getNamespaceStatementForPosition(position) {
|
|
434
|
+
if (position) {
|
|
435
|
+
for (const statement of this.parser.references.namespaceStatements) {
|
|
436
|
+
if (util_1.util.rangeContains(statement.range, position)) {
|
|
437
|
+
return statement;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
411
442
|
/**
|
|
412
443
|
* Get completions available at the given cursor. This aggregates all values from this file and the current scope.
|
|
413
444
|
*/
|
|
414
445
|
getCompletions(position, scope) {
|
|
446
|
+
var _a;
|
|
415
447
|
let result = [];
|
|
416
448
|
//a map of lower-case names of all added options
|
|
417
449
|
let names = {};
|
|
@@ -421,12 +453,12 @@ class BrsFile {
|
|
|
421
453
|
return this.program.getScriptImportCompletions(this.pkgPath, scriptImport);
|
|
422
454
|
}
|
|
423
455
|
//if cursor is within a comment, disable completions
|
|
424
|
-
let currentToken = this.getTokenAt(position);
|
|
456
|
+
let currentToken = this.parser.getTokenAt(position);
|
|
425
457
|
const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
|
|
426
|
-
if (tokenKind ===
|
|
458
|
+
if (tokenKind === TokenKind_1.TokenKind.Comment) {
|
|
427
459
|
return [];
|
|
428
460
|
}
|
|
429
|
-
else if (tokenKind ===
|
|
461
|
+
else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
|
|
430
462
|
const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
|
|
431
463
|
if (match) {
|
|
432
464
|
const [, openingQuote, fileProtocol] = match;
|
|
@@ -450,43 +482,56 @@ class BrsFile {
|
|
|
450
482
|
return [];
|
|
451
483
|
}
|
|
452
484
|
}
|
|
453
|
-
|
|
485
|
+
const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
|
|
454
486
|
if (namespaceCompletions.length > 0) {
|
|
455
|
-
return namespaceCompletions;
|
|
487
|
+
return [...namespaceCompletions];
|
|
488
|
+
}
|
|
489
|
+
const enumMemberCompletions = this.getEnumMemberStatementCompletions(currentToken, this.parseMode, scope);
|
|
490
|
+
if (enumMemberCompletions.length > 0) {
|
|
491
|
+
// no other completion is valid in this case
|
|
492
|
+
return enumMemberCompletions;
|
|
456
493
|
}
|
|
457
494
|
//determine if cursor is inside a function
|
|
458
495
|
let functionExpression = this.getFunctionExpressionAtPosition(position);
|
|
459
496
|
if (!functionExpression) {
|
|
460
497
|
//we aren't in any function scope, so return the keyword completions and namespaces
|
|
461
|
-
if (this.getTokenBefore(currentToken,
|
|
498
|
+
if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
|
|
462
499
|
// there's a new keyword, so only class types are viable here
|
|
463
|
-
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
|
|
500
|
+
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope)];
|
|
464
501
|
}
|
|
465
502
|
else {
|
|
466
|
-
return [
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
503
|
+
return [
|
|
504
|
+
...exports.KeywordCompletions,
|
|
505
|
+
...this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope),
|
|
506
|
+
...namespaceCompletions,
|
|
507
|
+
...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope),
|
|
508
|
+
...this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope)
|
|
509
|
+
];
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode, scope);
|
|
513
|
+
const interfaceNameCompletions = this.getGlobalInterfaceStatementCompletions(currentToken, this.parseMode, scope);
|
|
514
|
+
const newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
471
515
|
if (newToken) {
|
|
472
|
-
//we are after a new keyword; so we can only be namespaces or classes at this point
|
|
516
|
+
//we are after a new keyword; so we can only be top-level namespaces or classes at this point
|
|
473
517
|
result.push(...classNameCompletions);
|
|
474
518
|
result.push(...namespaceCompletions);
|
|
475
519
|
return result;
|
|
476
520
|
}
|
|
477
|
-
if (this.tokenFollows(currentToken,
|
|
521
|
+
if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
|
|
478
522
|
return this.getLabelCompletion(functionExpression);
|
|
479
523
|
}
|
|
480
|
-
if (this.isPositionNextToTokenKind(position,
|
|
481
|
-
if (namespaceCompletions.length > 0) {
|
|
482
|
-
//if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
|
|
483
|
-
return namespaceCompletions;
|
|
484
|
-
}
|
|
524
|
+
if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
|
|
485
525
|
const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
|
|
486
526
|
if (selfClassMemberCompletions.size > 0) {
|
|
487
527
|
return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
|
|
488
528
|
}
|
|
489
|
-
|
|
529
|
+
const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
|
|
530
|
+
if ((_a = tokenLookup.symbolContainer) === null || _a === void 0 ? void 0 : _a.memberTable) {
|
|
531
|
+
return this.getCompletionsFromSymbolTable(tokenLookup.symbolContainer.memberTable);
|
|
532
|
+
}
|
|
533
|
+
const foundClassLink = this.getClassFromTokenLookup(tokenLookup, scope);
|
|
534
|
+
if (!foundClassLink) {
|
|
490
535
|
//and anything from any class in scope to a non m class
|
|
491
536
|
let classMemberCompletions = scope.getAllClassMemberCompletions();
|
|
492
537
|
result.push(...classMemberCompletions.values());
|
|
@@ -501,6 +546,10 @@ class BrsFile {
|
|
|
501
546
|
result.push(...namespaceCompletions);
|
|
502
547
|
//include class names
|
|
503
548
|
result.push(...classNameCompletions);
|
|
549
|
+
//include interfaces
|
|
550
|
+
result.push(...interfaceNameCompletions);
|
|
551
|
+
//include enums
|
|
552
|
+
result.push(...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope));
|
|
504
553
|
//include the global callables
|
|
505
554
|
result.push(...scope.getCallablesAsCompletions(this.parseMode));
|
|
506
555
|
//add `m` because that's always valid within a function
|
|
@@ -511,22 +560,24 @@ class BrsFile {
|
|
|
511
560
|
names.m = true;
|
|
512
561
|
result.push(...exports.KeywordCompletions);
|
|
513
562
|
//include local variables
|
|
514
|
-
for (let symbol of functionExpression.symbolTable.
|
|
563
|
+
for (let symbol of functionExpression.symbolTable.getOwnSymbols()) {
|
|
515
564
|
const symbolNameLower = symbol.name.toLowerCase();
|
|
516
565
|
//skip duplicate variable names
|
|
517
566
|
if (names[symbolNameLower]) {
|
|
518
567
|
continue;
|
|
519
568
|
}
|
|
520
569
|
names[symbolNameLower] = true;
|
|
570
|
+
// TODO TYPES (This may be a performance hit?)
|
|
571
|
+
// const foundType = getTypeFromContext(symbol.type, { scope: scope, file: this });
|
|
521
572
|
result.push({
|
|
522
573
|
//TODO does this work?
|
|
523
574
|
label: symbol.name,
|
|
524
|
-
//TODO find type for local vars
|
|
575
|
+
//TODO TYPES find type for local vars - SEE above
|
|
525
576
|
kind: vscode_languageserver_1.CompletionItemKind.Variable
|
|
526
|
-
// kind: isFunctionType(
|
|
577
|
+
// kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
|
|
527
578
|
});
|
|
528
579
|
}
|
|
529
|
-
if (this.parseMode ===
|
|
580
|
+
if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
530
581
|
//include the first part of namespaces
|
|
531
582
|
let namespaces = scope.getAllNamespaceStatements();
|
|
532
583
|
for (let stmt of namespaces) {
|
|
@@ -545,6 +596,14 @@ class BrsFile {
|
|
|
545
596
|
}
|
|
546
597
|
return result;
|
|
547
598
|
}
|
|
599
|
+
getCompletionsFromSymbolTable(symbolTable) {
|
|
600
|
+
return symbolTable.getAllSymbols().map(bscType => {
|
|
601
|
+
return {
|
|
602
|
+
label: bscType.name,
|
|
603
|
+
kind: (0, reflection_1.isTypedFunctionType)(bscType.type) ? vscode_languageserver_1.CompletionItemKind.Method : vscode_languageserver_1.CompletionItemKind.Field
|
|
604
|
+
};
|
|
605
|
+
});
|
|
606
|
+
}
|
|
548
607
|
getLabelCompletion(func) {
|
|
549
608
|
return func.labelStatements.map(label => ({
|
|
550
609
|
label: label.tokens.identifier.text,
|
|
@@ -552,17 +611,17 @@ class BrsFile {
|
|
|
552
611
|
}));
|
|
553
612
|
}
|
|
554
613
|
getClassMemberCompletions(position, currentToken, functionExpression, scope) {
|
|
555
|
-
var _a, _b;
|
|
556
|
-
let classStatement = this.
|
|
614
|
+
var _a, _b, _c, _d;
|
|
615
|
+
let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
|
|
557
616
|
let results = new Map();
|
|
558
617
|
if (classStatement) {
|
|
559
|
-
let classes = scope.getClassHierarchy(classStatement.item.getName(
|
|
618
|
+
let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
560
619
|
for (let cs of classes) {
|
|
561
|
-
for (let member of [...(_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields, ...(
|
|
620
|
+
for (let member of [...(_b = (_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : [], ...(_d = (_c = cs === null || cs === void 0 ? void 0 : cs.item) === null || _c === void 0 ? void 0 : _c.methods) !== null && _d !== void 0 ? _d : []]) {
|
|
562
621
|
if (!results.has(member.name.text.toLowerCase())) {
|
|
563
622
|
results.set(member.name.text.toLowerCase(), {
|
|
564
623
|
label: member.name.text,
|
|
565
|
-
kind: reflection_1.
|
|
624
|
+
kind: (0, reflection_1.isFieldStatement)(member) ? vscode_languageserver_1.CompletionItemKind.Field : vscode_languageserver_1.CompletionItemKind.Method
|
|
566
625
|
});
|
|
567
626
|
}
|
|
568
627
|
}
|
|
@@ -570,69 +629,392 @@ class BrsFile {
|
|
|
570
629
|
}
|
|
571
630
|
return results;
|
|
572
631
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Gets the class (if any) of a given token based on the scope
|
|
634
|
+
* @param currentToken token in question
|
|
635
|
+
* @param functionExpression current functionExpression
|
|
636
|
+
* @param scope the current scope
|
|
637
|
+
* @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
|
|
638
|
+
*/
|
|
639
|
+
getClassFromToken(currentToken, functionExpression, scope) {
|
|
640
|
+
const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
|
|
641
|
+
return this.getClassFromTokenLookup(tokenLookup, scope);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Gets the class (if any) of a given token based on the scope
|
|
645
|
+
* @param currentToken token in question
|
|
646
|
+
* @param functionExpression current functionExpression
|
|
647
|
+
* @param scope the current scope
|
|
648
|
+
* @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
|
|
649
|
+
*/
|
|
650
|
+
getClassFromTokenLookup(tokenLookup, scope) {
|
|
651
|
+
const currentClass = tokenLookup === null || tokenLookup === void 0 ? void 0 : tokenLookup.symbolContainer;
|
|
652
|
+
if ((0, reflection_1.isClassStatement)(currentClass)) {
|
|
653
|
+
return { item: currentClass, file: this };
|
|
577
654
|
}
|
|
578
|
-
if ((
|
|
579
|
-
|
|
655
|
+
else if ((0, reflection_1.isCustomType)(currentClass)) {
|
|
656
|
+
const foundClass = scope.getClass(currentClass.name);
|
|
657
|
+
if (foundClass) {
|
|
658
|
+
return { item: foundClass, file: this };
|
|
659
|
+
}
|
|
580
660
|
}
|
|
581
661
|
return undefined;
|
|
582
662
|
}
|
|
583
|
-
|
|
663
|
+
findNamespaceFromTokenChain(originalTokenChain, scope) {
|
|
664
|
+
let namespaceTokens = [];
|
|
665
|
+
let startsWithNamespace = '';
|
|
666
|
+
let namespaceContainer;
|
|
667
|
+
let tokenChain = [...originalTokenChain];
|
|
668
|
+
while (tokenChain[0] && tokenChain[0].usage === Parser_1.TokenUsage.Direct) {
|
|
669
|
+
const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
|
|
670
|
+
const foundNamespace = scope.namespaceLookup.get(namespaceNameToCheck);
|
|
671
|
+
if (foundNamespace) {
|
|
672
|
+
namespaceContainer = foundNamespace;
|
|
673
|
+
namespaceTokens.push(tokenChain[0].token);
|
|
674
|
+
startsWithNamespace = namespaceTokens.map(token => token.text).join('.');
|
|
675
|
+
tokenChain.shift();
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (namespaceTokens.length > 0) {
|
|
682
|
+
namespaceContainer = scope.namespaceLookup.get(startsWithNamespace.toLowerCase());
|
|
683
|
+
}
|
|
684
|
+
return { namespaceContainer: namespaceContainer, tokenChain: tokenChain };
|
|
685
|
+
}
|
|
686
|
+
checkForSpecialClassSymbol(currentToken, scope, func) {
|
|
584
687
|
var _a;
|
|
585
|
-
|
|
688
|
+
const containingClass = this.parser.getContainingClass(currentToken);
|
|
689
|
+
let symbolType;
|
|
690
|
+
let currentClassRef;
|
|
691
|
+
const currentTokenLower = currentToken.text.toLowerCase();
|
|
692
|
+
const typeContext = { file: this, scope: scope, position: currentToken.range.start };
|
|
693
|
+
if (containingClass) {
|
|
694
|
+
// Special cases for a single token inside a class
|
|
695
|
+
let expandedText = '';
|
|
696
|
+
let useExpandedTextOnly = false;
|
|
697
|
+
if (containingClass.name === currentToken) {
|
|
698
|
+
symbolType = containingClass.getThisBscType();
|
|
699
|
+
expandedText = `class ${containingClass.getName(Parser_1.ParseMode.BrighterScript)}`;
|
|
700
|
+
useExpandedTextOnly = true;
|
|
701
|
+
currentClassRef = containingClass;
|
|
702
|
+
}
|
|
703
|
+
else if (currentTokenLower === 'm') {
|
|
704
|
+
symbolType = containingClass.getThisBscType();
|
|
705
|
+
expandedText = currentToken.text;
|
|
706
|
+
currentClassRef = containingClass;
|
|
707
|
+
}
|
|
708
|
+
else if (currentTokenLower === 'super') {
|
|
709
|
+
symbolType = (0, BscType_1.getTypeFromContext)(containingClass.symbolTable.getSymbolType(currentTokenLower, true, typeContext), typeContext);
|
|
710
|
+
if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
|
|
711
|
+
currentClassRef = scope.getParentClass(containingClass);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
else if (((_a = func === null || func === void 0 ? void 0 : func.functionStatement) === null || _a === void 0 ? void 0 : _a.name) === currentToken) {
|
|
715
|
+
// check if this is a method declaration
|
|
716
|
+
currentClassRef = containingClass;
|
|
717
|
+
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
718
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
719
|
+
}
|
|
720
|
+
else if (!func) {
|
|
721
|
+
// check if this is a field declaration
|
|
722
|
+
currentClassRef = containingClass;
|
|
723
|
+
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
724
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
725
|
+
}
|
|
726
|
+
if (symbolType) {
|
|
727
|
+
return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope) {
|
|
732
|
+
var _a;
|
|
733
|
+
const tokenChain = (_a = nameSpacedTokenChain.tokenChain) !== null && _a !== void 0 ? _a : [];
|
|
734
|
+
if (nameSpacedTokenChain.namespaceContainer && tokenChain.length === 0) {
|
|
735
|
+
//currentToken was part of a namespace
|
|
736
|
+
return {
|
|
737
|
+
type: null,
|
|
738
|
+
expandedTokenText: `namespace ${nameSpacedTokenChain.namespaceContainer.fullName}`,
|
|
739
|
+
useExpandedTextOnly: true
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
const specialCase = tokenChain.length === 1 ? this.checkForSpecialClassSymbol(tokenChain[0].token, scope, functionExpression) : null;
|
|
743
|
+
if (specialCase) {
|
|
744
|
+
return specialCase;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Checks previous tokens for the start of a symbol chain (eg. m.property.subProperty.method())
|
|
749
|
+
* @param currentToken The token to check
|
|
750
|
+
* @param functionExpression The current function context
|
|
751
|
+
* @param scope use this scope for finding class maps
|
|
752
|
+
* @returns the BscType, expanded text (e.g <Class.field>) and classStatement (if available) for the token
|
|
753
|
+
*/
|
|
754
|
+
getSymbolTypeFromToken(currentToken, functionExpression, scope) {
|
|
755
|
+
var _a, _b, _c, _d;
|
|
756
|
+
if (!scope || !currentToken) {
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
const cachedSymbolData = scope.symbolCache.get(currentToken);
|
|
760
|
+
if (cachedSymbolData) {
|
|
761
|
+
return cachedSymbolData;
|
|
762
|
+
}
|
|
763
|
+
const tokenChainResponse = this.parser.getTokenChain(currentToken);
|
|
764
|
+
if (tokenChainResponse.includesUnknowableTokenType) {
|
|
765
|
+
const symbolData = { type: new DynamicType_1.DynamicType(), expandedTokenText: currentToken.text };
|
|
766
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
767
|
+
return symbolData;
|
|
768
|
+
}
|
|
769
|
+
const nameSpacedTokenChain = this.findNamespaceFromTokenChain(tokenChainResponse.chain, scope);
|
|
770
|
+
const specialCase = this.checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope);
|
|
771
|
+
if (specialCase) {
|
|
772
|
+
scope.symbolCache.set(currentToken, specialCase);
|
|
773
|
+
return specialCase;
|
|
774
|
+
}
|
|
775
|
+
const tokenChain = nameSpacedTokenChain.tokenChain;
|
|
776
|
+
let symbolContainer = this.parser.getContainingAA(currentToken) || this.parser.getContainingClass(currentToken);
|
|
777
|
+
let currentSymbolTable = (_b = (_a = nameSpacedTokenChain.namespaceContainer) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : functionExpression === null || functionExpression === void 0 ? void 0 : functionExpression.symbolTable;
|
|
778
|
+
let tokenFoundCount = 0;
|
|
779
|
+
let symbolTypeBeforeReference;
|
|
780
|
+
let symbolType;
|
|
781
|
+
let tokenText = [];
|
|
782
|
+
let justReturnDynamic = false;
|
|
783
|
+
const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
|
|
784
|
+
for (const tokenChainMember of tokenChain) {
|
|
785
|
+
const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
|
|
786
|
+
const tokenUsage = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.usage;
|
|
787
|
+
const tokenLowerText = token.text.toLowerCase();
|
|
788
|
+
if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
|
|
789
|
+
/// Special cases for first item in chain inside a class
|
|
790
|
+
symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
|
|
791
|
+
currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
|
|
792
|
+
if (symbolContainer && currentSymbolTable) {
|
|
793
|
+
tokenText.push(symbolContainer.getName(Parser_1.ParseMode.BrighterScript));
|
|
794
|
+
tokenFoundCount++;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (!currentSymbolTable) {
|
|
799
|
+
// uh oh... no symbol table to continue to check
|
|
800
|
+
break;
|
|
801
|
+
}
|
|
802
|
+
symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
|
|
803
|
+
if (tokenFoundCount === 0 && !symbolType) {
|
|
804
|
+
//check for global callable
|
|
805
|
+
symbolType = (_d = scope.getGlobalCallableByName(tokenLowerText)) === null || _d === void 0 ? void 0 : _d.type;
|
|
806
|
+
}
|
|
807
|
+
if (symbolType) {
|
|
808
|
+
// found this symbol, and it's valid. increase found counter
|
|
809
|
+
tokenFoundCount++;
|
|
810
|
+
}
|
|
811
|
+
symbolTypeBeforeReference = symbolType;
|
|
812
|
+
if ((0, reflection_1.isTypedFunctionType)(symbolType)) {
|
|
813
|
+
// this is a function, and it is in the start or middle of the chain
|
|
814
|
+
// the next symbol to check will be the return value of this function
|
|
815
|
+
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
|
|
816
|
+
if (tokenFoundCount < tokenChain.length) {
|
|
817
|
+
// We still have more tokens, but remember the last known reference
|
|
818
|
+
symbolTypeBeforeReference = symbolType;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if ((0, reflection_1.isArrayType)(symbolType) && tokenUsage === Parser_1.TokenUsage.ArrayReference) {
|
|
822
|
+
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.getDefaultType(typeContext), typeContext);
|
|
823
|
+
}
|
|
824
|
+
if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
|
|
825
|
+
if ((0, reflection_1.isCustomType)(symbolType) || (0, reflection_1.isInterfaceType)(symbolType) || (0, reflection_1.isEnumType)(symbolType)) {
|
|
826
|
+
// we're currently looking at a type that has its own symbol table
|
|
827
|
+
// use the name of the custom type
|
|
828
|
+
// TODO TYPES: get proper parent name for methods/fields defined in super classes
|
|
829
|
+
tokenText.push(tokenChain.length === 1 ? token.text : symbolType.name);
|
|
830
|
+
}
|
|
831
|
+
else {
|
|
832
|
+
justReturnDynamic = true;
|
|
833
|
+
tokenText.push(token.text);
|
|
834
|
+
}
|
|
835
|
+
symbolContainer = symbolType;
|
|
836
|
+
currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
|
|
837
|
+
}
|
|
838
|
+
else if ((0, reflection_1.isObjectType)(symbolType) || (0, reflection_1.isArrayType)(symbolType) || (0, reflection_1.isDynamicType)(symbolType)) {
|
|
839
|
+
// this is an object that has no member table
|
|
840
|
+
// this could happen if a parameter is marked as object
|
|
841
|
+
// assume all fields are dynamic
|
|
842
|
+
symbolContainer = undefined;
|
|
843
|
+
tokenText.push(token.text);
|
|
844
|
+
justReturnDynamic = true;
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
// No further symbol tables were found
|
|
849
|
+
symbolContainer = undefined;
|
|
850
|
+
tokenText.push(token.text);
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (tokenText.length > 2) {
|
|
855
|
+
// TokenText is used for hovers. We only need the last two tokens for a hover
|
|
856
|
+
// So in a long chain (e.g. klass.getData()[0].anotherKlass.property), the hover
|
|
857
|
+
// for the last token should just be "AnotherKlass.property", not the whole chain
|
|
858
|
+
tokenText = tokenText.slice(-2);
|
|
859
|
+
}
|
|
860
|
+
let expandedTokenText = tokenText.join('.');
|
|
861
|
+
let backUpReturnType;
|
|
862
|
+
if (tokenFoundCount === tokenChain.length) {
|
|
863
|
+
// did we complete the chain? if so, we have a valid token at the end
|
|
864
|
+
const symbolData = { type: symbolTypeBeforeReference, expandedTokenText: tokenText.join('.'), symbolContainer: symbolContainer };
|
|
865
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
866
|
+
return symbolData;
|
|
867
|
+
}
|
|
868
|
+
if ((0, reflection_1.isDynamicType)(symbolTypeBeforeReference) || (0, reflection_1.isArrayType)(symbolTypeBeforeReference) || justReturnDynamic) {
|
|
869
|
+
// last type in chain is dynamic... so currentToken could be anything.
|
|
870
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
871
|
+
expandedTokenText = currentToken.text;
|
|
872
|
+
}
|
|
873
|
+
else if ((0, reflection_1.isPrimitiveType)(symbolTypeBeforeReference)) {
|
|
874
|
+
// last type in chain is dynamic... so currentToken could be anything.
|
|
875
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
876
|
+
expandedTokenText = currentToken.text;
|
|
877
|
+
}
|
|
878
|
+
else if (tokenChain.length === 1) {
|
|
879
|
+
// variable that has not been assigned
|
|
880
|
+
expandedTokenText = currentToken.text;
|
|
881
|
+
backUpReturnType = new UninitializedType_1.UninitializedType();
|
|
882
|
+
}
|
|
883
|
+
else if (tokenFoundCount === tokenChain.length - 1) {
|
|
884
|
+
// member field that is not known
|
|
885
|
+
if (symbolContainer) {
|
|
886
|
+
backUpReturnType = new InvalidType_1.InvalidType();
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
// TODO TYPES: once we have stricter object/node member type checking, we could say this is invalid, but until then, call it dynamic
|
|
890
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
891
|
+
expandedTokenText = currentToken.text;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
const symbolData = { type: backUpReturnType, expandedTokenText: expandedTokenText };
|
|
895
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
896
|
+
return symbolData;
|
|
897
|
+
}
|
|
898
|
+
getGlobalClassStatementCompletions(currentToken, parseMode, scope) {
|
|
899
|
+
var _a;
|
|
900
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
586
901
|
return [];
|
|
587
902
|
}
|
|
588
903
|
let results = new Map();
|
|
589
|
-
let completionName = (_a = this.getPartialVariableName(currentToken, [
|
|
904
|
+
let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
590
905
|
if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
|
|
591
906
|
return [];
|
|
592
907
|
}
|
|
593
|
-
let
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
908
|
+
let classMap = scope.getClassMap();
|
|
909
|
+
// let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
|
|
910
|
+
for (const key of [...classMap.keys()]) {
|
|
911
|
+
let cs = classMap.get(key).item;
|
|
912
|
+
if (!results.has(cs.name.text)) {
|
|
913
|
+
results.set(cs.name.text, {
|
|
914
|
+
label: cs.name.text,
|
|
915
|
+
kind: vscode_languageserver_1.CompletionItemKind.Class
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return [...results.values()];
|
|
920
|
+
}
|
|
921
|
+
getNonNamespacedEnumStatementCompletions(currentToken, parseMode, scope) {
|
|
922
|
+
var _a, _b;
|
|
923
|
+
if (parseMode !== Parser_1.ParseMode.BrighterScript) {
|
|
924
|
+
return [];
|
|
925
|
+
}
|
|
926
|
+
const containingNamespaceName = ((_b = this.getNamespaceStatementForPosition((_a = currentToken === null || currentToken === void 0 ? void 0 : currentToken.range) === null || _a === void 0 ? void 0 : _a.start)) === null || _b === void 0 ? void 0 : _b.name) + '.';
|
|
927
|
+
const results = new Map();
|
|
928
|
+
const enumMap = scope.getEnumMap();
|
|
929
|
+
for (const key of [...enumMap.keys()]) {
|
|
930
|
+
const enumStatement = enumMap.get(key).item;
|
|
931
|
+
const fullName = enumStatement.fullName;
|
|
932
|
+
//if the enum is contained within our own namespace, or if it's a non-namespaced enum
|
|
933
|
+
if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
|
|
934
|
+
results.set(fullName, {
|
|
935
|
+
label: enumStatement.name,
|
|
936
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return [...results.values()];
|
|
941
|
+
}
|
|
942
|
+
getEnumMemberStatementCompletions(currentToken, parseMode, scope) {
|
|
943
|
+
var _a, _b, _c, _d, _e;
|
|
944
|
+
if (parseMode === Parser_1.ParseMode.BrightScript || !currentToken) {
|
|
945
|
+
return [];
|
|
946
|
+
}
|
|
947
|
+
const results = new Map();
|
|
948
|
+
const completionName = (_a = this.getPartialVariableName(currentToken)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
949
|
+
//if we don't have a completion name, or if there's no period in the name, then this is not to the right of an enum name
|
|
950
|
+
if (!completionName || !completionName.includes('.')) {
|
|
951
|
+
return [];
|
|
952
|
+
}
|
|
953
|
+
const enumNameLower = (_b = completionName === null || completionName === void 0 ? void 0 : completionName.split(/\.(\w+)?$/)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
954
|
+
const namespaceNameLower = (_c = this.getNamespaceStatementForPosition(currentToken.range.end)) === null || _c === void 0 ? void 0 : _c.name.toLowerCase();
|
|
955
|
+
const enumMap = scope.getEnumMap();
|
|
956
|
+
//get the enum statement with this name (check without namespace prefix first, then with inferred namespace prefix next)
|
|
957
|
+
const enumStatement = (_e = ((_d = enumMap.get(enumNameLower)) !== null && _d !== void 0 ? _d : enumMap.get(namespaceNameLower + '.' + enumNameLower))) === null || _e === void 0 ? void 0 : _e.item;
|
|
958
|
+
//if we found an enum with this name
|
|
959
|
+
if (enumStatement) {
|
|
960
|
+
for (const member of enumStatement.getMembers()) {
|
|
961
|
+
const name = enumStatement.fullName + '.' + member.name;
|
|
962
|
+
const nameLower = name.toLowerCase();
|
|
963
|
+
results.set(nameLower, {
|
|
964
|
+
label: member.name,
|
|
965
|
+
kind: vscode_languageserver_1.CompletionItemKind.EnumMember
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return [...results.values()];
|
|
970
|
+
}
|
|
971
|
+
getGlobalInterfaceStatementCompletions(currentToken, parseMode, scope) {
|
|
972
|
+
var _a;
|
|
973
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
974
|
+
return [];
|
|
975
|
+
}
|
|
976
|
+
let results = new Map();
|
|
977
|
+
let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
978
|
+
if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
|
|
979
|
+
return [];
|
|
980
|
+
}
|
|
981
|
+
let ifaceMap = scope.getInterfaceMap();
|
|
982
|
+
for (const key of [...ifaceMap.keys()]) {
|
|
983
|
+
let cs = ifaceMap.get(key).item;
|
|
984
|
+
if (!results.has(cs.name.text)) {
|
|
985
|
+
results.set(cs.name.text, {
|
|
986
|
+
label: cs.name.text,
|
|
987
|
+
kind: vscode_languageserver_1.CompletionItemKind.Interface
|
|
988
|
+
});
|
|
605
989
|
}
|
|
606
990
|
}
|
|
607
991
|
return [...results.values()];
|
|
608
992
|
}
|
|
609
993
|
getNamespaceCompletions(currentToken, parseMode, scope) {
|
|
610
994
|
//BrightScript does not support namespaces, so return an empty list in that case
|
|
611
|
-
if (parseMode ===
|
|
995
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
612
996
|
return [];
|
|
613
997
|
}
|
|
614
|
-
|
|
615
|
-
if
|
|
998
|
+
const completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
|
|
999
|
+
//if we don't have a completion name, or if there's no period in the name, then this is not a namespaced variable
|
|
1000
|
+
if (!completionName || !completionName.includes('.')) {
|
|
616
1001
|
return [];
|
|
617
1002
|
}
|
|
618
1003
|
//remove any trailing identifer and then any trailing dot, to give us the
|
|
619
1004
|
//name of its immediate parent namespace
|
|
620
|
-
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
|
|
621
|
-
let newToken = this.getTokenBefore(currentToken,
|
|
622
|
-
let namespaceLookup = scope.namespaceLookup;
|
|
1005
|
+
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
|
|
1006
|
+
let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
623
1007
|
let result = new Map();
|
|
624
|
-
for (let
|
|
625
|
-
let namespace = namespaceLookup[key.toLowerCase()];
|
|
1008
|
+
for (let [, namespace] of scope.namespaceLookup) {
|
|
626
1009
|
//completionName = "NameA."
|
|
627
1010
|
//completionName = "NameA.Na
|
|
628
1011
|
//NameA
|
|
629
1012
|
//NameA.NameB
|
|
630
1013
|
//NameA.NameB.NameC
|
|
631
|
-
if (namespace.fullName.toLowerCase() === closestParentNamespaceName
|
|
1014
|
+
if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
|
|
632
1015
|
//add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
|
|
633
|
-
for (let
|
|
634
|
-
|
|
635
|
-
if (!newToken || ns.statements.find((s) => reflection_1.isClassStatement(s))) {
|
|
1016
|
+
for (let [, ns] of namespace.namespaces) {
|
|
1017
|
+
if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
|
|
636
1018
|
if (!result.has(ns.lastPartName)) {
|
|
637
1019
|
result.set(ns.lastPartName, {
|
|
638
1020
|
label: ns.lastPartName,
|
|
@@ -643,21 +1025,23 @@ class BrsFile {
|
|
|
643
1025
|
}
|
|
644
1026
|
//add function and class statement completions
|
|
645
1027
|
for (let stmt of namespace.statements) {
|
|
646
|
-
if (reflection_1.isClassStatement(stmt)) {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
});
|
|
652
|
-
}
|
|
1028
|
+
if ((0, reflection_1.isClassStatement)(stmt)) {
|
|
1029
|
+
result.set(stmt.name.text, {
|
|
1030
|
+
label: stmt.name.text,
|
|
1031
|
+
kind: vscode_languageserver_1.CompletionItemKind.Class
|
|
1032
|
+
});
|
|
653
1033
|
}
|
|
654
|
-
else if (reflection_1.isFunctionStatement(stmt) && !newToken) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
1034
|
+
else if ((0, reflection_1.isFunctionStatement)(stmt) && !newToken) {
|
|
1035
|
+
result.set(stmt.name.text, {
|
|
1036
|
+
label: stmt.name.text,
|
|
1037
|
+
kind: vscode_languageserver_1.CompletionItemKind.Function
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
else if ((0, reflection_1.isEnumStatement)(stmt) && !newToken) {
|
|
1041
|
+
result.set(stmt.name, {
|
|
1042
|
+
label: stmt.name,
|
|
1043
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
1044
|
+
});
|
|
661
1045
|
}
|
|
662
1046
|
}
|
|
663
1047
|
}
|
|
@@ -670,18 +1054,18 @@ class BrsFile {
|
|
|
670
1054
|
return undefined;
|
|
671
1055
|
}
|
|
672
1056
|
let location;
|
|
673
|
-
const nameParts = this.getPartialVariableName(token, [
|
|
1057
|
+
const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
|
|
674
1058
|
const endName = nameParts[nameParts.length - 1].toLowerCase();
|
|
675
1059
|
const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
|
|
676
1060
|
const statementHandler = (statement) => {
|
|
677
|
-
if (!location && statement.getName(
|
|
1061
|
+
if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
|
|
678
1062
|
const namespaceItemStatementHandler = (statement) => {
|
|
679
1063
|
if (!location && statement.name.text.toLowerCase() === endName) {
|
|
680
1064
|
const uri = util_1.util.pathToUri(file.srcPath);
|
|
681
1065
|
location = vscode_languageserver_1.Location.create(uri, statement.range);
|
|
682
1066
|
}
|
|
683
1067
|
};
|
|
684
|
-
file.parser.ast.walk(visitors_1.createVisitor({
|
|
1068
|
+
file.parser.ast.walk((0, visitors_1.createVisitor)({
|
|
685
1069
|
ClassStatement: namespaceItemStatementHandler,
|
|
686
1070
|
FunctionStatement: namespaceItemStatementHandler
|
|
687
1071
|
}), {
|
|
@@ -689,7 +1073,7 @@ class BrsFile {
|
|
|
689
1073
|
});
|
|
690
1074
|
}
|
|
691
1075
|
};
|
|
692
|
-
file.parser.ast.walk(visitors_1.createVisitor({
|
|
1076
|
+
file.parser.ast.walk((0, visitors_1.createVisitor)({
|
|
693
1077
|
NamespaceStatement: statementHandler
|
|
694
1078
|
}), {
|
|
695
1079
|
walkMode: visitors_1.WalkMode.visitStatements
|
|
@@ -700,7 +1084,7 @@ class BrsFile {
|
|
|
700
1084
|
* Given a current token, walk
|
|
701
1085
|
*/
|
|
702
1086
|
getPartialVariableName(currentToken, excludeTokens = null) {
|
|
703
|
-
let identifierAndDotKinds = [
|
|
1087
|
+
let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
|
|
704
1088
|
//consume tokens backwards until we find something other than a dot or an identifier
|
|
705
1089
|
let tokens = [];
|
|
706
1090
|
const parser = this.parser;
|
|
@@ -721,79 +1105,21 @@ class BrsFile {
|
|
|
721
1105
|
return undefined;
|
|
722
1106
|
}
|
|
723
1107
|
}
|
|
724
|
-
isPositionNextToTokenKind(position, tokenKind) {
|
|
725
|
-
const closestToken = this.getClosestToken(position);
|
|
726
|
-
const previousToken = this.getPreviousToken(closestToken);
|
|
727
|
-
const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
|
|
728
|
-
//next to matched token
|
|
729
|
-
if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
|
|
730
|
-
return false;
|
|
731
|
-
}
|
|
732
|
-
else if (closestToken.kind === tokenKind) {
|
|
733
|
-
return true;
|
|
734
|
-
}
|
|
735
|
-
else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
|
|
736
|
-
return false;
|
|
737
|
-
//next to an identifier, which is next to token kind
|
|
738
|
-
}
|
|
739
|
-
else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
|
|
740
|
-
return true;
|
|
741
|
-
}
|
|
742
|
-
else {
|
|
743
|
-
return false;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
getTokenBefore(currentToken, tokenKind) {
|
|
747
|
-
const index = this.parser.tokens.indexOf(currentToken);
|
|
748
|
-
for (let i = index - 1; i >= 0; i--) {
|
|
749
|
-
currentToken = this.parser.tokens[i];
|
|
750
|
-
if (currentToken.kind === lexer_1.TokenKind.Newline) {
|
|
751
|
-
break;
|
|
752
|
-
}
|
|
753
|
-
else if (currentToken.kind === tokenKind) {
|
|
754
|
-
return currentToken;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
return undefined;
|
|
758
|
-
}
|
|
759
|
-
tokenFollows(currentToken, tokenKind) {
|
|
760
|
-
const index = this.parser.tokens.indexOf(currentToken);
|
|
761
|
-
if (index > 0) {
|
|
762
|
-
return this.parser.tokens[index - 1].kind === tokenKind;
|
|
763
|
-
}
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
766
|
-
getTokensUntil(currentToken, tokenKind, direction = -1) {
|
|
767
|
-
let tokens = [];
|
|
768
|
-
for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
|
|
769
|
-
currentToken = this.parser.tokens[i];
|
|
770
|
-
if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
|
|
771
|
-
break;
|
|
772
|
-
}
|
|
773
|
-
tokens.push(currentToken);
|
|
774
|
-
}
|
|
775
|
-
return tokens;
|
|
776
|
-
}
|
|
777
|
-
getPreviousToken(token) {
|
|
778
|
-
const parser = this.parser;
|
|
779
|
-
let idx = parser.tokens.indexOf(token);
|
|
780
|
-
return parser.tokens[idx - 1];
|
|
781
|
-
}
|
|
782
1108
|
/**
|
|
783
1109
|
* Find the first scope that has a namespace with this name.
|
|
784
1110
|
* Returns false if no namespace was found with that name
|
|
785
1111
|
*/
|
|
786
1112
|
calleeStartsWithNamespace(callee) {
|
|
787
1113
|
let left = callee;
|
|
788
|
-
while (reflection_1.isDottedGetExpression(left)) {
|
|
1114
|
+
while ((0, reflection_1.isDottedGetExpression)(left)) {
|
|
789
1115
|
left = left.obj;
|
|
790
1116
|
}
|
|
791
|
-
if (reflection_1.isVariableExpression(left)) {
|
|
1117
|
+
if ((0, reflection_1.isVariableExpression)(left)) {
|
|
792
1118
|
let lowerName = left.name.text.toLowerCase();
|
|
793
1119
|
//find the first scope that contains this namespace
|
|
794
1120
|
let scopes = this.program.getScopesForFile(this);
|
|
795
1121
|
for (let scope of scopes) {
|
|
796
|
-
if (scope.namespaceLookup
|
|
1122
|
+
if (scope.namespaceLookup.has(lowerName)) {
|
|
797
1123
|
return true;
|
|
798
1124
|
}
|
|
799
1125
|
}
|
|
@@ -806,12 +1132,12 @@ class BrsFile {
|
|
|
806
1132
|
calleeIsKnownNamespaceFunction(callee, namespaceName) {
|
|
807
1133
|
var _a, _b;
|
|
808
1134
|
//if we have a variable and a namespace
|
|
809
|
-
if (reflection_1.isVariableExpression(callee) && namespaceName) {
|
|
1135
|
+
if ((0, reflection_1.isVariableExpression)(callee) && namespaceName) {
|
|
810
1136
|
let lowerCalleeName = (_b = (_a = callee === null || callee === void 0 ? void 0 : callee.name) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
811
1137
|
if (lowerCalleeName) {
|
|
812
1138
|
let scopes = this.program.getScopesForFile(this);
|
|
813
1139
|
for (let scope of scopes) {
|
|
814
|
-
let namespace = scope.namespaceLookup
|
|
1140
|
+
let namespace = scope.namespaceLookup.get(namespaceName.toLowerCase());
|
|
815
1141
|
if (namespace.functionStatements[lowerCalleeName]) {
|
|
816
1142
|
return true;
|
|
817
1143
|
}
|
|
@@ -820,28 +1146,6 @@ class BrsFile {
|
|
|
820
1146
|
}
|
|
821
1147
|
return false;
|
|
822
1148
|
}
|
|
823
|
-
/**
|
|
824
|
-
* Get the token closest to the position. if no token is found, the previous token is returned
|
|
825
|
-
* @param position
|
|
826
|
-
* @param tokens
|
|
827
|
-
*/
|
|
828
|
-
getClosestToken(position) {
|
|
829
|
-
let tokens = this.parser.tokens;
|
|
830
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
831
|
-
let token = tokens[i];
|
|
832
|
-
if (util_1.util.rangeContains(token.range, position)) {
|
|
833
|
-
return token;
|
|
834
|
-
}
|
|
835
|
-
//if the position less than this token range, then this position touches no token,
|
|
836
|
-
if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
|
|
837
|
-
let t = tokens[i - 1];
|
|
838
|
-
//return the token or the first token
|
|
839
|
-
return t ? t : tokens[0];
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
//return the last token
|
|
843
|
-
return tokens[tokens.length - 1];
|
|
844
|
-
}
|
|
845
1149
|
/**
|
|
846
1150
|
* Builds a list of document symbols for this file. Used by LanguageServer's onDocumentSymbol functionality
|
|
847
1151
|
*/
|
|
@@ -881,16 +1185,16 @@ class BrsFile {
|
|
|
881
1185
|
getDocumentSymbol(statement) {
|
|
882
1186
|
let symbolKind;
|
|
883
1187
|
const children = [];
|
|
884
|
-
if (reflection_1.isFunctionStatement(statement)) {
|
|
1188
|
+
if ((0, reflection_1.isFunctionStatement)(statement)) {
|
|
885
1189
|
symbolKind = vscode_languageserver_1.SymbolKind.Function;
|
|
886
1190
|
}
|
|
887
|
-
else if (reflection_1.
|
|
1191
|
+
else if ((0, reflection_1.isMethodStatement)(statement)) {
|
|
888
1192
|
symbolKind = vscode_languageserver_1.SymbolKind.Method;
|
|
889
1193
|
}
|
|
890
|
-
else if (reflection_1.
|
|
1194
|
+
else if ((0, reflection_1.isFieldStatement)(statement)) {
|
|
891
1195
|
symbolKind = vscode_languageserver_1.SymbolKind.Field;
|
|
892
1196
|
}
|
|
893
|
-
else if (reflection_1.isNamespaceStatement(statement)) {
|
|
1197
|
+
else if ((0, reflection_1.isNamespaceStatement)(statement)) {
|
|
894
1198
|
symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
|
|
895
1199
|
for (const childStatement of statement.body.statements) {
|
|
896
1200
|
const symbol = this.getDocumentSymbol(childStatement);
|
|
@@ -899,7 +1203,7 @@ class BrsFile {
|
|
|
899
1203
|
}
|
|
900
1204
|
}
|
|
901
1205
|
}
|
|
902
|
-
else if (reflection_1.isClassStatement(statement)) {
|
|
1206
|
+
else if ((0, reflection_1.isClassStatement)(statement)) {
|
|
903
1207
|
symbolKind = vscode_languageserver_1.SymbolKind.Class;
|
|
904
1208
|
for (const childStatement of statement.body) {
|
|
905
1209
|
const symbol = this.getDocumentSymbol(childStatement);
|
|
@@ -911,7 +1215,7 @@ class BrsFile {
|
|
|
911
1215
|
else {
|
|
912
1216
|
return;
|
|
913
1217
|
}
|
|
914
|
-
const name = reflection_1.
|
|
1218
|
+
const name = (0, reflection_1.isFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
915
1219
|
return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
|
|
916
1220
|
}
|
|
917
1221
|
/**
|
|
@@ -920,13 +1224,13 @@ class BrsFile {
|
|
|
920
1224
|
generateWorkspaceSymbols(statement, containerStatement) {
|
|
921
1225
|
let symbolKind;
|
|
922
1226
|
const symbols = [];
|
|
923
|
-
if (reflection_1.isFunctionStatement(statement)) {
|
|
1227
|
+
if ((0, reflection_1.isFunctionStatement)(statement)) {
|
|
924
1228
|
symbolKind = vscode_languageserver_1.SymbolKind.Function;
|
|
925
1229
|
}
|
|
926
|
-
else if (reflection_1.
|
|
1230
|
+
else if ((0, reflection_1.isMethodStatement)(statement)) {
|
|
927
1231
|
symbolKind = vscode_languageserver_1.SymbolKind.Method;
|
|
928
1232
|
}
|
|
929
|
-
else if (reflection_1.isNamespaceStatement(statement)) {
|
|
1233
|
+
else if ((0, reflection_1.isNamespaceStatement)(statement)) {
|
|
930
1234
|
symbolKind = vscode_languageserver_1.SymbolKind.Namespace;
|
|
931
1235
|
for (const childStatement of statement.body.statements) {
|
|
932
1236
|
for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
|
|
@@ -934,7 +1238,7 @@ class BrsFile {
|
|
|
934
1238
|
}
|
|
935
1239
|
}
|
|
936
1240
|
}
|
|
937
|
-
else if (reflection_1.isClassStatement(statement)) {
|
|
1241
|
+
else if ((0, reflection_1.isClassStatement)(statement)) {
|
|
938
1242
|
symbolKind = vscode_languageserver_1.SymbolKind.Class;
|
|
939
1243
|
for (const childStatement of statement.body) {
|
|
940
1244
|
for (const symbol of this.generateWorkspaceSymbols(childStatement, statement)) {
|
|
@@ -945,9 +1249,9 @@ class BrsFile {
|
|
|
945
1249
|
else {
|
|
946
1250
|
return symbols;
|
|
947
1251
|
}
|
|
948
|
-
const name = statement.getName(
|
|
1252
|
+
const name = statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
949
1253
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
950
|
-
const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(
|
|
1254
|
+
const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(Parser_1.ParseMode.BrighterScript));
|
|
951
1255
|
symbols.push(symbol);
|
|
952
1256
|
return symbols;
|
|
953
1257
|
}
|
|
@@ -958,19 +1262,19 @@ class BrsFile {
|
|
|
958
1262
|
getDefinition(position) {
|
|
959
1263
|
let results = [];
|
|
960
1264
|
//get the token at the position
|
|
961
|
-
const token = this.getTokenAt(position);
|
|
1265
|
+
const token = this.parser.getTokenAt(position);
|
|
962
1266
|
// While certain other tokens are allowed as local variables (AllowedLocalIdentifiers: https://github.com/rokucommunity/brighterscript/blob/master/src/lexer/TokenKind.ts#L418), these are converted by the parser to TokenKind.Identifier by the time we retrieve the token using getTokenAt
|
|
963
1267
|
let definitionTokenTypes = [
|
|
964
|
-
|
|
965
|
-
|
|
1268
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1269
|
+
TokenKind_1.TokenKind.StringLiteral
|
|
966
1270
|
];
|
|
967
1271
|
//throw out invalid tokens and the wrong kind of tokens
|
|
968
1272
|
if (!token || !definitionTokenTypes.includes(token.kind)) {
|
|
969
1273
|
return results;
|
|
970
1274
|
}
|
|
971
1275
|
let textToSearchFor = token.text.toLowerCase();
|
|
972
|
-
const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
973
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1276
|
+
const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
1277
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
|
|
974
1278
|
for (const scope of this.program.getScopes()) {
|
|
975
1279
|
//to only get functions defined in interface methods
|
|
976
1280
|
const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
|
|
@@ -980,7 +1284,7 @@ class BrsFile {
|
|
|
980
1284
|
}
|
|
981
1285
|
return results;
|
|
982
1286
|
}
|
|
983
|
-
let classToken = this.getTokenBefore(token,
|
|
1287
|
+
let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
|
|
984
1288
|
if (classToken) {
|
|
985
1289
|
let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
|
|
986
1290
|
if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
|
|
@@ -992,7 +1296,7 @@ class BrsFile {
|
|
|
992
1296
|
}
|
|
993
1297
|
return results;
|
|
994
1298
|
}
|
|
995
|
-
if (token.kind ===
|
|
1299
|
+
if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
|
|
996
1300
|
// We need to strip off the quotes but only if present
|
|
997
1301
|
const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
|
|
998
1302
|
let endIndex = textToSearchFor.length;
|
|
@@ -1002,20 +1306,22 @@ class BrsFile {
|
|
|
1002
1306
|
textToSearchFor = textToSearchFor.substring(startIndex, endIndex);
|
|
1003
1307
|
}
|
|
1004
1308
|
const func = this.getFunctionExpressionAtPosition(position);
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
if (this.tokenFollows(token, lexer_1.TokenKind.Goto)) {
|
|
1015
|
-
for (const label of func.labelStatements) {
|
|
1016
|
-
if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
|
|
1309
|
+
if (func) {
|
|
1310
|
+
//look through local variables first
|
|
1311
|
+
//find any variable with this name
|
|
1312
|
+
for (const symbol of func.symbolTable.getOwnSymbols()) {
|
|
1313
|
+
//we found a variable declaration with this token text
|
|
1314
|
+
if (symbol.name.toLowerCase() === textToSearchFor) {
|
|
1017
1315
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1018
|
-
results.push(vscode_languageserver_1.Location.create(uri,
|
|
1316
|
+
results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if (this.parser.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
|
|
1320
|
+
for (const label of func.labelStatements) {
|
|
1321
|
+
if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
|
|
1322
|
+
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1323
|
+
results.push(vscode_languageserver_1.Location.create(uri, label.tokens.identifier.range));
|
|
1324
|
+
}
|
|
1019
1325
|
}
|
|
1020
1326
|
}
|
|
1021
1327
|
}
|
|
@@ -1023,11 +1329,11 @@ class BrsFile {
|
|
|
1023
1329
|
//look through all files in scope for matches
|
|
1024
1330
|
for (const scope of this.program.getScopesForFile(this)) {
|
|
1025
1331
|
for (const file of scope.getAllFiles()) {
|
|
1026
|
-
if (reflection_1.isXmlFile(file) || filesSearched.has(file)) {
|
|
1332
|
+
if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
|
|
1027
1333
|
continue;
|
|
1028
1334
|
}
|
|
1029
1335
|
filesSearched.add(file);
|
|
1030
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1336
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
1031
1337
|
results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
|
|
1032
1338
|
const namespaceDefinition = this.getNamespaceDefinitions(token, file);
|
|
1033
1339
|
if (namespaceDefinition) {
|
|
@@ -1040,7 +1346,7 @@ class BrsFile {
|
|
|
1040
1346
|
results.push(vscode_languageserver_1.Location.create(uri, statement.range));
|
|
1041
1347
|
}
|
|
1042
1348
|
};
|
|
1043
|
-
file.parser.ast.walk(visitors_1.createVisitor({
|
|
1349
|
+
file.parser.ast.walk((0, visitors_1.createVisitor)({
|
|
1044
1350
|
FunctionStatement: statementHandler
|
|
1045
1351
|
}), {
|
|
1046
1352
|
walkMode: visitors_1.WalkMode.visitStatements
|
|
@@ -1052,34 +1358,33 @@ class BrsFile {
|
|
|
1052
1358
|
getClassMemberDefinitions(textToSearchFor, file) {
|
|
1053
1359
|
let results = [];
|
|
1054
1360
|
//get class fields and members
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1361
|
+
file.parser.ast.walk((0, visitors_1.createVisitor)({
|
|
1362
|
+
MethodStatement: (statement) => {
|
|
1363
|
+
if (statement.getName(file.parseMode).toLowerCase() === textToSearchFor) {
|
|
1364
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), statement.range));
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
FieldStatement: (statement) => {
|
|
1368
|
+
if (statement.name.text.toLowerCase() === textToSearchFor) {
|
|
1369
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), statement.range));
|
|
1370
|
+
}
|
|
1063
1371
|
}
|
|
1064
|
-
};
|
|
1065
|
-
file.parser.ast.walk(visitors_1.createVisitor({
|
|
1066
|
-
ClassMethodStatement: statementHandler,
|
|
1067
|
-
ClassFieldStatement: fieldStatementHandler
|
|
1068
1372
|
}), {
|
|
1069
1373
|
walkMode: visitors_1.WalkMode.visitStatements
|
|
1070
1374
|
});
|
|
1071
1375
|
return results;
|
|
1072
1376
|
}
|
|
1073
1377
|
getHover(position) {
|
|
1074
|
-
var _a;
|
|
1378
|
+
var _a, _b, _c;
|
|
1379
|
+
const fence = (code) => util_1.util.mdFence(code, 'brightscript');
|
|
1075
1380
|
//get the token at the position
|
|
1076
|
-
let token = this.getTokenAt(position);
|
|
1381
|
+
let token = this.parser.getTokenAt(position);
|
|
1077
1382
|
let hoverTokenTypes = [
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1383
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1384
|
+
TokenKind_1.TokenKind.Function,
|
|
1385
|
+
TokenKind_1.TokenKind.EndFunction,
|
|
1386
|
+
TokenKind_1.TokenKind.Sub,
|
|
1387
|
+
TokenKind_1.TokenKind.EndSub
|
|
1083
1388
|
];
|
|
1084
1389
|
//throw out invalid tokens and the wrong kind of tokens
|
|
1085
1390
|
if (!token || !hoverTokenTypes.includes(token.kind)) {
|
|
@@ -1089,63 +1394,114 @@ class BrsFile {
|
|
|
1089
1394
|
//look through local variables first
|
|
1090
1395
|
{
|
|
1091
1396
|
const func = this.getFunctionExpressionAtPosition(position);
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1397
|
+
if (func) {
|
|
1398
|
+
// this identifier could possibly be a class field, so no function expression is available
|
|
1399
|
+
for (const labelStatement of (_a = func === null || func === void 0 ? void 0 : func.labelStatements) !== null && _a !== void 0 ? _a : []) {
|
|
1400
|
+
if (labelStatement.tokens.identifier.text.toLocaleLowerCase() === lowerTokenText) {
|
|
1401
|
+
return {
|
|
1402
|
+
range: token.range,
|
|
1403
|
+
contents: `${labelStatement.tokens.identifier.text}: label`
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1098
1406
|
}
|
|
1099
1407
|
}
|
|
1100
|
-
const typeTexts =
|
|
1101
|
-
|
|
1408
|
+
const typeTexts = new Set();
|
|
1409
|
+
const fileScopes = this.program.getScopesForFile(this).sort((a, b) => { var _a; return (_a = a.dependencyGraphKey) === null || _a === void 0 ? void 0 : _a.localeCompare(b.dependencyGraphKey); });
|
|
1410
|
+
const callables = [];
|
|
1411
|
+
for (const scope of fileScopes) {
|
|
1102
1412
|
scope.linkSymbolTable();
|
|
1103
|
-
|
|
1104
|
-
|
|
1413
|
+
const typeContext = { file: this, scope: scope, position: position };
|
|
1414
|
+
const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
|
|
1415
|
+
if (typeTextPair) {
|
|
1105
1416
|
let scopeTypeText = '';
|
|
1106
|
-
if (reflection_1.
|
|
1107
|
-
scopeTypeText = type.toString();
|
|
1417
|
+
if ((0, reflection_1.isTypedFunctionType)(typeTextPair.type)) {
|
|
1418
|
+
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString(typeContext);
|
|
1419
|
+
//keep unique references to the callables for this function
|
|
1420
|
+
if (!typeTexts.has(scopeTypeText)) {
|
|
1421
|
+
callables.push(scope.getCallableByName(lowerTokenText));
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
else if (typeTextPair.useExpandedTextOnly) {
|
|
1425
|
+
scopeTypeText = typeTextPair.expandedTokenText;
|
|
1108
1426
|
}
|
|
1109
1427
|
else {
|
|
1110
|
-
scopeTypeText = `${
|
|
1428
|
+
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString(typeContext)}`;
|
|
1111
1429
|
}
|
|
1112
|
-
if (
|
|
1113
|
-
typeTexts.
|
|
1430
|
+
if (scopeTypeText) {
|
|
1431
|
+
typeTexts.add(scopeTypeText);
|
|
1114
1432
|
}
|
|
1115
1433
|
}
|
|
1116
1434
|
scope.unlinkSymbolTable();
|
|
1117
1435
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1436
|
+
if (callables.length === typeTexts.size) {
|
|
1437
|
+
//this is a function in all scopes, so build the function hover
|
|
1120
1438
|
return {
|
|
1121
1439
|
range: token.range,
|
|
1122
|
-
contents:
|
|
1440
|
+
contents: this.getCallableDocumentation([...typeTexts], callables)
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
else if ((typeTexts === null || typeTexts === void 0 ? void 0 : typeTexts.size) > 0) {
|
|
1444
|
+
const typeText = [...typeTexts].join(' | ');
|
|
1445
|
+
return {
|
|
1446
|
+
range: token.range,
|
|
1447
|
+
contents: fence(typeText)
|
|
1123
1448
|
};
|
|
1124
1449
|
}
|
|
1125
1450
|
}
|
|
1126
|
-
//look through all callables in relevant scopes
|
|
1127
|
-
{
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1451
|
+
// //look through all callables in relevant scopes
|
|
1452
|
+
// {
|
|
1453
|
+
// let scopes = this.program.getScopesForFile(this);
|
|
1454
|
+
// for (let scope of scopes) {
|
|
1455
|
+
// let callable = scope.getCallableByName(lowerTokenText);
|
|
1456
|
+
// if (callable) {
|
|
1457
|
+
// return {
|
|
1458
|
+
// range: token.range,
|
|
1459
|
+
// contents: this.getCallableDocumentation(callables)
|
|
1460
|
+
// };
|
|
1461
|
+
// }
|
|
1462
|
+
// }
|
|
1463
|
+
// }
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Build a hover documentation for a callable.
|
|
1467
|
+
*/
|
|
1468
|
+
getCallableDocumentation(typeTexts, callables) {
|
|
1469
|
+
var _a;
|
|
1470
|
+
const callable = callables[0];
|
|
1471
|
+
const typeText = typeTexts[0];
|
|
1472
|
+
const comments = [];
|
|
1473
|
+
const tokens = callable === null || callable === void 0 ? void 0 : callable.file.parser.tokens;
|
|
1474
|
+
const idx = tokens === null || tokens === void 0 ? void 0 : tokens.indexOf((_a = callable.functionStatement) === null || _a === void 0 ? void 0 : _a.func.functionType);
|
|
1475
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
1476
|
+
const token = tokens[i];
|
|
1477
|
+
//skip whitespace and newline chars
|
|
1478
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
1479
|
+
comments.push(token);
|
|
1480
|
+
}
|
|
1481
|
+
else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
|
|
1482
|
+
//skip these tokens
|
|
1483
|
+
continue;
|
|
1484
|
+
//any other token means there are no more comments
|
|
1137
1485
|
}
|
|
1486
|
+
else {
|
|
1487
|
+
break;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
//message indicating if there are variations. example: (+3 variations) if there are 4 unique function signatures
|
|
1491
|
+
const multiText = callables.length > 1 ? ` (+${callables.length - 1} variations)` : '';
|
|
1492
|
+
let result = util_1.util.mdFence(typeText + multiText, 'brightscript');
|
|
1493
|
+
if (comments.length > 0) {
|
|
1494
|
+
result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
|
|
1138
1495
|
}
|
|
1496
|
+
return result;
|
|
1139
1497
|
}
|
|
1140
1498
|
getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
|
|
1141
1499
|
var _a;
|
|
1142
1500
|
if (!dottedGetText) {
|
|
1143
1501
|
return [];
|
|
1144
1502
|
}
|
|
1145
|
-
let namespaceLookup = scope.namespaceLookup;
|
|
1146
1503
|
let resultsMap = new Map();
|
|
1147
|
-
for (let
|
|
1148
|
-
let namespace = namespaceLookup[key.toLowerCase()];
|
|
1504
|
+
for (let [, namespace] of scope.namespaceLookup) {
|
|
1149
1505
|
//completionName = "NameA."
|
|
1150
1506
|
//completionName = "NameA.Na
|
|
1151
1507
|
//NameA
|
|
@@ -1154,7 +1510,7 @@ class BrsFile {
|
|
|
1154
1510
|
if (namespace.fullName.toLowerCase() === dottedGetText.toLowerCase()) {
|
|
1155
1511
|
//add function and class statement completions
|
|
1156
1512
|
for (let stmt of namespace.statements) {
|
|
1157
|
-
if (reflection_1.isFunctionStatement(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
|
|
1513
|
+
if ((0, reflection_1.isFunctionStatement)(stmt) && stmt.name.text.toLowerCase() === callableName.toLowerCase()) {
|
|
1158
1514
|
const result = (_a = namespace.file) === null || _a === void 0 ? void 0 : _a.getSignatureHelpForStatement(stmt);
|
|
1159
1515
|
if (!resultsMap.has(result.key)) {
|
|
1160
1516
|
resultsMap.set(result.key, result);
|
|
@@ -1166,16 +1522,16 @@ class BrsFile {
|
|
|
1166
1522
|
return [...resultsMap.values()];
|
|
1167
1523
|
}
|
|
1168
1524
|
getSignatureHelpForStatement(statement) {
|
|
1169
|
-
if (!reflection_1.isFunctionStatement(statement) && !reflection_1.
|
|
1525
|
+
if (!(0, reflection_1.isFunctionStatement)(statement) && !(0, reflection_1.isMethodStatement)(statement)) {
|
|
1170
1526
|
return undefined;
|
|
1171
1527
|
}
|
|
1172
1528
|
const func = statement.func;
|
|
1173
1529
|
const funcStartPosition = func.range.start;
|
|
1174
1530
|
// Get function comments in reverse order
|
|
1175
|
-
let currentToken = this.getTokenAt(funcStartPosition);
|
|
1531
|
+
let currentToken = this.parser.getTokenAt(funcStartPosition);
|
|
1176
1532
|
let functionComments = [];
|
|
1177
1533
|
while (currentToken) {
|
|
1178
|
-
currentToken = this.getPreviousToken(currentToken);
|
|
1534
|
+
currentToken = this.parser.getPreviousToken(currentToken);
|
|
1179
1535
|
if (!currentToken) {
|
|
1180
1536
|
break;
|
|
1181
1537
|
}
|
|
@@ -1185,12 +1541,12 @@ class BrsFile {
|
|
|
1185
1541
|
}
|
|
1186
1542
|
}
|
|
1187
1543
|
const kind = currentToken.kind;
|
|
1188
|
-
if (kind ===
|
|
1544
|
+
if (kind === TokenKind_1.TokenKind.Comment) {
|
|
1189
1545
|
// Strip off common leading characters to make it easier to read
|
|
1190
1546
|
const commentText = currentToken.text.replace(/^[' *\/]+/, '');
|
|
1191
1547
|
functionComments.unshift(commentText);
|
|
1192
1548
|
}
|
|
1193
|
-
else if (kind ===
|
|
1549
|
+
else if (kind === TokenKind_1.TokenKind.Newline) {
|
|
1194
1550
|
if (functionComments.length === 0) {
|
|
1195
1551
|
continue;
|
|
1196
1552
|
}
|
|
@@ -1212,14 +1568,15 @@ class BrsFile {
|
|
|
1212
1568
|
params.push(vscode_languageserver_1.ParameterInformation.create(param.name.text));
|
|
1213
1569
|
key += param.name.text;
|
|
1214
1570
|
}
|
|
1215
|
-
const label = util_1.util.getTextForRange(lines,
|
|
1571
|
+
const label = util_1.util.getTextForRange(lines, func.functionDeclarationRange).trim();
|
|
1216
1572
|
const signature = vscode_languageserver_1.SignatureInformation.create(label, documentation, ...params);
|
|
1217
1573
|
const index = 1;
|
|
1218
1574
|
return { key: key, signature: signature, index: index };
|
|
1219
1575
|
}
|
|
1220
1576
|
getClassMethod(classStatement, name, walkParents = true) {
|
|
1221
1577
|
var _a;
|
|
1222
|
-
//TODO - would like to write this with
|
|
1578
|
+
//TODO - would like to write this with getClassHierarchy; but got stuck on working out the scopes to use... :(
|
|
1579
|
+
//TODO types - this could be solved with symbolTable?
|
|
1223
1580
|
let statement;
|
|
1224
1581
|
const statementHandler = (e) => {
|
|
1225
1582
|
if (!statement && e.name.text.toLowerCase() === name.toLowerCase()) {
|
|
@@ -1227,8 +1584,8 @@ class BrsFile {
|
|
|
1227
1584
|
}
|
|
1228
1585
|
};
|
|
1229
1586
|
while (classStatement) {
|
|
1230
|
-
classStatement.walk(visitors_1.createVisitor({
|
|
1231
|
-
|
|
1587
|
+
classStatement.walk((0, visitors_1.createVisitor)({
|
|
1588
|
+
MethodStatement: statementHandler
|
|
1232
1589
|
}), {
|
|
1233
1590
|
walkMode: visitors_1.WalkMode.visitStatements
|
|
1234
1591
|
});
|
|
@@ -1249,24 +1606,24 @@ class BrsFile {
|
|
|
1249
1606
|
const classConstructor = this.getClassMethod(classStatement, 'new');
|
|
1250
1607
|
let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
|
|
1251
1608
|
if (sigHelp) {
|
|
1252
|
-
sigHelp.key = classStatement.getName(
|
|
1609
|
+
sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1253
1610
|
sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
|
|
1254
1611
|
}
|
|
1255
1612
|
return sigHelp;
|
|
1256
1613
|
}
|
|
1257
1614
|
getReferences(position) {
|
|
1258
|
-
const callSiteToken = this.getTokenAt(position);
|
|
1615
|
+
const callSiteToken = this.parser.getTokenAt(position);
|
|
1259
1616
|
let locations = [];
|
|
1260
1617
|
const searchFor = callSiteToken.text.toLowerCase();
|
|
1261
1618
|
const scopes = this.program.getScopesForFile(this);
|
|
1262
1619
|
for (const scope of scopes) {
|
|
1263
1620
|
const processedFiles = new Set();
|
|
1264
1621
|
for (const file of scope.getAllFiles()) {
|
|
1265
|
-
if (reflection_1.isXmlFile(file) || processedFiles.has(file)) {
|
|
1622
|
+
if ((0, reflection_1.isXmlFile)(file) || processedFiles.has(file)) {
|
|
1266
1623
|
continue;
|
|
1267
1624
|
}
|
|
1268
1625
|
processedFiles.add(file);
|
|
1269
|
-
file.ast.walk(visitors_1.createVisitor({
|
|
1626
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
1270
1627
|
VariableExpression: (e) => {
|
|
1271
1628
|
if (e.name.text.toLowerCase() === searchFor) {
|
|
1272
1629
|
locations.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), e.range));
|
|
@@ -1296,6 +1653,8 @@ class BrsFile {
|
|
|
1296
1653
|
//simple SourceNode wrapping the entire file to simplify the logic below
|
|
1297
1654
|
transpileResult = new source_map_1.SourceNode(null, null, state.srcPath, this.fileContents);
|
|
1298
1655
|
}
|
|
1656
|
+
//undo any AST edits that the transpile cycle has made
|
|
1657
|
+
state.editor.undoAll();
|
|
1299
1658
|
if (this.program.options.sourceMap) {
|
|
1300
1659
|
return new source_map_1.SourceNode(null, null, null, [
|
|
1301
1660
|
transpileResult,
|
|
@@ -1317,8 +1676,15 @@ class BrsFile {
|
|
|
1317
1676
|
return programNode.toString();
|
|
1318
1677
|
}
|
|
1319
1678
|
dispose() {
|
|
1320
|
-
var _a;
|
|
1679
|
+
var _a, _b;
|
|
1321
1680
|
(_a = this._parser) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
1681
|
+
//unsubscribe from any DependencyGraph subscriptions
|
|
1682
|
+
(_b = this.unsubscribeFromDependencyGraph) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
1683
|
+
//deleting these properties result in lower memory usage (garbage collection is magic!)
|
|
1684
|
+
delete this.fileContents;
|
|
1685
|
+
delete this._parser;
|
|
1686
|
+
delete this.callables;
|
|
1687
|
+
delete this.functionCalls;
|
|
1322
1688
|
}
|
|
1323
1689
|
}
|
|
1324
1690
|
exports.BrsFile = BrsFile;
|
|
@@ -1326,7 +1692,7 @@ exports.BrsFile = BrsFile;
|
|
|
1326
1692
|
* List of completions for all valid keywords/reserved words.
|
|
1327
1693
|
* Build this list once because it won't change for the lifetime of this process
|
|
1328
1694
|
*/
|
|
1329
|
-
exports.KeywordCompletions = Object.keys(
|
|
1695
|
+
exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
|
|
1330
1696
|
//remove any keywords with whitespace
|
|
1331
1697
|
.filter(x => !x.includes(' '))
|
|
1332
1698
|
//create completions
|