brighterscript 1.0.0-alpha.3 → 1.0.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1230 -285
- package/README.md +61 -131
- package/bsconfig.schema.json +68 -2
- package/dist/ActionPipeline.d.ts +10 -0
- package/dist/ActionPipeline.js +40 -0
- package/dist/ActionPipeline.js.map +1 -0
- package/dist/AstValidationSegmenter.d.ts +35 -0
- package/dist/AstValidationSegmenter.js +209 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/BsConfig.d.ts +51 -6
- package/dist/BusyStatusTracker.d.ts +31 -0
- package/dist/BusyStatusTracker.js +83 -0
- package/dist/BusyStatusTracker.js.map +1 -0
- package/dist/Cache.d.ts +5 -6
- package/dist/Cache.js +12 -11
- package/dist/Cache.js.map +1 -1
- package/dist/CacheVerifier.d.ts +7 -0
- package/dist/CacheVerifier.js +20 -0
- package/dist/CacheVerifier.js.map +1 -0
- package/dist/CodeActionUtil.d.ts +11 -2
- package/dist/CodeActionUtil.js +17 -3
- package/dist/CodeActionUtil.js.map +1 -1
- package/dist/CommentFlagProcessor.d.ts +7 -6
- package/dist/CommentFlagProcessor.js +10 -7
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DependencyGraph.d.ts +8 -3
- package/dist/DependencyGraph.js +49 -16
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticCollection.d.ts +5 -3
- package/dist/DiagnosticCollection.js +18 -16
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +8 -4
- package/dist/DiagnosticFilterer.js +77 -44
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticManager.d.ts +55 -0
- package/dist/DiagnosticManager.js +214 -0
- package/dist/DiagnosticManager.js.map +1 -0
- package/dist/DiagnosticMessages.d.ts +184 -17
- package/dist/DiagnosticMessages.js +242 -24
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
- package/dist/DiagnosticSeverityAdjuster.js +41 -0
- package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
- package/dist/FunctionScope.d.ts +28 -0
- package/dist/FunctionScope.js +52 -0
- package/dist/FunctionScope.js.map +1 -0
- package/dist/KeyedThrottler.d.ts +3 -3
- package/dist/KeyedThrottler.js +3 -3
- package/dist/KeyedThrottler.js.map +1 -1
- package/dist/LanguageServer.d.ts +72 -47
- package/dist/LanguageServer.js +544 -312
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +9 -10
- package/dist/Logger.js +36 -30
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +29 -7
- package/dist/PluginInterface.js +90 -7
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +204 -99
- package/dist/Program.js +1060 -699
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +29 -18
- package/dist/ProgramBuilder.js +170 -132
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +144 -109
- package/dist/Scope.js +538 -551
- package/dist/Scope.js.map +1 -1
- package/dist/SemanticTokenUtils.d.ts +14 -0
- package/dist/SemanticTokenUtils.js +81 -0
- package/dist/SemanticTokenUtils.js.map +1 -0
- package/dist/Stopwatch.d.ts +4 -0
- package/dist/Stopwatch.js +8 -1
- package/dist/Stopwatch.js.map +1 -1
- package/dist/SymbolTable.d.ts +91 -24
- package/dist/SymbolTable.js +286 -63
- package/dist/SymbolTable.js.map +1 -1
- package/dist/SymbolTypeFlag.d.ts +8 -0
- package/dist/SymbolTypeFlag.js +13 -0
- package/dist/SymbolTypeFlag.js.map +1 -0
- package/dist/Throttler.d.ts +12 -0
- package/dist/Throttler.js +39 -0
- package/dist/Throttler.js.map +1 -1
- package/dist/Watcher.d.ts +0 -3
- package/dist/Watcher.js +0 -3
- package/dist/Watcher.js.map +1 -1
- package/dist/XmlScope.d.ts +5 -15
- package/dist/XmlScope.js +35 -87
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/CachedLookups.d.ts +49 -0
- package/dist/astUtils/CachedLookups.js +324 -0
- package/dist/astUtils/CachedLookups.js.map +1 -0
- package/dist/astUtils/Editor.d.ts +69 -0
- package/dist/astUtils/Editor.js +245 -0
- package/dist/astUtils/Editor.js.map +1 -0
- package/dist/astUtils/Editor.spec.js +258 -0
- package/dist/astUtils/Editor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +33 -10
- package/dist/astUtils/creators.js +224 -30
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +5 -5
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +145 -82
- package/dist/astUtils/reflection.js +304 -132
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +267 -162
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/stackedVisitor.js.map +1 -1
- package/dist/astUtils/stackedVisitor.spec.js +14 -14
- package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +114 -53
- package/dist/astUtils/visitors.js +70 -13
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +465 -51
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +9 -8
- package/dist/astUtils/xml.js +10 -5
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +22 -1
- package/dist/bscPlugin/BscPlugin.js +88 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
- package/dist/bscPlugin/CallExpressionInfo.js +131 -0
- package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
- package/dist/bscPlugin/FileWriter.d.ts +6 -0
- package/dist/bscPlugin/FileWriter.js +24 -0
- package/dist/bscPlugin/FileWriter.js.map +1 -0
- package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
- package/dist/bscPlugin/SignatureHelpUtil.js +137 -0
- package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +26 -17
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +94 -20
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +60 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +601 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +2139 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
- package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.d.ts +18 -0
- package/dist/bscPlugin/hover/HoverProcessor.js +218 -0
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +737 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
- package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
- package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +138 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +491 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
- package/dist/bscPlugin/serialize/BslibManager.js +40 -0
- package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
- package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
- package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
- package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.d.ts +7 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js +22 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js.map +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js +291 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.d.ts +7 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js +26 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js.map +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js +245 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/symbols/symbolUtils.d.ts +5 -0
- package/dist/bscPlugin/symbols/symbolUtils.js +140 -0
- package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +21 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +202 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.d.ts +7 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.js +18 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidatior.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +34 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +462 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +758 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/ProgramValidator.d.ts +11 -0
- package/dist/bscPlugin/validation/ProgramValidator.js +33 -0
- package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +131 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +1097 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +2796 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
- package/dist/cli.js +117 -11
- package/dist/cli.js.map +1 -1
- package/dist/deferred.d.ts +3 -3
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +10 -3
- package/dist/diagnosticUtils.js +58 -21
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +8 -12
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/AssetFile.d.ts +24 -0
- package/dist/files/AssetFile.js +25 -0
- package/dist/files/AssetFile.js.map +1 -0
- package/dist/files/BrsFile.Class.spec.js +858 -153
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +144 -82
- package/dist/files/BrsFile.js +847 -911
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +2928 -834
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/BscFile.d.ts +101 -0
- package/dist/files/BscFile.js +15 -0
- package/dist/files/BscFile.js.map +1 -0
- package/dist/files/Factory.d.ts +25 -0
- package/dist/files/Factory.js +22 -0
- package/dist/files/Factory.js.map +1 -0
- package/dist/files/LazyFileData.d.ts +20 -0
- package/dist/files/LazyFileData.js +54 -0
- package/dist/files/LazyFileData.js.map +1 -0
- package/dist/files/LazyFileData.spec.d.ts +1 -0
- package/dist/files/LazyFileData.spec.js +27 -0
- package/dist/files/LazyFileData.spec.js.map +1 -0
- package/dist/files/XmlFile.d.ts +73 -41
- package/dist/files/XmlFile.js +126 -138
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +450 -318
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +62 -52
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
- package/dist/files/tests/optionalChaning.spec.js +152 -0
- package/dist/files/tests/optionalChaning.spec.js.map +1 -0
- package/dist/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +416 -162
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +25 -3
- package/dist/index.js +42 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +722 -119
- package/dist/interfaces.js +31 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Character.spec.js +5 -5
- package/dist/lexer/Character.spec.js.map +1 -1
- package/dist/lexer/Lexer.d.ts +40 -9
- package/dist/lexer/Lexer.js +191 -49
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +775 -563
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.d.ts +11 -3
- package/dist/lexer/Token.js +10 -2
- package/dist/lexer/Token.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +27 -1
- package/dist/lexer/TokenKind.js +112 -5
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/logging.d.ts +9 -0
- package/dist/logging.js +16 -0
- package/dist/logging.js.map +1 -0
- package/dist/parser/AstNode.d.ts +180 -0
- package/dist/parser/AstNode.js +245 -0
- package/dist/parser/AstNode.js.map +1 -0
- package/dist/parser/AstNode.spec.d.ts +1 -0
- package/dist/parser/AstNode.spec.js +165 -0
- package/dist/parser/AstNode.spec.js.map +1 -0
- package/dist/parser/BrsTranspileState.d.ts +12 -2
- package/dist/parser/BrsTranspileState.js +6 -0
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +454 -210
- package/dist/parser/Expression.js +953 -498
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +200 -95
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +105 -120
- package/dist/parser/Parser.js +1406 -912
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.d.ts +3 -1
- package/dist/parser/Parser.spec.js +1383 -456
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +44 -6
- package/dist/parser/SGParser.js +212 -185
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +30 -28
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +293 -50
- package/dist/parser/SGTypes.js +540 -187
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/Statement.d.ts +734 -244
- package/dist/parser/Statement.js +1758 -611
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +45 -34
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +17 -8
- package/dist/parser/TranspileState.js +73 -11
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +10 -9
- package/dist/parser/tests/Parser.spec.js +18 -14
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +79 -69
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +53 -47
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +217 -196
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +48 -42
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +31 -31
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +157 -120
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +202 -139
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +25 -25
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +150 -41
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +18 -18
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +257 -257
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +160 -90
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +38 -38
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +196 -98
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +42 -42
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +42 -42
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/Relational.spec.js +44 -44
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +31 -31
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +230 -90
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +377 -148
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js +126 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +37 -37
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Continue.spec.js +119 -0
- package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
- package/dist/parser/tests/statement/Declaration.spec.js +45 -45
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Dim.spec.js +22 -22
- package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Enum.spec.js +684 -0
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
- package/dist/parser/tests/statement/For.spec.d.ts +1 -0
- package/dist/parser/tests/statement/For.spec.js +45 -0
- package/dist/parser/tests/statement/For.spec.js.map +1 -0
- package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ForEach.spec.js +36 -0
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
- package/dist/parser/tests/statement/Function.spec.js +208 -198
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +16 -15
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +51 -51
- package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +109 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/LibraryStatement.spec.js +18 -18
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +123 -163
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +125 -108
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +51 -49
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +110 -97
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +13 -12
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/parser/tests/statement/Throw.spec.js +6 -6
- package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +26 -15
- package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
- package/dist/preprocessor/Manifest.d.ts +6 -6
- package/dist/preprocessor/Manifest.js +17 -38
- package/dist/preprocessor/Manifest.js.map +1 -1
- package/dist/preprocessor/Manifest.spec.d.ts +1 -0
- package/dist/preprocessor/Manifest.spec.js +78 -103
- package/dist/preprocessor/Manifest.spec.js.map +1 -1
- package/dist/roku-types/data.json +19351 -0
- package/dist/roku-types/index.d.ts +5483 -0
- package/dist/roku-types/index.js +11 -0
- package/dist/roku-types/index.js.map +1 -0
- package/dist/types/ArrayType.d.ts +9 -5
- package/dist/types/ArrayType.js +68 -24
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +39 -11
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +14 -0
- package/dist/types/AssociativeArrayType.js +60 -0
- package/dist/types/AssociativeArrayType.js.map +1 -0
- package/dist/types/BaseFunctionType.d.ts +9 -0
- package/dist/types/BaseFunctionType.js +25 -0
- package/dist/types/BaseFunctionType.js.map +1 -0
- package/dist/types/BooleanType.d.ts +10 -5
- package/dist/types/BooleanType.js +21 -9
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BooleanType.spec.js +10 -4
- package/dist/types/BooleanType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +29 -3
- package/dist/types/BscType.js +121 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BscTypeKind.d.ts +25 -0
- package/dist/types/BscTypeKind.js +30 -0
- package/dist/types/BscTypeKind.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
- package/dist/types/BuiltInInterfaceAdder.js +174 -0
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js +115 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
- package/dist/types/ClassType.d.ts +17 -0
- package/dist/types/ClassType.js +58 -0
- package/dist/types/ClassType.js.map +1 -0
- package/dist/types/ClassType.spec.d.ts +1 -0
- package/dist/types/ClassType.spec.js +76 -0
- package/dist/types/ClassType.spec.js.map +1 -0
- package/dist/types/ComponentType.d.ts +27 -0
- package/dist/types/ComponentType.js +83 -0
- package/dist/types/ComponentType.js.map +1 -0
- package/dist/types/DoubleType.d.ts +10 -5
- package/dist/types/DoubleType.js +25 -18
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DoubleType.spec.js +12 -4
- package/dist/types/DoubleType.spec.js.map +1 -1
- package/dist/types/DynamicType.d.ts +12 -5
- package/dist/types/DynamicType.js +22 -6
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/DynamicType.spec.js +16 -5
- package/dist/types/DynamicType.spec.js.map +1 -1
- package/dist/types/EnumType.d.ts +40 -0
- package/dist/types/EnumType.js +80 -0
- package/dist/types/EnumType.js.map +1 -0
- package/dist/types/EnumType.spec.d.ts +1 -0
- package/dist/types/EnumType.spec.js +33 -0
- package/dist/types/EnumType.spec.js.map +1 -0
- package/dist/types/FloatType.d.ts +10 -5
- package/dist/types/FloatType.js +25 -18
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FloatType.spec.js +4 -4
- package/dist/types/FloatType.spec.js.map +1 -1
- package/dist/types/FunctionType.d.ts +10 -22
- package/dist/types/FunctionType.js +26 -63
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/InheritableType.d.ts +28 -0
- package/dist/types/InheritableType.js +157 -0
- package/dist/types/InheritableType.js.map +1 -0
- package/dist/types/IntegerType.d.ts +10 -5
- package/dist/types/IntegerType.js +25 -18
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/IntegerType.spec.js +8 -4
- package/dist/types/IntegerType.spec.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +14 -6
- package/dist/types/InterfaceType.js +26 -15
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.d.ts +1 -0
- package/dist/types/InterfaceType.spec.js +227 -0
- package/dist/types/InterfaceType.spec.js.map +1 -0
- package/dist/types/InvalidType.d.ts +9 -5
- package/dist/types/InvalidType.js +20 -9
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/InvalidType.spec.js +8 -4
- package/dist/types/InvalidType.spec.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +10 -5
- package/dist/types/LongIntegerType.js +25 -18
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.spec.js +10 -4
- package/dist/types/LongIntegerType.spec.js.map +1 -1
- package/dist/types/NamespaceType.d.ts +12 -0
- package/dist/types/NamespaceType.js +28 -0
- package/dist/types/NamespaceType.js.map +1 -0
- package/dist/types/ObjectType.d.ts +10 -5
- package/dist/types/ObjectType.js +23 -9
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ObjectType.spec.js +3 -3
- package/dist/types/ObjectType.spec.js.map +1 -1
- package/dist/types/ReferenceType.d.ts +71 -0
- package/dist/types/ReferenceType.js +467 -0
- package/dist/types/ReferenceType.js.map +1 -0
- package/dist/types/ReferenceType.spec.d.ts +1 -0
- package/dist/types/ReferenceType.spec.js +151 -0
- package/dist/types/ReferenceType.spec.js.map +1 -0
- package/dist/types/StringType.d.ts +13 -5
- package/dist/types/StringType.js +25 -9
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/StringType.spec.js +3 -3
- package/dist/types/StringType.spec.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +33 -0
- package/dist/types/TypedFunctionType.js +106 -0
- package/dist/types/TypedFunctionType.js.map +1 -0
- package/dist/types/TypedFunctionType.spec.d.ts +1 -0
- package/dist/types/TypedFunctionType.spec.js +122 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -0
- package/dist/types/UninitializedType.d.ts +8 -6
- package/dist/types/UninitializedType.js +15 -9
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/UnionType.d.ts +20 -0
- package/dist/types/UnionType.js +127 -0
- package/dist/types/UnionType.js.map +1 -0
- package/dist/types/UnionType.spec.d.ts +1 -0
- package/dist/types/UnionType.spec.js +129 -0
- package/dist/types/UnionType.spec.js.map +1 -0
- package/dist/types/VoidType.d.ts +10 -5
- package/dist/types/VoidType.js +20 -9
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/VoidType.spec.js +3 -3
- package/dist/types/VoidType.spec.js.map +1 -1
- package/dist/types/helper.spec.d.ts +1 -0
- package/dist/types/helper.spec.js +144 -0
- package/dist/types/helper.spec.js.map +1 -0
- package/dist/types/helpers.d.ts +24 -0
- package/dist/types/helpers.js +178 -0
- package/dist/types/helpers.js.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.js +39 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util.d.ts +216 -106
- package/dist/util.js +1289 -319
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +9 -15
- package/dist/validators/ClassValidator.js +81 -134
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +169 -138
- package/dist/astUtils/index.d.ts +0 -7
- package/dist/astUtils/index.js +0 -26
- package/dist/astUtils/index.js.map +0 -1
- package/dist/lexer/index.d.ts +0 -3
- package/dist/lexer/index.js +0 -17
- package/dist/lexer/index.js.map +0 -1
- package/dist/parser/index.d.ts +0 -3
- package/dist/parser/index.js +0 -16
- package/dist/parser/index.js.map +0 -1
- package/dist/preprocessor/Chunk.d.ts +0 -82
- package/dist/preprocessor/Chunk.js +0 -77
- package/dist/preprocessor/Chunk.js.map +0 -1
- package/dist/preprocessor/Preprocessor.d.ts +0 -60
- package/dist/preprocessor/Preprocessor.js +0 -156
- package/dist/preprocessor/Preprocessor.js.map +0 -1
- package/dist/preprocessor/Preprocessor.spec.js +0 -152
- package/dist/preprocessor/Preprocessor.spec.js.map +0 -1
- package/dist/preprocessor/PreprocessorParser.d.ts +0 -61
- package/dist/preprocessor/PreprocessorParser.js +0 -194
- package/dist/preprocessor/PreprocessorParser.js.map +0 -1
- package/dist/preprocessor/PreprocessorParser.spec.js +0 -116
- package/dist/preprocessor/PreprocessorParser.spec.js.map +0 -1
- package/dist/preprocessor/index.d.ts +0 -3
- package/dist/preprocessor/index.js +0 -16
- package/dist/preprocessor/index.js.map +0 -1
- package/dist/types/CustomType.d.ts +0 -10
- package/dist/types/CustomType.js +0 -35
- package/dist/types/CustomType.js.map +0 -1
- package/dist/types/FunctionType.spec.js +0 -29
- package/dist/types/FunctionType.spec.js.map +0 -1
- package/dist/types/LazyType.d.ts +0 -15
- package/dist/types/LazyType.js +0 -32
- package/dist/types/LazyType.js.map +0 -1
- /package/dist/{preprocessor/Preprocessor.spec.d.ts → astUtils/Editor.spec.d.ts} +0 -0
- /package/dist/{preprocessor/PreprocessorParser.spec.d.ts → bscPlugin/completions/CompletionsProcessor.spec.d.ts} +0 -0
- /package/dist/{types/FunctionType.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
|
@@ -0,0 +1,2796 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const sinonImport = require("sinon");
|
|
4
|
+
const DiagnosticMessages_1 = require("../../DiagnosticMessages");
|
|
5
|
+
const Program_1 = require("../../Program");
|
|
6
|
+
const testHelpers_spec_1 = require("../../testHelpers.spec");
|
|
7
|
+
const chai_1 = require("chai");
|
|
8
|
+
const IntegerType_1 = require("../../types/IntegerType");
|
|
9
|
+
const StringType_1 = require("../../types/StringType");
|
|
10
|
+
const types_1 = require("../../types");
|
|
11
|
+
const AssociativeArrayType_1 = require("../../types/AssociativeArrayType");
|
|
12
|
+
describe('ScopeValidator', () => {
|
|
13
|
+
let sinon = sinonImport.createSandbox();
|
|
14
|
+
let rootDir = process.cwd();
|
|
15
|
+
let program;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
program = new Program_1.Program({
|
|
18
|
+
rootDir: rootDir
|
|
19
|
+
});
|
|
20
|
+
program.createSourceScope();
|
|
21
|
+
});
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
sinon.restore();
|
|
24
|
+
program.dispose();
|
|
25
|
+
});
|
|
26
|
+
describe('mismatchArgumentCount', () => {
|
|
27
|
+
it('detects calling functions with too many arguments', () => {
|
|
28
|
+
program.setFile('source/file.brs', `
|
|
29
|
+
sub a()
|
|
30
|
+
end sub
|
|
31
|
+
sub b()
|
|
32
|
+
a(1)
|
|
33
|
+
end sub
|
|
34
|
+
`);
|
|
35
|
+
program.validate();
|
|
36
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
37
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(0, 1).message
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
it('detects calling class constructors with too many arguments', () => {
|
|
41
|
+
program.setFile('source/main.bs', `
|
|
42
|
+
function noop0()
|
|
43
|
+
end function
|
|
44
|
+
|
|
45
|
+
function noop1(p1)
|
|
46
|
+
end function
|
|
47
|
+
|
|
48
|
+
sub main()
|
|
49
|
+
noop0(1)
|
|
50
|
+
noop1(1,2)
|
|
51
|
+
noop1()
|
|
52
|
+
end sub
|
|
53
|
+
`);
|
|
54
|
+
program.validate();
|
|
55
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
56
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(0, 1),
|
|
57
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 2),
|
|
58
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0)
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
61
|
+
it('detects calling functions with too few arguments', () => {
|
|
62
|
+
program.setFile('source/file.brs', `
|
|
63
|
+
sub a(name)
|
|
64
|
+
end sub
|
|
65
|
+
sub b()
|
|
66
|
+
a()
|
|
67
|
+
end sub
|
|
68
|
+
`);
|
|
69
|
+
program.validate();
|
|
70
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
71
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0)
|
|
72
|
+
]);
|
|
73
|
+
});
|
|
74
|
+
it('allows skipping optional parameter', () => {
|
|
75
|
+
program.setFile('source/file.brs', `
|
|
76
|
+
sub a(name="Bob")
|
|
77
|
+
end sub
|
|
78
|
+
sub b()
|
|
79
|
+
a()
|
|
80
|
+
end sub
|
|
81
|
+
`);
|
|
82
|
+
program.validate();
|
|
83
|
+
//should have an error
|
|
84
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
85
|
+
});
|
|
86
|
+
it('shows expected parameter range in error message', () => {
|
|
87
|
+
program.setFile('source/file.brs', `
|
|
88
|
+
sub a(age, name="Bob")
|
|
89
|
+
end sub
|
|
90
|
+
sub b()
|
|
91
|
+
a()
|
|
92
|
+
end sub
|
|
93
|
+
`);
|
|
94
|
+
program.validate();
|
|
95
|
+
//should have an error
|
|
96
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
97
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount('1-2', 0)
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
it('handles expressions as arguments to a function', () => {
|
|
101
|
+
program.setFile('source/file.brs', `
|
|
102
|
+
sub a(age, name="Bob")
|
|
103
|
+
end sub
|
|
104
|
+
sub b()
|
|
105
|
+
a("cat" + "dog" + "mouse")
|
|
106
|
+
end sub
|
|
107
|
+
`);
|
|
108
|
+
program.validate();
|
|
109
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
110
|
+
});
|
|
111
|
+
it('Catches extra arguments for expressions as arguments to a function', () => {
|
|
112
|
+
program.setFile('source/file.brs', `
|
|
113
|
+
sub a(age)
|
|
114
|
+
end sub
|
|
115
|
+
sub b()
|
|
116
|
+
a(m.lib.movies[0], 1)
|
|
117
|
+
end sub
|
|
118
|
+
`);
|
|
119
|
+
program.validate();
|
|
120
|
+
//should have an error
|
|
121
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
122
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 2)
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
it('allows any number of parameters in a function used as an argument', () => {
|
|
126
|
+
program.setFile('source/file.brs', `
|
|
127
|
+
sub tryManyParams(someFunc as function)
|
|
128
|
+
someFunc(1, 2, "hello", "world")
|
|
129
|
+
end sub
|
|
130
|
+
`);
|
|
131
|
+
program.validate();
|
|
132
|
+
//should have no errors
|
|
133
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
134
|
+
});
|
|
135
|
+
it('checks for at least the number of non-optional args on variadic (callFunc) functions', () => {
|
|
136
|
+
program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
|
|
137
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
|
138
|
+
<component name="Widget" extends="Group">
|
|
139
|
+
<script uri="Widget.brs"/>
|
|
140
|
+
<interface>
|
|
141
|
+
<function name="someFunc" />
|
|
142
|
+
</interface>
|
|
143
|
+
</component>
|
|
144
|
+
`);
|
|
145
|
+
program.setFile('components/Widget.brs', `
|
|
146
|
+
sub someFunc(input as object)
|
|
147
|
+
print input
|
|
148
|
+
end sub
|
|
149
|
+
`);
|
|
150
|
+
program.setFile('source/util.brs', `
|
|
151
|
+
sub useCallFunc(input as roSGNodeWidget)
|
|
152
|
+
input.callFunc()
|
|
153
|
+
end sub
|
|
154
|
+
`);
|
|
155
|
+
program.validate();
|
|
156
|
+
//should have an error
|
|
157
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
158
|
+
DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount('1-63', 0)
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
161
|
+
it('any number number of args on variadic (callFunc) functions', () => {
|
|
162
|
+
program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
|
|
163
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
|
164
|
+
<component name="Widget" extends="Group">
|
|
165
|
+
<script uri="Widget.brs"/>
|
|
166
|
+
<interface>
|
|
167
|
+
<function name="someFunc" />
|
|
168
|
+
</interface>
|
|
169
|
+
</component>
|
|
170
|
+
`);
|
|
171
|
+
program.setFile('components/Widget.brs', `
|
|
172
|
+
sub someFunc(input as object)
|
|
173
|
+
print input
|
|
174
|
+
end sub
|
|
175
|
+
`);
|
|
176
|
+
program.setFile('source/util.brs', `
|
|
177
|
+
sub useCallFunc(input as roSGNodeWidget)
|
|
178
|
+
input.callFunc("someFunc", 1, 2, 3, {})
|
|
179
|
+
end sub
|
|
180
|
+
`);
|
|
181
|
+
program.validate();
|
|
182
|
+
//TODO: do a better job of handling callFunc() invocations!
|
|
183
|
+
//should have an error
|
|
184
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
describe('argumentTypeMismatch', () => {
|
|
188
|
+
it('param `as object` supports all known types', () => {
|
|
189
|
+
program.setFile('source/file.bs', `
|
|
190
|
+
sub main()
|
|
191
|
+
consoleLog(Direction.up)
|
|
192
|
+
consoleLog(true)
|
|
193
|
+
consoleLog(main)
|
|
194
|
+
consoleLog(1.2)
|
|
195
|
+
consoleLog({} as Video)
|
|
196
|
+
consoleLog("test")
|
|
197
|
+
end sub
|
|
198
|
+
|
|
199
|
+
sub consoleLog(thing as object)
|
|
200
|
+
print thing
|
|
201
|
+
end sub
|
|
202
|
+
|
|
203
|
+
interface Video
|
|
204
|
+
url as string
|
|
205
|
+
end interface
|
|
206
|
+
enum Direction
|
|
207
|
+
up = "up"
|
|
208
|
+
down = "down"
|
|
209
|
+
end enum
|
|
210
|
+
`);
|
|
211
|
+
program.validate();
|
|
212
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
213
|
+
});
|
|
214
|
+
it('`as object` var can be passed to various param types', () => {
|
|
215
|
+
program.setFile('source/file.bs', `
|
|
216
|
+
sub main()
|
|
217
|
+
obj = {} as object
|
|
218
|
+
|
|
219
|
+
printBoolean(obj)
|
|
220
|
+
printClass(obj)
|
|
221
|
+
printDouble(obj)
|
|
222
|
+
printEnum(obj)
|
|
223
|
+
printFloat(obj)
|
|
224
|
+
printFunction(obj)
|
|
225
|
+
printInteger(obj)
|
|
226
|
+
printInterface(obj)
|
|
227
|
+
printLongInteger(obj)
|
|
228
|
+
printString(obj)
|
|
229
|
+
end sub
|
|
230
|
+
|
|
231
|
+
sub printBoolean(value as boolean)
|
|
232
|
+
print value
|
|
233
|
+
end sub
|
|
234
|
+
|
|
235
|
+
class Person
|
|
236
|
+
name as string
|
|
237
|
+
end class
|
|
238
|
+
|
|
239
|
+
sub printClass(value as Person)
|
|
240
|
+
print value
|
|
241
|
+
end sub
|
|
242
|
+
|
|
243
|
+
sub printDouble(value as double)
|
|
244
|
+
print value
|
|
245
|
+
end sub
|
|
246
|
+
|
|
247
|
+
enum Direction
|
|
248
|
+
up = "up"
|
|
249
|
+
end enum
|
|
250
|
+
|
|
251
|
+
sub printEnum(value as Direction)
|
|
252
|
+
print value
|
|
253
|
+
end sub
|
|
254
|
+
|
|
255
|
+
sub printFloat(value as float)
|
|
256
|
+
print value
|
|
257
|
+
end sub
|
|
258
|
+
|
|
259
|
+
sub printFunction(value as function)
|
|
260
|
+
print value
|
|
261
|
+
print value(1)
|
|
262
|
+
end sub
|
|
263
|
+
|
|
264
|
+
interface Video
|
|
265
|
+
url as string
|
|
266
|
+
end interface
|
|
267
|
+
|
|
268
|
+
sub printInterface(value as Video)
|
|
269
|
+
print value
|
|
270
|
+
end sub
|
|
271
|
+
|
|
272
|
+
sub printInteger(value as integer)
|
|
273
|
+
print value
|
|
274
|
+
end sub
|
|
275
|
+
|
|
276
|
+
sub printLongInteger(value as LongInteger)
|
|
277
|
+
print value
|
|
278
|
+
end sub
|
|
279
|
+
|
|
280
|
+
sub printString(value as string)
|
|
281
|
+
print value
|
|
282
|
+
end sub
|
|
283
|
+
`);
|
|
284
|
+
program.validate();
|
|
285
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
286
|
+
});
|
|
287
|
+
it('treats string enums as strings when assigned to string vars', () => {
|
|
288
|
+
program.setFile('source/file.bs', `
|
|
289
|
+
sub main()
|
|
290
|
+
printDirection(Direction.up)
|
|
291
|
+
end sub
|
|
292
|
+
|
|
293
|
+
sub printDirection(theDirection as string)
|
|
294
|
+
print theDirection
|
|
295
|
+
end sub
|
|
296
|
+
|
|
297
|
+
enum Direction
|
|
298
|
+
up = "up"
|
|
299
|
+
down = "down"
|
|
300
|
+
end enum
|
|
301
|
+
`);
|
|
302
|
+
program.validate();
|
|
303
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
304
|
+
});
|
|
305
|
+
it('does not treat strings as a string enum', () => {
|
|
306
|
+
program.setFile('source/file.bs', `
|
|
307
|
+
sub main()
|
|
308
|
+
printDirection("up")
|
|
309
|
+
end sub
|
|
310
|
+
|
|
311
|
+
sub printDirection(theDirection as Direction)
|
|
312
|
+
print theDirection
|
|
313
|
+
end sub
|
|
314
|
+
|
|
315
|
+
enum Direction
|
|
316
|
+
up = "up"
|
|
317
|
+
down = "down"
|
|
318
|
+
end enum
|
|
319
|
+
|
|
320
|
+
`);
|
|
321
|
+
program.validate();
|
|
322
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
323
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'Direction').message
|
|
324
|
+
]);
|
|
325
|
+
});
|
|
326
|
+
it('supports passing enum type as enum type', () => {
|
|
327
|
+
program.setFile('source/file.bs', `
|
|
328
|
+
sub test(theDirection as Direction)
|
|
329
|
+
printDirection(theDirection)
|
|
330
|
+
end sub
|
|
331
|
+
|
|
332
|
+
sub printDirection(theDirection as Direction)
|
|
333
|
+
print theDirection
|
|
334
|
+
end sub
|
|
335
|
+
|
|
336
|
+
enum Direction
|
|
337
|
+
up = "up"
|
|
338
|
+
down = "down"
|
|
339
|
+
end enum
|
|
340
|
+
`);
|
|
341
|
+
program.validate();
|
|
342
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, []);
|
|
343
|
+
});
|
|
344
|
+
it('Catches argument type mismatches on function calls', () => {
|
|
345
|
+
program.setFile('source/file.brs', `
|
|
346
|
+
sub a(age as integer)
|
|
347
|
+
end sub
|
|
348
|
+
sub b()
|
|
349
|
+
a("hello")
|
|
350
|
+
end sub
|
|
351
|
+
`);
|
|
352
|
+
program.validate();
|
|
353
|
+
//should have an error
|
|
354
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
|
|
355
|
+
});
|
|
356
|
+
it('Catches argument type mismatches on function calls for functions defined in another file', () => {
|
|
357
|
+
program.setFile('source/file.brs', `
|
|
358
|
+
sub a(age as integer)
|
|
359
|
+
end sub
|
|
360
|
+
`);
|
|
361
|
+
program.setFile('source/file2.brs', `
|
|
362
|
+
sub b()
|
|
363
|
+
a("hello")
|
|
364
|
+
foo = "foo"
|
|
365
|
+
a(foo)
|
|
366
|
+
end sub
|
|
367
|
+
`);
|
|
368
|
+
program.validate();
|
|
369
|
+
//should have an error
|
|
370
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
|
|
371
|
+
});
|
|
372
|
+
it('catches argument type mismatches on function calls within namespaces', () => {
|
|
373
|
+
program.setFile('source/file.bs', `
|
|
374
|
+
namespace Name.Space
|
|
375
|
+
sub a(param as integer)
|
|
376
|
+
print param
|
|
377
|
+
end sub
|
|
378
|
+
|
|
379
|
+
sub b()
|
|
380
|
+
a("hello")
|
|
381
|
+
foo = "foo"
|
|
382
|
+
a(foo)
|
|
383
|
+
end sub
|
|
384
|
+
end namespace
|
|
385
|
+
`);
|
|
386
|
+
program.validate();
|
|
387
|
+
//should have an error
|
|
388
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
|
|
389
|
+
});
|
|
390
|
+
it('catches argument type mismatches on function calls as arguments', () => {
|
|
391
|
+
program.setFile('source/file1.bs', `
|
|
392
|
+
sub a(param as string)
|
|
393
|
+
print param
|
|
394
|
+
end sub
|
|
395
|
+
|
|
396
|
+
function getNum() as integer
|
|
397
|
+
return 1
|
|
398
|
+
end function
|
|
399
|
+
|
|
400
|
+
sub b()
|
|
401
|
+
a(getNum())
|
|
402
|
+
end sub
|
|
403
|
+
`);
|
|
404
|
+
program.validate();
|
|
405
|
+
//should have an error
|
|
406
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string').message);
|
|
407
|
+
});
|
|
408
|
+
it('catches argument type mismatches on function calls within namespaces across files', () => {
|
|
409
|
+
program.setFile('source/file1.bs', `
|
|
410
|
+
namespace Name.Space
|
|
411
|
+
function getNum() as integer
|
|
412
|
+
return 1
|
|
413
|
+
end function
|
|
414
|
+
|
|
415
|
+
function getStr() as string
|
|
416
|
+
return "hello"
|
|
417
|
+
end function
|
|
418
|
+
end namespace
|
|
419
|
+
`);
|
|
420
|
+
program.setFile('source/file2.bs', `
|
|
421
|
+
namespace Name.Space
|
|
422
|
+
sub needsInt(param as integer)
|
|
423
|
+
print param
|
|
424
|
+
end sub
|
|
425
|
+
|
|
426
|
+
sub someFunc()
|
|
427
|
+
needsInt(getStr())
|
|
428
|
+
needsInt(getNum())
|
|
429
|
+
end sub
|
|
430
|
+
end namespace
|
|
431
|
+
`);
|
|
432
|
+
program.validate();
|
|
433
|
+
//should have an error
|
|
434
|
+
(0, chai_1.expect)(program.getDiagnostics().length).to.equal(1);
|
|
435
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
|
|
436
|
+
});
|
|
437
|
+
it('correctly validates correct parameters that are class members', () => {
|
|
438
|
+
program.setFile('source/main.bs', `
|
|
439
|
+
class PiHolder
|
|
440
|
+
pi = 3.14
|
|
441
|
+
function getPi() as float
|
|
442
|
+
return m.pi
|
|
443
|
+
end function
|
|
444
|
+
end class
|
|
445
|
+
|
|
446
|
+
sub takesFloat(fl as float)
|
|
447
|
+
end sub
|
|
448
|
+
|
|
449
|
+
sub someFunc()
|
|
450
|
+
holder = new PiHolder()
|
|
451
|
+
takesFloat(holder.pi)
|
|
452
|
+
takesFloat(holder.getPI())
|
|
453
|
+
end sub`);
|
|
454
|
+
program.validate();
|
|
455
|
+
//should have no error
|
|
456
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
457
|
+
});
|
|
458
|
+
it('correctly validates wrong parameters that are class members', () => {
|
|
459
|
+
program.setFile('source/main.bs', `
|
|
460
|
+
class PiHolder
|
|
461
|
+
pi = 3.14
|
|
462
|
+
name = "hello"
|
|
463
|
+
function getPi() as float
|
|
464
|
+
return m.pi
|
|
465
|
+
end function
|
|
466
|
+
end class
|
|
467
|
+
|
|
468
|
+
sub takesFloat(fl as float)
|
|
469
|
+
end sub
|
|
470
|
+
|
|
471
|
+
sub someFunc()
|
|
472
|
+
holder = new PiHolder()
|
|
473
|
+
takesFloat(holder.name)
|
|
474
|
+
takesFloat(Str(holder.getPI()))
|
|
475
|
+
end sub`);
|
|
476
|
+
program.validate();
|
|
477
|
+
//should have error: holder.name is string
|
|
478
|
+
(0, chai_1.expect)(program.getDiagnostics().length).to.equal(2);
|
|
479
|
+
(0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'float').message);
|
|
480
|
+
});
|
|
481
|
+
it('correctly validates correct parameters that are interface members', () => {
|
|
482
|
+
program.setFile('source/main.bs', `
|
|
483
|
+
interface IPerson
|
|
484
|
+
height as float
|
|
485
|
+
name as string
|
|
486
|
+
function getWeight() as float
|
|
487
|
+
function getAddress() as string
|
|
488
|
+
end interface
|
|
489
|
+
|
|
490
|
+
sub takesFloat(fl as float)
|
|
491
|
+
end sub
|
|
492
|
+
|
|
493
|
+
sub someFunc(person as IPerson)
|
|
494
|
+
takesFloat(person.height)
|
|
495
|
+
takesFloat(person.getWeight())
|
|
496
|
+
end sub`);
|
|
497
|
+
program.validate();
|
|
498
|
+
//should have no error
|
|
499
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
500
|
+
});
|
|
501
|
+
it('correctly validates wrong parameters that are interface members', () => {
|
|
502
|
+
program.setFile('source/main.bs', `
|
|
503
|
+
interface IPerson
|
|
504
|
+
isAlive as boolean
|
|
505
|
+
function getAddress() as string
|
|
506
|
+
end interface
|
|
507
|
+
|
|
508
|
+
sub takesFloat(fl as float)
|
|
509
|
+
end sub
|
|
510
|
+
|
|
511
|
+
sub someFunc(person as IPerson)
|
|
512
|
+
takesFloat(person.isAlive)
|
|
513
|
+
takesFloat(person.getAddress())
|
|
514
|
+
end sub
|
|
515
|
+
`);
|
|
516
|
+
program.validate();
|
|
517
|
+
//should have 2 errors: person.name is string (not float) and person.getAddress() is object (not float)
|
|
518
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
519
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('boolean', 'float').message,
|
|
520
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'float').message
|
|
521
|
+
]);
|
|
522
|
+
});
|
|
523
|
+
it('`as object` param allows all types', () => {
|
|
524
|
+
program.setFile('source/main.bs', `
|
|
525
|
+
sub takesObject(obj as Object)
|
|
526
|
+
end sub
|
|
527
|
+
|
|
528
|
+
sub main()
|
|
529
|
+
takesObject(true)
|
|
530
|
+
takesObject(1)
|
|
531
|
+
takesObject(1.2)
|
|
532
|
+
takesObject(1.2#)
|
|
533
|
+
takesObject("text")
|
|
534
|
+
takesObject({})
|
|
535
|
+
takesObject([])
|
|
536
|
+
end sub
|
|
537
|
+
`);
|
|
538
|
+
program.validate();
|
|
539
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
540
|
+
});
|
|
541
|
+
it('allows conversions for arguments', () => {
|
|
542
|
+
program.setFile('source/main.bs', `
|
|
543
|
+
sub takesFloat(fl as float)
|
|
544
|
+
end sub
|
|
545
|
+
|
|
546
|
+
sub someFunc()
|
|
547
|
+
takesFloat(1)
|
|
548
|
+
end sub`);
|
|
549
|
+
program.validate();
|
|
550
|
+
//should have no error
|
|
551
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
552
|
+
});
|
|
553
|
+
it('allows subclasses as arguments', () => {
|
|
554
|
+
program.setFile('source/main.bs', `
|
|
555
|
+
|
|
556
|
+
class Animal
|
|
557
|
+
end class
|
|
558
|
+
|
|
559
|
+
class Dog extends Animal
|
|
560
|
+
end class
|
|
561
|
+
|
|
562
|
+
class Retriever extends Dog
|
|
563
|
+
end class
|
|
564
|
+
|
|
565
|
+
class Lab extends Retriever
|
|
566
|
+
end class
|
|
567
|
+
|
|
568
|
+
sub takesAnimal(thing as Animal)
|
|
569
|
+
end sub
|
|
570
|
+
|
|
571
|
+
sub someFunc()
|
|
572
|
+
fido = new Lab()
|
|
573
|
+
takesAnimal(fido)
|
|
574
|
+
end sub`);
|
|
575
|
+
program.validate();
|
|
576
|
+
//should have no error
|
|
577
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
578
|
+
});
|
|
579
|
+
it('allows subclasses from namespaces as arguments', () => {
|
|
580
|
+
program.setFile('source/main.bs', `
|
|
581
|
+
|
|
582
|
+
class Outside
|
|
583
|
+
end class
|
|
584
|
+
|
|
585
|
+
class ChildOutExtendsInside extends NS.Inside
|
|
586
|
+
end class
|
|
587
|
+
|
|
588
|
+
namespace NS
|
|
589
|
+
class Inside
|
|
590
|
+
end class
|
|
591
|
+
|
|
592
|
+
class ChildInExtendsOutside extends Outside
|
|
593
|
+
end class
|
|
594
|
+
|
|
595
|
+
class ChildInExtendsInside extends Inside
|
|
596
|
+
sub methodTakesInside(i as Inside)
|
|
597
|
+
end sub
|
|
598
|
+
end class
|
|
599
|
+
|
|
600
|
+
sub takesInside(klass as Inside)
|
|
601
|
+
end sub
|
|
602
|
+
|
|
603
|
+
sub testFuncInNamespace()
|
|
604
|
+
takesOutside(new Outside())
|
|
605
|
+
takesOutside(new NS.ChildInExtendsOutside())
|
|
606
|
+
|
|
607
|
+
' These call NS.takesInside
|
|
608
|
+
takesInside(new NS.Inside())
|
|
609
|
+
takesInside(new Inside())
|
|
610
|
+
takesInside(new NS.ChildInExtendsInside())
|
|
611
|
+
takesInside(new ChildInExtendsInside())
|
|
612
|
+
takesInside(new ChildOutExtendsInside())
|
|
613
|
+
|
|
614
|
+
child = new ChildInExtendsInside()
|
|
615
|
+
child.methodTakesInside(new Inside())
|
|
616
|
+
child.methodTakesInside(new ChildInExtendsInside())
|
|
617
|
+
child.methodTakesInside(new ChildOutExtendsInside())
|
|
618
|
+
end sub
|
|
619
|
+
|
|
620
|
+
end namespace
|
|
621
|
+
|
|
622
|
+
sub takesOutside(klass as Outside)
|
|
623
|
+
end sub
|
|
624
|
+
|
|
625
|
+
sub takesInside(klass as NS.Inside)
|
|
626
|
+
end sub
|
|
627
|
+
|
|
628
|
+
sub testFunc()
|
|
629
|
+
takesOutside(new Outside())
|
|
630
|
+
takesOutside(new NS.ChildInExtendsOutside())
|
|
631
|
+
|
|
632
|
+
takesInside(new NS.Inside())
|
|
633
|
+
takesInside(new NS.ChildInExtendsInside())
|
|
634
|
+
takesInside(new ChildOutExtendsInside())
|
|
635
|
+
|
|
636
|
+
NS.takesInside(new NS.Inside())
|
|
637
|
+
NS.takesInside(new NS.ChildInExtendsInside())
|
|
638
|
+
NS.takesInside(new ChildOutExtendsInside())
|
|
639
|
+
|
|
640
|
+
child = new NS.ChildInExtendsInside()
|
|
641
|
+
child.methodTakesInside(new NS.Inside())
|
|
642
|
+
child.methodTakesInside(new NS.ChildInExtendsInside())
|
|
643
|
+
child.methodTakesInside(new ChildOutExtendsInside())
|
|
644
|
+
end sub`);
|
|
645
|
+
program.validate();
|
|
646
|
+
//should have no error
|
|
647
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
648
|
+
});
|
|
649
|
+
it('respects union types', () => {
|
|
650
|
+
program.setFile('source/main.bs', `
|
|
651
|
+
sub takesStringOrKlass(p as string or Klass)
|
|
652
|
+
end sub
|
|
653
|
+
|
|
654
|
+
class Klass
|
|
655
|
+
end class
|
|
656
|
+
|
|
657
|
+
sub someFunc()
|
|
658
|
+
myKlass = new Klass()
|
|
659
|
+
takesStringOrKlass("test")
|
|
660
|
+
takesStringOrKlass(myKlass)
|
|
661
|
+
takesStringOrKlass(1)
|
|
662
|
+
end sub`);
|
|
663
|
+
program.validate();
|
|
664
|
+
//should have error when passed an integer
|
|
665
|
+
(0, chai_1.expect)(program.getDiagnostics().length).to.equal(1);
|
|
666
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
667
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string or Klass').message
|
|
668
|
+
]);
|
|
669
|
+
});
|
|
670
|
+
it('validates functions assigned to variables', () => {
|
|
671
|
+
program.setFile('source/main.bs', `
|
|
672
|
+
sub someFunc()
|
|
673
|
+
myFunc = function(i as integer, s as string)
|
|
674
|
+
print i+1
|
|
675
|
+
print s.len()
|
|
676
|
+
end function
|
|
677
|
+
myFunc("hello", 2)
|
|
678
|
+
end sub`);
|
|
679
|
+
program.validate();
|
|
680
|
+
//should have error when passed incorrect types
|
|
681
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
682
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message,
|
|
683
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string').message
|
|
684
|
+
]);
|
|
685
|
+
});
|
|
686
|
+
it('allows any parameter types in a function passed as an argument', () => {
|
|
687
|
+
program.setFile('source/file.brs', `
|
|
688
|
+
function getStrLength(name as string) as integer
|
|
689
|
+
return len(name)
|
|
690
|
+
end function
|
|
691
|
+
|
|
692
|
+
sub tryManyParams(someFunc as function)
|
|
693
|
+
print someFunc(1, 2, "hello", "world")
|
|
694
|
+
end sub
|
|
695
|
+
|
|
696
|
+
sub test()
|
|
697
|
+
tryManyParams(getStrLength)
|
|
698
|
+
end sub
|
|
699
|
+
`);
|
|
700
|
+
program.validate();
|
|
701
|
+
//should have no errors
|
|
702
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
703
|
+
});
|
|
704
|
+
it('allows a inline function as an argument of type function', () => {
|
|
705
|
+
program.setFile('source/file.brs', `
|
|
706
|
+
sub tryManyParams(someFunc as function)
|
|
707
|
+
print someFunc(1, 2, "hello", "world")
|
|
708
|
+
end sub
|
|
709
|
+
|
|
710
|
+
sub test()
|
|
711
|
+
tryManyParams(sub (i as integer)
|
|
712
|
+
print i
|
|
713
|
+
end sub)
|
|
714
|
+
end sub
|
|
715
|
+
`);
|
|
716
|
+
program.validate();
|
|
717
|
+
//should have no errors
|
|
718
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
719
|
+
});
|
|
720
|
+
it('validates when a non-function is used as an argument expecting a function', () => {
|
|
721
|
+
program.setFile('source/file.brs', `
|
|
722
|
+
sub tryManyParams(someFunc as function)
|
|
723
|
+
print someFunc(1, 2, "hello", "world")
|
|
724
|
+
end sub
|
|
725
|
+
|
|
726
|
+
sub test()
|
|
727
|
+
notAFunction = 3.14
|
|
728
|
+
tryManyParams(notAFunction)
|
|
729
|
+
end sub
|
|
730
|
+
`);
|
|
731
|
+
program.validate();
|
|
732
|
+
//should have an error that the argument is not a function
|
|
733
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
734
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'function').message
|
|
735
|
+
]);
|
|
736
|
+
});
|
|
737
|
+
it('allows a class constructor to be passed as arg to param typed `as function`', () => {
|
|
738
|
+
program.setFile('source/file.bs', `
|
|
739
|
+
sub callSomeFunc(someFunc as function)
|
|
740
|
+
someFunc()
|
|
741
|
+
end sub
|
|
742
|
+
|
|
743
|
+
class MyKlass
|
|
744
|
+
end class
|
|
745
|
+
|
|
746
|
+
sub doStuff()
|
|
747
|
+
callSomeFunc(MyKlass)
|
|
748
|
+
end sub
|
|
749
|
+
`);
|
|
750
|
+
program.validate();
|
|
751
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
752
|
+
});
|
|
753
|
+
it('allows a namespaced class constructor to be passed as arg to param typed `as function`', () => {
|
|
754
|
+
program.setFile('source/file.bs', `
|
|
755
|
+
sub callSomeFunc(someFunc as function)
|
|
756
|
+
someFunc()
|
|
757
|
+
end sub
|
|
758
|
+
|
|
759
|
+
namespace Alpha
|
|
760
|
+
class MyKlass
|
|
761
|
+
end class
|
|
762
|
+
|
|
763
|
+
sub doStuff()
|
|
764
|
+
callSomeFunc(MyKlass)
|
|
765
|
+
end sub
|
|
766
|
+
end namespace
|
|
767
|
+
`);
|
|
768
|
+
program.validate();
|
|
769
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
770
|
+
});
|
|
771
|
+
it('allows any variable to passed as argument to an untyped param with default type invalid', () => {
|
|
772
|
+
program.setFile('source/util.brs', `
|
|
773
|
+
sub doSomething(x = invalid)
|
|
774
|
+
print x
|
|
775
|
+
end sub
|
|
776
|
+
|
|
777
|
+
sub tests()
|
|
778
|
+
doSomething(1)
|
|
779
|
+
doSomething(1.1)
|
|
780
|
+
doSomething("Hello")
|
|
781
|
+
doSomething(true)
|
|
782
|
+
doSomething({test: true})
|
|
783
|
+
end sub
|
|
784
|
+
`);
|
|
785
|
+
program.validate();
|
|
786
|
+
//should have no errors
|
|
787
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
788
|
+
});
|
|
789
|
+
it('allows calling future function and save to same variable', () => {
|
|
790
|
+
program.setFile('source/util.brs', `
|
|
791
|
+
function getSomeInt() as integer
|
|
792
|
+
numVal = getUntypedNum()
|
|
793
|
+
numVal = cInt(numVal)
|
|
794
|
+
return numVal
|
|
795
|
+
end function
|
|
796
|
+
|
|
797
|
+
function getUntypedNum()
|
|
798
|
+
return 1
|
|
799
|
+
end function
|
|
800
|
+
`);
|
|
801
|
+
program.validate();
|
|
802
|
+
//should have no errors
|
|
803
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
804
|
+
});
|
|
805
|
+
it('allows union types of all compatible types as arg', () => {
|
|
806
|
+
program.setFile('source/util.bs', `
|
|
807
|
+
sub printIntNum(num as float or double or integer)
|
|
808
|
+
print cInt(num)
|
|
809
|
+
end sub
|
|
810
|
+
`);
|
|
811
|
+
program.validate();
|
|
812
|
+
//should have no errors
|
|
813
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
814
|
+
});
|
|
815
|
+
it('allows function calls of built-in members of primitives', () => {
|
|
816
|
+
program.setFile('source/util.brs', `
|
|
817
|
+
sub doSomething()
|
|
818
|
+
myStr = "Hello World"
|
|
819
|
+
myStr = myStr.replace("World", "You")
|
|
820
|
+
print myStr
|
|
821
|
+
end sub
|
|
822
|
+
`);
|
|
823
|
+
program.validate();
|
|
824
|
+
//should have no errors
|
|
825
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
826
|
+
});
|
|
827
|
+
it('validates union types of all compatible types as arg - when some do not work', () => {
|
|
828
|
+
program.setFile('source/util.bs', `
|
|
829
|
+
sub printIntNum(maybeNum as float or string)
|
|
830
|
+
print cInt(maybeNum)
|
|
831
|
+
end sub
|
|
832
|
+
`);
|
|
833
|
+
program.validate();
|
|
834
|
+
//should have no errors
|
|
835
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
836
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float or string', 'float').message
|
|
837
|
+
]);
|
|
838
|
+
});
|
|
839
|
+
it('validates function calls of built-in members of primitives', () => {
|
|
840
|
+
program.setFile('source/util.brs', `
|
|
841
|
+
sub doSomething()
|
|
842
|
+
myStr = "Hello World"
|
|
843
|
+
notAString = 3.14
|
|
844
|
+
myStr = myStr.replace("World", notAString)
|
|
845
|
+
print myStr
|
|
846
|
+
end sub
|
|
847
|
+
`);
|
|
848
|
+
program.validate();
|
|
849
|
+
//should have error - 2nd param should be a string, not a float
|
|
850
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
851
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
852
|
+
]);
|
|
853
|
+
});
|
|
854
|
+
it('validates method calls of classes', () => {
|
|
855
|
+
program.setFile('source/util.bs', `
|
|
856
|
+
class Klass
|
|
857
|
+
sub test(input as string)
|
|
858
|
+
end sub
|
|
859
|
+
end class
|
|
860
|
+
|
|
861
|
+
sub doSomething()
|
|
862
|
+
k = new Klass()
|
|
863
|
+
k.test(3.14)
|
|
864
|
+
end sub
|
|
865
|
+
`);
|
|
866
|
+
program.validate();
|
|
867
|
+
//should have error - param should be a string, not a float
|
|
868
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
869
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
870
|
+
]);
|
|
871
|
+
});
|
|
872
|
+
it('validates inside method calls of classes', () => {
|
|
873
|
+
program.setFile('source/util.bs', `
|
|
874
|
+
class Klass
|
|
875
|
+
sub test(input as string)
|
|
876
|
+
end sub
|
|
877
|
+
|
|
878
|
+
sub otherTest()
|
|
879
|
+
m.test(3.14)
|
|
880
|
+
end sub
|
|
881
|
+
end class
|
|
882
|
+
`);
|
|
883
|
+
program.validate();
|
|
884
|
+
//should have error - param should be a string, not a float
|
|
885
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
886
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
887
|
+
]);
|
|
888
|
+
});
|
|
889
|
+
it('validates calls of a constructor', () => {
|
|
890
|
+
program.setFile('source/util.bs', `
|
|
891
|
+
class Klass
|
|
892
|
+
sub new(name as string)
|
|
893
|
+
end sub
|
|
894
|
+
end class
|
|
895
|
+
|
|
896
|
+
sub createKlass()
|
|
897
|
+
k = new Klass(3.14)
|
|
898
|
+
end sub
|
|
899
|
+
`);
|
|
900
|
+
program.validate();
|
|
901
|
+
//should have error - param should be a string, not a float
|
|
902
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
903
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
904
|
+
]);
|
|
905
|
+
});
|
|
906
|
+
it('validates super calls in a constructor', () => {
|
|
907
|
+
program.setFile('source/util.bs', `
|
|
908
|
+
class Klass
|
|
909
|
+
sub new(name as string)
|
|
910
|
+
end sub
|
|
911
|
+
end class
|
|
912
|
+
|
|
913
|
+
class SubKlass extends Klass
|
|
914
|
+
sub new()
|
|
915
|
+
super(3.14)
|
|
916
|
+
end sub
|
|
917
|
+
end class
|
|
918
|
+
`);
|
|
919
|
+
program.validate();
|
|
920
|
+
//should have error - param should be a string, not a float
|
|
921
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
922
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
923
|
+
]);
|
|
924
|
+
});
|
|
925
|
+
it('validates super calls in a class methods', () => {
|
|
926
|
+
program.setFile('source/util.bs', `
|
|
927
|
+
class Klass
|
|
928
|
+
sub test(name as string)
|
|
929
|
+
end sub
|
|
930
|
+
end class
|
|
931
|
+
|
|
932
|
+
class SubKlass extends Klass
|
|
933
|
+
sub test2()
|
|
934
|
+
super.test(3.14)
|
|
935
|
+
end sub
|
|
936
|
+
end class
|
|
937
|
+
`);
|
|
938
|
+
program.validate();
|
|
939
|
+
//should have error - param should be a string, not a float
|
|
940
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
941
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
|
|
942
|
+
]);
|
|
943
|
+
});
|
|
944
|
+
it('validates a function passed as an arg', () => {
|
|
945
|
+
program.setFile('source/util.bs', `
|
|
946
|
+
sub foo()
|
|
947
|
+
getPi = function()
|
|
948
|
+
return 3.14
|
|
949
|
+
end function
|
|
950
|
+
bar(getPi)
|
|
951
|
+
end sub
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
sub bar(num as integer)
|
|
955
|
+
print num
|
|
956
|
+
end sub
|
|
957
|
+
`);
|
|
958
|
+
program.validate();
|
|
959
|
+
//should have error - param should be a string, not a float
|
|
960
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
961
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('function () as dynamic', 'integer').message
|
|
962
|
+
]);
|
|
963
|
+
});
|
|
964
|
+
it('allows AAs that match an interface to be passed as args', () => {
|
|
965
|
+
program.setFile('source/util.bs', `
|
|
966
|
+
sub doStuff()
|
|
967
|
+
takesMyIface({beta: "hello", charlie: "world"})
|
|
968
|
+
end sub
|
|
969
|
+
|
|
970
|
+
sub takesMyIface(iFace as MyIFace)
|
|
971
|
+
end sub
|
|
972
|
+
|
|
973
|
+
interface MyIFace
|
|
974
|
+
beta as string
|
|
975
|
+
charlie as string
|
|
976
|
+
end interface
|
|
977
|
+
`);
|
|
978
|
+
program.validate();
|
|
979
|
+
//should have error
|
|
980
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
981
|
+
});
|
|
982
|
+
it('validates empty AAs that are passed as args to param expecting interface', () => {
|
|
983
|
+
program.setFile('source/util.bs', `
|
|
984
|
+
sub doStuff()
|
|
985
|
+
takesMyIface({})
|
|
986
|
+
end sub
|
|
987
|
+
|
|
988
|
+
sub takesMyIface(iFace as MyIFace)
|
|
989
|
+
end sub
|
|
990
|
+
|
|
991
|
+
interface MyIFace
|
|
992
|
+
beta as string
|
|
993
|
+
charlie as string
|
|
994
|
+
end interface
|
|
995
|
+
`);
|
|
996
|
+
program.validate();
|
|
997
|
+
//should have error
|
|
998
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
999
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
|
|
1000
|
+
missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }, { name: 'charlie', expectedType: StringType_1.StringType.instance }]
|
|
1001
|
+
}).message
|
|
1002
|
+
]);
|
|
1003
|
+
});
|
|
1004
|
+
it('includes data on missing fields', () => {
|
|
1005
|
+
program.setFile('source/util.bs', `
|
|
1006
|
+
sub doStuff()
|
|
1007
|
+
takesMyIface({charlie: "hello"})
|
|
1008
|
+
end sub
|
|
1009
|
+
|
|
1010
|
+
sub takesMyIface(iFace as MyIFace)
|
|
1011
|
+
end sub
|
|
1012
|
+
|
|
1013
|
+
interface MyIFace
|
|
1014
|
+
beta as string
|
|
1015
|
+
charlie as integer
|
|
1016
|
+
end interface
|
|
1017
|
+
`);
|
|
1018
|
+
program.validate();
|
|
1019
|
+
//should have error
|
|
1020
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1021
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
|
|
1022
|
+
missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }],
|
|
1023
|
+
fieldMismatches: [{ name: 'charlie', expectedType: IntegerType_1.IntegerType.instance, actualType: StringType_1.StringType.instance }]
|
|
1024
|
+
}).message
|
|
1025
|
+
]);
|
|
1026
|
+
//The aa should have 'beta' and 'charlie' properties of type string and integer
|
|
1027
|
+
const diagnostics = program.getDiagnostics();
|
|
1028
|
+
(0, chai_1.expect)(diagnostics.length).to.eq(1);
|
|
1029
|
+
const data = diagnostics[0].data;
|
|
1030
|
+
(0, chai_1.expect)(data.missingFields.length).to.eq(1);
|
|
1031
|
+
(0, chai_1.expect)(data.missingFields[0].name).to.eq('beta');
|
|
1032
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.missingFields[0].expectedType, StringType_1.StringType);
|
|
1033
|
+
(0, chai_1.expect)(data.fieldMismatches.length).to.eq(1);
|
|
1034
|
+
(0, chai_1.expect)(data.fieldMismatches[0].name).to.eq('charlie');
|
|
1035
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].expectedType, IntegerType_1.IntegerType);
|
|
1036
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].actualType, StringType_1.StringType);
|
|
1037
|
+
});
|
|
1038
|
+
it('allows interfaces that have a superset of properties', () => {
|
|
1039
|
+
program.setFile('source/util.bs', `
|
|
1040
|
+
sub doStuff()
|
|
1041
|
+
takesMyIface({alpha: true, beta: "hello", charlie: 1})
|
|
1042
|
+
end sub
|
|
1043
|
+
|
|
1044
|
+
sub takesMyIface(iFace as MyIFace)
|
|
1045
|
+
end sub
|
|
1046
|
+
|
|
1047
|
+
interface MyIFace
|
|
1048
|
+
beta as string
|
|
1049
|
+
charlie as integer
|
|
1050
|
+
end interface
|
|
1051
|
+
`);
|
|
1052
|
+
program.validate();
|
|
1053
|
+
//should have no errors
|
|
1054
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1055
|
+
});
|
|
1056
|
+
it('allows interfaces that have a superset of properties', () => {
|
|
1057
|
+
program.setFile('source/util.bs', `
|
|
1058
|
+
sub doStuff(otherFace as MyOtherFace)
|
|
1059
|
+
takesMyIface(otherFace)
|
|
1060
|
+
end sub
|
|
1061
|
+
|
|
1062
|
+
sub takesMyIface(iFace as MyIFace)
|
|
1063
|
+
end sub
|
|
1064
|
+
|
|
1065
|
+
interface MyIFace
|
|
1066
|
+
beta as string
|
|
1067
|
+
charlie as integer
|
|
1068
|
+
end interface
|
|
1069
|
+
|
|
1070
|
+
interface MyOtherFace
|
|
1071
|
+
alpha as boolean
|
|
1072
|
+
beta as string
|
|
1073
|
+
charlie as integer
|
|
1074
|
+
end interface
|
|
1075
|
+
`);
|
|
1076
|
+
program.validate();
|
|
1077
|
+
//should have no errors
|
|
1078
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1079
|
+
});
|
|
1080
|
+
it('includes data on missing fields', () => {
|
|
1081
|
+
program.setFile('source/util.bs', `
|
|
1082
|
+
sub doStuff()
|
|
1083
|
+
takesMyIface({charlie: "hello"})
|
|
1084
|
+
end sub
|
|
1085
|
+
|
|
1086
|
+
sub takesMyIface(iFace as MyIFace)
|
|
1087
|
+
end sub
|
|
1088
|
+
|
|
1089
|
+
interface MyIFace
|
|
1090
|
+
beta as string
|
|
1091
|
+
charlie as integer
|
|
1092
|
+
end interface
|
|
1093
|
+
`);
|
|
1094
|
+
program.validate();
|
|
1095
|
+
//should have error
|
|
1096
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1097
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
|
|
1098
|
+
missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }],
|
|
1099
|
+
fieldMismatches: [{ name: 'charlie', expectedType: IntegerType_1.IntegerType.instance, actualType: StringType_1.StringType.instance }]
|
|
1100
|
+
}).message
|
|
1101
|
+
]);
|
|
1102
|
+
//The aa should have 'beta' and 'charlie' properties of type string and integer
|
|
1103
|
+
const diagnostics = program.getDiagnostics();
|
|
1104
|
+
(0, chai_1.expect)(diagnostics.length).to.eq(1);
|
|
1105
|
+
const data = diagnostics[0].data;
|
|
1106
|
+
(0, chai_1.expect)(data.missingFields.length).to.eq(1);
|
|
1107
|
+
(0, chai_1.expect)(data.missingFields[0].name).to.eq('beta');
|
|
1108
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.missingFields[0].expectedType, StringType_1.StringType);
|
|
1109
|
+
(0, chai_1.expect)(data.fieldMismatches.length).to.eq(1);
|
|
1110
|
+
(0, chai_1.expect)(data.fieldMismatches[0].name).to.eq('charlie');
|
|
1111
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].expectedType, IntegerType_1.IntegerType);
|
|
1112
|
+
(0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].actualType, StringType_1.StringType);
|
|
1113
|
+
});
|
|
1114
|
+
describe('array compatibility', () => {
|
|
1115
|
+
it('accepts dynamic when assigning to a roArray', () => {
|
|
1116
|
+
program.setFile('source/util.bs', `
|
|
1117
|
+
sub takesArray(arr as roArray)
|
|
1118
|
+
end sub
|
|
1119
|
+
|
|
1120
|
+
sub doStuff(someArray)
|
|
1121
|
+
takesArray(someArray)
|
|
1122
|
+
end sub
|
|
1123
|
+
`);
|
|
1124
|
+
program.validate();
|
|
1125
|
+
//should have no errors
|
|
1126
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1127
|
+
});
|
|
1128
|
+
it('accepts roArray when assigning to a roArray', () => {
|
|
1129
|
+
program.setFile('source/util.bs', `
|
|
1130
|
+
sub takesArray(arr as roArray)
|
|
1131
|
+
end sub
|
|
1132
|
+
|
|
1133
|
+
sub doStuff(someArray as roArray)
|
|
1134
|
+
takesArray(someArray)
|
|
1135
|
+
end sub
|
|
1136
|
+
`);
|
|
1137
|
+
program.validate();
|
|
1138
|
+
//should have no errors
|
|
1139
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1140
|
+
});
|
|
1141
|
+
it('accepts typed arrays when assigning to a roArray', () => {
|
|
1142
|
+
program.setFile('source/util.bs', `
|
|
1143
|
+
sub takesArray(arr as roArray)
|
|
1144
|
+
end sub
|
|
1145
|
+
|
|
1146
|
+
sub doStuff(someArray as dynamic[])
|
|
1147
|
+
takesArray(someArray)
|
|
1148
|
+
end sub
|
|
1149
|
+
`);
|
|
1150
|
+
program.validate();
|
|
1151
|
+
//should have no errors
|
|
1152
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1153
|
+
});
|
|
1154
|
+
it('accepts roArray when assigning to dynamic[]', () => {
|
|
1155
|
+
program.setFile('source/util.bs', `
|
|
1156
|
+
sub takesArray(arr as dynamic[])
|
|
1157
|
+
end sub
|
|
1158
|
+
|
|
1159
|
+
sub doStuff(someArray as roArray)
|
|
1160
|
+
takesArray(someArray)
|
|
1161
|
+
end sub
|
|
1162
|
+
`);
|
|
1163
|
+
program.validate();
|
|
1164
|
+
//should have no errors
|
|
1165
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1166
|
+
});
|
|
1167
|
+
it('accepts roArray when assigning to typed array', () => {
|
|
1168
|
+
program.setFile('source/util.bs', `
|
|
1169
|
+
sub takesArray(arr as string[])
|
|
1170
|
+
end sub
|
|
1171
|
+
|
|
1172
|
+
sub doStuff(someArray as roArray)
|
|
1173
|
+
takesArray(someArray)
|
|
1174
|
+
end sub
|
|
1175
|
+
`);
|
|
1176
|
+
program.validate();
|
|
1177
|
+
//should have no errors
|
|
1178
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1179
|
+
});
|
|
1180
|
+
it('validates when typed array types are incompatible', () => {
|
|
1181
|
+
program.setFile('source/util.bs', `
|
|
1182
|
+
sub takesArray(arr as string[])
|
|
1183
|
+
end sub
|
|
1184
|
+
|
|
1185
|
+
sub doStuff(someArray as integer[])
|
|
1186
|
+
takesArray(someArray)
|
|
1187
|
+
end sub
|
|
1188
|
+
`);
|
|
1189
|
+
program.validate();
|
|
1190
|
+
//should have errors
|
|
1191
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1192
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('Array<integer>', 'Array<string>').message
|
|
1193
|
+
]);
|
|
1194
|
+
});
|
|
1195
|
+
it('accepts when typed array types are compatible', () => {
|
|
1196
|
+
program.setFile('source/util.bs', `
|
|
1197
|
+
sub takesArray(arr as float[])
|
|
1198
|
+
end sub
|
|
1199
|
+
|
|
1200
|
+
sub doStuff(someArray as integer[])
|
|
1201
|
+
takesArray(someArray)
|
|
1202
|
+
end sub
|
|
1203
|
+
`);
|
|
1204
|
+
program.validate();
|
|
1205
|
+
//should have no errors
|
|
1206
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
describe('interface with optional properties', () => {
|
|
1210
|
+
it('allows using interfaces with optional props', () => {
|
|
1211
|
+
program.setFile('source/util.bs', `
|
|
1212
|
+
function takesIFace(iface as MyIFace) as string
|
|
1213
|
+
if invalid <> iface.name
|
|
1214
|
+
return iface.name
|
|
1215
|
+
else if invalid <> iface.data
|
|
1216
|
+
return FormatJson(iface.data)
|
|
1217
|
+
end if
|
|
1218
|
+
return "no"
|
|
1219
|
+
end function
|
|
1220
|
+
|
|
1221
|
+
sub doStuff(iface as MyIFace)
|
|
1222
|
+
print takesIFace(iface)
|
|
1223
|
+
end sub
|
|
1224
|
+
|
|
1225
|
+
interface MyIFace
|
|
1226
|
+
optional name as string
|
|
1227
|
+
optional data
|
|
1228
|
+
end interface
|
|
1229
|
+
`);
|
|
1230
|
+
program.validate();
|
|
1231
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1232
|
+
});
|
|
1233
|
+
it('allows using passing AAs with missing optional properties', () => {
|
|
1234
|
+
program.setFile('source/util.bs', `
|
|
1235
|
+
function takesIFace(iface as MyIFace) as string
|
|
1236
|
+
if invalid <> iface.name
|
|
1237
|
+
return iface.name
|
|
1238
|
+
else if invalid <> iface.data
|
|
1239
|
+
return FormatJson(iface.data)
|
|
1240
|
+
end if
|
|
1241
|
+
return "no"
|
|
1242
|
+
end function
|
|
1243
|
+
|
|
1244
|
+
sub doStuff(iface as MyIFace)
|
|
1245
|
+
print takesIFace({name: "Hello"})
|
|
1246
|
+
end sub
|
|
1247
|
+
|
|
1248
|
+
interface MyIFace
|
|
1249
|
+
optional name as string
|
|
1250
|
+
optional data
|
|
1251
|
+
end interface
|
|
1252
|
+
`);
|
|
1253
|
+
program.validate();
|
|
1254
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1255
|
+
});
|
|
1256
|
+
it('disallows using AAs with bad types for optional properties', () => {
|
|
1257
|
+
program.setFile('source/util.bs', `
|
|
1258
|
+
function takesIFace(iface as MyIFace) as string
|
|
1259
|
+
if invalid <> iface.name
|
|
1260
|
+
return iface.name
|
|
1261
|
+
else if invalid <> iface.data
|
|
1262
|
+
return FormatJson(iface.data)
|
|
1263
|
+
end if
|
|
1264
|
+
return "no"
|
|
1265
|
+
end function
|
|
1266
|
+
|
|
1267
|
+
sub doStuff(iface as MyIFace)
|
|
1268
|
+
print takesIFace({name: 3.14})
|
|
1269
|
+
end sub
|
|
1270
|
+
|
|
1271
|
+
interface MyIFace
|
|
1272
|
+
optional name as string
|
|
1273
|
+
optional data
|
|
1274
|
+
end interface
|
|
1275
|
+
`);
|
|
1276
|
+
program.validate();
|
|
1277
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1278
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
|
|
1279
|
+
fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: types_1.FloatType.instance }]
|
|
1280
|
+
}).message
|
|
1281
|
+
]);
|
|
1282
|
+
});
|
|
1283
|
+
it('disallows passing classes with bad types for optional properties', () => {
|
|
1284
|
+
program.setFile('source/util.bs', `
|
|
1285
|
+
function takesIFace(iface as MyIFace) as string
|
|
1286
|
+
if invalid <> iface.name
|
|
1287
|
+
return iface.name
|
|
1288
|
+
else if invalid <> iface.data
|
|
1289
|
+
return FormatJson(iface.data)
|
|
1290
|
+
end if
|
|
1291
|
+
return "no"
|
|
1292
|
+
end function
|
|
1293
|
+
|
|
1294
|
+
sub doStuff(iface as MyIFace)
|
|
1295
|
+
k = new MyKlass()
|
|
1296
|
+
print takesIFace(k)
|
|
1297
|
+
end sub
|
|
1298
|
+
|
|
1299
|
+
interface MyIFace
|
|
1300
|
+
optional name as string
|
|
1301
|
+
optional data
|
|
1302
|
+
end interface
|
|
1303
|
+
|
|
1304
|
+
class MyKlass
|
|
1305
|
+
name as float
|
|
1306
|
+
end class
|
|
1307
|
+
`);
|
|
1308
|
+
program.validate();
|
|
1309
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1310
|
+
DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('MyKlass', 'MyIFace', {
|
|
1311
|
+
fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: types_1.FloatType.instance }]
|
|
1312
|
+
}).message
|
|
1313
|
+
]);
|
|
1314
|
+
});
|
|
1315
|
+
it('allows passing classes as args for interfaces with optional properties', () => {
|
|
1316
|
+
program.setFile('source/util.bs', `
|
|
1317
|
+
function takesIFace(iface as MyIFace) as string
|
|
1318
|
+
if invalid <> iface.name
|
|
1319
|
+
return iface.name
|
|
1320
|
+
else if invalid <> iface.data
|
|
1321
|
+
return FormatJson(iface.data)
|
|
1322
|
+
end if
|
|
1323
|
+
return "no"
|
|
1324
|
+
end function
|
|
1325
|
+
|
|
1326
|
+
sub doStuff(iface as MyIFace)
|
|
1327
|
+
k = new MyKlass()
|
|
1328
|
+
k2 = new MyKlass2()
|
|
1329
|
+
print takesIFace(k)
|
|
1330
|
+
print takesIFace(k2)
|
|
1331
|
+
end sub
|
|
1332
|
+
|
|
1333
|
+
interface MyIFace
|
|
1334
|
+
optional name as string
|
|
1335
|
+
optional data
|
|
1336
|
+
end interface
|
|
1337
|
+
|
|
1338
|
+
class MyKlass
|
|
1339
|
+
data = {}
|
|
1340
|
+
end class
|
|
1341
|
+
|
|
1342
|
+
class MyKlass2
|
|
1343
|
+
data = "test"
|
|
1344
|
+
end class
|
|
1345
|
+
`);
|
|
1346
|
+
program.validate();
|
|
1347
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1348
|
+
});
|
|
1349
|
+
});
|
|
1350
|
+
it('recursive types are allowed', () => {
|
|
1351
|
+
program.setFile('source/util.bs', `
|
|
1352
|
+
interface ChainNode
|
|
1353
|
+
name as string
|
|
1354
|
+
next as ChainNode
|
|
1355
|
+
end interface
|
|
1356
|
+
|
|
1357
|
+
function getChain(cNode as ChainNode) as string
|
|
1358
|
+
output = cNode.name
|
|
1359
|
+
if cNode.next <> invalid
|
|
1360
|
+
output += " - " + getChain(cNode.next)
|
|
1361
|
+
end if
|
|
1362
|
+
return output
|
|
1363
|
+
end function
|
|
1364
|
+
`);
|
|
1365
|
+
program.validate();
|
|
1366
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1367
|
+
});
|
|
1368
|
+
it('recursive types are allowed as array members', () => {
|
|
1369
|
+
program.setFile('source/util.bs', `
|
|
1370
|
+
interface ChainNode
|
|
1371
|
+
name as string
|
|
1372
|
+
nextItems as ChainNode[]
|
|
1373
|
+
end interface
|
|
1374
|
+
|
|
1375
|
+
function getChain(cNode as ChainNode) as string
|
|
1376
|
+
output = cNode.name
|
|
1377
|
+
for each item in cNode.nextItems
|
|
1378
|
+
output += " - " + getChain(item)
|
|
1379
|
+
end for
|
|
1380
|
+
return output
|
|
1381
|
+
end function
|
|
1382
|
+
`);
|
|
1383
|
+
program.validate();
|
|
1384
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1385
|
+
});
|
|
1386
|
+
it('deeply recursive types are allowed', () => {
|
|
1387
|
+
program.setFile('source/util.bs', `
|
|
1388
|
+
interface ChainNode
|
|
1389
|
+
name as string
|
|
1390
|
+
nextItem as ChainNodeWrapper
|
|
1391
|
+
end interface
|
|
1392
|
+
|
|
1393
|
+
interface ChainNodeWrapper
|
|
1394
|
+
node as ChainNode
|
|
1395
|
+
end interface
|
|
1396
|
+
|
|
1397
|
+
function getChain(cNode as ChainNode) as string
|
|
1398
|
+
output = cNode.name
|
|
1399
|
+
if cNode.nextItem <> invalid
|
|
1400
|
+
output += " - " + getChain(cNode.nextItem.node)
|
|
1401
|
+
end if
|
|
1402
|
+
return output
|
|
1403
|
+
end function
|
|
1404
|
+
|
|
1405
|
+
sub useChain()
|
|
1406
|
+
chain3 = {name: "C", nextItem: invalid}
|
|
1407
|
+
wrapper3 = {node: chain3}
|
|
1408
|
+
chain2 = {name: "B", nextItem: wrapper3}
|
|
1409
|
+
wrapper2 = {node: chain2}
|
|
1410
|
+
chain1 = {name: "A", nextItem: wrapper2}
|
|
1411
|
+
|
|
1412
|
+
print getChain(chain1)
|
|
1413
|
+
end sub
|
|
1414
|
+
`);
|
|
1415
|
+
program.validate();
|
|
1416
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1417
|
+
});
|
|
1418
|
+
describe('allowed arg type conversions', () => {
|
|
1419
|
+
it('allows numbers passed to a function that accepts booleans', () => {
|
|
1420
|
+
program.setFile('source/util.bs', `
|
|
1421
|
+
sub takesBool(input as boolean)
|
|
1422
|
+
end sub
|
|
1423
|
+
|
|
1424
|
+
sub tryNums()
|
|
1425
|
+
pi = 3.14
|
|
1426
|
+
takesBool(1)
|
|
1427
|
+
takesBool(-1)
|
|
1428
|
+
takesBool(123.456)
|
|
1429
|
+
takesBool(23!)
|
|
1430
|
+
takesBool(&hABCD)
|
|
1431
|
+
takesBool(1.22#)
|
|
1432
|
+
takesBool(pi)
|
|
1433
|
+
takesBool(0)
|
|
1434
|
+
takesBool(true)
|
|
1435
|
+
takesBool(false)
|
|
1436
|
+
end sub
|
|
1437
|
+
`);
|
|
1438
|
+
program.validate();
|
|
1439
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1440
|
+
});
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1443
|
+
describe('cannotFindName', () => {
|
|
1444
|
+
it('finds variables from assignments from member functions of primitive types', () => {
|
|
1445
|
+
program.setFile('source/util.brs', `
|
|
1446
|
+
function lcaseTrim(str)
|
|
1447
|
+
trimmedLowerStr = lcase(str).trim()
|
|
1448
|
+
print trimmedLowerStr
|
|
1449
|
+
end function
|
|
1450
|
+
`);
|
|
1451
|
+
program.validate();
|
|
1452
|
+
//should have no errors
|
|
1453
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1454
|
+
});
|
|
1455
|
+
it('validates when lhs of compound assignment does not exist', () => {
|
|
1456
|
+
program.setFile('source/util.brs', `
|
|
1457
|
+
sub main()
|
|
1458
|
+
expected += chr(10) + " version=""2.0"""
|
|
1459
|
+
end sub
|
|
1460
|
+
`);
|
|
1461
|
+
program.validate();
|
|
1462
|
+
//should have error - cannot find "expected"
|
|
1463
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1464
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('expected').message
|
|
1465
|
+
]);
|
|
1466
|
+
});
|
|
1467
|
+
it('does not have a diagnostic for using a variable the result of an assignment with unresolved value', () => {
|
|
1468
|
+
program.setFile('source/util.bs', `
|
|
1469
|
+
sub doStuff()
|
|
1470
|
+
myValue = UndeclaredValue
|
|
1471
|
+
if myValue > 0
|
|
1472
|
+
print "hello"
|
|
1473
|
+
end if
|
|
1474
|
+
end sub
|
|
1475
|
+
`);
|
|
1476
|
+
program.validate();
|
|
1477
|
+
//should have only 1 error - cannot find "UndeclaredValue"
|
|
1478
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1479
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('UndeclaredValue').message
|
|
1480
|
+
]);
|
|
1481
|
+
});
|
|
1482
|
+
it('detects assigning to an unknown field in a class', () => {
|
|
1483
|
+
program.setFile('source/main.bs', `
|
|
1484
|
+
class Klass
|
|
1485
|
+
sub new()
|
|
1486
|
+
m.unknown = "hello"
|
|
1487
|
+
end sub
|
|
1488
|
+
end class
|
|
1489
|
+
`);
|
|
1490
|
+
program.validate();
|
|
1491
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1492
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('unknown', 'Klass.unknown', 'Klass')
|
|
1493
|
+
]);
|
|
1494
|
+
});
|
|
1495
|
+
it('detects assigning to an unknown field in a primitive', () => {
|
|
1496
|
+
program.setFile('source/main.bs', `
|
|
1497
|
+
sub main()
|
|
1498
|
+
myStr = "hello"
|
|
1499
|
+
myStr.length = 2
|
|
1500
|
+
end sub
|
|
1501
|
+
`);
|
|
1502
|
+
program.validate();
|
|
1503
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1504
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('length', 'string.length', 'string')
|
|
1505
|
+
]);
|
|
1506
|
+
});
|
|
1507
|
+
it('allows assigning to an unknown field in an AA', () => {
|
|
1508
|
+
program.setFile('source/main.bs', `
|
|
1509
|
+
sub main()
|
|
1510
|
+
myAA = {}
|
|
1511
|
+
myAA.unknown = 4
|
|
1512
|
+
end sub
|
|
1513
|
+
`);
|
|
1514
|
+
program.validate();
|
|
1515
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1516
|
+
});
|
|
1517
|
+
it('allows setting a member of an overriden member of an aa', () => {
|
|
1518
|
+
program.setFile('source/main.bs', `
|
|
1519
|
+
sub makeAA()
|
|
1520
|
+
myAA = {}
|
|
1521
|
+
addItemsToAA(myAA)
|
|
1522
|
+
myAA.items.value = "other string"
|
|
1523
|
+
end sub
|
|
1524
|
+
|
|
1525
|
+
sub addItemsToAA(someAA)
|
|
1526
|
+
someAA.items = {value: "some string"}
|
|
1527
|
+
end sub
|
|
1528
|
+
`);
|
|
1529
|
+
program.validate();
|
|
1530
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1531
|
+
});
|
|
1532
|
+
it('allows accessing a member of an overriden member of an aa', () => {
|
|
1533
|
+
program.setFile('source/main.bs', `
|
|
1534
|
+
sub makeAA()
|
|
1535
|
+
myAA = {}
|
|
1536
|
+
addItemsToAA(myAA)
|
|
1537
|
+
print myAA.items.value.len()
|
|
1538
|
+
end sub
|
|
1539
|
+
|
|
1540
|
+
sub addItemsToAA(someAA)
|
|
1541
|
+
someAA.items = {value: "some string"}
|
|
1542
|
+
end sub
|
|
1543
|
+
`);
|
|
1544
|
+
program.validate();
|
|
1545
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1546
|
+
});
|
|
1547
|
+
it('allows using a member of an overriden member of an aa in a different way', () => {
|
|
1548
|
+
program.setFile('source/main.bs', `
|
|
1549
|
+
sub makeAA()
|
|
1550
|
+
myAA = {}
|
|
1551
|
+
addItemsToAA(myAA)
|
|
1552
|
+
for each item in myAA.items
|
|
1553
|
+
print item
|
|
1554
|
+
end for
|
|
1555
|
+
end sub
|
|
1556
|
+
|
|
1557
|
+
sub addItemsToAA(someAA)
|
|
1558
|
+
someAA.items = [0, 1, 2, 3]
|
|
1559
|
+
end sub
|
|
1560
|
+
`);
|
|
1561
|
+
program.validate();
|
|
1562
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1563
|
+
});
|
|
1564
|
+
it('does not show a diagnostic when using a function param with unknown type', () => {
|
|
1565
|
+
program.setFile('source/main.bs', `
|
|
1566
|
+
function test(item as Whatever)
|
|
1567
|
+
return {data: item}
|
|
1568
|
+
end function
|
|
1569
|
+
`);
|
|
1570
|
+
program.validate();
|
|
1571
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1572
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('Whatever')
|
|
1573
|
+
]);
|
|
1574
|
+
});
|
|
1575
|
+
it('does not show a diagnostic when using a variable declared with unknown type cast', () => {
|
|
1576
|
+
program.setFile('source/main.bs', `
|
|
1577
|
+
function test()
|
|
1578
|
+
item = {} as Whatever
|
|
1579
|
+
return {data: item}
|
|
1580
|
+
end function
|
|
1581
|
+
`);
|
|
1582
|
+
program.validate();
|
|
1583
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1584
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('Whatever')
|
|
1585
|
+
]);
|
|
1586
|
+
});
|
|
1587
|
+
it('does not show a diagnostic when using a variable declared with unknown type', () => {
|
|
1588
|
+
program.setFile('source/main.bs', `
|
|
1589
|
+
function test()
|
|
1590
|
+
item as Whatever = {}
|
|
1591
|
+
return {data: item}
|
|
1592
|
+
end function
|
|
1593
|
+
`);
|
|
1594
|
+
program.validate();
|
|
1595
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1596
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('Whatever')
|
|
1597
|
+
]);
|
|
1598
|
+
});
|
|
1599
|
+
it('allows function default params to reference earlier params', () => {
|
|
1600
|
+
program.setFile('source/main.bs', `
|
|
1601
|
+
function test(param1 as integer, param2 = param1 + 2)
|
|
1602
|
+
print param1; param2
|
|
1603
|
+
end function
|
|
1604
|
+
`);
|
|
1605
|
+
program.validate();
|
|
1606
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1607
|
+
});
|
|
1608
|
+
it('has diagnostic when function default params reference unknown', () => {
|
|
1609
|
+
program.setFile('source/main.bs', `
|
|
1610
|
+
function test(param1 as integer, param2 = paramX + 2)
|
|
1611
|
+
print param1; param2
|
|
1612
|
+
end function
|
|
1613
|
+
`);
|
|
1614
|
+
program.validate();
|
|
1615
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1616
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('paramX').message
|
|
1617
|
+
]);
|
|
1618
|
+
});
|
|
1619
|
+
it('has diagnostic when function default params reference variable from inside function', () => {
|
|
1620
|
+
program.setFile('source/main.bs', `
|
|
1621
|
+
function test(param1 as integer, param2 = paramX + 2)
|
|
1622
|
+
paramX = 3
|
|
1623
|
+
print param1; param2
|
|
1624
|
+
end function
|
|
1625
|
+
`);
|
|
1626
|
+
program.validate();
|
|
1627
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1628
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('paramX').message
|
|
1629
|
+
]);
|
|
1630
|
+
});
|
|
1631
|
+
it('has diagnostic when trying to use a method on an union that does not exist in one type', () => {
|
|
1632
|
+
program.setFile('source/main.bs', `
|
|
1633
|
+
function typeHoverTest(x as string or integer)
|
|
1634
|
+
value = x.len()
|
|
1635
|
+
return value
|
|
1636
|
+
end function
|
|
1637
|
+
`);
|
|
1638
|
+
program.validate();
|
|
1639
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1640
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindFunction('len', null, '(string or integer)').message
|
|
1641
|
+
]);
|
|
1642
|
+
});
|
|
1643
|
+
it('does not have diagnostic when accessing unknown member of union in Brightscript mode, when variable is a param', () => {
|
|
1644
|
+
program.setFile('source/main.brs', `
|
|
1645
|
+
function typeHoverTest(x as string)
|
|
1646
|
+
x = x.len()
|
|
1647
|
+
return x
|
|
1648
|
+
end function
|
|
1649
|
+
`);
|
|
1650
|
+
program.validate();
|
|
1651
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1652
|
+
});
|
|
1653
|
+
it('does not have diagnostic when accessing unknown member of union in Brightscript mode, when variable is defined in block', () => {
|
|
1654
|
+
program.setFile('source/main.brs', `
|
|
1655
|
+
function typeHoverTest()
|
|
1656
|
+
x = "hello"
|
|
1657
|
+
x = x.len()
|
|
1658
|
+
return x
|
|
1659
|
+
end function
|
|
1660
|
+
`);
|
|
1661
|
+
program.validate();
|
|
1662
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1663
|
+
});
|
|
1664
|
+
});
|
|
1665
|
+
describe('itemCannotBeUsedAsVariable', () => {
|
|
1666
|
+
it('detects assigning to a member of a namespace outside the namespace', () => {
|
|
1667
|
+
program.setFile('source/main.bs', `
|
|
1668
|
+
namespace Alpha
|
|
1669
|
+
const Name = "Alpha"
|
|
1670
|
+
end namespace
|
|
1671
|
+
|
|
1672
|
+
sub main()
|
|
1673
|
+
Alpha.name = "Beta"
|
|
1674
|
+
end sub
|
|
1675
|
+
`);
|
|
1676
|
+
program.validate();
|
|
1677
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1678
|
+
DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
|
|
1679
|
+
]);
|
|
1680
|
+
});
|
|
1681
|
+
it('detects assigning to a member of a namespace inside the namespace', () => {
|
|
1682
|
+
program.setFile('source/main.bs', `
|
|
1683
|
+
namespace Alpha
|
|
1684
|
+
const Name = "Alpha"
|
|
1685
|
+
|
|
1686
|
+
sub inAlpha()
|
|
1687
|
+
alpha.name = "Beta"
|
|
1688
|
+
end sub
|
|
1689
|
+
end namespace
|
|
1690
|
+
`);
|
|
1691
|
+
program.validate();
|
|
1692
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1693
|
+
DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
|
|
1694
|
+
]);
|
|
1695
|
+
});
|
|
1696
|
+
it('detects assigning to a member of a namespace outside the namespace', () => {
|
|
1697
|
+
program.setFile('source/main.bs', `
|
|
1698
|
+
namespace Alpha
|
|
1699
|
+
class Klass
|
|
1700
|
+
end class
|
|
1701
|
+
end namespace
|
|
1702
|
+
|
|
1703
|
+
sub main()
|
|
1704
|
+
myKlass = new Alpha.Klass()
|
|
1705
|
+
Alpha.klass = myKlass
|
|
1706
|
+
end sub
|
|
1707
|
+
`);
|
|
1708
|
+
program.validate();
|
|
1709
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1710
|
+
DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
|
|
1711
|
+
]);
|
|
1712
|
+
});
|
|
1713
|
+
it('detects assigning to a member of a namespace outside the namespace', () => {
|
|
1714
|
+
program.setFile('source/main.bs', `
|
|
1715
|
+
namespace Alpha
|
|
1716
|
+
class Klass
|
|
1717
|
+
function new()
|
|
1718
|
+
end function
|
|
1719
|
+
|
|
1720
|
+
function init()
|
|
1721
|
+
Alpha.innerFunc = someFunc
|
|
1722
|
+
end function
|
|
1723
|
+
end class
|
|
1724
|
+
|
|
1725
|
+
sub innerFunc()
|
|
1726
|
+
end sub
|
|
1727
|
+
end namespace
|
|
1728
|
+
|
|
1729
|
+
sub someFunc()
|
|
1730
|
+
end sub
|
|
1731
|
+
`);
|
|
1732
|
+
program.validate();
|
|
1733
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1734
|
+
DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
|
|
1735
|
+
]);
|
|
1736
|
+
});
|
|
1737
|
+
it('validates when a class member is accessed from a class directly', () => {
|
|
1738
|
+
program.setFile('source/util.bs', `
|
|
1739
|
+
class Klass
|
|
1740
|
+
name as string
|
|
1741
|
+
end class
|
|
1742
|
+
|
|
1743
|
+
sub doStuff()
|
|
1744
|
+
print klass.name ' only valid use of "Klass" is as a constructor: "new Klass()", or as a function
|
|
1745
|
+
end sub
|
|
1746
|
+
`);
|
|
1747
|
+
program.validate();
|
|
1748
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1749
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('name', 'function.name', 'function')
|
|
1750
|
+
]);
|
|
1751
|
+
});
|
|
1752
|
+
it('validates when a class member is accessed from a class directly when class has a namespace', () => {
|
|
1753
|
+
program.setFile('source/util.bs', `
|
|
1754
|
+
namespace Alpha
|
|
1755
|
+
class Klass
|
|
1756
|
+
name as string
|
|
1757
|
+
end class
|
|
1758
|
+
end namespace
|
|
1759
|
+
|
|
1760
|
+
sub doStuff()
|
|
1761
|
+
print alpha.klass.name ' only valid use of "Klass" is as a constructor: "new Klass()"
|
|
1762
|
+
end sub
|
|
1763
|
+
`);
|
|
1764
|
+
program.validate();
|
|
1765
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1766
|
+
DiagnosticMessages_1.DiagnosticMessages.cannotFindName('name', 'function.name', 'function')
|
|
1767
|
+
]);
|
|
1768
|
+
});
|
|
1769
|
+
it('validates when new is is used on a class instance', () => {
|
|
1770
|
+
program.setFile('source/util.bs', `
|
|
1771
|
+
class Klass
|
|
1772
|
+
name as string
|
|
1773
|
+
end class
|
|
1774
|
+
|
|
1775
|
+
sub doStuff(someKlass as Klass)
|
|
1776
|
+
print new someKlass()
|
|
1777
|
+
end sub
|
|
1778
|
+
`);
|
|
1779
|
+
program.validate();
|
|
1780
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1781
|
+
DiagnosticMessages_1.DiagnosticMessages.expressionIsNotConstructable('someKlass')
|
|
1782
|
+
]);
|
|
1783
|
+
});
|
|
1784
|
+
it('allows when a class name is used as field name', () => {
|
|
1785
|
+
program.setFile('source/util.bs', `
|
|
1786
|
+
class Klass
|
|
1787
|
+
name as string
|
|
1788
|
+
end class
|
|
1789
|
+
|
|
1790
|
+
class OtherKlass
|
|
1791
|
+
klass as Klass
|
|
1792
|
+
|
|
1793
|
+
sub foo()
|
|
1794
|
+
print m.klass.name
|
|
1795
|
+
end sub
|
|
1796
|
+
end class
|
|
1797
|
+
`);
|
|
1798
|
+
program.validate();
|
|
1799
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1800
|
+
});
|
|
1801
|
+
it('allows when a class name from a namespace is used as field name', () => {
|
|
1802
|
+
program.setFile('source/util.bs', `
|
|
1803
|
+
namespace Alpha
|
|
1804
|
+
class Klass
|
|
1805
|
+
name as string
|
|
1806
|
+
end class
|
|
1807
|
+
end namespace
|
|
1808
|
+
|
|
1809
|
+
class OtherKlass
|
|
1810
|
+
klass as Alpha.Klass
|
|
1811
|
+
|
|
1812
|
+
sub foo()
|
|
1813
|
+
m.klass = new Alpha.Klass()
|
|
1814
|
+
end sub
|
|
1815
|
+
end class
|
|
1816
|
+
`);
|
|
1817
|
+
program.validate();
|
|
1818
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1819
|
+
});
|
|
1820
|
+
});
|
|
1821
|
+
describe('returnTypeMismatch', () => {
|
|
1822
|
+
it('finds when a function returns a type that is not what was declared', () => {
|
|
1823
|
+
program.setFile('source/util.bs', `
|
|
1824
|
+
function getPi() as float
|
|
1825
|
+
return "apple" ' get it?
|
|
1826
|
+
end function
|
|
1827
|
+
`);
|
|
1828
|
+
program.validate();
|
|
1829
|
+
//should have error - return value should be a float, not a string
|
|
1830
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1831
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message
|
|
1832
|
+
]);
|
|
1833
|
+
});
|
|
1834
|
+
it('finds all return statements that do not match', () => {
|
|
1835
|
+
program.setFile('source/util.bs', `
|
|
1836
|
+
function getPi(kind as integer) as float
|
|
1837
|
+
if kind = 1
|
|
1838
|
+
return "apple"
|
|
1839
|
+
else if kind = 2
|
|
1840
|
+
return false
|
|
1841
|
+
else if kind = 3
|
|
1842
|
+
return new Pie("lemon")
|
|
1843
|
+
end if
|
|
1844
|
+
return 3.14
|
|
1845
|
+
end function
|
|
1846
|
+
|
|
1847
|
+
class Pie
|
|
1848
|
+
kind as string
|
|
1849
|
+
sub new(kind as string)
|
|
1850
|
+
m.kind = kind
|
|
1851
|
+
end sub
|
|
1852
|
+
end class
|
|
1853
|
+
`);
|
|
1854
|
+
program.validate();
|
|
1855
|
+
//should have error - return value should be a float, not whatever else
|
|
1856
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1857
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message,
|
|
1858
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('boolean', 'float').message,
|
|
1859
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('Pie', 'float').message
|
|
1860
|
+
]);
|
|
1861
|
+
});
|
|
1862
|
+
it('allows returning compatible types', () => {
|
|
1863
|
+
program.setFile('source/util.bs', `
|
|
1864
|
+
function getPi() as float
|
|
1865
|
+
return 3 ' integers are compatible with floats
|
|
1866
|
+
end function
|
|
1867
|
+
|
|
1868
|
+
function getPie() as Pie
|
|
1869
|
+
return new Tart("lemon") ' Tart extends Pie
|
|
1870
|
+
end function
|
|
1871
|
+
|
|
1872
|
+
class Pie
|
|
1873
|
+
kind as string
|
|
1874
|
+
sub new(kind as string)
|
|
1875
|
+
m.kind = kind
|
|
1876
|
+
end sub
|
|
1877
|
+
end class
|
|
1878
|
+
|
|
1879
|
+
class Tart extends Pie
|
|
1880
|
+
size = "small"
|
|
1881
|
+
end class
|
|
1882
|
+
`);
|
|
1883
|
+
program.validate();
|
|
1884
|
+
//should have no errors
|
|
1885
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1886
|
+
});
|
|
1887
|
+
it('detects return types on void functions (subs)', () => {
|
|
1888
|
+
program.setFile('source/util.bs', `
|
|
1889
|
+
sub sayHello(name as string)
|
|
1890
|
+
return "hello " + name ' return should be void in subs
|
|
1891
|
+
end sub
|
|
1892
|
+
`);
|
|
1893
|
+
program.validate();
|
|
1894
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1895
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
|
|
1896
|
+
]);
|
|
1897
|
+
});
|
|
1898
|
+
it('detects return types on void functions', () => {
|
|
1899
|
+
program.setFile('source/util.bs', `
|
|
1900
|
+
function sayHello(name as string) as void
|
|
1901
|
+
return "hello " + name ' return should be void in subs
|
|
1902
|
+
end function
|
|
1903
|
+
`);
|
|
1904
|
+
program.validate();
|
|
1905
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1906
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
|
|
1907
|
+
]);
|
|
1908
|
+
});
|
|
1909
|
+
it('allows returning enums with the default type that matches the declared return type', () => {
|
|
1910
|
+
program.setFile('source/util.bs', `
|
|
1911
|
+
enum MyEnum
|
|
1912
|
+
val1
|
|
1913
|
+
val2
|
|
1914
|
+
end enum
|
|
1915
|
+
|
|
1916
|
+
function getInt() as integer
|
|
1917
|
+
return MyEnum.val1
|
|
1918
|
+
end function
|
|
1919
|
+
`);
|
|
1920
|
+
program.validate();
|
|
1921
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1922
|
+
});
|
|
1923
|
+
it('allows returning enums passed as a param with the default type that matches the declared return type', () => {
|
|
1924
|
+
program.setFile('source/util.bs', `
|
|
1925
|
+
enum MyEnum
|
|
1926
|
+
val1
|
|
1927
|
+
val2
|
|
1928
|
+
end enum
|
|
1929
|
+
|
|
1930
|
+
function getInt(enumVal as MyEnum) as integer
|
|
1931
|
+
return enumVal
|
|
1932
|
+
end function
|
|
1933
|
+
`);
|
|
1934
|
+
program.validate();
|
|
1935
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1936
|
+
});
|
|
1937
|
+
it('allows returning enums with the default type that matches the declared return type for string enums', () => {
|
|
1938
|
+
program.setFile('source/util.bs', `
|
|
1939
|
+
enum MyEnum
|
|
1940
|
+
val1 = "hello"
|
|
1941
|
+
val2 = "world"
|
|
1942
|
+
end enum
|
|
1943
|
+
|
|
1944
|
+
function getInt() as string
|
|
1945
|
+
return MyEnum.val1
|
|
1946
|
+
end function
|
|
1947
|
+
`);
|
|
1948
|
+
program.validate();
|
|
1949
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
1950
|
+
});
|
|
1951
|
+
it('flags returning enums with the default type that does not matches the declared return type', () => {
|
|
1952
|
+
program.setFile('source/util.bs', `
|
|
1953
|
+
enum MyEnum
|
|
1954
|
+
val1 = "hello"
|
|
1955
|
+
val2 = "world"
|
|
1956
|
+
end enum
|
|
1957
|
+
|
|
1958
|
+
function getInt() as integer
|
|
1959
|
+
return MyEnum.val1
|
|
1960
|
+
end function
|
|
1961
|
+
`);
|
|
1962
|
+
program.validate();
|
|
1963
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1964
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
|
|
1965
|
+
]);
|
|
1966
|
+
});
|
|
1967
|
+
it('flags returning enums passed as params with the default type that does not matches the declared return type', () => {
|
|
1968
|
+
program.setFile('source/util.bs', `
|
|
1969
|
+
enum MyEnum
|
|
1970
|
+
val1 = "hello"
|
|
1971
|
+
val2 = "world"
|
|
1972
|
+
end enum
|
|
1973
|
+
|
|
1974
|
+
function getInt(enumVal as MyEnum) as integer
|
|
1975
|
+
return enumVal
|
|
1976
|
+
end function
|
|
1977
|
+
`);
|
|
1978
|
+
program.validate();
|
|
1979
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
1980
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
|
|
1981
|
+
]);
|
|
1982
|
+
});
|
|
1983
|
+
it('flags returning enums type', () => {
|
|
1984
|
+
program.setFile('source/util.bs', `
|
|
1985
|
+
enum MyEnum
|
|
1986
|
+
val1 = "hello"
|
|
1987
|
+
val2 = "world"
|
|
1988
|
+
end enum
|
|
1989
|
+
|
|
1990
|
+
|
|
1991
|
+
function getInt() as integer
|
|
1992
|
+
return MyEnum
|
|
1993
|
+
end function
|
|
1994
|
+
`);
|
|
1995
|
+
program.validate();
|
|
1996
|
+
(0, chai_1.expect)(program.getDiagnostics().length).to.be.greaterThan(0);
|
|
1997
|
+
});
|
|
1998
|
+
it('allows returning an Enum', () => {
|
|
1999
|
+
program.setFile('source/util.bs', `
|
|
2000
|
+
enum MyEnum
|
|
2001
|
+
val1 = "hello"
|
|
2002
|
+
val2 = "world"
|
|
2003
|
+
end enum
|
|
2004
|
+
|
|
2005
|
+
|
|
2006
|
+
function getInt() as MyEnum
|
|
2007
|
+
return MyEnum.val1
|
|
2008
|
+
end function
|
|
2009
|
+
`);
|
|
2010
|
+
program.validate();
|
|
2011
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2012
|
+
});
|
|
2013
|
+
it('allows AA with overidden props to meet interface', () => {
|
|
2014
|
+
program.setFile('source/code.bs', `
|
|
2015
|
+
namespace alpha.beta
|
|
2016
|
+
interface Stream
|
|
2017
|
+
thumbnailTiler as Thumbnail
|
|
2018
|
+
end interface
|
|
2019
|
+
|
|
2020
|
+
interface Thumbnail
|
|
2021
|
+
count as integer
|
|
2022
|
+
end interface
|
|
2023
|
+
|
|
2024
|
+
function createStreamObject() as Stream
|
|
2025
|
+
return {
|
|
2026
|
+
thumbnailTiler: {
|
|
2027
|
+
count: 1
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
end function
|
|
2031
|
+
end namespace
|
|
2032
|
+
`);
|
|
2033
|
+
program.validate();
|
|
2034
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2035
|
+
});
|
|
2036
|
+
it('allows AA with inside AA to be validated properly', () => {
|
|
2037
|
+
program.setFile('source/code.bs', `
|
|
2038
|
+
namespace alpha.beta
|
|
2039
|
+
interface Stream
|
|
2040
|
+
thumbnailTiler as Thumbnail
|
|
2041
|
+
end interface
|
|
2042
|
+
|
|
2043
|
+
interface Thumbnail
|
|
2044
|
+
count as integer
|
|
2045
|
+
end interface
|
|
2046
|
+
|
|
2047
|
+
function createStreamObject() as Stream
|
|
2048
|
+
return {
|
|
2049
|
+
thumbnailTiler: {
|
|
2050
|
+
count: "hello"
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
end function
|
|
2054
|
+
end namespace
|
|
2055
|
+
`);
|
|
2056
|
+
program.validate();
|
|
2057
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2058
|
+
DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('roAssociativeArray', 'alpha.beta.Stream', {
|
|
2059
|
+
fieldMismatches: [{ name: 'thumbnailTiler', expectedType: new types_1.InterfaceType('alpha.beta.Thumbnail'), actualType: new AssociativeArrayType_1.AssociativeArrayType() }]
|
|
2060
|
+
}).message
|
|
2061
|
+
]);
|
|
2062
|
+
});
|
|
2063
|
+
});
|
|
2064
|
+
describe('assignmentTypeMismatch', () => {
|
|
2065
|
+
it('finds when the type of the lhs is not compatible with the expected type', () => {
|
|
2066
|
+
program.setFile('source/util.bs', `
|
|
2067
|
+
sub doStuff(thing as iThing)
|
|
2068
|
+
thing.name = 123
|
|
2069
|
+
end sub
|
|
2070
|
+
|
|
2071
|
+
interface iThing
|
|
2072
|
+
name as string
|
|
2073
|
+
end interface
|
|
2074
|
+
`);
|
|
2075
|
+
program.validate();
|
|
2076
|
+
//should have error - assignment value should be a string, not a float
|
|
2077
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2078
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
|
|
2079
|
+
]);
|
|
2080
|
+
});
|
|
2081
|
+
it('allows setting a member with correct type that is a union type', () => {
|
|
2082
|
+
program.setFile('source/util.bs', `
|
|
2083
|
+
sub doStuff(thing as iThing)
|
|
2084
|
+
thing.name = 123
|
|
2085
|
+
end sub
|
|
2086
|
+
|
|
2087
|
+
interface iThing
|
|
2088
|
+
name as string or integer
|
|
2089
|
+
end interface
|
|
2090
|
+
`);
|
|
2091
|
+
program.validate();
|
|
2092
|
+
//should have no error - assignment value should be a string, not a float
|
|
2093
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2094
|
+
});
|
|
2095
|
+
it('finds when the rhs type is not compatible with the lhs, which is a union type', () => {
|
|
2096
|
+
program.setFile('source/util.bs', `
|
|
2097
|
+
sub doStuff(thing as iThing)
|
|
2098
|
+
thing.name = false
|
|
2099
|
+
end sub
|
|
2100
|
+
|
|
2101
|
+
interface iThing
|
|
2102
|
+
name as string or integer
|
|
2103
|
+
end interface
|
|
2104
|
+
`);
|
|
2105
|
+
program.validate();
|
|
2106
|
+
//should have error - assignment value should be a string or integer, not a boolean
|
|
2107
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2108
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('boolean', 'string or integer').message
|
|
2109
|
+
]);
|
|
2110
|
+
});
|
|
2111
|
+
it('validates when trying to assign to a class method', () => {
|
|
2112
|
+
program.setFile('source/util.bs', `
|
|
2113
|
+
sub doStuff(myThing as Thing)
|
|
2114
|
+
myThing.getPi = 3.14
|
|
2115
|
+
end sub
|
|
2116
|
+
|
|
2117
|
+
class Thing
|
|
2118
|
+
function getPi() as float
|
|
2119
|
+
return 3.14
|
|
2120
|
+
end function
|
|
2121
|
+
end class
|
|
2122
|
+
`);
|
|
2123
|
+
program.validate();
|
|
2124
|
+
//should have error
|
|
2125
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2126
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('float', 'function getPi() as float').message
|
|
2127
|
+
]);
|
|
2128
|
+
});
|
|
2129
|
+
it('disallows adding new properties to a class', () => {
|
|
2130
|
+
program.setFile('source/util.bs', `
|
|
2131
|
+
sub doStuff(myThing as Thing)
|
|
2132
|
+
myThing.getPi = 3.14
|
|
2133
|
+
end sub
|
|
2134
|
+
|
|
2135
|
+
class Thing
|
|
2136
|
+
end class
|
|
2137
|
+
`);
|
|
2138
|
+
program.validate();
|
|
2139
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('getPi', 'Thing.getPi', 'Thing')]);
|
|
2140
|
+
});
|
|
2141
|
+
it('validates class constructors', () => {
|
|
2142
|
+
program.setFile('source/util.bs', `
|
|
2143
|
+
class Video
|
|
2144
|
+
sub new(url as integer)
|
|
2145
|
+
m.url = url 'this should be a compile error
|
|
2146
|
+
end sub
|
|
2147
|
+
public url as string
|
|
2148
|
+
end class
|
|
2149
|
+
`);
|
|
2150
|
+
program.validate();
|
|
2151
|
+
//should have errors
|
|
2152
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2153
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
|
|
2154
|
+
]);
|
|
2155
|
+
});
|
|
2156
|
+
it('validates when assigning to a sgNode', () => {
|
|
2157
|
+
program.setFile('source/util.bs', `
|
|
2158
|
+
sub setLabelText(label as roSGNodeLabel)
|
|
2159
|
+
label.text = 1234
|
|
2160
|
+
end sub
|
|
2161
|
+
|
|
2162
|
+
`);
|
|
2163
|
+
program.validate();
|
|
2164
|
+
//should have errors
|
|
2165
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2166
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
|
|
2167
|
+
]);
|
|
2168
|
+
});
|
|
2169
|
+
it('allows an assignment to a variable when the declared type does match the rhs type', () => {
|
|
2170
|
+
program.setFile('source/util.bs', `
|
|
2171
|
+
sub setX(value)
|
|
2172
|
+
x as integer = value ' value is dynamic
|
|
2173
|
+
end sub
|
|
2174
|
+
|
|
2175
|
+
sub setY()
|
|
2176
|
+
y as integer = len("hello") ' len returns an integer
|
|
2177
|
+
end sub
|
|
2178
|
+
`);
|
|
2179
|
+
program.validate();
|
|
2180
|
+
//should have errors
|
|
2181
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2182
|
+
});
|
|
2183
|
+
it('validates an assignment to a variable when the declared type does not match the rhs type', () => {
|
|
2184
|
+
program.setFile('source/util.bs', `
|
|
2185
|
+
sub setLabelText(label as roSGNodeLabel)
|
|
2186
|
+
x as integer = label.text
|
|
2187
|
+
end sub
|
|
2188
|
+
`);
|
|
2189
|
+
program.validate();
|
|
2190
|
+
//should have errors
|
|
2191
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2192
|
+
DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('string', 'integer').message
|
|
2193
|
+
]);
|
|
2194
|
+
});
|
|
2195
|
+
it('allows assigning string to font fields', () => {
|
|
2196
|
+
program.setFile('source/util.bs', `
|
|
2197
|
+
sub setLabelFont(label as roSGNodeLabel)
|
|
2198
|
+
label.font = "font:LargeSystemFont"
|
|
2199
|
+
label.font.size = 50
|
|
2200
|
+
end sub
|
|
2201
|
+
`);
|
|
2202
|
+
program.validate();
|
|
2203
|
+
//should have no errors
|
|
2204
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2205
|
+
});
|
|
2206
|
+
});
|
|
2207
|
+
describe('operatorTypeMismatch', () => {
|
|
2208
|
+
it('finds when the type of the lhs is not compatible with the rhs type', () => {
|
|
2209
|
+
program.setFile('source/util.bs', `
|
|
2210
|
+
sub doStuff()
|
|
2211
|
+
a = 1 + true
|
|
2212
|
+
b = "hello" * 2
|
|
2213
|
+
end sub
|
|
2214
|
+
|
|
2215
|
+
`);
|
|
2216
|
+
program.validate();
|
|
2217
|
+
//should have errors
|
|
2218
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2219
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'integer', 'boolean').message,
|
|
2220
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'string', 'integer').message
|
|
2221
|
+
]);
|
|
2222
|
+
});
|
|
2223
|
+
it('allows when the type of the lhs is compatible with the rhs type', () => {
|
|
2224
|
+
program.setFile('source/util.bs', `
|
|
2225
|
+
sub doStuff()
|
|
2226
|
+
a = 10 << 1
|
|
2227
|
+
b = "hello" + "world"
|
|
2228
|
+
c = 78 / 34
|
|
2229
|
+
d = 100 \\ 5
|
|
2230
|
+
thing = new Klass()
|
|
2231
|
+
e = thing <> invalid
|
|
2232
|
+
end sub
|
|
2233
|
+
|
|
2234
|
+
class Klass
|
|
2235
|
+
end class
|
|
2236
|
+
`);
|
|
2237
|
+
program.validate();
|
|
2238
|
+
//should have no errors
|
|
2239
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2240
|
+
});
|
|
2241
|
+
it('allows tests against invalid', () => {
|
|
2242
|
+
program.setFile('source/util.bs', `
|
|
2243
|
+
sub doStuff()
|
|
2244
|
+
thing = new Klass()
|
|
2245
|
+
x = thing <> invalid
|
|
2246
|
+
end sub
|
|
2247
|
+
|
|
2248
|
+
class Klass
|
|
2249
|
+
end class
|
|
2250
|
+
`);
|
|
2251
|
+
program.validate();
|
|
2252
|
+
//should have no errors
|
|
2253
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2254
|
+
});
|
|
2255
|
+
it('disallows equality tests of classes', () => {
|
|
2256
|
+
program.setFile('source/util.bs', `
|
|
2257
|
+
sub doStuff()
|
|
2258
|
+
thing = new Klass()
|
|
2259
|
+
thing2 = new Klass()
|
|
2260
|
+
x = thing = thing2
|
|
2261
|
+
end sub
|
|
2262
|
+
|
|
2263
|
+
class Klass
|
|
2264
|
+
end class
|
|
2265
|
+
`);
|
|
2266
|
+
program.validate();
|
|
2267
|
+
//should have errors
|
|
2268
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2269
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('=', 'Klass', 'Klass').message
|
|
2270
|
+
]);
|
|
2271
|
+
});
|
|
2272
|
+
it('disallows operations between dynamic and custom types', () => {
|
|
2273
|
+
program.setFile('source/util.bs', `
|
|
2274
|
+
sub doStuff(input)
|
|
2275
|
+
thing = new Klass()
|
|
2276
|
+
x = thing + input
|
|
2277
|
+
end sub
|
|
2278
|
+
|
|
2279
|
+
class Klass
|
|
2280
|
+
end class
|
|
2281
|
+
`);
|
|
2282
|
+
program.validate();
|
|
2283
|
+
//should have errors
|
|
2284
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2285
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Klass', 'dynamic').message
|
|
2286
|
+
]);
|
|
2287
|
+
});
|
|
2288
|
+
it('allows valid operations on enum members', () => {
|
|
2289
|
+
program.setFile('source/util.bs', `
|
|
2290
|
+
sub makeEasterly(d as Direction)
|
|
2291
|
+
print d + "e"
|
|
2292
|
+
print Direction.north + "east"
|
|
2293
|
+
end sub
|
|
2294
|
+
|
|
2295
|
+
function getTax(itemAmt as ItemCost) as Float
|
|
2296
|
+
return itemAmt * 1.15
|
|
2297
|
+
end function
|
|
2298
|
+
|
|
2299
|
+
enum Direction
|
|
2300
|
+
north = "n"
|
|
2301
|
+
south = "s"
|
|
2302
|
+
end enum
|
|
2303
|
+
|
|
2304
|
+
enum ItemCost
|
|
2305
|
+
x = 99.99
|
|
2306
|
+
y = 29.99
|
|
2307
|
+
end enum
|
|
2308
|
+
|
|
2309
|
+
`);
|
|
2310
|
+
program.validate();
|
|
2311
|
+
//should have no errors
|
|
2312
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2313
|
+
});
|
|
2314
|
+
it('finds invalid operations on enum members', () => {
|
|
2315
|
+
program.setFile('source/util.bs', `
|
|
2316
|
+
enum Direction
|
|
2317
|
+
north = "n"
|
|
2318
|
+
south = "s"
|
|
2319
|
+
end enum
|
|
2320
|
+
|
|
2321
|
+
sub makeEasterly(d as Direction)
|
|
2322
|
+
print d + 2
|
|
2323
|
+
print 3.14 * Direction.north
|
|
2324
|
+
end sub
|
|
2325
|
+
`);
|
|
2326
|
+
program.validate();
|
|
2327
|
+
//should have errors
|
|
2328
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2329
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Direction', 'integer').message,
|
|
2330
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'float', 'Direction').message
|
|
2331
|
+
]);
|
|
2332
|
+
});
|
|
2333
|
+
it('validates unary operators', () => {
|
|
2334
|
+
program.setFile('source/util.bs', `
|
|
2335
|
+
sub doStuff()
|
|
2336
|
+
x = - "hello world"
|
|
2337
|
+
end sub
|
|
2338
|
+
`);
|
|
2339
|
+
program.validate();
|
|
2340
|
+
//should have errors
|
|
2341
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2342
|
+
DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('-', 'string').message
|
|
2343
|
+
]);
|
|
2344
|
+
});
|
|
2345
|
+
it('allows unary on dynamic and union types', () => {
|
|
2346
|
+
program.setFile('source/util.bs', `
|
|
2347
|
+
sub doStuff(x)
|
|
2348
|
+
y = -x
|
|
2349
|
+
print y
|
|
2350
|
+
end sub
|
|
2351
|
+
|
|
2352
|
+
sub doOtherStuff(x as float or integer)
|
|
2353
|
+
y = -x
|
|
2354
|
+
print y
|
|
2355
|
+
end sub
|
|
2356
|
+
|
|
2357
|
+
sub doEventMoreStuff(x as boolean or dynamic)
|
|
2358
|
+
if not x
|
|
2359
|
+
print "ok"
|
|
2360
|
+
end if
|
|
2361
|
+
end sub
|
|
2362
|
+
`);
|
|
2363
|
+
program.validate();
|
|
2364
|
+
//should have no errors
|
|
2365
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2366
|
+
});
|
|
2367
|
+
});
|
|
2368
|
+
describe('memberAccessibilityMismatch', () => {
|
|
2369
|
+
it('should flag when accessing a private member', () => {
|
|
2370
|
+
program.setFile('source/main.bs', `
|
|
2371
|
+
class SomeKlass
|
|
2372
|
+
private name as string
|
|
2373
|
+
end class
|
|
2374
|
+
|
|
2375
|
+
sub foo(x as SomeKlass)
|
|
2376
|
+
print x.name
|
|
2377
|
+
end sub
|
|
2378
|
+
`);
|
|
2379
|
+
program.validate();
|
|
2380
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2381
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 8 /* SymbolTypeFlag.private */, 'SomeKlass')
|
|
2382
|
+
]);
|
|
2383
|
+
});
|
|
2384
|
+
it('should allow accessing a private member in a class', () => {
|
|
2385
|
+
program.setFile('source/main.bs', `
|
|
2386
|
+
class SomeKlass
|
|
2387
|
+
private name as string
|
|
2388
|
+
|
|
2389
|
+
sub foo(x as SomeKlass)
|
|
2390
|
+
print x.name
|
|
2391
|
+
print m.name
|
|
2392
|
+
end sub
|
|
2393
|
+
end class
|
|
2394
|
+
`);
|
|
2395
|
+
program.validate();
|
|
2396
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2397
|
+
});
|
|
2398
|
+
it('should flag when calling a private method outside the class', () => {
|
|
2399
|
+
program.setFile('source/main.bs', `
|
|
2400
|
+
class SomeKlass
|
|
2401
|
+
private sub sayHello()
|
|
2402
|
+
print "Hello"
|
|
2403
|
+
end sub
|
|
2404
|
+
end class
|
|
2405
|
+
|
|
2406
|
+
sub foo(x as SomeKlass)
|
|
2407
|
+
x.sayHello()
|
|
2408
|
+
end sub
|
|
2409
|
+
`);
|
|
2410
|
+
program.validate();
|
|
2411
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2412
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', 8 /* SymbolTypeFlag.private */, 'SomeKlass')
|
|
2413
|
+
]);
|
|
2414
|
+
});
|
|
2415
|
+
it('should allow calling a private method in a class', () => {
|
|
2416
|
+
program.setFile('source/main.bs', `
|
|
2417
|
+
class SomeKlass
|
|
2418
|
+
private sub sayHello()
|
|
2419
|
+
print "Hello"
|
|
2420
|
+
end sub
|
|
2421
|
+
|
|
2422
|
+
sub foo(x as SomeKlass)
|
|
2423
|
+
x.sayHello()
|
|
2424
|
+
m.sayHello()
|
|
2425
|
+
end sub
|
|
2426
|
+
end class
|
|
2427
|
+
`);
|
|
2428
|
+
program.validate();
|
|
2429
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2430
|
+
});
|
|
2431
|
+
it('should not allow accessing a private member in a subclass', () => {
|
|
2432
|
+
program.setFile('source/main.bs', `
|
|
2433
|
+
class SomeKlass
|
|
2434
|
+
private name as string
|
|
2435
|
+
end class
|
|
2436
|
+
|
|
2437
|
+
class SubKlass extends SomeKlass
|
|
2438
|
+
sub foo()
|
|
2439
|
+
print m.name
|
|
2440
|
+
end sub
|
|
2441
|
+
end class
|
|
2442
|
+
`);
|
|
2443
|
+
program.validate();
|
|
2444
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2445
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 8 /* SymbolTypeFlag.private */, 'SomeKlass')
|
|
2446
|
+
]);
|
|
2447
|
+
});
|
|
2448
|
+
it('should flag when setting a value on a private member', () => {
|
|
2449
|
+
program.setFile('source/main.bs', `
|
|
2450
|
+
class SomeKlass
|
|
2451
|
+
private name as string
|
|
2452
|
+
end class
|
|
2453
|
+
|
|
2454
|
+
sub foo(x as SomeKlass)
|
|
2455
|
+
x.name = "foo"
|
|
2456
|
+
end sub
|
|
2457
|
+
`);
|
|
2458
|
+
program.validate();
|
|
2459
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2460
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 8 /* SymbolTypeFlag.private */, 'SomeKlass')
|
|
2461
|
+
]);
|
|
2462
|
+
});
|
|
2463
|
+
it('should flag when accessing a protected member', () => {
|
|
2464
|
+
program.setFile('source/main.bs', `
|
|
2465
|
+
class SomeKlass
|
|
2466
|
+
protected name as string
|
|
2467
|
+
end class
|
|
2468
|
+
|
|
2469
|
+
sub foo(x as SomeKlass)
|
|
2470
|
+
print x.name
|
|
2471
|
+
end sub
|
|
2472
|
+
`);
|
|
2473
|
+
program.validate();
|
|
2474
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2475
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 16 /* SymbolTypeFlag.protected */, 'SomeKlass')
|
|
2476
|
+
]);
|
|
2477
|
+
});
|
|
2478
|
+
it('should allow accessing a protected member in a class', () => {
|
|
2479
|
+
program.setFile('source/main.bs', `
|
|
2480
|
+
class SomeKlass
|
|
2481
|
+
protected name as string
|
|
2482
|
+
|
|
2483
|
+
sub foo(x as SomeKlass)
|
|
2484
|
+
print x.name
|
|
2485
|
+
print m.name
|
|
2486
|
+
end sub
|
|
2487
|
+
end class
|
|
2488
|
+
`);
|
|
2489
|
+
program.validate();
|
|
2490
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2491
|
+
});
|
|
2492
|
+
it('should flag when calling a protected method outside the class', () => {
|
|
2493
|
+
program.setFile('source/main.bs', `
|
|
2494
|
+
class SomeKlass
|
|
2495
|
+
protected sub sayHello()
|
|
2496
|
+
print "Hello"
|
|
2497
|
+
end sub
|
|
2498
|
+
end class
|
|
2499
|
+
|
|
2500
|
+
class SubKlass extends SomeKlass
|
|
2501
|
+
end class
|
|
2502
|
+
|
|
2503
|
+
sub foo(x as SomeKlass, y as SubKlass)
|
|
2504
|
+
x.sayHello()
|
|
2505
|
+
y.sayHello()
|
|
2506
|
+
end sub
|
|
2507
|
+
`);
|
|
2508
|
+
program.validate();
|
|
2509
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2510
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', 16 /* SymbolTypeFlag.protected */, 'SomeKlass'),
|
|
2511
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', 16 /* SymbolTypeFlag.protected */, 'SomeKlass')
|
|
2512
|
+
]);
|
|
2513
|
+
});
|
|
2514
|
+
it('should allow calling a protected method in a class', () => {
|
|
2515
|
+
program.setFile('source/main.bs', `
|
|
2516
|
+
class SomeKlass
|
|
2517
|
+
protected sub sayHello()
|
|
2518
|
+
print "Hello"
|
|
2519
|
+
end sub
|
|
2520
|
+
end class
|
|
2521
|
+
|
|
2522
|
+
class SubKlass extends SomeKlass
|
|
2523
|
+
sub foo(x as SomeKlass, y as SubKlass)
|
|
2524
|
+
m.sayHello()
|
|
2525
|
+
x.sayHello()
|
|
2526
|
+
y.sayHello()
|
|
2527
|
+
end sub
|
|
2528
|
+
end class
|
|
2529
|
+
`);
|
|
2530
|
+
program.validate();
|
|
2531
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2532
|
+
});
|
|
2533
|
+
it('should allow accessing a protected member in a subclass', () => {
|
|
2534
|
+
program.setFile('source/main.bs', `
|
|
2535
|
+
class SomeKlass
|
|
2536
|
+
protected name as string
|
|
2537
|
+
end class
|
|
2538
|
+
|
|
2539
|
+
class SubKlass extends SomeKlass
|
|
2540
|
+
sub foo()
|
|
2541
|
+
print m.name
|
|
2542
|
+
end sub
|
|
2543
|
+
end class
|
|
2544
|
+
`);
|
|
2545
|
+
program.validate();
|
|
2546
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2547
|
+
});
|
|
2548
|
+
it('should flag when setting a value on a protected member', () => {
|
|
2549
|
+
program.setFile('source/main.bs', `
|
|
2550
|
+
class SomeKlass
|
|
2551
|
+
protected name as string
|
|
2552
|
+
end class
|
|
2553
|
+
|
|
2554
|
+
class SubKlass extends SomeKlass
|
|
2555
|
+
end class
|
|
2556
|
+
|
|
2557
|
+
sub foo(x as SubKlass)
|
|
2558
|
+
x.name = "foo"
|
|
2559
|
+
end sub
|
|
2560
|
+
`);
|
|
2561
|
+
program.validate();
|
|
2562
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2563
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 16 /* SymbolTypeFlag.protected */, 'SomeKlass')
|
|
2564
|
+
]);
|
|
2565
|
+
});
|
|
2566
|
+
it('should flag when trying to use an inaccessible member in the middle of a chain', () => {
|
|
2567
|
+
program.setFile('source/main.bs', `
|
|
2568
|
+
class SomeKlass
|
|
2569
|
+
protected name as string
|
|
2570
|
+
end class
|
|
2571
|
+
|
|
2572
|
+
sub foo(x as SomeKlass)
|
|
2573
|
+
print x.name.len()
|
|
2574
|
+
end sub
|
|
2575
|
+
`);
|
|
2576
|
+
program.validate();
|
|
2577
|
+
(0, testHelpers_spec_1.expectDiagnostics)(program, [
|
|
2578
|
+
DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', 16 /* SymbolTypeFlag.protected */, 'SomeKlass')
|
|
2579
|
+
]);
|
|
2580
|
+
});
|
|
2581
|
+
describe('with namespaces', () => {
|
|
2582
|
+
it('protected members are accessible', () => {
|
|
2583
|
+
program.setFile('source/main.bs', `
|
|
2584
|
+
namespace AccessibilityTest
|
|
2585
|
+
class MyClass
|
|
2586
|
+
private data as roAssociativeArray = {}
|
|
2587
|
+
sub new()
|
|
2588
|
+
m.data.AddReplace("key", "value")
|
|
2589
|
+
end sub
|
|
2590
|
+
|
|
2591
|
+
protected sub printData()
|
|
2592
|
+
print m.data
|
|
2593
|
+
end sub
|
|
2594
|
+
end class
|
|
2595
|
+
|
|
2596
|
+
class SubClass extends MyClass
|
|
2597
|
+
sub foo()
|
|
2598
|
+
m.printData()
|
|
2599
|
+
end sub
|
|
2600
|
+
end class
|
|
2601
|
+
end namespace
|
|
2602
|
+
`);
|
|
2603
|
+
program.validate();
|
|
2604
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2605
|
+
});
|
|
2606
|
+
});
|
|
2607
|
+
});
|
|
2608
|
+
describe('revalidation', () => {
|
|
2609
|
+
it('revalidates when a enum defined in a different namespace changes', () => {
|
|
2610
|
+
program.setFile('source/file1.bs', `
|
|
2611
|
+
namespace Alpha
|
|
2612
|
+
function printEnum(enumVal as Alpha.Beta.Charlie.SomeEnum) as string
|
|
2613
|
+
return enumVal.toStr()
|
|
2614
|
+
end function
|
|
2615
|
+
end namespace
|
|
2616
|
+
`);
|
|
2617
|
+
program.setFile('source/file2.bs', `
|
|
2618
|
+
namespace Alpha.Beta.Charlie
|
|
2619
|
+
enum SomeEnum
|
|
2620
|
+
val1 = 1
|
|
2621
|
+
val2 = 2
|
|
2622
|
+
end enum
|
|
2623
|
+
end namespace
|
|
2624
|
+
`);
|
|
2625
|
+
program.validate();
|
|
2626
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2627
|
+
program.setFile('source/file2.bs', `
|
|
2628
|
+
namespace Alpha.Beta.Charlie
|
|
2629
|
+
enum ChangedEnum
|
|
2630
|
+
val1 = 1
|
|
2631
|
+
val2 = 2
|
|
2632
|
+
end enum
|
|
2633
|
+
end namespace
|
|
2634
|
+
`);
|
|
2635
|
+
program.validate();
|
|
2636
|
+
(0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('SomeEnum', null, 'Alpha.Beta.Charlie', 'namespace').message]);
|
|
2637
|
+
});
|
|
2638
|
+
it('revalidates when a class defined in a different namespace changes', () => {
|
|
2639
|
+
program.setFile('source/file1.bs', `
|
|
2640
|
+
namespace Alpha
|
|
2641
|
+
function printEnum(myKlass as Alpha.Beta.Charlie.SomeClass) as string
|
|
2642
|
+
return myKlass.getValue()
|
|
2643
|
+
end function
|
|
2644
|
+
end namespace
|
|
2645
|
+
`);
|
|
2646
|
+
program.setFile('source/file2.bs', `
|
|
2647
|
+
namespace Alpha.Beta.Charlie
|
|
2648
|
+
class SomeClass
|
|
2649
|
+
private myValue as string
|
|
2650
|
+
function getValue() as string
|
|
2651
|
+
return m.myValue
|
|
2652
|
+
end function
|
|
2653
|
+
end class
|
|
2654
|
+
end namespace
|
|
2655
|
+
`);
|
|
2656
|
+
program.validate();
|
|
2657
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2658
|
+
program.setFile('source/file2.bs', `
|
|
2659
|
+
namespace Alpha.Beta.Charlie
|
|
2660
|
+
class SomeClass
|
|
2661
|
+
private myValue as string
|
|
2662
|
+
function getValue(lowerCase as boolean) as string
|
|
2663
|
+
if lowerCase
|
|
2664
|
+
return lcase(m.myValue)
|
|
2665
|
+
end if
|
|
2666
|
+
return m.myValue
|
|
2667
|
+
end function
|
|
2668
|
+
end class
|
|
2669
|
+
end namespace
|
|
2670
|
+
`);
|
|
2671
|
+
program.validate();
|
|
2672
|
+
(0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0).message]);
|
|
2673
|
+
});
|
|
2674
|
+
it('validates only parts of files that need revalidation on scope validation', () => {
|
|
2675
|
+
function validateFile(file) {
|
|
2676
|
+
const validateFileEvent = {
|
|
2677
|
+
program: program,
|
|
2678
|
+
file: file
|
|
2679
|
+
};
|
|
2680
|
+
//emit an event to allow plugins to contribute to the file validation process
|
|
2681
|
+
program.plugins.emit('onFileValidate', validateFileEvent);
|
|
2682
|
+
program.plugins.emit('afterFileValidate', validateFileEvent);
|
|
2683
|
+
}
|
|
2684
|
+
const commonContents = `
|
|
2685
|
+
sub noValidationForEachScope()
|
|
2686
|
+
k = new KlassInSameFile()
|
|
2687
|
+
print k.value
|
|
2688
|
+
end sub
|
|
2689
|
+
|
|
2690
|
+
class KlassInSameFile
|
|
2691
|
+
value = 1
|
|
2692
|
+
end class
|
|
2693
|
+
`;
|
|
2694
|
+
let commonBs = program.setFile('source/common.bs', commonContents);
|
|
2695
|
+
validateFile(commonBs);
|
|
2696
|
+
(0, chai_1.expect)(commonBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 1 func, 1 classField
|
|
2697
|
+
(0, chai_1.expect)(commonBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
|
|
2698
|
+
commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
|
|
2699
|
+
(0, chai_1.expect)(commonBs.validationSegmenter.singleValidationSegments.size).to.eq(2); // no references needed to other files
|
|
2700
|
+
let common2Contents = `
|
|
2701
|
+
sub doesValidationForEachScope()
|
|
2702
|
+
k = new KlassInDiffFile()
|
|
2703
|
+
print k.value
|
|
2704
|
+
end sub
|
|
2705
|
+
|
|
2706
|
+
function alsoNoValidationForEachScope() as integer
|
|
2707
|
+
return 1
|
|
2708
|
+
end function
|
|
2709
|
+
`;
|
|
2710
|
+
let common2Bs = program.setFile('source/common2.bs', common2Contents);
|
|
2711
|
+
validateFile(common2Bs);
|
|
2712
|
+
(0, chai_1.expect)(common2Bs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 func
|
|
2713
|
+
(0, chai_1.expect)(common2Bs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1);
|
|
2714
|
+
commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
|
|
2715
|
+
(0, chai_1.expect)(common2Bs.validationSegmenter.singleValidationSegments.size).to.eq(1); // alsoNoValidationForEachScope() does not reference other files
|
|
2716
|
+
let klassContents = `
|
|
2717
|
+
class KlassInDiffFile
|
|
2718
|
+
value = 2
|
|
2719
|
+
end class
|
|
2720
|
+
`;
|
|
2721
|
+
let klassBs = program.setFile('source/klass.bs', klassContents);
|
|
2722
|
+
validateFile(klassBs);
|
|
2723
|
+
(0, chai_1.expect)(klassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
|
|
2724
|
+
(0, chai_1.expect)(klassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
|
|
2725
|
+
klassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
|
|
2726
|
+
(0, chai_1.expect)(klassBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // does not reference other files
|
|
2727
|
+
const widgetFileContents = `
|
|
2728
|
+
sub init()
|
|
2729
|
+
noValidationForEachScope()
|
|
2730
|
+
doesValidationForEachScope()
|
|
2731
|
+
end sub
|
|
2732
|
+
|
|
2733
|
+
sub anotherFunction()
|
|
2734
|
+
print "hello"
|
|
2735
|
+
end sub
|
|
2736
|
+
`;
|
|
2737
|
+
let widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
|
|
2738
|
+
validateFile(widgetBs);
|
|
2739
|
+
(0, chai_1.expect)(widgetBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 funcs
|
|
2740
|
+
(0, chai_1.expect)(widgetBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1); // 1 func (init)
|
|
2741
|
+
widgetBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
|
|
2742
|
+
(0, chai_1.expect)(widgetBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // 1 func (anotherFunction)
|
|
2743
|
+
const diffKlassContent = `
|
|
2744
|
+
class KlassInDiffFile
|
|
2745
|
+
value = 3
|
|
2746
|
+
end class
|
|
2747
|
+
`;
|
|
2748
|
+
let diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
|
|
2749
|
+
validateFile(diffKlassBs);
|
|
2750
|
+
(0, chai_1.expect)(diffKlassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
|
|
2751
|
+
(0, chai_1.expect)(diffKlassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
|
|
2752
|
+
diffKlassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
|
|
2753
|
+
(0, chai_1.expect)(diffKlassBs.validationSegmenter.singleValidationSegments.size).to.eq(1);
|
|
2754
|
+
program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
|
|
2755
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
|
2756
|
+
<component name="Widget" extends="Group">
|
|
2757
|
+
<script uri="Widget.bs"/>
|
|
2758
|
+
<script uri="pkg:/source/common.bs"/>
|
|
2759
|
+
<script uri="pkg:/source/common2.bs"/>
|
|
2760
|
+
<script uri="diffKlass.bs"/>
|
|
2761
|
+
</component>
|
|
2762
|
+
`);
|
|
2763
|
+
//reset files
|
|
2764
|
+
commonBs = program.setFile('source/common.bs', commonContents);
|
|
2765
|
+
common2Bs = program.setFile('source/common2.bs', common2Contents);
|
|
2766
|
+
klassBs = program.setFile('source/klass.bs', klassContents);
|
|
2767
|
+
widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
|
|
2768
|
+
diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
|
|
2769
|
+
program.validate();
|
|
2770
|
+
// all segments should be validated
|
|
2771
|
+
[commonBs, common2Bs, klassBs, widgetBs, diffKlassBs].forEach(file => {
|
|
2772
|
+
(0, chai_1.expect)(file.validationSegmenter.validatedSegments.size).to.gte(file.validationSegmenter.segmentsForValidation.length);
|
|
2773
|
+
file.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.true);
|
|
2774
|
+
});
|
|
2775
|
+
(0, testHelpers_spec_1.expectZeroDiagnostics)(program);
|
|
2776
|
+
program.setFile('components/Widget.bs', widgetFileContents);
|
|
2777
|
+
program.validate();
|
|
2778
|
+
// Widget.bs has changed. it needs to totally re-validated
|
|
2779
|
+
// and other files in the scope need to revalidate only the unresolved segments - should be source/common2.bs
|
|
2780
|
+
// TODO: how to test this?
|
|
2781
|
+
program.validate();
|
|
2782
|
+
program.setFile('components/diffKlass.bs', diffKlassContent);
|
|
2783
|
+
// diffKlass.bs has changed. it needs to totally re-validated
|
|
2784
|
+
// no other files in scope reference it .. no other files need revalidation
|
|
2785
|
+
// TODO: how to test this?
|
|
2786
|
+
program.validate();
|
|
2787
|
+
program.setFile('source/common.bs', commonContents);
|
|
2788
|
+
// common.bs has changed. it needs to totally re-validated
|
|
2789
|
+
// in source scope, common2.bs still has unresolves, it needs revalidation
|
|
2790
|
+
// in widget scope, widget.bs references it
|
|
2791
|
+
// TODO: how to test this?
|
|
2792
|
+
program.validate();
|
|
2793
|
+
});
|
|
2794
|
+
});
|
|
2795
|
+
});
|
|
2796
|
+
//# sourceMappingURL=ScopeValidator.spec.js.map
|