brighterscript 1.0.0-alpha.11 → 1.0.0-alpha.15
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 +253 -268
- package/README.md +2 -2
- package/dist/Cache.d.ts +3 -8
- package/dist/Cache.js +9 -14
- package/dist/Cache.js.map +1 -1
- package/dist/CommentFlagProcessor.js +5 -3
- package/dist/CommentFlagProcessor.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 +110 -45
- 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 +31 -17
- package/dist/Scope.js +86 -48
- 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 +33 -0
- package/dist/astUtils/AstEditor.js +107 -0
- package/dist/astUtils/AstEditor.js.map +1 -0
- package/dist/{bscPlugin/semanticTokens/SemanticTokensProcessor.spec.d.ts → astUtils/AstEditor.spec.d.ts} +0 -0
- package/dist/astUtils/AstEditor.spec.js +170 -0
- package/dist/astUtils/AstEditor.spec.js.map +1 -0
- package/dist/astUtils/reflection.d.ts +3 -1
- package/dist/astUtils/reflection.js +10 -2
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +6 -6
- 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/astUtils/xml.d.ts +1 -0
- package/dist/astUtils/xml.js +6 -1
- package/dist/astUtils/xml.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/BrsFileSemanticTokensProcessor.spec.d.ts +1 -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/files/BrsFile.Class.spec.js +404 -230
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +26 -12
- package/dist/files/BrsFile.js +265 -127
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +586 -169
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +11 -10
- package/dist/files/XmlFile.js +13 -8
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +106 -59
- 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/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +198 -99
- package/dist/globalCallables.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 +68 -15
- 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 +1 -1
- package/dist/parser/Expression.js +10 -10
- 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 +494 -290
- 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/SGParser.js +1 -1
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +3 -0
- package/dist/parser/SGTypes.js +8 -3
- package/dist/parser/SGTypes.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 +55 -3
- package/dist/parser/Statement.js +162 -9
- 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 +30 -18
- 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/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 +5 -5
- package/dist/types/FunctionType.js +11 -11
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/FunctionType.spec.js +1 -1
- 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/helpers.js +1 -1
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +25 -9
- package/dist/util.js +139 -55
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js +27 -27
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +4 -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) {
|
|
@@ -135,11 +137,13 @@ class BrsFile {
|
|
|
135
137
|
this.diagnostics = [];
|
|
136
138
|
//if we have a typedef file, skip parsing this file
|
|
137
139
|
if (this.hasTypedef) {
|
|
140
|
+
//skip validation since the typedef is shadowing this file
|
|
141
|
+
this.isValidated = true;
|
|
138
142
|
return;
|
|
139
143
|
}
|
|
140
144
|
//tokenize the input file
|
|
141
145
|
let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
|
|
142
|
-
return
|
|
146
|
+
return Lexer_1.Lexer.scan(fileContents, {
|
|
143
147
|
includeWhitespace: false
|
|
144
148
|
});
|
|
145
149
|
});
|
|
@@ -162,7 +166,7 @@ class BrsFile {
|
|
|
162
166
|
//if the preprocessor generated tokens, use them.
|
|
163
167
|
let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
|
|
164
168
|
this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
|
|
165
|
-
this._parser =
|
|
169
|
+
this._parser = Parser_1.Parser.parse(tokens, {
|
|
166
170
|
mode: this.parseMode,
|
|
167
171
|
logger: this.program.logger
|
|
168
172
|
});
|
|
@@ -173,20 +177,39 @@ class BrsFile {
|
|
|
173
177
|
this.findCallables();
|
|
174
178
|
//find all places where a sub/function is being called
|
|
175
179
|
this.findFunctionCalls();
|
|
176
|
-
|
|
180
|
+
//register all import statements for use in the rest of the program
|
|
181
|
+
this.registerImports();
|
|
177
182
|
//attach this file to every diagnostic
|
|
178
183
|
for (let diagnostic of this.diagnostics) {
|
|
179
184
|
diagnostic.file = this;
|
|
180
185
|
}
|
|
181
186
|
}
|
|
182
187
|
catch (e) {
|
|
183
|
-
this._parser = new
|
|
188
|
+
this._parser = new Parser_1.Parser();
|
|
184
189
|
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
190
|
}
|
|
186
191
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
192
|
+
registerImports() {
|
|
193
|
+
var _a, _b, _c, _d;
|
|
194
|
+
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 : []) {
|
|
195
|
+
//register import statements
|
|
196
|
+
if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
|
|
197
|
+
this.ownScriptImports.push({
|
|
198
|
+
filePathRange: statement.filePathToken.range,
|
|
199
|
+
pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
|
|
200
|
+
sourceFile: this,
|
|
201
|
+
text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
validate() {
|
|
207
|
+
//only validate the file if it was actually parsed (skip files containing typedefs)
|
|
208
|
+
if (!this.hasTypedef) {
|
|
209
|
+
this.validateImportStatements();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
validateImportStatements() {
|
|
190
213
|
let topOfFileIncludeStatements = [];
|
|
191
214
|
for (let stmt of this.ast.statements) {
|
|
192
215
|
//skip comments
|
|
@@ -207,15 +230,6 @@ class BrsFile {
|
|
|
207
230
|
...this._parser.references.importStatements
|
|
208
231
|
];
|
|
209
232
|
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
233
|
//if this statement is not one of the top-of-file statements,
|
|
220
234
|
//then add a diagnostic explaining that it is invalid
|
|
221
235
|
if (!topOfFileIncludeStatements.includes(result)) {
|
|
@@ -273,7 +287,7 @@ class BrsFile {
|
|
|
273
287
|
const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
|
|
274
288
|
this.commentFlags = [];
|
|
275
289
|
for (let token of tokens) {
|
|
276
|
-
if (token.kind ===
|
|
290
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
277
291
|
processor.tryAdd(token.text, token.range);
|
|
278
292
|
}
|
|
279
293
|
}
|
|
@@ -325,7 +339,7 @@ class BrsFile {
|
|
|
325
339
|
let args = [];
|
|
326
340
|
//TODO convert if stmts to use instanceof instead
|
|
327
341
|
for (let arg of expression.args) {
|
|
328
|
-
let inferredType = (0,
|
|
342
|
+
let inferredType = (0, Parser_1.getBscTypeFromExpression)(arg, func);
|
|
329
343
|
let argText = '';
|
|
330
344
|
// Get the text to display for the arg
|
|
331
345
|
if (arg.token) {
|
|
@@ -333,7 +347,7 @@ class BrsFile {
|
|
|
333
347
|
//is a function call being passed into argument
|
|
334
348
|
}
|
|
335
349
|
else if (arg.name) {
|
|
336
|
-
if ((0,
|
|
350
|
+
if ((0, Token_1.isToken)(arg.name)) {
|
|
337
351
|
argText = arg.name.text;
|
|
338
352
|
}
|
|
339
353
|
}
|
|
@@ -388,6 +402,20 @@ class BrsFile {
|
|
|
388
402
|
}
|
|
389
403
|
}
|
|
390
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* Find the NamespaceStatement enclosing the given position
|
|
407
|
+
* @param position
|
|
408
|
+
* @param functionScopes
|
|
409
|
+
*/
|
|
410
|
+
getNamespaceStatementForPosition(position) {
|
|
411
|
+
if (position) {
|
|
412
|
+
for (const statement of this.parser.references.namespaceStatements) {
|
|
413
|
+
if (util_1.util.rangeContains(statement.range, position)) {
|
|
414
|
+
return statement;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
391
419
|
/**
|
|
392
420
|
* Get completions available at the given cursor. This aggregates all values from this file and the current scope.
|
|
393
421
|
*/
|
|
@@ -404,10 +432,10 @@ class BrsFile {
|
|
|
404
432
|
//if cursor is within a comment, disable completions
|
|
405
433
|
let currentToken = this.parser.getTokenAt(position);
|
|
406
434
|
const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
|
|
407
|
-
if (tokenKind ===
|
|
435
|
+
if (tokenKind === TokenKind_1.TokenKind.Comment) {
|
|
408
436
|
return [];
|
|
409
437
|
}
|
|
410
|
-
else if (tokenKind ===
|
|
438
|
+
else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
|
|
411
439
|
const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
|
|
412
440
|
if (match) {
|
|
413
441
|
const [, openingQuote, fileProtocol] = match;
|
|
@@ -431,38 +459,44 @@ class BrsFile {
|
|
|
431
459
|
return [];
|
|
432
460
|
}
|
|
433
461
|
}
|
|
434
|
-
|
|
462
|
+
const namespaceCompletions = this.getNamespaceCompletions(currentToken, this.parseMode, scope);
|
|
435
463
|
if (namespaceCompletions.length > 0) {
|
|
436
|
-
return namespaceCompletions;
|
|
464
|
+
return [...namespaceCompletions];
|
|
465
|
+
}
|
|
466
|
+
const enumMemberCompletions = this.getEnumMemberStatementCompletions(currentToken, this.parseMode, scope);
|
|
467
|
+
if (enumMemberCompletions.length > 0) {
|
|
468
|
+
// no other completion is valid in this case
|
|
469
|
+
return enumMemberCompletions;
|
|
437
470
|
}
|
|
438
471
|
//determine if cursor is inside a function
|
|
439
472
|
let functionExpression = this.getFunctionExpressionAtPosition(position);
|
|
440
473
|
if (!functionExpression) {
|
|
441
474
|
//we aren't in any function scope, so return the keyword completions and namespaces
|
|
442
|
-
if (this.parser.getTokenBefore(currentToken,
|
|
475
|
+
if (this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
|
|
443
476
|
// there's a new keyword, so only class types are viable here
|
|
444
477
|
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
|
|
445
478
|
}
|
|
446
479
|
else {
|
|
447
|
-
return [
|
|
480
|
+
return [
|
|
481
|
+
...exports.KeywordCompletions,
|
|
482
|
+
...this.getGlobalClassStatementCompletions(currentToken, this.parseMode),
|
|
483
|
+
...namespaceCompletions,
|
|
484
|
+
...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope)
|
|
485
|
+
];
|
|
448
486
|
}
|
|
449
487
|
}
|
|
450
488
|
const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
|
|
451
|
-
const newToken = this.parser.getTokenBefore(currentToken,
|
|
489
|
+
const newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
452
490
|
if (newToken) {
|
|
453
|
-
//we are after a new keyword; so we can only be namespaces or classes at this point
|
|
491
|
+
//we are after a new keyword; so we can only be top-level namespaces or classes at this point
|
|
454
492
|
result.push(...classNameCompletions);
|
|
455
493
|
result.push(...namespaceCompletions);
|
|
456
494
|
return result;
|
|
457
495
|
}
|
|
458
|
-
if (this.parser.tokenFollows(currentToken,
|
|
496
|
+
if (this.parser.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
|
|
459
497
|
return this.getLabelCompletion(functionExpression);
|
|
460
498
|
}
|
|
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
|
-
}
|
|
499
|
+
if (this.parser.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
|
|
466
500
|
const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
|
|
467
501
|
if (selfClassMemberCompletions.size > 0) {
|
|
468
502
|
return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
|
|
@@ -487,6 +521,8 @@ class BrsFile {
|
|
|
487
521
|
result.push(...namespaceCompletions);
|
|
488
522
|
//include class names
|
|
489
523
|
result.push(...classNameCompletions);
|
|
524
|
+
//include enums
|
|
525
|
+
result.push(...this.getNonNamespacedEnumStatementCompletions(currentToken, this.parseMode, scope));
|
|
490
526
|
//include the global callables
|
|
491
527
|
result.push(...scope.getCallablesAsCompletions(this.parseMode));
|
|
492
528
|
//add `m` because that's always valid within a function
|
|
@@ -514,7 +550,7 @@ class BrsFile {
|
|
|
514
550
|
// kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
|
|
515
551
|
});
|
|
516
552
|
}
|
|
517
|
-
if (this.parseMode ===
|
|
553
|
+
if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
518
554
|
//include the first part of namespaces
|
|
519
555
|
let namespaces = scope.getAllNamespaceStatements();
|
|
520
556
|
for (let stmt of namespaces) {
|
|
@@ -552,7 +588,7 @@ class BrsFile {
|
|
|
552
588
|
let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
|
|
553
589
|
let results = new Map();
|
|
554
590
|
if (classStatement) {
|
|
555
|
-
let classes = scope.getClassHierarchy(classStatement.item.getName(
|
|
591
|
+
let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
556
592
|
for (let cs of classes) {
|
|
557
593
|
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
594
|
if (!results.has(member.name.text.toLowerCase())) {
|
|
@@ -602,9 +638,9 @@ class BrsFile {
|
|
|
602
638
|
let startsWithNamespace = '';
|
|
603
639
|
let namespaceContainer;
|
|
604
640
|
let tokenChain = [...originalTokenChain];
|
|
605
|
-
while (tokenChain[0] && tokenChain[0].usage ===
|
|
641
|
+
while (tokenChain[0] && tokenChain[0].usage === Parser_1.TokenUsage.Direct) {
|
|
606
642
|
const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
|
|
607
|
-
const foundNamespace = scope.namespaceLookup
|
|
643
|
+
const foundNamespace = scope.namespaceLookup.get(namespaceNameToCheck);
|
|
608
644
|
if (foundNamespace) {
|
|
609
645
|
namespaceContainer = foundNamespace;
|
|
610
646
|
namespaceTokens.push(tokenChain[0].token);
|
|
@@ -616,7 +652,7 @@ class BrsFile {
|
|
|
616
652
|
}
|
|
617
653
|
}
|
|
618
654
|
if (namespaceTokens.length > 0) {
|
|
619
|
-
namespaceContainer = scope.namespaceLookup
|
|
655
|
+
namespaceContainer = scope.namespaceLookup.get(startsWithNamespace.toLowerCase());
|
|
620
656
|
}
|
|
621
657
|
return { namespaceContainer: namespaceContainer, tokenChain: tokenChain };
|
|
622
658
|
}
|
|
@@ -633,7 +669,7 @@ class BrsFile {
|
|
|
633
669
|
let useExpandedTextOnly = false;
|
|
634
670
|
if (containingClass.name === currentToken) {
|
|
635
671
|
symbolType = containingClass.getCustomType();
|
|
636
|
-
expandedText = `class ${containingClass.getName(
|
|
672
|
+
expandedText = `class ${containingClass.getName(Parser_1.ParseMode.BrighterScript)}`;
|
|
637
673
|
useExpandedTextOnly = true;
|
|
638
674
|
currentClassRef = containingClass;
|
|
639
675
|
}
|
|
@@ -652,13 +688,13 @@ class BrsFile {
|
|
|
652
688
|
// check if this is a method declaration
|
|
653
689
|
currentClassRef = containingClass;
|
|
654
690
|
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
655
|
-
expandedText = [containingClass.getName(
|
|
691
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
656
692
|
}
|
|
657
693
|
else if (!func) {
|
|
658
694
|
// check if this is a field declaration
|
|
659
695
|
currentClassRef = containingClass;
|
|
660
696
|
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
661
|
-
expandedText = [containingClass.getName(
|
|
697
|
+
expandedText = [containingClass.getName(Parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
662
698
|
}
|
|
663
699
|
if (symbolType) {
|
|
664
700
|
return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
|
|
@@ -690,7 +726,7 @@ class BrsFile {
|
|
|
690
726
|
*/
|
|
691
727
|
getSymbolTypeFromToken(currentToken, functionExpression, scope) {
|
|
692
728
|
var _a, _b, _c, _d, _e;
|
|
693
|
-
if (!scope) {
|
|
729
|
+
if (!scope || !currentToken) {
|
|
694
730
|
return undefined;
|
|
695
731
|
}
|
|
696
732
|
const cachedSymbolData = scope.symbolCache.get(currentToken);
|
|
@@ -720,13 +756,14 @@ class BrsFile {
|
|
|
720
756
|
const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
|
|
721
757
|
for (const tokenChainMember of tokenChain) {
|
|
722
758
|
const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
|
|
759
|
+
const tokenUsage = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.usage;
|
|
723
760
|
const tokenLowerText = token.text.toLowerCase();
|
|
724
761
|
if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
|
|
725
762
|
/// Special cases for first item in chain inside a class
|
|
726
763
|
symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
|
|
727
764
|
currentSymbolTable = (_d = symbolContainer) === null || _d === void 0 ? void 0 : _d.memberTable;
|
|
728
765
|
if (symbolContainer && currentSymbolTable) {
|
|
729
|
-
tokenText.push(symbolContainer.getName(
|
|
766
|
+
tokenText.push(symbolContainer.getName(Parser_1.ParseMode.BrighterScript));
|
|
730
767
|
tokenFoundCount++;
|
|
731
768
|
continue;
|
|
732
769
|
}
|
|
@@ -738,7 +775,7 @@ class BrsFile {
|
|
|
738
775
|
symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
|
|
739
776
|
if (tokenFoundCount === 0 && !symbolType) {
|
|
740
777
|
//check for global callable
|
|
741
|
-
symbolType = (_e =
|
|
778
|
+
symbolType = (_e = scope.getGlobalCallableByName(tokenLowerText)) === null || _e === void 0 ? void 0 : _e.type;
|
|
742
779
|
}
|
|
743
780
|
if (symbolType) {
|
|
744
781
|
// found this symbol, and it's valid. increase found counter
|
|
@@ -750,10 +787,13 @@ class BrsFile {
|
|
|
750
787
|
// the next symbol to check will be the return value of this function
|
|
751
788
|
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
|
|
752
789
|
if (tokenFoundCount < tokenChain.length) {
|
|
753
|
-
// We
|
|
790
|
+
// We still have more tokens, but remember the last known reference
|
|
754
791
|
symbolTypeBeforeReference = symbolType;
|
|
755
792
|
}
|
|
756
793
|
}
|
|
794
|
+
if ((0, reflection_1.isArrayType)(symbolType) && tokenUsage === Parser_1.TokenUsage.ArrayReference) {
|
|
795
|
+
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.getDefaultType(typeContext), typeContext);
|
|
796
|
+
}
|
|
757
797
|
if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
|
|
758
798
|
if ((0, reflection_1.isCustomType)(symbolType)) {
|
|
759
799
|
// we're currently looking at a customType, that has it's own symbol table
|
|
@@ -783,9 +823,12 @@ class BrsFile {
|
|
|
783
823
|
tokenText.push(token.text);
|
|
784
824
|
break;
|
|
785
825
|
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
826
|
+
}
|
|
827
|
+
if (tokenText.length > 2) {
|
|
828
|
+
// TokenText is used for hovers. We only need the last two tokens for a hover
|
|
829
|
+
// So in a long chain (e.g. klass.getData()[0].anotherKlass.property), the hover
|
|
830
|
+
// for the last token should just be "AnotherKlass.property", not the whole chain
|
|
831
|
+
tokenText = tokenText.slice(-2);
|
|
789
832
|
}
|
|
790
833
|
let expandedTokenText = tokenText.join('.');
|
|
791
834
|
let backUpReturnType;
|
|
@@ -827,18 +870,17 @@ class BrsFile {
|
|
|
827
870
|
}
|
|
828
871
|
getGlobalClassStatementCompletions(currentToken, parseMode) {
|
|
829
872
|
var _a;
|
|
830
|
-
if (parseMode ===
|
|
873
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
831
874
|
return [];
|
|
832
875
|
}
|
|
833
876
|
let results = new Map();
|
|
834
|
-
let completionName = (_a = this.getPartialVariableName(currentToken, [
|
|
877
|
+
let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
835
878
|
if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
|
|
836
879
|
return [];
|
|
837
880
|
}
|
|
838
881
|
let scopes = this.program.getScopesForFile(this);
|
|
839
882
|
for (let scope of scopes) {
|
|
840
883
|
let classMap = scope.getClassMap();
|
|
841
|
-
// let viableKeys = [...classMap.keys()].filter((k) => k.startsWith(completionName));
|
|
842
884
|
for (const key of [...classMap.keys()]) {
|
|
843
885
|
let cs = classMap.get(key).item;
|
|
844
886
|
if (!results.has(cs.name.text)) {
|
|
@@ -851,32 +893,80 @@ class BrsFile {
|
|
|
851
893
|
}
|
|
852
894
|
return [...results.values()];
|
|
853
895
|
}
|
|
896
|
+
getNonNamespacedEnumStatementCompletions(currentToken, parseMode, scope) {
|
|
897
|
+
var _a, _b;
|
|
898
|
+
if (parseMode !== Parser_1.ParseMode.BrighterScript) {
|
|
899
|
+
return [];
|
|
900
|
+
}
|
|
901
|
+
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) + '.';
|
|
902
|
+
const results = new Map();
|
|
903
|
+
const enumMap = scope.getEnumMap();
|
|
904
|
+
for (const key of [...enumMap.keys()]) {
|
|
905
|
+
const enumStatement = enumMap.get(key).item;
|
|
906
|
+
const fullName = enumStatement.fullName;
|
|
907
|
+
//if the enum is contained within our own namespace, or if it's a non-namespaced enum
|
|
908
|
+
if (fullName.startsWith(containingNamespaceName) || !fullName.includes('.')) {
|
|
909
|
+
results.set(fullName, {
|
|
910
|
+
label: enumStatement.name,
|
|
911
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
return [...results.values()];
|
|
916
|
+
}
|
|
917
|
+
getEnumMemberStatementCompletions(currentToken, parseMode, scope) {
|
|
918
|
+
var _a, _b, _c, _d, _e;
|
|
919
|
+
if (parseMode === Parser_1.ParseMode.BrightScript || !currentToken) {
|
|
920
|
+
return [];
|
|
921
|
+
}
|
|
922
|
+
const results = new Map();
|
|
923
|
+
const completionName = (_a = this.getPartialVariableName(currentToken)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
924
|
+
//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
|
|
925
|
+
if (!completionName || !completionName.includes('.')) {
|
|
926
|
+
return [];
|
|
927
|
+
}
|
|
928
|
+
const enumNameLower = (_b = completionName === null || completionName === void 0 ? void 0 : completionName.split(/\.(\w+)?$/)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
929
|
+
const namespaceNameLower = (_c = this.getNamespaceStatementForPosition(currentToken.range.end)) === null || _c === void 0 ? void 0 : _c.name.toLowerCase();
|
|
930
|
+
const enumMap = scope.getEnumMap();
|
|
931
|
+
//get the enum statement with this name (check without namespace prefix first, then with inferred namespace prefix next)
|
|
932
|
+
const enumStatement = (_e = ((_d = enumMap.get(enumNameLower)) !== null && _d !== void 0 ? _d : enumMap.get(namespaceNameLower + '.' + enumNameLower))) === null || _e === void 0 ? void 0 : _e.item;
|
|
933
|
+
//if we found an enum with this name
|
|
934
|
+
if (enumStatement) {
|
|
935
|
+
for (const member of enumStatement.getMembers()) {
|
|
936
|
+
const name = enumStatement.fullName + '.' + member.name;
|
|
937
|
+
const nameLower = name.toLowerCase();
|
|
938
|
+
results.set(nameLower, {
|
|
939
|
+
label: member.name,
|
|
940
|
+
kind: vscode_languageserver_1.CompletionItemKind.EnumMember
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return [...results.values()];
|
|
945
|
+
}
|
|
854
946
|
getNamespaceCompletions(currentToken, parseMode, scope) {
|
|
855
947
|
//BrightScript does not support namespaces, so return an empty list in that case
|
|
856
|
-
if (parseMode ===
|
|
948
|
+
if (parseMode === Parser_1.ParseMode.BrightScript) {
|
|
857
949
|
return [];
|
|
858
950
|
}
|
|
859
|
-
|
|
860
|
-
if
|
|
951
|
+
const completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
|
|
952
|
+
//if we don't have a completion name, or if there's no period in the name, then this is not a namespaced variable
|
|
953
|
+
if (!completionName || !completionName.includes('.')) {
|
|
861
954
|
return [];
|
|
862
955
|
}
|
|
863
956
|
//remove any trailing identifer and then any trailing dot, to give us the
|
|
864
957
|
//name of its immediate parent namespace
|
|
865
|
-
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
|
|
866
|
-
let newToken = this.parser.getTokenBefore(currentToken,
|
|
867
|
-
let namespaceLookup = scope.namespaceLookup;
|
|
958
|
+
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '').toLowerCase();
|
|
959
|
+
let newToken = this.parser.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
|
|
868
960
|
let result = new Map();
|
|
869
|
-
for (let
|
|
870
|
-
let namespace = namespaceLookup[key.toLowerCase()];
|
|
961
|
+
for (let [, namespace] of scope.namespaceLookup) {
|
|
871
962
|
//completionName = "NameA."
|
|
872
963
|
//completionName = "NameA.Na
|
|
873
964
|
//NameA
|
|
874
965
|
//NameA.NameB
|
|
875
966
|
//NameA.NameB.NameC
|
|
876
|
-
if (namespace.fullName.toLowerCase() === closestParentNamespaceName
|
|
967
|
+
if (namespace.fullName.toLowerCase() === closestParentNamespaceName) {
|
|
877
968
|
//add all of this namespace's immediate child namespaces, bearing in mind if we are after a new keyword
|
|
878
|
-
for (let
|
|
879
|
-
const ns = namespace.namespaces[childKey];
|
|
969
|
+
for (let [, ns] of namespace.namespaces) {
|
|
880
970
|
if (!newToken || ns.statements.find((s) => (0, reflection_1.isClassStatement)(s))) {
|
|
881
971
|
if (!result.has(ns.lastPartName)) {
|
|
882
972
|
result.set(ns.lastPartName, {
|
|
@@ -889,20 +979,22 @@ class BrsFile {
|
|
|
889
979
|
//add function and class statement completions
|
|
890
980
|
for (let stmt of namespace.statements) {
|
|
891
981
|
if ((0, reflection_1.isClassStatement)(stmt)) {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
});
|
|
897
|
-
}
|
|
982
|
+
result.set(stmt.name.text, {
|
|
983
|
+
label: stmt.name.text,
|
|
984
|
+
kind: vscode_languageserver_1.CompletionItemKind.Class
|
|
985
|
+
});
|
|
898
986
|
}
|
|
899
987
|
else if ((0, reflection_1.isFunctionStatement)(stmt) && !newToken) {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
988
|
+
result.set(stmt.name.text, {
|
|
989
|
+
label: stmt.name.text,
|
|
990
|
+
kind: vscode_languageserver_1.CompletionItemKind.Function
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
else if ((0, reflection_1.isEnumStatement)(stmt) && !newToken) {
|
|
994
|
+
result.set(stmt.name, {
|
|
995
|
+
label: stmt.name,
|
|
996
|
+
kind: vscode_languageserver_1.CompletionItemKind.Enum
|
|
997
|
+
});
|
|
906
998
|
}
|
|
907
999
|
}
|
|
908
1000
|
}
|
|
@@ -915,11 +1007,11 @@ class BrsFile {
|
|
|
915
1007
|
return undefined;
|
|
916
1008
|
}
|
|
917
1009
|
let location;
|
|
918
|
-
const nameParts = this.getPartialVariableName(token, [
|
|
1010
|
+
const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
|
|
919
1011
|
const endName = nameParts[nameParts.length - 1].toLowerCase();
|
|
920
1012
|
const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
|
|
921
1013
|
const statementHandler = (statement) => {
|
|
922
|
-
if (!location && statement.getName(
|
|
1014
|
+
if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
|
|
923
1015
|
const namespaceItemStatementHandler = (statement) => {
|
|
924
1016
|
if (!location && statement.name.text.toLowerCase() === endName) {
|
|
925
1017
|
const uri = util_1.util.pathToUri(file.srcPath);
|
|
@@ -945,7 +1037,7 @@ class BrsFile {
|
|
|
945
1037
|
* Given a current token, walk
|
|
946
1038
|
*/
|
|
947
1039
|
getPartialVariableName(currentToken, excludeTokens = null) {
|
|
948
|
-
let identifierAndDotKinds = [
|
|
1040
|
+
let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
|
|
949
1041
|
//consume tokens backwards until we find something other than a dot or an identifier
|
|
950
1042
|
let tokens = [];
|
|
951
1043
|
const parser = this.parser;
|
|
@@ -980,7 +1072,7 @@ class BrsFile {
|
|
|
980
1072
|
//find the first scope that contains this namespace
|
|
981
1073
|
let scopes = this.program.getScopesForFile(this);
|
|
982
1074
|
for (let scope of scopes) {
|
|
983
|
-
if (scope.namespaceLookup
|
|
1075
|
+
if (scope.namespaceLookup.has(lowerName)) {
|
|
984
1076
|
return true;
|
|
985
1077
|
}
|
|
986
1078
|
}
|
|
@@ -998,7 +1090,7 @@ class BrsFile {
|
|
|
998
1090
|
if (lowerCalleeName) {
|
|
999
1091
|
let scopes = this.program.getScopesForFile(this);
|
|
1000
1092
|
for (let scope of scopes) {
|
|
1001
|
-
let namespace = scope.namespaceLookup
|
|
1093
|
+
let namespace = scope.namespaceLookup.get(namespaceName.toLowerCase());
|
|
1002
1094
|
if (namespace.functionStatements[lowerCalleeName]) {
|
|
1003
1095
|
return true;
|
|
1004
1096
|
}
|
|
@@ -1076,7 +1168,7 @@ class BrsFile {
|
|
|
1076
1168
|
else {
|
|
1077
1169
|
return;
|
|
1078
1170
|
}
|
|
1079
|
-
const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(
|
|
1171
|
+
const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1080
1172
|
return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
|
|
1081
1173
|
}
|
|
1082
1174
|
/**
|
|
@@ -1110,9 +1202,9 @@ class BrsFile {
|
|
|
1110
1202
|
else {
|
|
1111
1203
|
return symbols;
|
|
1112
1204
|
}
|
|
1113
|
-
const name = statement.getName(
|
|
1205
|
+
const name = statement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1114
1206
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1115
|
-
const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(
|
|
1207
|
+
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));
|
|
1116
1208
|
symbols.push(symbol);
|
|
1117
1209
|
return symbols;
|
|
1118
1210
|
}
|
|
@@ -1126,8 +1218,8 @@ class BrsFile {
|
|
|
1126
1218
|
const token = this.parser.getTokenAt(position);
|
|
1127
1219
|
// 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
|
|
1128
1220
|
let definitionTokenTypes = [
|
|
1129
|
-
|
|
1130
|
-
|
|
1221
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1222
|
+
TokenKind_1.TokenKind.StringLiteral
|
|
1131
1223
|
];
|
|
1132
1224
|
//throw out invalid tokens and the wrong kind of tokens
|
|
1133
1225
|
if (!token || !definitionTokenTypes.includes(token.kind)) {
|
|
@@ -1135,7 +1227,7 @@ class BrsFile {
|
|
|
1135
1227
|
}
|
|
1136
1228
|
let textToSearchFor = token.text.toLowerCase();
|
|
1137
1229
|
const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
1138
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1230
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
|
|
1139
1231
|
for (const scope of this.program.getScopes()) {
|
|
1140
1232
|
//to only get functions defined in interface methods
|
|
1141
1233
|
const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
|
|
@@ -1145,7 +1237,7 @@ class BrsFile {
|
|
|
1145
1237
|
}
|
|
1146
1238
|
return results;
|
|
1147
1239
|
}
|
|
1148
|
-
let classToken = this.parser.getTokenBefore(token,
|
|
1240
|
+
let classToken = this.parser.getTokenBefore(token, TokenKind_1.TokenKind.Class);
|
|
1149
1241
|
if (classToken) {
|
|
1150
1242
|
let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
|
|
1151
1243
|
if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
|
|
@@ -1157,7 +1249,7 @@ class BrsFile {
|
|
|
1157
1249
|
}
|
|
1158
1250
|
return results;
|
|
1159
1251
|
}
|
|
1160
|
-
if (token.kind ===
|
|
1252
|
+
if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
|
|
1161
1253
|
// We need to strip off the quotes but only if present
|
|
1162
1254
|
const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
|
|
1163
1255
|
let endIndex = textToSearchFor.length;
|
|
@@ -1176,7 +1268,7 @@ class BrsFile {
|
|
|
1176
1268
|
results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
|
|
1177
1269
|
}
|
|
1178
1270
|
}
|
|
1179
|
-
if (this.parser.tokenFollows(token,
|
|
1271
|
+
if (this.parser.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
|
|
1180
1272
|
for (const label of func.labelStatements) {
|
|
1181
1273
|
if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
|
|
1182
1274
|
const uri = util_1.util.pathToUri(this.srcPath);
|
|
@@ -1192,7 +1284,7 @@ class BrsFile {
|
|
|
1192
1284
|
continue;
|
|
1193
1285
|
}
|
|
1194
1286
|
filesSearched.add(file);
|
|
1195
|
-
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) ===
|
|
1287
|
+
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
|
|
1196
1288
|
results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
|
|
1197
1289
|
const namespaceDefinition = this.getNamespaceDefinitions(token, file);
|
|
1198
1290
|
if (namespaceDefinition) {
|
|
@@ -1237,14 +1329,15 @@ class BrsFile {
|
|
|
1237
1329
|
}
|
|
1238
1330
|
getHover(position) {
|
|
1239
1331
|
var _a, _b, _c;
|
|
1332
|
+
const fence = (code) => util_1.util.mdFence(code, 'brightscript');
|
|
1240
1333
|
//get the token at the position
|
|
1241
1334
|
let token = this.parser.getTokenAt(position);
|
|
1242
1335
|
let hoverTokenTypes = [
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1336
|
+
TokenKind_1.TokenKind.Identifier,
|
|
1337
|
+
TokenKind_1.TokenKind.Function,
|
|
1338
|
+
TokenKind_1.TokenKind.EndFunction,
|
|
1339
|
+
TokenKind_1.TokenKind.Sub,
|
|
1340
|
+
TokenKind_1.TokenKind.EndSub
|
|
1248
1341
|
];
|
|
1249
1342
|
//throw out invalid tokens and the wrong kind of tokens
|
|
1250
1343
|
if (!token || !hoverTokenTypes.includes(token.kind)) {
|
|
@@ -1265,58 +1358,103 @@ class BrsFile {
|
|
|
1265
1358
|
}
|
|
1266
1359
|
}
|
|
1267
1360
|
}
|
|
1268
|
-
const typeTexts =
|
|
1269
|
-
|
|
1361
|
+
const typeTexts = new Set();
|
|
1362
|
+
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); });
|
|
1363
|
+
const callables = [];
|
|
1364
|
+
for (const scope of fileScopes) {
|
|
1270
1365
|
scope.linkSymbolTable();
|
|
1366
|
+
const typeContext = { file: this, scope: scope, position: position };
|
|
1271
1367
|
const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
|
|
1272
1368
|
if (typeTextPair) {
|
|
1273
1369
|
let scopeTypeText = '';
|
|
1274
1370
|
if ((0, reflection_1.isFunctionType)(typeTextPair.type)) {
|
|
1275
|
-
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString();
|
|
1371
|
+
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString(typeContext);
|
|
1372
|
+
//keep unique references to the callables for this function
|
|
1373
|
+
if (!typeTexts.has(scopeTypeText)) {
|
|
1374
|
+
callables.push(scope.getCallableByName(lowerTokenText));
|
|
1375
|
+
}
|
|
1276
1376
|
}
|
|
1277
1377
|
else if (typeTextPair.useExpandedTextOnly) {
|
|
1278
1378
|
scopeTypeText = typeTextPair.expandedTokenText;
|
|
1279
1379
|
}
|
|
1280
1380
|
else {
|
|
1281
|
-
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString()}`;
|
|
1381
|
+
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString(typeContext)}`;
|
|
1282
1382
|
}
|
|
1283
|
-
if (scopeTypeText
|
|
1284
|
-
typeTexts.
|
|
1383
|
+
if (scopeTypeText) {
|
|
1384
|
+
typeTexts.add(scopeTypeText);
|
|
1285
1385
|
}
|
|
1286
1386
|
}
|
|
1287
1387
|
scope.unlinkSymbolTable();
|
|
1288
1388
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1389
|
+
if (callables.length === typeTexts.size) {
|
|
1390
|
+
//this is a function in all scopes, so build the function hover
|
|
1291
1391
|
return {
|
|
1292
1392
|
range: token.range,
|
|
1293
|
-
contents:
|
|
1393
|
+
contents: this.getCallableDocumentation([...typeTexts], callables)
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
else if ((typeTexts === null || typeTexts === void 0 ? void 0 : typeTexts.size) > 0) {
|
|
1397
|
+
const typeText = [...typeTexts].join(' | ');
|
|
1398
|
+
return {
|
|
1399
|
+
range: token.range,
|
|
1400
|
+
contents: fence(typeText)
|
|
1294
1401
|
};
|
|
1295
1402
|
}
|
|
1296
1403
|
}
|
|
1297
|
-
//look through all callables in relevant scopes
|
|
1298
|
-
{
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1404
|
+
// //look through all callables in relevant scopes
|
|
1405
|
+
// {
|
|
1406
|
+
// let scopes = this.program.getScopesForFile(this);
|
|
1407
|
+
// for (let scope of scopes) {
|
|
1408
|
+
// let callable = scope.getCallableByName(lowerTokenText);
|
|
1409
|
+
// if (callable) {
|
|
1410
|
+
// return {
|
|
1411
|
+
// range: token.range,
|
|
1412
|
+
// contents: this.getCallableDocumentation(callables)
|
|
1413
|
+
// };
|
|
1414
|
+
// }
|
|
1415
|
+
// }
|
|
1416
|
+
// }
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Build a hover documentation for a callable.
|
|
1420
|
+
*/
|
|
1421
|
+
getCallableDocumentation(typeTexts, callables) {
|
|
1422
|
+
var _a;
|
|
1423
|
+
const callable = callables[0];
|
|
1424
|
+
const typeText = typeTexts[0];
|
|
1425
|
+
const comments = [];
|
|
1426
|
+
const tokens = callable === null || callable === void 0 ? void 0 : callable.file.parser.tokens;
|
|
1427
|
+
const idx = tokens === null || tokens === void 0 ? void 0 : tokens.indexOf((_a = callable.functionStatement) === null || _a === void 0 ? void 0 : _a.func.functionType);
|
|
1428
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
1429
|
+
const token = tokens[i];
|
|
1430
|
+
//skip whitespace and newline chars
|
|
1431
|
+
if (token.kind === TokenKind_1.TokenKind.Comment) {
|
|
1432
|
+
comments.push(token);
|
|
1433
|
+
}
|
|
1434
|
+
else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
|
|
1435
|
+
//skip these tokens
|
|
1436
|
+
continue;
|
|
1437
|
+
//any other token means there are no more comments
|
|
1438
|
+
}
|
|
1439
|
+
else {
|
|
1440
|
+
break;
|
|
1308
1441
|
}
|
|
1309
1442
|
}
|
|
1443
|
+
//message indicating if there are variations. example: (+3 variations) if there are 4 unique function signatures
|
|
1444
|
+
const multiText = callables.length > 1 ? ` (+${callables.length - 1} variations)` : '';
|
|
1445
|
+
let result = util_1.util.mdFence(typeText + multiText, 'brightscript');
|
|
1446
|
+
if (comments.length > 0) {
|
|
1447
|
+
result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
|
|
1448
|
+
}
|
|
1449
|
+
return result;
|
|
1310
1450
|
}
|
|
1311
1451
|
getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
|
|
1312
1452
|
var _a;
|
|
1313
1453
|
if (!dottedGetText) {
|
|
1314
1454
|
return [];
|
|
1315
1455
|
}
|
|
1316
|
-
let namespaceLookup = scope.namespaceLookup;
|
|
1317
1456
|
let resultsMap = new Map();
|
|
1318
|
-
for (let
|
|
1319
|
-
let namespace = namespaceLookup[key.toLowerCase()];
|
|
1457
|
+
for (let [, namespace] of scope.namespaceLookup) {
|
|
1320
1458
|
//completionName = "NameA."
|
|
1321
1459
|
//completionName = "NameA.Na
|
|
1322
1460
|
//NameA
|
|
@@ -1356,12 +1494,12 @@ class BrsFile {
|
|
|
1356
1494
|
}
|
|
1357
1495
|
}
|
|
1358
1496
|
const kind = currentToken.kind;
|
|
1359
|
-
if (kind ===
|
|
1497
|
+
if (kind === TokenKind_1.TokenKind.Comment) {
|
|
1360
1498
|
// Strip off common leading characters to make it easier to read
|
|
1361
1499
|
const commentText = currentToken.text.replace(/^[' *\/]+/, '');
|
|
1362
1500
|
functionComments.unshift(commentText);
|
|
1363
1501
|
}
|
|
1364
|
-
else if (kind ===
|
|
1502
|
+
else if (kind === TokenKind_1.TokenKind.Newline) {
|
|
1365
1503
|
if (functionComments.length === 0) {
|
|
1366
1504
|
continue;
|
|
1367
1505
|
}
|
|
@@ -1421,7 +1559,7 @@ class BrsFile {
|
|
|
1421
1559
|
const classConstructor = this.getClassMethod(classStatement, 'new');
|
|
1422
1560
|
let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
|
|
1423
1561
|
if (sigHelp) {
|
|
1424
|
-
sigHelp.key = classStatement.getName(
|
|
1562
|
+
sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
|
|
1425
1563
|
sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
|
|
1426
1564
|
}
|
|
1427
1565
|
return sigHelp;
|
|
@@ -1498,7 +1636,7 @@ exports.BrsFile = BrsFile;
|
|
|
1498
1636
|
* List of completions for all valid keywords/reserved words.
|
|
1499
1637
|
* Build this list once because it won't change for the lifetime of this process
|
|
1500
1638
|
*/
|
|
1501
|
-
exports.KeywordCompletions = Object.keys(
|
|
1639
|
+
exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
|
|
1502
1640
|
//remove any keywords with whitespace
|
|
1503
1641
|
.filter(x => !x.includes(' '))
|
|
1504
1642
|
//create completions
|