brighterscript 1.0.0-alpha.13 → 1.0.0-alpha.16
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 +87 -2
- package/dist/Cache.d.ts +3 -8
- package/dist/Cache.js +9 -14
- package/dist/Cache.js.map +1 -1
- package/dist/DependencyGraph.js +5 -4
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +21 -1
- package/dist/DiagnosticMessages.js +21 -1
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.d.ts +1 -6
- package/dist/LanguageServer.js +0 -9
- package/dist/LanguageServer.js.map +1 -1
- package/dist/PluginInterface.d.ts +3 -3
- package/dist/PluginInterface.js +3 -0
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +30 -16
- package/dist/Program.js +108 -43
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.js +3 -3
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +29 -15
- package/dist/Scope.js +68 -28
- package/dist/Scope.js.map +1 -1
- package/dist/SymbolTable.d.ts +1 -1
- package/dist/XmlScope.d.ts +3 -3
- package/dist/astUtils/AstEditor.d.ts +6 -0
- package/dist/astUtils/AstEditor.js +10 -0
- package/dist/astUtils/AstEditor.js.map +1 -1
- package/dist/astUtils/AstEditor.spec.js +37 -0
- package/dist/astUtils/AstEditor.spec.js.map +1 -1
- package/dist/astUtils/creators.d.ts +8 -4
- package/dist/astUtils/creators.js +87 -6
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +5 -1
- package/dist/astUtils/reflection.js +15 -3
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +11 -10
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +3 -1
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +8 -8
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +4 -1
- package/dist/bscPlugin/BscPlugin.js +21 -2
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +3 -3
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +9 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +97 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.d.ts → BrsFileSemanticTokensProcessor.spec.d.ts} +0 -0
- package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.js → BrsFileSemanticTokensProcessor.spec.js} +30 -2
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +36 -0
- package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +11 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +94 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/diagnosticUtils.js +3 -3
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +382 -232
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +26 -12
- package/dist/files/BrsFile.js +268 -119
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +570 -168
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +11 -10
- package/dist/files/XmlFile.js +16 -11
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +60 -58
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +8 -6
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +21 -4
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +63 -35
- package/dist/lexer/Lexer.js +1 -2
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +470 -462
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +2 -0
- package/dist/lexer/TokenKind.js +5 -0
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/Expression.d.ts +18 -16
- package/dist/parser/Expression.js +57 -48
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +33 -32
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +28 -7
- package/dist/parser/Parser.js +508 -296
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +157 -35
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGTypes.spec.js +9 -9
- package/dist/parser/SGTypes.spec.js.map +1 -1
- package/dist/parser/Statement.d.ts +80 -20
- package/dist/parser/Statement.js +257 -92
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +3 -3
- package/dist/parser/tests/Parser.spec.js +4 -4
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +40 -40
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +22 -21
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +100 -99
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +25 -25
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +21 -21
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +91 -91
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +102 -102
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +15 -15
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +22 -21
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +11 -11
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +171 -171
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +50 -50
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +25 -25
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +26 -26
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +27 -27
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +3 -2
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/Relational.spec.js +25 -25
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +7 -7
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +6 -6
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/Declaration.spec.js +20 -20
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Enum.spec.js +774 -0
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
- package/dist/parser/tests/statement/For.spec.d.ts +1 -0
- package/dist/parser/tests/statement/For.spec.js +46 -0
- package/dist/parser/tests/statement/For.spec.js.map +1 -0
- package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ForEach.spec.js +37 -0
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
- package/dist/parser/tests/statement/Function.spec.js +121 -120
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +9 -8
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +22 -22
- package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +12 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/LibraryStatement.spec.js +7 -7
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +71 -70
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +17 -17
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +33 -33
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +53 -53
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +7 -6
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/preprocessor/Chunk.d.ts +1 -1
- package/dist/preprocessor/Preprocessor.d.ts +1 -1
- package/dist/preprocessor/Preprocessor.js +7 -7
- package/dist/preprocessor/Preprocessor.js.map +1 -1
- package/dist/types/ArrayType.d.ts +8 -5
- package/dist/types/ArrayType.js +45 -9
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +62 -3
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +1 -1
- package/dist/types/CustomType.d.ts +1 -1
- package/dist/types/CustomType.js +4 -2
- package/dist/types/CustomType.js.map +1 -1
- package/dist/types/FunctionType.d.ts +7 -6
- package/dist/types/FunctionType.js +21 -18
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/FunctionType.spec.js +6 -0
- package/dist/types/FunctionType.spec.js.map +1 -1
- package/dist/types/LazyType.d.ts +1 -2
- package/dist/types/LazyType.js +1 -5
- package/dist/types/LazyType.js.map +1 -1
- package/dist/types/UniversalFunctionType.d.ts +9 -0
- package/dist/types/UniversalFunctionType.js +25 -0
- package/dist/types/UniversalFunctionType.js.map +1 -0
- package/dist/types/helpers.js +1 -1
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +26 -10
- package/dist/util.js +145 -61
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js +17 -24
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +3 -3
- 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/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +0 -7
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +0 -63
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +0 -1
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +0 -1
- package/dist/lexer/index.d.ts +0 -3
- package/dist/lexer/index.js +0 -18
- package/dist/lexer/index.js.map +0 -1
- package/dist/parser/index.d.ts +0 -3
- package/dist/parser/index.js +0 -16
- package/dist/parser/index.js.map +0 -1
- package/dist/preprocessor/index.d.ts +0 -3
- package/dist/preprocessor/index.js +0 -16
- package/dist/preprocessor/index.js.map +0 -1
package/dist/files/BrsFile.js
CHANGED
|
@@ -6,8 +6,11 @@ const vscode_languageserver_1 = require("vscode-languageserver");
|
|
|
6
6
|
const chalk_1 = require("chalk");
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const DiagnosticMessages_1 = require("../DiagnosticMessages");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
9
|
+
const Token_1 = require("../lexer/Token");
|
|
10
|
+
const Lexer_1 = require("../lexer/Lexer");
|
|
11
|
+
const TokenKind_1 = require("../lexer/TokenKind");
|
|
12
|
+
const Parser_1 = require("../parser/Parser");
|
|
13
|
+
const DynamicType_1 = require("../types/DynamicType");
|
|
11
14
|
const util_1 = require("../util");
|
|
12
15
|
const BrsTranspileState_1 = require("../parser/BrsTranspileState");
|
|
13
16
|
const Preprocessor_1 = require("../preprocessor/Preprocessor");
|
|
@@ -19,8 +22,6 @@ const CommentFlagProcessor_1 = require("../CommentFlagProcessor");
|
|
|
19
22
|
const BscType_1 = require("../types/BscType");
|
|
20
23
|
const UninitializedType_1 = require("../types/UninitializedType");
|
|
21
24
|
const InvalidType_1 = require("../types/InvalidType");
|
|
22
|
-
const globalCallables_1 = require("../globalCallables");
|
|
23
|
-
const DynamicType_1 = require("../types/DynamicType");
|
|
24
25
|
/**
|
|
25
26
|
* Holds all details about this file within the scope of the whole program
|
|
26
27
|
*/
|
|
@@ -41,9 +42,10 @@ class BrsFile {
|
|
|
41
42
|
/**
|
|
42
43
|
* The parseMode used for the parser for this file
|
|
43
44
|
*/
|
|
44
|
-
this.parseMode =
|
|
45
|
+
this.parseMode = Parser_1.ParseMode.BrightScript;
|
|
45
46
|
/**
|
|
46
47
|
* Indicates whether this file needs to be validated.
|
|
48
|
+
* Files are only ever validated a single time
|
|
47
49
|
*/
|
|
48
50
|
this.isValidated = false;
|
|
49
51
|
this.diagnostics = [];
|
|
@@ -64,7 +66,7 @@ class BrsFile {
|
|
|
64
66
|
//all BrighterScript files need to be transpiled
|
|
65
67
|
if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
|
|
66
68
|
this.needsTranspiled = true;
|
|
67
|
-
this.parseMode =
|
|
69
|
+
this.parseMode = Parser_1.ParseMode.BrighterScript;
|
|
68
70
|
}
|
|
69
71
|
this.isTypedef = this.extension === '.d.bs';
|
|
70
72
|
if (!this.isTypedef) {
|
|
@@ -111,9 +113,8 @@ class BrsFile {
|
|
|
111
113
|
* Also notify the dependency graph of our current dependencies so other dependents can be notified.
|
|
112
114
|
*/
|
|
113
115
|
attachDependencyGraph(dependencyGraph) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
116
|
+
var _a;
|
|
117
|
+
(_a = this.unsubscribeFromDependencyGraph) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
117
118
|
//event that fires anytime a dependency changes
|
|
118
119
|
this.unsubscribeFromDependencyGraph = dependencyGraph.onchange(this.dependencyGraphKey, () => {
|
|
119
120
|
this.resolveTypedef();
|
|
@@ -135,11 +136,13 @@ class BrsFile {
|
|
|
135
136
|
this.diagnostics = [];
|
|
136
137
|
//if we have a typedef file, skip parsing this file
|
|
137
138
|
if (this.hasTypedef) {
|
|
139
|
+
//skip validation since the typedef is shadowing this file
|
|
140
|
+
this.isValidated = true;
|
|
138
141
|
return;
|
|
139
142
|
}
|
|
140
143
|
//tokenize the input file
|
|
141
144
|
let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
|
|
142
|
-
return
|
|
145
|
+
return Lexer_1.Lexer.scan(fileContents, {
|
|
143
146
|
includeWhitespace: false
|
|
144
147
|
});
|
|
145
148
|
});
|
|
@@ -162,7 +165,7 @@ class BrsFile {
|
|
|
162
165
|
//if the preprocessor generated tokens, use them.
|
|
163
166
|
let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
|
|
164
167
|
this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
|
|
165
|
-
this._parser =
|
|
168
|
+
this._parser = Parser_1.Parser.parse(tokens, {
|
|
166
169
|
mode: this.parseMode,
|
|
167
170
|
logger: this.program.logger
|
|
168
171
|
});
|
|
@@ -173,20 +176,39 @@ class BrsFile {
|
|
|
173
176
|
this.findCallables();
|
|
174
177
|
//find all places where a sub/function is being called
|
|
175
178
|
this.findFunctionCalls();
|
|
176
|
-
|
|
179
|
+
//register all import statements for use in the rest of the program
|
|
180
|
+
this.registerImports();
|
|
177
181
|
//attach this file to every diagnostic
|
|
178
182
|
for (let diagnostic of this.diagnostics) {
|
|
179
183
|
diagnostic.file = this;
|
|
180
184
|
}
|
|
181
185
|
}
|
|
182
186
|
catch (e) {
|
|
183
|
-
this._parser = new
|
|
187
|
+
this._parser = new Parser_1.Parser();
|
|
184
188
|
this.diagnostics.push(Object.assign({ file: this, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }, DiagnosticMessages_1.DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify((0, serialize_error_1.serializeError)(e)))));
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
191
|
+
registerImports() {
|
|
192
|
+
var _a, _b, _c, _d;
|
|
193
|
+
for (const statement of (_c = (_b = (_a = this.parser) === null || _a === void 0 ? void 0 : _a.references) === null || _b === void 0 ? void 0 : _b.importStatements) !== null && _c !== void 0 ? _c : []) {
|
|
194
|
+
//register import statements
|
|
195
|
+
if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
|
|
196
|
+
this.ownScriptImports.push({
|
|
197
|
+
filePathRange: statement.filePathToken.range,
|
|
198
|
+
pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
|
|
199
|
+
sourceFile: this,
|
|
200
|
+
text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
validate() {
|
|
206
|
+
//only validate the file if it was actually parsed (skip files containing typedefs)
|
|
207
|
+
if (!this.hasTypedef) {
|
|
208
|
+
this.validateImportStatements();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
validateImportStatements() {
|
|
190
212
|
let topOfFileIncludeStatements = [];
|
|
191
213
|
for (let stmt of this.ast.statements) {
|
|
192
214
|
//skip comments
|
|
@@ -207,15 +229,6 @@ class BrsFile {
|
|
|
207
229
|
...this._parser.references.importStatements
|
|
208
230
|
];
|
|
209
231
|
for (let result of statements) {
|
|
210
|
-
//register import statements
|
|
211
|
-
if ((0, reflection_1.isImportStatement)(result) && result.filePathToken) {
|
|
212
|
-
this.ownScriptImports.push({
|
|
213
|
-
filePathRange: result.filePathToken.range,
|
|
214
|
-
pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, result.filePath),
|
|
215
|
-
sourceFile: this,
|
|
216
|
-
text: (_a = result.filePathToken) === null || _a === void 0 ? void 0 : _a.text
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
232
|
//if this statement is not one of the top-of-file statements,
|
|
220
233
|
//then add a diagnostic explaining that it is invalid
|
|
221
234
|
if (!topOfFileIncludeStatements.includes(result)) {
|
|
@@ -273,7 +286,7 @@ class BrsFile {
|
|
|
273
286
|
const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
|
|
274
287
|
this.commentFlags = [];
|
|
275
288
|
for (let token of tokens) {
|
|
276
|
-
if (token.kind ===
|
|
289
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
277
290
|
processor.tryAdd(token.text, token.range);
|
|
278
291
|
}
|
|
279
292
|
}
|
|
@@ -325,7 +338,7 @@ class BrsFile {
|
|
|
325
338
|
let args = [];
|
|
326
339
|
//TODO convert if stmts to use instanceof instead
|
|
327
340
|
for (let arg of expression.args) {
|
|
328
|
-
let inferredType = (0,
|
|
341
|
+
let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
|
|
329
342
|
let argText = '';
|
|
330
343
|
// Get the text to display for the arg
|
|
331
344
|
if (arg.token) {
|
|
@@ -333,7 +346,7 @@ class BrsFile {
|
|
|
333
346
|
//is a function call being passed into argument
|
|
334
347
|
}
|
|
335
348
|
else if (arg.name) {
|
|
336
|
-
if ((0,
|
|
349
|
+
if ((0, Token_1.isToken)(arg.name)) {
|
|
337
350
|
argText = arg.name.text;
|
|
338
351
|
}
|
|
339
352
|
}
|
|
@@ -388,6 +401,20 @@ class BrsFile {
|
|
|
388
401
|
}
|
|
389
402
|
}
|
|
390
403
|
}
|
|
404
|
+
/**
|
|
405
|
+
* Find the NamespaceStatement enclosing the given position
|
|
406
|
+
* @param position
|
|
407
|
+
* @param functionScopes
|
|
408
|
+
*/
|
|
409
|
+
getNamespaceStatementForPosition(position) {
|
|
410
|
+
if (position) {
|
|
411
|
+
for (const statement of this.parser.references.namespaceStatements) {
|
|
412
|
+
if (util_1.util.rangeContains(statement.range, position)) {
|
|
413
|
+
return statement;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
391
418
|
/**
|
|
392
419
|
* Get completions available at the given cursor. This aggregates all values from this file and the current scope.
|
|
393
420
|
*/
|
|
@@ -404,10 +431,10 @@ class BrsFile {
|
|
|
404
431
|
//if cursor is within a comment, disable completions
|
|
405
432
|
let currentToken = this.parser.getTokenAt(position);
|
|
406
433
|
const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
|
|
407
|
-
if (tokenKind ===
|
|
434
|
+
if (tokenKind === TokenKind_1.TokenKind.Comment) {
|
|
408
435
|
return [];
|
|
409
436
|
}
|
|
410
|
-
else if (tokenKind ===
|
|
437
|
+
else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
|
|
411
438
|
const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
|
|
412
439
|
if (match) {
|
|
413
440
|
const [, openingQuote, fileProtocol] = match;
|
|
@@ -431,38 +458,44 @@ class BrsFile {
|
|
|
431
458
|
return [];
|
|
432
459
|
}
|
|
433
460
|
}
|
|
434
|
-
|
|
461
|
+
const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
|
|
435
462
|
if (namespaceCompletions.length > 0) {
|
|
436
|
-
return namespaceCompletions;
|
|
463
|
+
return [...namespaceCompletions];
|
|
464
|
+
}
|
|
465
|
+
const enumMemberCompletions = this.getEnumMemberStatementCompletions(currentToken, this.parseMode, scope);
|
|
466
|
+
if (enumMemberCompletions.length > 0) {
|
|
467
|
+
// no other completion is valid in this case
|
|
468
|
+
return enumMemberCompletions;
|
|
437
469
|
}
|
|
438
470
|
//determine if cursor is inside a function
|
|
439
471
|
let functionExpression = this.getFunctionExpressionAtPosition(position);
|
|
440
472
|
if (!functionExpression) {
|
|
441
473
|
//we aren't in any function scope, so return the keyword completions and namespaces
|
|
442
|
-
if (this.parser.getTokenBefore(currentToken,
|
|
474
|
+
if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
|
|
443
475
|
// there's a new keyword, so only class types are viable here
|
|
444
476
|
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
|
|
445
477
|
}
|
|
446
478
|
else {
|
|
447
|
-
return [
|
|
479
|
+
return [
|
|
480
|
+
...exports.KeywordCompletions,
|
|
481
|
+
...this.getGlobalClassStatementCompletions(currentToken, this.parseMode),
|
|
482
|
+
...namespaceCompletions,
|
|
483
|
+
...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope)
|
|
484
|
+
];
|
|
448
485
|
}
|
|
449
486
|
}
|
|
450
487
|
const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
|
|
451
|
-
const newToken = this.parser.getTokenBefore(currentToken,
|
|
488
|
+
const newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
452
489
|
if (newToken) {
|
|
453
|
-
//we are after a new keyword; so we can only be namespaces or classes at this point
|
|
490
|
+
//we are after a new keyword; so we can only be top-level namespaces or classes at this point
|
|
454
491
|
result.push(...classNameCompletions);
|
|
455
492
|
result.push(...namespaceCompletions);
|
|
456
493
|
return result;
|
|
457
494
|
}
|
|
458
|
-
if (this.parser.tokenFollows(currentToken,
|
|
495
|
+
if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
|
|
459
496
|
return this.getLabelCompletion(functionExpression);
|
|
460
497
|
}
|
|
461
|
-
if (this.parser.isPositionNextToTokenKind(position,
|
|
462
|
-
if (namespaceCompletions.length > 0) {
|
|
463
|
-
//if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
|
|
464
|
-
return namespaceCompletions;
|
|
465
|
-
}
|
|
498
|
+
if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
|
|
466
499
|
const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
|
|
467
500
|
if (selfClassMemberCompletions.size > 0) {
|
|
468
501
|
return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
|
|
@@ -487,6 +520,8 @@ class BrsFile {
|
|
|
487
520
|
result.push(...namespaceCompletions);
|
|
488
521
|
//include class names
|
|
489
522
|
result.push(...classNameCompletions);
|
|
523
|
+
//include enums
|
|
524
|
+
result.push(...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope));
|
|
490
525
|
//include the global callables
|
|
491
526
|
result.push(...scope.getCallablesAsCompletions(this.parseMode));
|
|
492
527
|
//add `m` because that's always valid within a function
|
|
@@ -514,7 +549,7 @@ class BrsFile {
|
|
|
514
549
|
// kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
|
|
515
550
|
});
|
|
516
551
|
}
|
|
517
|
-
if (this.parseMode ===
|
|
552
|
+
if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
518
553
|
//include the first part of namespaces
|
|
519
554
|
let namespaces = scope.getAllNamespaceStatements();
|
|
520
555
|
for (let stmt of namespaces) {
|
|
@@ -552,7 +587,7 @@ class BrsFile {
|
|
|
552
587
|
let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
|
|
553
588
|
let results = new Map();
|
|
554
589
|
if (classStatement) {
|
|
555
|
-
let classes = scope.getClassHierarchy(classStatement.item.getName(
|
|
590
|
+
let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
556
591
|
for (let cs of classes) {
|
|
557
592
|
for (let member of [...(_b = (_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : [], ...(_d = (_c = cs === null || cs === void 0 ? void 0 : cs.item) === null || _c === void 0 ? void 0 : _c.methods) !== null && _d !== void 0 ? _d : []]) {
|
|
558
593
|
if (!results.has(member.name.text.toLowerCase())) {
|
|
@@ -602,7 +637,7 @@ class BrsFile {
|
|
|
602
637
|
let startsWithNamespace = '';
|
|
603
638
|
let namespaceContainer;
|
|
604
639
|
let tokenChain = [...originalTokenChain];
|
|
605
|
-
while (tokenChain[0] && tokenChain[0].usage ===
|
|
640
|
+
while (tokenChain[0] && tokenChain[0].usage === Parser_1.TokenUsage.Direct) {
|
|
606
641
|
const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
|
|
607
642
|
const foundNamespace = scope.namespaceLookup.get(namespaceNameToCheck);
|
|
608
643
|
if (foundNamespace) {
|
|
@@ -633,7 +668,7 @@ class BrsFile {
|
|
|
633
668
|
let useExpandedTextOnly = false;
|
|
634
669
|
if (containingClass.name === currentToken) {
|
|
635
670
|
symbolType = containingClass.getCustomType();
|
|
636
|
-
expandedText = `class ${containingClass.getName(
|
|
671
|
+
expandedText = `class ${containingClass.getName(Parser_1.ParseMode.BrighterScript)}`;
|
|
637
672
|
useExpandedTextOnly = true;
|
|
638
673
|
currentClassRef = containingClass;
|
|
639
674
|
}
|
|
@@ -652,13 +687,13 @@ class BrsFile {
|
|
|
652
687
|
// check if this is a method declaration
|
|
653
688
|
currentClassRef = containingClass;
|
|
654
689
|
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
655
|
-
expandedText = [containingClass.getName(
|
|
690
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
656
691
|
}
|
|
657
692
|
else if (!func) {
|
|
658
693
|
// check if this is a field declaration
|
|
659
694
|
currentClassRef = containingClass;
|
|
660
695
|
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
661
|
-
expandedText = [containingClass.getName(
|
|
696
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
662
697
|
}
|
|
663
698
|
if (symbolType) {
|
|
664
699
|
return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
|
|
@@ -690,7 +725,7 @@ class BrsFile {
|
|
|
690
725
|
*/
|
|
691
726
|
getSymbolTypeFromToken(currentToken, functionExpression, scope) {
|
|
692
727
|
var _a, _b, _c, _d, _e;
|
|
693
|
-
if (!scope) {
|
|
728
|
+
if (!scope || !currentToken) {
|
|
694
729
|
return undefined;
|
|
695
730
|
}
|
|
696
731
|
const cachedSymbolData = scope.symbolCache.get(currentToken);
|
|
@@ -720,13 +755,14 @@ class BrsFile {
|
|
|
720
755
|
const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
|
|
721
756
|
for (const tokenChainMember of tokenChain) {
|
|
722
757
|
const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
|
|
758
|
+
const tokenUsage = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.usage;
|
|
723
759
|
const tokenLowerText = token.text.toLowerCase();
|
|
724
760
|
if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
|
|
725
761
|
/// Special cases for first item in chain inside a class
|
|
726
762
|
symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
|
|
727
763
|
currentSymbolTable = (_d = symbolContainer) === null || _d === void 0 ? void 0 : _d.memberTable;
|
|
728
764
|
if (symbolContainer && currentSymbolTable) {
|
|
729
|
-
tokenText.push(symbolContainer.getName(
|
|
765
|
+
tokenText.push(symbolContainer.getName(Parser_1.ParseMode.BrighterScript));
|
|
730
766
|
tokenFoundCount++;
|
|
731
767
|
continue;
|
|
732
768
|
}
|
|
@@ -738,7 +774,7 @@ class BrsFile {
|
|
|
738
774
|
symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
|
|
739
775
|
if (tokenFoundCount === 0 && !symbolType) {
|
|
740
776
|
//check for global callable
|
|
741
|
-
symbolType = (_e =
|
|
777
|
+
symbolType = (_e = scope.getGlobalCallableByName(tokenLowerText)) === null || _e === void 0 ? void 0 : _e.type;
|
|
742
778
|
}
|
|
743
779
|
if (symbolType) {
|
|
744
780
|
// found this symbol, and it's valid. increase found counter
|
|
@@ -750,10 +786,13 @@ class BrsFile {
|
|
|
750
786
|
// the next symbol to check will be the return value of this function
|
|
751
787
|
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
|
|
752
788
|
if (tokenFoundCount < tokenChain.length) {
|
|
753
|
-
// We
|
|
789
|
+
// We still have more tokens, but remember the last known reference
|
|
754
790
|
symbolTypeBeforeReference = symbolType;
|
|
755
791
|
}
|
|
756
792
|
}
|
|
793
|
+
if ((0, reflection_1.isArrayType)(symbolType) && tokenUsage === Parser_1.TokenUsage.ArrayReference) {
|
|
794
|
+
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.getDefaultType(typeContext), typeContext);
|
|
795
|
+
}
|
|
757
796
|
if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
|
|
758
797
|
if ((0, reflection_1.isCustomType)(symbolType)) {
|
|
759
798
|
// we're currently looking at a customType, that has it's own symbol table
|
|
@@ -783,9 +822,12 @@ class BrsFile {
|
|
|
783
822
|
tokenText.push(token.text);
|
|
784
823
|
break;
|
|
785
824
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
825
|
+
}
|
|
826
|
+
if (tokenText.length > 2) {
|
|
827
|
+
// TokenText is used for hovers. We only need the last two tokens for a hover
|
|
828
|
+
// So in a long chain (e.g. klass.getData()[0].anotherKlass.property), the hover
|
|
829
|
+
// for the last token should just be "AnotherKlass.property", not the whole chain
|
|
830
|
+
tokenText = tokenText.slice(-2);
|
|
789
831
|
}
|
|
790
832
|
let expandedTokenText = tokenText.join('.');
|
|
791
833
|
let backUpReturnType;
|
|
@@ -827,18 +869,17 @@ class BrsFile {
|
|
|
827
869
|
}
|
|
828
870
|
getGlobalClassStatementCompletions(currentToken, parseMode) {
|
|
829
871
|
var _a;
|
|
830
|
-
if (parseMode ===
|
|
872
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
831
873
|
return [];
|
|
832
874
|
}
|
|
833
875
|
let results = new Map();
|
|
834
|
-
let completionName = (_a = this.getPartialVariableName(currentToken, [
|
|
876
|
+
let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
835
877
|
if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
|
|
836
878
|
return [];
|
|
837
879
|
}
|
|
838
880
|
let scopes = this.program.getScopesForFile(this);
|
|
839
881
|
for (let scope of scopes) {
|
|
840
882
|
let classMap = scope.getClassMap();
|
|
841
|
-
// let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
|
|
842
883
|
for (const key of [...classMap.keys()]) {
|
|
843
884
|
let cs = classMap.get(key).item;
|
|
844
885
|
if (!results.has(cs.name.text)) {
|
|
@@ -851,19 +892,70 @@ class BrsFile {
|
|
|
851
892
|
}
|
|
852
893
|
return [...results.values()];
|
|
853
894
|
}
|
|
895
|
+
getNonNamespacedEnumStatementCompletions(currentToken, parseMode, scope) {
|
|
896
|
+
var _a, _b;
|
|
897
|
+
if (parseMode !== Parser_1.ParseMode.BrighterScript) {
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
const containingNamespaceName = ((_b = this.getNamespaceStatementForPosition((_a = currentToken === null || currentToken === void 0 ? void 0 : currentToken.range) === null || _a === void 0 ? void 0 : _a.start)) === null || _b === void 0 ? void 0 : _b.name) + '.';
|
|
901
|
+
const results = new Map();
|
|
902
|
+
const enumMap = scope.getEnumMap();
|
|
903
|
+
for (const key of [...enumMap.keys()]) {
|
|
904
|
+
const enumStatement = enumMap.get(key).item;
|
|
905
|
+
const fullName = enumStatement.fullName;
|
|
906
|
+
//if the enum is contained within our own namespace, or if it's a non-namespaced enum
|
|
907
|
+
if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
|
|
908
|
+
results.set(fullName, {
|
|
909
|
+
label: enumStatement.name,
|
|
910
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return [...results.values()];
|
|
915
|
+
}
|
|
916
|
+
getEnumMemberStatementCompletions(currentToken, parseMode, scope) {
|
|
917
|
+
var _a, _b, _c, _d, _e;
|
|
918
|
+
if (parseMode === Parser_1.ParseMode.BrightScript || !currentToken) {
|
|
919
|
+
return [];
|
|
920
|
+
}
|
|
921
|
+
const results = new Map();
|
|
922
|
+
const completionName = (_a = this.getPartialVariableName(currentToken)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
923
|
+
//if we don't have a completion name, or if there's no period in the name, then this is not to the right of an enum name
|
|
924
|
+
if (!completionName || !completionName.includes('.')) {
|
|
925
|
+
return [];
|
|
926
|
+
}
|
|
927
|
+
const enumNameLower = (_b = completionName === null || completionName === void 0 ? void 0 : completionName.split(/\.(\w+)?$/)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
928
|
+
const namespaceNameLower = (_c = this.getNamespaceStatementForPosition(currentToken.range.end)) === null || _c === void 0 ? void 0 : _c.name.toLowerCase();
|
|
929
|
+
const enumMap = scope.getEnumMap();
|
|
930
|
+
//get the enum statement with this name (check without namespace prefix first, then with inferred namespace prefix next)
|
|
931
|
+
const enumStatement = (_e = ((_d = enumMap.get(enumNameLower)) !== null && _d !== void 0 ? _d : enumMap.get(namespaceNameLower + '.' + enumNameLower))) === null || _e === void 0 ? void 0 : _e.item;
|
|
932
|
+
//if we found an enum with this name
|
|
933
|
+
if (enumStatement) {
|
|
934
|
+
for (const member of enumStatement.getMembers()) {
|
|
935
|
+
const name = enumStatement.fullName + '.' + member.name;
|
|
936
|
+
const nameLower = name.toLowerCase();
|
|
937
|
+
results.set(nameLower, {
|
|
938
|
+
label: member.name,
|
|
939
|
+
kind: vscode_languageserver_1.CompletionItemKind.EnumMember
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return [...results.values()];
|
|
944
|
+
}
|
|
854
945
|
getNamespaceCompletions(currentToken, parseMode, scope) {
|
|
855
946
|
//BrightScript does not support namespaces, so return an empty list in that case
|
|
856
|
-
if (parseMode ===
|
|
947
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
857
948
|
return [];
|
|
858
949
|
}
|
|
859
|
-
|
|
860
|
-
if
|
|
950
|
+
const completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
|
|
951
|
+
//if we don't have a completion name, or if there's no period in the name, then this is not a namespaced variable
|
|
952
|
+
if (!completionName || !completionName.includes('.')) {
|
|
861
953
|
return [];
|
|
862
954
|
}
|
|
863
955
|
//remove any trailing identifer and then any trailing dot, to give us the
|
|
864
956
|
//name of its immediate parent namespace
|
|
865
|
-
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
|
|
866
|
-
let newToken = this.parser.getTokenBefore(currentToken,
|
|
957
|
+
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
|
|
958
|
+
let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
867
959
|
let result = new Map();
|
|
868
960
|
for (let [, namespace] of scope.namespaceLookup) {
|
|
869
961
|
//completionName = "NameA."
|
|
@@ -871,7 +963,7 @@ class BrsFile {
|
|
|
871
963
|
//NameA
|
|
872
964
|
//NameA.NameB
|
|
873
965
|
//NameA.NameB.NameC
|
|
874
|
-
if (namespace.fullName.toLowerCase() === closestParentNamespaceName
|
|
966
|
+
if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
|
|
875
967
|
//add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
|
|
876
968
|
for (let [, ns] of namespace.namespaces) {
|
|
877
969
|
if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
|
|
@@ -886,20 +978,22 @@ class BrsFile {
|
|
|
886
978
|
//add function and class statement completions
|
|
887
979
|
for (let stmt of namespace.statements) {
|
|
888
980
|
if ((0, reflection_1.isClassStatement)(stmt)) {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
});
|
|
894
|
-
}
|
|
981
|
+
result.set(stmt.name.text, {
|
|
982
|
+
label: stmt.name.text,
|
|
983
|
+
kind: vscode_languageserver_1.CompletionItemKind.Class
|
|
984
|
+
});
|
|
895
985
|
}
|
|
896
986
|
else if ((0, reflection_1.isFunctionStatement)(stmt) && !newToken) {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
987
|
+
result.set(stmt.name.text, {
|
|
988
|
+
label: stmt.name.text,
|
|
989
|
+
kind: vscode_languageserver_1.CompletionItemKind.Function
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
else if ((0, reflection_1.isEnumStatement)(stmt) && !newToken) {
|
|
993
|
+
result.set(stmt.name, {
|
|
994
|
+
label: stmt.name,
|
|
995
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
996
|
+
});
|
|
903
997
|
}
|
|
904
998
|
}
|
|
905
999
|
}
|
|
@@ -912,11 +1006,11 @@ class BrsFile {
|
|
|
912
1006
|
return undefined;
|
|
913
1007
|
}
|
|
914
1008
|
let location;
|
|
915
|
-
const nameParts = this.getPartialVariableName(token, [
|
|
1009
|
+
const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
|
|
916
1010
|
const endName = nameParts[nameParts.length - 1].toLowerCase();
|
|
917
1011
|
const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
|
|
918
1012
|
const statementHandler = (statement) => {
|
|
919
|
-
if (!location && statement.getName(
|
|
1013
|
+
if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
|
|
920
1014
|
const namespaceItemStatementHandler = (statement) => {
|
|
921
1015
|
if (!location && statement.name.text.toLowerCase() === endName) {
|
|
922
1016
|
const uri = util_1.util.pathToUri(file.srcPath);
|
|
@@ -942,7 +1036,7 @@ class BrsFile {
|
|
|
942
1036
|
* Given a current token, walk
|
|
943
1037
|
*/
|
|
944
1038
|
getPartialVariableName(currentToken, excludeTokens = null) {
|
|
945
|
-
let identifierAndDotKinds = [
|
|
1039
|
+
let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
|
|
946
1040
|
//consume tokens backwards until we find something other than a dot or an identifier
|
|
947
1041
|
let tokens = [];
|
|
948
1042
|
const parser = this.parser;
|
|
@@ -1073,7 +1167,7 @@ class BrsFile {
|
|
|
1073
1167
|
else {
|
|
1074
1168
|
return;
|
|
1075
1169
|
}
|
|
1076
|
-
const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(
|
|
1170
|
+
const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1077
1171
|
return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
|
|
1078
1172
|
}
|
|
1079
1173
|
/**
|
|
@@ -1107,9 +1201,9 @@ class BrsFile {
|
|
|
1107
1201
|
else {
|
|
1108
1202
|
return symbols;
|
|
1109
1203
|
}
|
|
1110
|
-
const name = statement.getName(
|
|
1204
|
+
const name = statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1111
1205
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1112
|
-
const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(
|
|
1206
|
+
const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(Parser_1.ParseMode.BrighterScript));
|
|
1113
1207
|
symbols.push(symbol);
|
|
1114
1208
|
return symbols;
|
|
1115
1209
|
}
|
|
@@ -1123,8 +1217,8 @@ class BrsFile {
|
|
|
1123
1217
|
const token = this.parser.getTokenAt(position);
|
|
1124
1218
|
// While certain other tokens are allowed as local variables (AllowedLocalIdentifiers: https://github.com/rokucommunity/brighterscript/blob/master/src/lexer/TokenKind.ts#L418), these are converted by the parser to TokenKind.Identifier by the time we retrieve the token using getTokenAt
|
|
1125
1219
|
let definitionTokenTypes = [
|
|
1126
|
-
|
|
1127
|
-
|
|
1220
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1221
|
+
TokenKind_1.TokenKind.StringLiteral
|
|
1128
1222
|
];
|
|
1129
1223
|
//throw out invalid tokens and the wrong kind of tokens
|
|
1130
1224
|
if (!token || !definitionTokenTypes.includes(token.kind)) {
|
|
@@ -1132,7 +1226,7 @@ class BrsFile {
|
|
|
1132
1226
|
}
|
|
1133
1227
|
let textToSearchFor = token.text.toLowerCase();
|
|
1134
1228
|
const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
1135
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1229
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
|
|
1136
1230
|
for (const scope of this.program.getScopes()) {
|
|
1137
1231
|
//to only get functions defined in interface methods
|
|
1138
1232
|
const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
|
|
@@ -1142,7 +1236,7 @@ class BrsFile {
|
|
|
1142
1236
|
}
|
|
1143
1237
|
return results;
|
|
1144
1238
|
}
|
|
1145
|
-
let classToken = this.parser.getTokenBefore(token,
|
|
1239
|
+
let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
|
|
1146
1240
|
if (classToken) {
|
|
1147
1241
|
let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
|
|
1148
1242
|
if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
|
|
@@ -1154,7 +1248,7 @@ class BrsFile {
|
|
|
1154
1248
|
}
|
|
1155
1249
|
return results;
|
|
1156
1250
|
}
|
|
1157
|
-
if (token.kind ===
|
|
1251
|
+
if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
|
|
1158
1252
|
// We need to strip off the quotes but only if present
|
|
1159
1253
|
const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
|
|
1160
1254
|
let endIndex = textToSearchFor.length;
|
|
@@ -1173,7 +1267,7 @@ class BrsFile {
|
|
|
1173
1267
|
results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
|
|
1174
1268
|
}
|
|
1175
1269
|
}
|
|
1176
|
-
if (this.parser.tokenFollows(token,
|
|
1270
|
+
if (this.parser.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
|
|
1177
1271
|
for (const label of func.labelStatements) {
|
|
1178
1272
|
if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
|
|
1179
1273
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
@@ -1189,7 +1283,7 @@ class BrsFile {
|
|
|
1189
1283
|
continue;
|
|
1190
1284
|
}
|
|
1191
1285
|
filesSearched.add(file);
|
|
1192
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1286
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
1193
1287
|
results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
|
|
1194
1288
|
const namespaceDefinition = this.getNamespaceDefinitions(token, file);
|
|
1195
1289
|
if (namespaceDefinition) {
|
|
@@ -1234,14 +1328,15 @@ class BrsFile {
|
|
|
1234
1328
|
}
|
|
1235
1329
|
getHover(position) {
|
|
1236
1330
|
var _a, _b, _c;
|
|
1331
|
+
const fence = (code) => util_1.util.mdFence(code, 'brightscript');
|
|
1237
1332
|
//get the token at the position
|
|
1238
1333
|
let token = this.parser.getTokenAt(position);
|
|
1239
1334
|
let hoverTokenTypes = [
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1335
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1336
|
+
TokenKind_1.TokenKind.Function,
|
|
1337
|
+
TokenKind_1.TokenKind.EndFunction,
|
|
1338
|
+
TokenKind_1.TokenKind.Sub,
|
|
1339
|
+
TokenKind_1.TokenKind.EndSub
|
|
1245
1340
|
];
|
|
1246
1341
|
//throw out invalid tokens and the wrong kind of tokens
|
|
1247
1342
|
if (!token || !hoverTokenTypes.includes(token.kind)) {
|
|
@@ -1262,48 +1357,95 @@ class BrsFile {
|
|
|
1262
1357
|
}
|
|
1263
1358
|
}
|
|
1264
1359
|
}
|
|
1265
|
-
const typeTexts =
|
|
1266
|
-
|
|
1360
|
+
const typeTexts = new Set();
|
|
1361
|
+
const fileScopes = this.program.getScopesForFile(this).sort((a, b) => { var _a; return (_a = a.dependencyGraphKey) === null || _a === void 0 ? void 0 : _a.localeCompare(b.dependencyGraphKey); });
|
|
1362
|
+
const callables = [];
|
|
1363
|
+
for (const scope of fileScopes) {
|
|
1267
1364
|
scope.linkSymbolTable();
|
|
1365
|
+
const typeContext = { file: this, scope: scope, position: position };
|
|
1268
1366
|
const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
|
|
1269
1367
|
if (typeTextPair) {
|
|
1270
1368
|
let scopeTypeText = '';
|
|
1271
1369
|
if ((0, reflection_1.isFunctionType)(typeTextPair.type)) {
|
|
1272
|
-
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString();
|
|
1370
|
+
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString(typeContext);
|
|
1371
|
+
//keep unique references to the callables for this function
|
|
1372
|
+
if (!typeTexts.has(scopeTypeText)) {
|
|
1373
|
+
callables.push(scope.getCallableByName(lowerTokenText));
|
|
1374
|
+
}
|
|
1273
1375
|
}
|
|
1274
1376
|
else if (typeTextPair.useExpandedTextOnly) {
|
|
1275
1377
|
scopeTypeText = typeTextPair.expandedTokenText;
|
|
1276
1378
|
}
|
|
1277
1379
|
else {
|
|
1278
|
-
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString()}`;
|
|
1380
|
+
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString(typeContext)}`;
|
|
1279
1381
|
}
|
|
1280
|
-
if (scopeTypeText
|
|
1281
|
-
typeTexts.
|
|
1382
|
+
if (scopeTypeText) {
|
|
1383
|
+
typeTexts.add(scopeTypeText);
|
|
1282
1384
|
}
|
|
1283
1385
|
}
|
|
1284
1386
|
scope.unlinkSymbolTable();
|
|
1285
1387
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1388
|
+
if (callables.length === typeTexts.size) {
|
|
1389
|
+
//this is a function in all scopes, so build the function hover
|
|
1288
1390
|
return {
|
|
1289
1391
|
range: token.range,
|
|
1290
|
-
contents:
|
|
1392
|
+
contents: this.getCallableDocumentation([...typeTexts], callables)
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
else if ((typeTexts === null || typeTexts === void 0 ? void 0 : typeTexts.size) > 0) {
|
|
1396
|
+
const typeText = [...typeTexts].join(' | ');
|
|
1397
|
+
return {
|
|
1398
|
+
range: token.range,
|
|
1399
|
+
contents: fence(typeText)
|
|
1291
1400
|
};
|
|
1292
1401
|
}
|
|
1293
1402
|
}
|
|
1294
|
-
//look through all callables in relevant scopes
|
|
1295
|
-
{
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1403
|
+
// //look through all callables in relevant scopes
|
|
1404
|
+
// {
|
|
1405
|
+
// let scopes = this.program.getScopesForFile(this);
|
|
1406
|
+
// for (let scope of scopes) {
|
|
1407
|
+
// let callable = scope.getCallableByName(lowerTokenText);
|
|
1408
|
+
// if (callable) {
|
|
1409
|
+
// return {
|
|
1410
|
+
// range: token.range,
|
|
1411
|
+
// contents: this.getCallableDocumentation(callables)
|
|
1412
|
+
// };
|
|
1413
|
+
// }
|
|
1414
|
+
// }
|
|
1415
|
+
// }
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Build a hover documentation for a callable.
|
|
1419
|
+
*/
|
|
1420
|
+
getCallableDocumentation(typeTexts, callables) {
|
|
1421
|
+
var _a;
|
|
1422
|
+
const callable = callables[0];
|
|
1423
|
+
const typeText = typeTexts[0];
|
|
1424
|
+
const comments = [];
|
|
1425
|
+
const tokens = callable === null || callable === void 0 ? void 0 : callable.file.parser.tokens;
|
|
1426
|
+
const idx = tokens === null || tokens === void 0 ? void 0 : tokens.indexOf((_a = callable.functionStatement) === null || _a === void 0 ? void 0 : _a.func.functionType);
|
|
1427
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
1428
|
+
const token = tokens[i];
|
|
1429
|
+
//skip whitespace and newline chars
|
|
1430
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
1431
|
+
comments.push(token);
|
|
1432
|
+
}
|
|
1433
|
+
else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
|
|
1434
|
+
//skip these tokens
|
|
1435
|
+
continue;
|
|
1436
|
+
//any other token means there are no more comments
|
|
1437
|
+
}
|
|
1438
|
+
else {
|
|
1439
|
+
break;
|
|
1305
1440
|
}
|
|
1306
1441
|
}
|
|
1442
|
+
//message indicating if there are variations. example: (+3 variations) if there are 4 unique function signatures
|
|
1443
|
+
const multiText = callables.length > 1 ? ` (+${callables.length - 1} variations)` : '';
|
|
1444
|
+
let result = util_1.util.mdFence(typeText + multiText, 'brightscript');
|
|
1445
|
+
if (comments.length > 0) {
|
|
1446
|
+
result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
|
|
1447
|
+
}
|
|
1448
|
+
return result;
|
|
1307
1449
|
}
|
|
1308
1450
|
getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
|
|
1309
1451
|
var _a;
|
|
@@ -1351,12 +1493,12 @@ class BrsFile {
|
|
|
1351
1493
|
}
|
|
1352
1494
|
}
|
|
1353
1495
|
const kind = currentToken.kind;
|
|
1354
|
-
if (kind ===
|
|
1496
|
+
if (kind === TokenKind_1.TokenKind.Comment) {
|
|
1355
1497
|
// Strip off common leading characters to make it easier to read
|
|
1356
1498
|
const commentText = currentToken.text.replace(/^[' *\/]+/, '');
|
|
1357
1499
|
functionComments.unshift(commentText);
|
|
1358
1500
|
}
|
|
1359
|
-
else if (kind ===
|
|
1501
|
+
else if (kind === TokenKind_1.TokenKind.Newline) {
|
|
1360
1502
|
if (functionComments.length === 0) {
|
|
1361
1503
|
continue;
|
|
1362
1504
|
}
|
|
@@ -1416,7 +1558,7 @@ class BrsFile {
|
|
|
1416
1558
|
const classConstructor = this.getClassMethod(classStatement, 'new');
|
|
1417
1559
|
let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
|
|
1418
1560
|
if (sigHelp) {
|
|
1419
|
-
sigHelp.key = classStatement.getName(
|
|
1561
|
+
sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1420
1562
|
sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
|
|
1421
1563
|
}
|
|
1422
1564
|
return sigHelp;
|
|
@@ -1484,8 +1626,15 @@ class BrsFile {
|
|
|
1484
1626
|
return programNode.toString();
|
|
1485
1627
|
}
|
|
1486
1628
|
dispose() {
|
|
1487
|
-
var _a;
|
|
1629
|
+
var _a, _b;
|
|
1488
1630
|
(_a = this._parser) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
1631
|
+
//unsubscribe from any DependencyGraph subscriptions
|
|
1632
|
+
(_b = this.unsubscribeFromDependencyGraph) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
1633
|
+
//deleting these properties result in lower memory usage (garbage collection is magic!)
|
|
1634
|
+
delete this.fileContents;
|
|
1635
|
+
delete this._parser;
|
|
1636
|
+
delete this.callables;
|
|
1637
|
+
delete this.functionCalls;
|
|
1489
1638
|
}
|
|
1490
1639
|
}
|
|
1491
1640
|
exports.BrsFile = BrsFile;
|
|
@@ -1493,7 +1642,7 @@ exports.BrsFile = BrsFile;
|
|
|
1493
1642
|
* List of completions for all valid keywords/reserved words.
|
|
1494
1643
|
* Build this list once because it won't change for the lifetime of this process
|
|
1495
1644
|
*/
|
|
1496
|
-
exports.KeywordCompletions = Object.keys(
|
|
1645
|
+
exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
|
|
1497
1646
|
//remove any keywords with whitespace
|
|
1498
1647
|
.filter(x => !x.includes(' '))
|
|
1499
1648
|
//create completions
|