brighterscript 0.41.2 → 1.0.0-alpha.12
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 +112 -0
- package/README.md +2 -2
- package/dist/DiagnosticCollection.js +2 -2
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.js +2 -2
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +6 -1
- package/dist/DiagnosticMessages.js +5 -0
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.d.ts +8 -2
- package/dist/LanguageServer.js +50 -44
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Program.d.ts +61 -45
- package/dist/Program.js +305 -188
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +7 -7
- package/dist/ProgramBuilder.js +60 -51
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +42 -19
- package/dist/Scope.js +261 -129
- package/dist/Scope.js.map +1 -1
- package/dist/SymbolTable.d.ts +73 -0
- package/dist/SymbolTable.js +157 -0
- package/dist/SymbolTable.js.map +1 -0
- package/dist/XmlScope.d.ts +5 -0
- package/dist/XmlScope.js +66 -28
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/creators.d.ts +15 -1
- package/dist/astUtils/creators.js +39 -9
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +28 -16
- package/dist/astUtils/reflection.js +52 -30
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +3 -3
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +12 -13
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +3 -3
- package/dist/astUtils/xml.js +2 -2
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +5 -6
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +24 -22
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +2 -2
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +1 -1
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/BrsFile.Class.spec.js +356 -41
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +55 -37
- package/dist/files/BrsFile.js +430 -399
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +199 -158
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +20 -9
- package/dist/files/XmlFile.js +36 -31
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +113 -113
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +32 -32
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/globalCallables.js +17 -6
- package/dist/globalCallables.js.map +1 -1
- package/dist/interfaces.d.ts +155 -39
- package/dist/parser/BrsTranspileState.d.ts +7 -0
- package/dist/parser/BrsTranspileState.js +10 -1
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +23 -12
- package/dist/parser/Expression.js +45 -30
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +100 -1
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +118 -5
- package/dist/parser/Parser.js +398 -37
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +404 -7
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +41 -4
- package/dist/parser/SGParser.js +185 -174
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +17 -4
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +203 -38
- package/dist/parser/SGTypes.js +464 -160
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/SGTypes.spec.d.ts +1 -0
- package/dist/parser/SGTypes.spec.js +351 -0
- package/dist/parser/SGTypes.spec.js.map +1 -0
- package/dist/parser/Statement.d.ts +37 -26
- package/dist/parser/Statement.js +81 -20
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +5 -5
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +1 -1
- package/dist/parser/TranspileState.js +15 -7
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +5 -4
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/types/ArrayType.d.ts +1 -0
- package/dist/types/ArrayType.js +23 -19
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/BooleanType.d.ts +3 -2
- package/dist/types/BooleanType.js +6 -3
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BscType.d.ts +19 -4
- package/dist/types/BscType.js +9 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/CustomType.d.ts +8 -5
- package/dist/types/CustomType.js +12 -12
- package/dist/types/CustomType.js.map +1 -1
- package/dist/types/DoubleType.d.ts +1 -0
- package/dist/types/DoubleType.js +11 -11
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DynamicType.d.ts +1 -0
- package/dist/types/DynamicType.js +4 -0
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/FloatType.d.ts +2 -1
- package/dist/types/FloatType.js +11 -11
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FunctionType.d.ts +13 -10
- package/dist/types/FunctionType.js +34 -18
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/FunctionType.spec.js +8 -2
- package/dist/types/FunctionType.spec.js.map +1 -1
- package/dist/types/IntegerType.d.ts +2 -1
- package/dist/types/IntegerType.js +11 -11
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/InvalidType.d.ts +3 -2
- package/dist/types/InvalidType.js +7 -4
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/LazyType.d.ts +17 -0
- package/dist/types/LazyType.js +44 -0
- package/dist/types/LazyType.js.map +1 -0
- package/dist/types/LongIntegerType.d.ts +2 -1
- package/dist/types/LongIntegerType.js +11 -11
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/ObjectType.d.ts +6 -2
- package/dist/types/ObjectType.js +9 -3
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/StringType.d.ts +3 -2
- package/dist/types/StringType.js +6 -3
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/UninitializedType.d.ts +4 -2
- package/dist/types/UninitializedType.js +8 -3
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/VoidType.d.ts +3 -2
- package/dist/types/VoidType.js +6 -3
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/helpers.d.ts +42 -0
- package/dist/types/helpers.js +113 -0
- package/dist/types/helpers.js.map +1 -0
- package/dist/util.d.ts +68 -15
- package/dist/util.js +193 -45
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +5 -1
- package/dist/validators/ClassValidator.js +31 -17
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +1 -1
- package/dist/FunctionScope.d.ts +0 -27
- package/dist/FunctionScope.js +0 -49
- package/dist/FunctionScope.js.map +0 -1
package/dist/files/BrsFile.js
CHANGED
|
@@ -6,12 +6,8 @@ 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 FunctionScope_1 = require("../FunctionScope");
|
|
10
9
|
const lexer_1 = require("../lexer");
|
|
11
10
|
const parser_1 = require("../parser");
|
|
12
|
-
const DynamicType_1 = require("../types/DynamicType");
|
|
13
|
-
const FunctionType_1 = require("../types/FunctionType");
|
|
14
|
-
const VoidType_1 = require("../types/VoidType");
|
|
15
11
|
const util_1 = require("../util");
|
|
16
12
|
const BrsTranspileState_1 = require("../parser/BrsTranspileState");
|
|
17
13
|
const Preprocessor_1 = require("../preprocessor/Preprocessor");
|
|
@@ -20,23 +16,36 @@ const serialize_error_1 = require("serialize-error");
|
|
|
20
16
|
const reflection_1 = require("../astUtils/reflection");
|
|
21
17
|
const visitors_1 = require("../astUtils/visitors");
|
|
22
18
|
const CommentFlagProcessor_1 = require("../CommentFlagProcessor");
|
|
19
|
+
const BscType_1 = require("../types/BscType");
|
|
20
|
+
const UninitializedType_1 = require("../types/UninitializedType");
|
|
21
|
+
const InvalidType_1 = require("../types/InvalidType");
|
|
22
|
+
const globalCallables_1 = require("../globalCallables");
|
|
23
|
+
const DynamicType_1 = require("../types/DynamicType");
|
|
23
24
|
/**
|
|
24
25
|
* Holds all details about this file within the scope of the whole program
|
|
25
26
|
*/
|
|
26
27
|
class BrsFile {
|
|
27
|
-
constructor(
|
|
28
|
+
constructor(
|
|
29
|
+
/**
|
|
30
|
+
* The absolute path to the source file on disk (e.g. '/usr/you/projects/RokuApp/source/main.brs' or 'c:/projects/RokuApp/source/main.brs').
|
|
31
|
+
*/
|
|
32
|
+
srcPath,
|
|
28
33
|
/**
|
|
29
|
-
* The full pkg path to
|
|
34
|
+
* The full pkg path (i.e. `pkg:/path/to/file.brs`)
|
|
30
35
|
*/
|
|
31
36
|
pkgPath, program) {
|
|
32
37
|
var _a;
|
|
33
|
-
this.
|
|
38
|
+
this.srcPath = srcPath;
|
|
34
39
|
this.pkgPath = pkgPath;
|
|
35
40
|
this.program = program;
|
|
36
41
|
/**
|
|
37
42
|
* The parseMode used for the parser for this file
|
|
38
43
|
*/
|
|
39
44
|
this.parseMode = parser_1.ParseMode.BrightScript;
|
|
45
|
+
/**
|
|
46
|
+
* Indicates whether this file needs to be validated.
|
|
47
|
+
*/
|
|
48
|
+
this.isValidated = false;
|
|
40
49
|
this.diagnostics = [];
|
|
41
50
|
this.commentFlags = [];
|
|
42
51
|
this.callables = [];
|
|
@@ -49,11 +58,9 @@ class BrsFile {
|
|
|
49
58
|
* Does this file need to be transpiled?
|
|
50
59
|
*/
|
|
51
60
|
this.needsTranspiled = false;
|
|
52
|
-
this.
|
|
53
|
-
this.pathAbsolute = (0, util_1.standardizePath) `${this.pathAbsolute}`;
|
|
54
|
-
this.pkgPath = (0, util_1.standardizePath) `${this.pkgPath}`;
|
|
61
|
+
this.srcPath = (0, util_1.standardizePath) `${this.srcPath}`;
|
|
55
62
|
this.dependencyGraphKey = this.pkgPath.toLowerCase();
|
|
56
|
-
this.extension = util_1.util.getExtension(this.
|
|
63
|
+
this.extension = util_1.util.getExtension(this.srcPath);
|
|
57
64
|
//all BrighterScript files need to be transpiled
|
|
58
65
|
if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
|
|
59
66
|
this.needsTranspiled = true;
|
|
@@ -61,7 +68,7 @@ class BrsFile {
|
|
|
61
68
|
}
|
|
62
69
|
this.isTypedef = this.extension === '.d.bs';
|
|
63
70
|
if (!this.isTypedef) {
|
|
64
|
-
this.
|
|
71
|
+
this.typedefSrcPath = util_1.util.getTypedefPath(this.srcPath);
|
|
65
72
|
}
|
|
66
73
|
//global file doesn't have a program, so only resolve typedef info if we have a program
|
|
67
74
|
if (this.program) {
|
|
@@ -74,29 +81,12 @@ class BrsFile {
|
|
|
74
81
|
addDiagnostics(diagnostics) {
|
|
75
82
|
this.diagnostics.push(...diagnostics);
|
|
76
83
|
}
|
|
77
|
-
get functionScopes() {
|
|
78
|
-
if (!this._functionScopes) {
|
|
79
|
-
this.createFunctionScopes();
|
|
80
|
-
}
|
|
81
|
-
return this._functionScopes;
|
|
82
|
-
}
|
|
83
84
|
/**
|
|
84
85
|
* The AST for this file
|
|
85
86
|
*/
|
|
86
87
|
get ast() {
|
|
87
88
|
return this.parser.ast;
|
|
88
89
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Get the token at the specified position
|
|
91
|
-
* @param position
|
|
92
|
-
*/
|
|
93
|
-
getTokenAt(position) {
|
|
94
|
-
for (let token of this.parser.tokens) {
|
|
95
|
-
if (util_1.util.rangeContains(token.range, position)) {
|
|
96
|
-
return token;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
90
|
get parser() {
|
|
101
91
|
if (!this._parser) {
|
|
102
92
|
//remove the typedef file (if it exists)
|
|
@@ -113,7 +103,7 @@ class BrsFile {
|
|
|
113
103
|
* Find and set the typedef variables (if a matching typedef file exists)
|
|
114
104
|
*/
|
|
115
105
|
resolveTypedef() {
|
|
116
|
-
this.typedefFile = this.program.
|
|
106
|
+
this.typedefFile = this.program.getFile(this.typedefSrcPath);
|
|
117
107
|
this.hasTypedef = !!this.typedefFile;
|
|
118
108
|
}
|
|
119
109
|
/**
|
|
@@ -148,7 +138,7 @@ class BrsFile {
|
|
|
148
138
|
return;
|
|
149
139
|
}
|
|
150
140
|
//tokenize the input file
|
|
151
|
-
let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.
|
|
141
|
+
let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.srcPath)], () => {
|
|
152
142
|
return lexer_1.Lexer.scan(fileContents, {
|
|
153
143
|
includeWhitespace: false
|
|
154
144
|
});
|
|
@@ -159,7 +149,7 @@ class BrsFile {
|
|
|
159
149
|
//TODO preprocessor should go away in favor of the AST handling this internally (because it affects transpile)
|
|
160
150
|
//currently the preprocessor throws exceptions on syntax errors...so we need to catch it
|
|
161
151
|
try {
|
|
162
|
-
this.program.logger.time(Logger_1.LogLevel.debug, ['preprocessor.process', chalk_1.default.green(this.
|
|
152
|
+
this.program.logger.time(Logger_1.LogLevel.debug, ['preprocessor.process', chalk_1.default.green(this.srcPath)], () => {
|
|
163
153
|
preprocessor.process(lexer.tokens, this.program.getManifest());
|
|
164
154
|
});
|
|
165
155
|
}
|
|
@@ -171,7 +161,7 @@ class BrsFile {
|
|
|
171
161
|
}
|
|
172
162
|
//if the preprocessor generated tokens, use them.
|
|
173
163
|
let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
|
|
174
|
-
this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.
|
|
164
|
+
this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.srcPath)], () => {
|
|
175
165
|
this._parser = parser_1.Parser.parse(tokens, {
|
|
176
166
|
mode: this.parseMode,
|
|
177
167
|
logger: this.program.logger
|
|
@@ -179,8 +169,6 @@ class BrsFile {
|
|
|
179
169
|
});
|
|
180
170
|
//absorb all lexing/preprocessing/parsing diagnostics
|
|
181
171
|
this.diagnostics.push(...lexer.diagnostics, ...preprocessor.diagnostics, ...this._parser.diagnostics);
|
|
182
|
-
//notify AST ready
|
|
183
|
-
this.program.plugins.emit('afterFileParse', this);
|
|
184
172
|
//extract all callables from this file
|
|
185
173
|
this.findCallables();
|
|
186
174
|
//find all places where a sub/function is being called
|
|
@@ -196,6 +184,7 @@ class BrsFile {
|
|
|
196
184
|
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)))));
|
|
197
185
|
}
|
|
198
186
|
}
|
|
187
|
+
validate() { }
|
|
199
188
|
findAndValidateImportAndImportStatements() {
|
|
200
189
|
var _a;
|
|
201
190
|
let topOfFileIncludeStatements = [];
|
|
@@ -291,160 +280,17 @@ class BrsFile {
|
|
|
291
280
|
this.commentFlags.push(...processor.commentFlags);
|
|
292
281
|
this.diagnostics.push(...processor.diagnostics);
|
|
293
282
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Create a scope for every function in this file
|
|
296
|
-
*/
|
|
297
|
-
createFunctionScopes() {
|
|
298
|
-
var _a;
|
|
299
|
-
//find every function
|
|
300
|
-
let functions = this.parser.references.functionExpressions;
|
|
301
|
-
//create a functionScope for every function
|
|
302
|
-
this._functionScopes = [];
|
|
303
|
-
for (let func of functions) {
|
|
304
|
-
let scope = new FunctionScope_1.FunctionScope(func);
|
|
305
|
-
//find parent function, and add this scope to it if found
|
|
306
|
-
{
|
|
307
|
-
let parentScope = this.scopesByFunc.get(func.parentFunction);
|
|
308
|
-
//add this child scope to its parent
|
|
309
|
-
if (parentScope) {
|
|
310
|
-
parentScope.childrenScopes.push(scope);
|
|
311
|
-
}
|
|
312
|
-
//store the parent scope for this scope
|
|
313
|
-
scope.parentScope = parentScope;
|
|
314
|
-
}
|
|
315
|
-
//add every parameter
|
|
316
|
-
for (let param of func.parameters) {
|
|
317
|
-
scope.variableDeclarations.push({
|
|
318
|
-
nameRange: param.name.range,
|
|
319
|
-
lineIndex: param.name.range.start.line,
|
|
320
|
-
name: param.name.text,
|
|
321
|
-
type: param.type
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
//add all of ForEachStatement loop varibales
|
|
325
|
-
(_a = func.body) === null || _a === void 0 ? void 0 : _a.walk((0, visitors_1.createVisitor)({
|
|
326
|
-
ForEachStatement: (stmt) => {
|
|
327
|
-
scope.variableDeclarations.push({
|
|
328
|
-
nameRange: stmt.item.range,
|
|
329
|
-
lineIndex: stmt.item.range.start.line,
|
|
330
|
-
name: stmt.item.text,
|
|
331
|
-
type: new DynamicType_1.DynamicType()
|
|
332
|
-
});
|
|
333
|
-
},
|
|
334
|
-
LabelStatement: (stmt) => {
|
|
335
|
-
const { identifier } = stmt.tokens;
|
|
336
|
-
scope.labelStatements.push({
|
|
337
|
-
nameRange: identifier.range,
|
|
338
|
-
lineIndex: identifier.range.start.line,
|
|
339
|
-
name: identifier.text
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}), {
|
|
343
|
-
walkMode: visitors_1.WalkMode.visitStatements
|
|
344
|
-
});
|
|
345
|
-
this.scopesByFunc.set(func, scope);
|
|
346
|
-
//find every statement in the scope
|
|
347
|
-
this._functionScopes.push(scope);
|
|
348
|
-
}
|
|
349
|
-
//find every variable assignment in the whole file
|
|
350
|
-
let assignmentStatements = this.parser.references.assignmentStatements;
|
|
351
|
-
for (let statement of assignmentStatements) {
|
|
352
|
-
//find this statement's function scope
|
|
353
|
-
let scope = this.scopesByFunc.get(statement.containingFunction);
|
|
354
|
-
//skip variable declarations that are outside of any scope
|
|
355
|
-
if (scope) {
|
|
356
|
-
scope.variableDeclarations.push({
|
|
357
|
-
nameRange: statement.name.range,
|
|
358
|
-
lineIndex: statement.name.range.start.line,
|
|
359
|
-
name: statement.name.text,
|
|
360
|
-
type: this.getBscTypeFromAssignment(statement, scope)
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
getBscTypeFromAssignment(assignment, scope) {
|
|
366
|
-
var _a, _b, _c, _d;
|
|
367
|
-
try {
|
|
368
|
-
//function
|
|
369
|
-
if ((0, reflection_1.isFunctionExpression)(assignment.value)) {
|
|
370
|
-
let functionType = new FunctionType_1.FunctionType(assignment.value.returnType);
|
|
371
|
-
functionType.isSub = assignment.value.functionType.text === 'sub';
|
|
372
|
-
if (functionType.isSub) {
|
|
373
|
-
functionType.returnType = new VoidType_1.VoidType();
|
|
374
|
-
}
|
|
375
|
-
functionType.setName(assignment.name.text);
|
|
376
|
-
for (let param of assignment.value.parameters) {
|
|
377
|
-
let isRequired = !param.defaultValue;
|
|
378
|
-
//TODO compute optional parameters
|
|
379
|
-
functionType.addParameter(param.name.text, param.type, isRequired);
|
|
380
|
-
}
|
|
381
|
-
return functionType;
|
|
382
|
-
//literal
|
|
383
|
-
}
|
|
384
|
-
else if ((0, reflection_1.isLiteralExpression)(assignment.value)) {
|
|
385
|
-
return assignment.value.type;
|
|
386
|
-
//function call
|
|
387
|
-
}
|
|
388
|
-
else if ((0, reflection_1.isCallExpression)(assignment.value)) {
|
|
389
|
-
let calleeName = (_b = (_a = assignment.value.callee) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.text;
|
|
390
|
-
if (calleeName) {
|
|
391
|
-
let func = this.getCallableByName(calleeName);
|
|
392
|
-
if (func) {
|
|
393
|
-
return func.type.returnType;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
else if ((0, reflection_1.isVariableExpression)(assignment.value)) {
|
|
398
|
-
let variableName = (_d = (_c = assignment.value) === null || _c === void 0 ? void 0 : _c.name) === null || _d === void 0 ? void 0 : _d.text;
|
|
399
|
-
let variable = scope.getVariableByName(variableName);
|
|
400
|
-
return variable.type;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
catch (e) {
|
|
404
|
-
//do nothing. Just return dynamic
|
|
405
|
-
}
|
|
406
|
-
//fallback to dynamic
|
|
407
|
-
return new DynamicType_1.DynamicType();
|
|
408
|
-
}
|
|
409
|
-
getCallableByName(name) {
|
|
410
|
-
name = name ? name.toLowerCase() : undefined;
|
|
411
|
-
if (!name) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
for (let func of this.callables) {
|
|
415
|
-
if (func.name.toLowerCase() === name) {
|
|
416
|
-
return func;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
283
|
findCallables() {
|
|
421
284
|
var _a;
|
|
422
285
|
for (let statement of (_a = this.parser.references.functionStatements) !== null && _a !== void 0 ? _a : []) {
|
|
423
|
-
let functionType =
|
|
286
|
+
let functionType = statement.func.getFunctionType();
|
|
424
287
|
functionType.setName(statement.name.text);
|
|
425
|
-
functionType.isSub = statement.func.functionType.text.toLowerCase() === 'sub';
|
|
426
|
-
if (functionType.isSub) {
|
|
427
|
-
functionType.returnType = new VoidType_1.VoidType();
|
|
428
|
-
}
|
|
429
|
-
//extract the parameters
|
|
430
|
-
let params = [];
|
|
431
|
-
for (let param of statement.func.parameters) {
|
|
432
|
-
let callableParam = {
|
|
433
|
-
name: param.name.text,
|
|
434
|
-
type: param.type,
|
|
435
|
-
isOptional: !!param.defaultValue,
|
|
436
|
-
isRestArgument: false
|
|
437
|
-
};
|
|
438
|
-
params.push(callableParam);
|
|
439
|
-
let isRequired = !param.defaultValue;
|
|
440
|
-
functionType.addParameter(callableParam.name, callableParam.type, isRequired);
|
|
441
|
-
}
|
|
442
288
|
this.callables.push({
|
|
443
289
|
isSub: statement.func.functionType.text.toLowerCase() === 'sub',
|
|
444
290
|
name: statement.name.text,
|
|
445
291
|
nameRange: statement.name.range,
|
|
446
292
|
file: this,
|
|
447
|
-
params: params,
|
|
293
|
+
params: functionType.params,
|
|
448
294
|
range: statement.func.range,
|
|
449
295
|
type: functionType,
|
|
450
296
|
getName: statement.getName.bind(statement),
|
|
@@ -454,21 +300,24 @@ class BrsFile {
|
|
|
454
300
|
}
|
|
455
301
|
}
|
|
456
302
|
findFunctionCalls() {
|
|
303
|
+
var _a;
|
|
457
304
|
this.functionCalls = [];
|
|
458
305
|
//for every function in the file
|
|
459
306
|
for (let func of this._parser.references.functionExpressions) {
|
|
460
307
|
//for all function calls in this function
|
|
461
308
|
for (let expression of func.callExpressions) {
|
|
462
309
|
if (
|
|
463
|
-
//filter out
|
|
464
|
-
expression.callee.
|
|
465
|
-
//filter out method calls on
|
|
466
|
-
expression.callee.
|
|
310
|
+
//filter out method calls on method calls for now (i.e. getSomething().getSomethingElse())
|
|
311
|
+
expression.callee.callee ||
|
|
312
|
+
//filter out method calls on regexp literals for now
|
|
313
|
+
(0, reflection_1.isRegexLiteralExpression)((_a = expression.callee) === null || _a === void 0 ? void 0 : _a.obj) ||
|
|
467
314
|
//filter out callees without a name (immediately-invoked function expressions)
|
|
468
315
|
!expression.callee.name) {
|
|
469
316
|
continue;
|
|
470
317
|
}
|
|
471
|
-
|
|
318
|
+
//Flag dotted function invocations (i.e. object.doSomething())
|
|
319
|
+
const dottedInvocation = expression.callee.obj;
|
|
320
|
+
let functionName = expression.callee.name;
|
|
472
321
|
//callee is the name of the function being called
|
|
473
322
|
let callee = expression.callee;
|
|
474
323
|
let columnIndexBegin = callee.range.start.character;
|
|
@@ -476,81 +325,65 @@ class BrsFile {
|
|
|
476
325
|
let args = [];
|
|
477
326
|
//TODO convert if stmts to use instanceof instead
|
|
478
327
|
for (let arg of expression.args) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
});
|
|
486
|
-
//is variable being passed into argument
|
|
328
|
+
let inferredType = (0, parser_1.getBscTypeFromExpression)(arg, func);
|
|
329
|
+
let argText = '';
|
|
330
|
+
// Get the text to display for the arg
|
|
331
|
+
if (arg.token) {
|
|
332
|
+
argText = arg.token.text;
|
|
333
|
+
//is a function call being passed into argument
|
|
487
334
|
}
|
|
488
335
|
else if (arg.name) {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
type: new DynamicType_1.DynamicType(),
|
|
493
|
-
text: arg.name.text
|
|
494
|
-
});
|
|
336
|
+
if ((0, lexer_1.isToken)(arg.name)) {
|
|
337
|
+
argText = arg.name.text;
|
|
338
|
+
}
|
|
495
339
|
}
|
|
496
340
|
else if (arg.value) {
|
|
497
|
-
let text = '';
|
|
498
341
|
/* istanbul ignore next: TODO figure out why value is undefined sometimes */
|
|
499
342
|
if (arg.value.value) {
|
|
500
|
-
|
|
343
|
+
if (arg.value.value.toString) {
|
|
344
|
+
argText = arg.value.value.toString();
|
|
345
|
+
}
|
|
501
346
|
}
|
|
502
|
-
let callableArg = {
|
|
503
|
-
range: arg.range,
|
|
504
|
-
//TODO not sure what to do here
|
|
505
|
-
type: new DynamicType_1.DynamicType(),
|
|
506
|
-
text: text
|
|
507
|
-
};
|
|
508
347
|
//wrap the value in quotes because that's how it appears in the code
|
|
509
|
-
if ((0, reflection_1.isStringType)(
|
|
510
|
-
|
|
348
|
+
if (argText && (0, reflection_1.isStringType)(inferredType)) {
|
|
349
|
+
argText = '"' + argText + '"';
|
|
511
350
|
}
|
|
512
|
-
args.push(callableArg);
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
args.push({
|
|
516
|
-
range: arg.range,
|
|
517
|
-
type: new DynamicType_1.DynamicType(),
|
|
518
|
-
//TODO get text from other types of args
|
|
519
|
-
text: ''
|
|
520
|
-
});
|
|
521
351
|
}
|
|
352
|
+
args.push({
|
|
353
|
+
range: arg.range,
|
|
354
|
+
type: inferredType,
|
|
355
|
+
text: argText
|
|
356
|
+
});
|
|
522
357
|
}
|
|
523
358
|
let functionCall = {
|
|
524
359
|
range: util_1.util.createRangeFromPositions(expression.range.start, expression.closingParen.range.end),
|
|
525
|
-
|
|
360
|
+
functionExpression: this.getFunctionExpressionAtPosition(callee.range.start),
|
|
526
361
|
file: this,
|
|
527
362
|
name: functionName,
|
|
528
363
|
nameRange: util_1.util.createRange(callee.range.start.line, columnIndexBegin, callee.range.start.line, columnIndexEnd),
|
|
529
|
-
|
|
530
|
-
|
|
364
|
+
args: args,
|
|
365
|
+
isDottedInvocation: dottedInvocation
|
|
531
366
|
};
|
|
532
367
|
this.functionCalls.push(functionCall);
|
|
533
368
|
}
|
|
534
369
|
}
|
|
535
370
|
}
|
|
536
371
|
/**
|
|
537
|
-
* Find the function
|
|
538
|
-
* @param position
|
|
539
|
-
* @param functionScopes
|
|
372
|
+
* Find the function expression at the given position.
|
|
540
373
|
*/
|
|
541
|
-
|
|
542
|
-
if (!
|
|
543
|
-
|
|
374
|
+
getFunctionExpressionAtPosition(position, functionExpressions) {
|
|
375
|
+
if (!functionExpressions) {
|
|
376
|
+
functionExpressions = this.parser.references.functionExpressions;
|
|
544
377
|
}
|
|
545
|
-
for (let
|
|
546
|
-
if (util_1.util.rangeContains(
|
|
378
|
+
for (let functionExpression of functionExpressions) {
|
|
379
|
+
if (util_1.util.rangeContains(functionExpression.range, position)) {
|
|
547
380
|
//see if any of that scope's children match the position also, and give them priority
|
|
548
|
-
let
|
|
549
|
-
if (
|
|
550
|
-
return
|
|
381
|
+
let childFunc = this.getFunctionExpressionAtPosition(position, functionExpression.childFunctionExpressions);
|
|
382
|
+
if (childFunc) {
|
|
383
|
+
return childFunc;
|
|
551
384
|
}
|
|
552
385
|
else {
|
|
553
|
-
return
|
|
386
|
+
return functionExpression;
|
|
554
387
|
}
|
|
555
388
|
}
|
|
556
389
|
}
|
|
@@ -559,6 +392,7 @@ class BrsFile {
|
|
|
559
392
|
* Get completions available at the given cursor. This aggregates all values from this file and the current scope.
|
|
560
393
|
*/
|
|
561
394
|
getCompletions(position, scope) {
|
|
395
|
+
var _a;
|
|
562
396
|
let result = [];
|
|
563
397
|
//a map of lower-case names of all added options
|
|
564
398
|
let names = {};
|
|
@@ -568,7 +402,7 @@ class BrsFile {
|
|
|
568
402
|
return this.program.getScriptImportCompletions(this.pkgPath, scriptImport);
|
|
569
403
|
}
|
|
570
404
|
//if cursor is within a comment, disable completions
|
|
571
|
-
let currentToken = this.getTokenAt(position);
|
|
405
|
+
let currentToken = this.parser.getTokenAt(position);
|
|
572
406
|
const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
|
|
573
407
|
if (tokenKind === lexer_1.TokenKind.Comment) {
|
|
574
408
|
return [];
|
|
@@ -577,9 +411,9 @@ class BrsFile {
|
|
|
577
411
|
const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
|
|
578
412
|
if (match) {
|
|
579
413
|
const [, openingQuote, fileProtocol] = match;
|
|
580
|
-
//include every
|
|
414
|
+
//include every pkgPath from this scope
|
|
581
415
|
for (const file of scope.getAllFiles()) {
|
|
582
|
-
const pkgPath = `${fileProtocol}:/${file.pkgPath.replace(
|
|
416
|
+
const pkgPath = `${fileProtocol}:/${file.pkgPath.replace('pkg:/', '')}`;
|
|
583
417
|
result.push({
|
|
584
418
|
label: pkgPath,
|
|
585
419
|
textEdit: vscode_languageserver_1.TextEdit.replace(util_1.util.createRange(currentToken.range.start.line,
|
|
@@ -602,10 +436,10 @@ class BrsFile {
|
|
|
602
436
|
return namespaceCompletions;
|
|
603
437
|
}
|
|
604
438
|
//determine if cursor is inside a function
|
|
605
|
-
let
|
|
606
|
-
if (!
|
|
439
|
+
let functionExpression = this.getFunctionExpressionAtPosition(position);
|
|
440
|
+
if (!functionExpression) {
|
|
607
441
|
//we aren't in any function scope, so return the keyword completions and namespaces
|
|
608
|
-
if (this.getTokenBefore(currentToken, lexer_1.TokenKind.New)) {
|
|
442
|
+
if (this.parser.getTokenBefore(currentToken, lexer_1.TokenKind.New)) {
|
|
609
443
|
// there's a new keyword, so only class types are viable here
|
|
610
444
|
return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
|
|
611
445
|
}
|
|
@@ -614,26 +448,31 @@ class BrsFile {
|
|
|
614
448
|
}
|
|
615
449
|
}
|
|
616
450
|
const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
|
|
617
|
-
const newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
|
|
451
|
+
const newToken = this.parser.getTokenBefore(currentToken, lexer_1.TokenKind.New);
|
|
618
452
|
if (newToken) {
|
|
619
453
|
//we are after a new keyword; so we can only be namespaces or classes at this point
|
|
620
454
|
result.push(...classNameCompletions);
|
|
621
455
|
result.push(...namespaceCompletions);
|
|
622
456
|
return result;
|
|
623
457
|
}
|
|
624
|
-
if (this.tokenFollows(currentToken, lexer_1.TokenKind.Goto)) {
|
|
625
|
-
return this.getLabelCompletion(
|
|
458
|
+
if (this.parser.tokenFollows(currentToken, lexer_1.TokenKind.Goto)) {
|
|
459
|
+
return this.getLabelCompletion(functionExpression);
|
|
626
460
|
}
|
|
627
|
-
if (this.isPositionNextToTokenKind(position, lexer_1.TokenKind.Dot)) {
|
|
461
|
+
if (this.parser.isPositionNextToTokenKind(position, lexer_1.TokenKind.Dot)) {
|
|
628
462
|
if (namespaceCompletions.length > 0) {
|
|
629
463
|
//if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
|
|
630
464
|
return namespaceCompletions;
|
|
631
465
|
}
|
|
632
|
-
const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken,
|
|
466
|
+
const selfClassMemberCompletions = this.getClassMemberCompletions(position, currentToken, functionExpression, scope);
|
|
633
467
|
if (selfClassMemberCompletions.size > 0) {
|
|
634
468
|
return [...selfClassMemberCompletions.values()].filter((i) => i.label !== 'new');
|
|
635
469
|
}
|
|
636
|
-
|
|
470
|
+
const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
|
|
471
|
+
if ((_a = tokenLookup.symbolContainer) === null || _a === void 0 ? void 0 : _a.memberTable) {
|
|
472
|
+
return this.getCompletionsFromSymbolTable(tokenLookup.symbolContainer.memberTable);
|
|
473
|
+
}
|
|
474
|
+
const foundClassLink = this.getClassFromTokenLookup(tokenLookup, scope);
|
|
475
|
+
if (!foundClassLink) {
|
|
637
476
|
//and anything from any class in scope to a non m class
|
|
638
477
|
let classMemberCompletions = scope.getAllClassMemberCompletions();
|
|
639
478
|
result.push(...classMemberCompletions.values());
|
|
@@ -658,16 +497,21 @@ class BrsFile {
|
|
|
658
497
|
names.m = true;
|
|
659
498
|
result.push(...exports.KeywordCompletions);
|
|
660
499
|
//include local variables
|
|
661
|
-
let
|
|
662
|
-
|
|
500
|
+
for (let symbol of functionExpression.symbolTable.getOwnSymbols()) {
|
|
501
|
+
const symbolNameLower = symbol.name.toLowerCase();
|
|
663
502
|
//skip duplicate variable names
|
|
664
|
-
if (names[
|
|
503
|
+
if (names[symbolNameLower]) {
|
|
665
504
|
continue;
|
|
666
505
|
}
|
|
667
|
-
names[
|
|
506
|
+
names[symbolNameLower] = true;
|
|
507
|
+
// TODO TYPES (This may be a performance hit?)
|
|
508
|
+
// const foundType = getTypeFromContext(symbol.type, { scope: scope, file: this });
|
|
668
509
|
result.push({
|
|
669
|
-
|
|
670
|
-
|
|
510
|
+
//TODO does this work?
|
|
511
|
+
label: symbol.name,
|
|
512
|
+
//TODO TYPES find type for local vars - SEE above
|
|
513
|
+
kind: vscode_languageserver_1.CompletionItemKind.Variable
|
|
514
|
+
// kind: isFunctionType(foundType) ? CompletionItemKind.Function : CompletionItemKind.Variable
|
|
671
515
|
});
|
|
672
516
|
}
|
|
673
517
|
if (this.parseMode === parser_1.ParseMode.BrighterScript) {
|
|
@@ -689,15 +533,23 @@ class BrsFile {
|
|
|
689
533
|
}
|
|
690
534
|
return result;
|
|
691
535
|
}
|
|
692
|
-
|
|
693
|
-
return
|
|
694
|
-
|
|
536
|
+
getCompletionsFromSymbolTable(symbolTable) {
|
|
537
|
+
return symbolTable.getAllSymbols().map(bscType => {
|
|
538
|
+
return {
|
|
539
|
+
label: bscType.name,
|
|
540
|
+
kind: (0, reflection_1.isFunctionType)(bscType.type) ? vscode_languageserver_1.CompletionItemKind.Method : vscode_languageserver_1.CompletionItemKind.Field
|
|
541
|
+
};
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
getLabelCompletion(func) {
|
|
545
|
+
return func.labelStatements.map(label => ({
|
|
546
|
+
label: label.tokens.identifier.text,
|
|
695
547
|
kind: vscode_languageserver_1.CompletionItemKind.Reference
|
|
696
548
|
}));
|
|
697
549
|
}
|
|
698
|
-
getClassMemberCompletions(position, currentToken,
|
|
550
|
+
getClassMemberCompletions(position, currentToken, functionExpression, scope) {
|
|
699
551
|
var _a, _b, _c, _d;
|
|
700
|
-
let classStatement = this.
|
|
552
|
+
let classStatement = this.getClassFromToken(currentToken, functionExpression, scope);
|
|
701
553
|
let results = new Map();
|
|
702
554
|
if (classStatement) {
|
|
703
555
|
let classes = scope.getClassHierarchy(classStatement.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
@@ -714,16 +566,265 @@ class BrsFile {
|
|
|
714
566
|
}
|
|
715
567
|
return results;
|
|
716
568
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
569
|
+
/**
|
|
570
|
+
* Gets the class (if any) of a given token based on the scope
|
|
571
|
+
* @param currentToken token in question
|
|
572
|
+
* @param functionExpression current functionExpression
|
|
573
|
+
* @param scope the current scope
|
|
574
|
+
* @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
|
|
575
|
+
*/
|
|
576
|
+
getClassFromToken(currentToken, functionExpression, scope) {
|
|
577
|
+
const tokenLookup = this.getSymbolTypeFromToken(currentToken, functionExpression, scope);
|
|
578
|
+
return this.getClassFromTokenLookup(tokenLookup, scope);
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Gets the class (if any) of a given token based on the scope
|
|
582
|
+
* @param currentToken token in question
|
|
583
|
+
* @param functionExpression current functionExpression
|
|
584
|
+
* @param scope the current scope
|
|
585
|
+
* @returns A fileLink of the ClassStatement, if it is a class, otherwise undefined
|
|
586
|
+
*/
|
|
587
|
+
getClassFromTokenLookup(tokenLookup, scope) {
|
|
588
|
+
const currentClass = tokenLookup === null || tokenLookup === void 0 ? void 0 : tokenLookup.symbolContainer;
|
|
589
|
+
if ((0, reflection_1.isClassStatement)(currentClass)) {
|
|
590
|
+
return { item: currentClass, file: this };
|
|
721
591
|
}
|
|
722
|
-
if ((
|
|
723
|
-
|
|
592
|
+
else if ((0, reflection_1.isCustomType)(currentClass)) {
|
|
593
|
+
const foundClass = scope.getClass(currentClass.name);
|
|
594
|
+
if (foundClass) {
|
|
595
|
+
return { item: foundClass, file: this };
|
|
596
|
+
}
|
|
724
597
|
}
|
|
725
598
|
return undefined;
|
|
726
599
|
}
|
|
600
|
+
findNamespaceFromTokenChain(originalTokenChain, scope) {
|
|
601
|
+
let namespaceTokens = [];
|
|
602
|
+
let startsWithNamespace = '';
|
|
603
|
+
let namespaceContainer;
|
|
604
|
+
let tokenChain = [...originalTokenChain];
|
|
605
|
+
while (tokenChain[0] && tokenChain[0].usage === parser_1.TokenUsage.Direct) {
|
|
606
|
+
const namespaceNameToCheck = `${startsWithNamespace}${startsWithNamespace.length > 0 ? '.' : ''}${tokenChain[0].token.text}`.toLowerCase();
|
|
607
|
+
const foundNamespace = scope.namespaceLookup[namespaceNameToCheck];
|
|
608
|
+
if (foundNamespace) {
|
|
609
|
+
namespaceContainer = foundNamespace;
|
|
610
|
+
namespaceTokens.push(tokenChain[0].token);
|
|
611
|
+
startsWithNamespace = namespaceTokens.map(token => token.text).join('.');
|
|
612
|
+
tokenChain.shift();
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (namespaceTokens.length > 0) {
|
|
619
|
+
namespaceContainer = scope.namespaceLookup[startsWithNamespace.toLowerCase()];
|
|
620
|
+
}
|
|
621
|
+
return { namespaceContainer: namespaceContainer, tokenChain: tokenChain };
|
|
622
|
+
}
|
|
623
|
+
checkForSpecialClassSymbol(currentToken, scope, func) {
|
|
624
|
+
var _a;
|
|
625
|
+
const containingClass = this.parser.getContainingClass(currentToken);
|
|
626
|
+
let symbolType;
|
|
627
|
+
let currentClassRef;
|
|
628
|
+
const currentTokenLower = currentToken.text.toLowerCase();
|
|
629
|
+
const typeContext = { file: this, scope: scope, position: currentToken.range.start };
|
|
630
|
+
if (containingClass) {
|
|
631
|
+
// Special cases for a single token inside a class
|
|
632
|
+
let expandedText = '';
|
|
633
|
+
let useExpandedTextOnly = false;
|
|
634
|
+
if (containingClass.name === currentToken) {
|
|
635
|
+
symbolType = containingClass.getCustomType();
|
|
636
|
+
expandedText = `class ${containingClass.getName(parser_1.ParseMode.BrighterScript)}`;
|
|
637
|
+
useExpandedTextOnly = true;
|
|
638
|
+
currentClassRef = containingClass;
|
|
639
|
+
}
|
|
640
|
+
else if (currentTokenLower === 'm') {
|
|
641
|
+
symbolType = containingClass.getCustomType();
|
|
642
|
+
expandedText = currentToken.text;
|
|
643
|
+
currentClassRef = containingClass;
|
|
644
|
+
}
|
|
645
|
+
else if (currentTokenLower === 'super') {
|
|
646
|
+
symbolType = (0, BscType_1.getTypeFromContext)(containingClass.symbolTable.getSymbolType(currentTokenLower, true, typeContext), typeContext);
|
|
647
|
+
if ((0, reflection_1.isFunctionType)(symbolType)) {
|
|
648
|
+
currentClassRef = scope.getParentClass(containingClass);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
else if (((_a = func === null || func === void 0 ? void 0 : func.functionStatement) === null || _a === void 0 ? void 0 : _a.name) === currentToken) {
|
|
652
|
+
// check if this is a method declaration
|
|
653
|
+
currentClassRef = containingClass;
|
|
654
|
+
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
655
|
+
expandedText = [containingClass.getName(parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
656
|
+
}
|
|
657
|
+
else if (!func) {
|
|
658
|
+
// check if this is a field declaration
|
|
659
|
+
currentClassRef = containingClass;
|
|
660
|
+
symbolType = containingClass === null || containingClass === void 0 ? void 0 : containingClass.memberTable.getSymbolType(currentTokenLower, true, { file: this, scope: scope });
|
|
661
|
+
expandedText = [containingClass.getName(parser_1.ParseMode.BrighterScript), currentToken.text].join('.');
|
|
662
|
+
}
|
|
663
|
+
if (symbolType) {
|
|
664
|
+
return { type: symbolType, expandedTokenText: expandedText, symbolContainer: currentClassRef, useExpandedTextOnly: useExpandedTextOnly };
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope) {
|
|
669
|
+
var _a;
|
|
670
|
+
const tokenChain = (_a = nameSpacedTokenChain.tokenChain) !== null && _a !== void 0 ? _a : [];
|
|
671
|
+
if (nameSpacedTokenChain.namespaceContainer && tokenChain.length === 0) {
|
|
672
|
+
//currentToken was part of a namespace
|
|
673
|
+
return {
|
|
674
|
+
type: null,
|
|
675
|
+
expandedTokenText: `namespace ${nameSpacedTokenChain.namespaceContainer.fullName}`,
|
|
676
|
+
useExpandedTextOnly: true
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
const specialCase = tokenChain.length === 1 ? this.checkForSpecialClassSymbol(tokenChain[0].token, scope, functionExpression) : null;
|
|
680
|
+
if (specialCase) {
|
|
681
|
+
return specialCase;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Checks previous tokens for the start of a symbol chain (eg. m.property.subProperty.method())
|
|
686
|
+
* @param currentToken The token to check
|
|
687
|
+
* @param functionExpression The current function context
|
|
688
|
+
* @param scope use this scope for finding class maps
|
|
689
|
+
* @returns the BscType, expanded text (e.g <Class.field>) and classStatement (if available) for the token
|
|
690
|
+
*/
|
|
691
|
+
getSymbolTypeFromToken(currentToken, functionExpression, scope) {
|
|
692
|
+
var _a, _b, _c, _d, _e;
|
|
693
|
+
if (!scope) {
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
const cachedSymbolData = scope.symbolCache.get(currentToken);
|
|
697
|
+
if (cachedSymbolData) {
|
|
698
|
+
return cachedSymbolData;
|
|
699
|
+
}
|
|
700
|
+
const tokenChainResponse = this.parser.getTokenChain(currentToken);
|
|
701
|
+
if (tokenChainResponse.includesUnknowableTokenType) {
|
|
702
|
+
const symbolData = { type: new DynamicType_1.DynamicType(), expandedTokenText: currentToken.text };
|
|
703
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
704
|
+
return symbolData;
|
|
705
|
+
}
|
|
706
|
+
const nameSpacedTokenChain = this.findNamespaceFromTokenChain(tokenChainResponse.chain, scope);
|
|
707
|
+
const specialCase = this.checkForSpecialCaseToken(nameSpacedTokenChain, functionExpression, scope);
|
|
708
|
+
if (specialCase) {
|
|
709
|
+
scope.symbolCache.set(currentToken, specialCase);
|
|
710
|
+
return specialCase;
|
|
711
|
+
}
|
|
712
|
+
const tokenChain = nameSpacedTokenChain.tokenChain;
|
|
713
|
+
let symbolContainer = this.parser.getContainingAA(currentToken) || this.parser.getContainingClass(currentToken);
|
|
714
|
+
let currentSymbolTable = (_b = (_a = nameSpacedTokenChain.namespaceContainer) === null || _a === void 0 ? void 0 : _a.symbolTable) !== null && _b !== void 0 ? _b : functionExpression === null || functionExpression === void 0 ? void 0 : functionExpression.symbolTable;
|
|
715
|
+
let tokenFoundCount = 0;
|
|
716
|
+
let symbolTypeBeforeReference;
|
|
717
|
+
let symbolType;
|
|
718
|
+
let tokenText = [];
|
|
719
|
+
let justReturnDynamic = false;
|
|
720
|
+
const typeContext = { file: this, scope: scope, position: (_c = tokenChain[0]) === null || _c === void 0 ? void 0 : _c.token.range.start };
|
|
721
|
+
for (const tokenChainMember of tokenChain) {
|
|
722
|
+
const token = tokenChainMember === null || tokenChainMember === void 0 ? void 0 : tokenChainMember.token;
|
|
723
|
+
const tokenLowerText = token.text.toLowerCase();
|
|
724
|
+
if (tokenLowerText === 'super' && (0, reflection_1.isClassStatement)(symbolContainer) && tokenFoundCount === 0) {
|
|
725
|
+
/// Special cases for first item in chain inside a class
|
|
726
|
+
symbolContainer = scope === null || scope === void 0 ? void 0 : scope.getParentClass(symbolContainer);
|
|
727
|
+
currentSymbolTable = (_d = symbolContainer) === null || _d === void 0 ? void 0 : _d.memberTable;
|
|
728
|
+
if (symbolContainer && currentSymbolTable) {
|
|
729
|
+
tokenText.push(symbolContainer.getName(parser_1.ParseMode.BrighterScript));
|
|
730
|
+
tokenFoundCount++;
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (!currentSymbolTable) {
|
|
735
|
+
// uh oh... no symbol table to continue to check
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
symbolType = currentSymbolTable.getSymbolType(tokenLowerText, true, typeContext);
|
|
739
|
+
if (tokenFoundCount === 0 && !symbolType) {
|
|
740
|
+
//check for global callable
|
|
741
|
+
symbolType = (_e = globalCallables_1.globalCallableMap.get(tokenLowerText)) === null || _e === void 0 ? void 0 : _e.type;
|
|
742
|
+
}
|
|
743
|
+
if (symbolType) {
|
|
744
|
+
// found this symbol, and it's valid. increase found counter
|
|
745
|
+
tokenFoundCount++;
|
|
746
|
+
}
|
|
747
|
+
symbolTypeBeforeReference = symbolType;
|
|
748
|
+
if ((0, reflection_1.isFunctionType)(symbolType)) {
|
|
749
|
+
// this is a function, and it is in the start or middle of the chain
|
|
750
|
+
// the next symbol to check will be the return value of this function
|
|
751
|
+
symbolType = (0, BscType_1.getTypeFromContext)(symbolType.returnType, typeContext);
|
|
752
|
+
if (tokenFoundCount < tokenChain.length) {
|
|
753
|
+
// We're still
|
|
754
|
+
symbolTypeBeforeReference = symbolType;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (symbolType === null || symbolType === void 0 ? void 0 : symbolType.memberTable) {
|
|
758
|
+
if ((0, reflection_1.isCustomType)(symbolType)) {
|
|
759
|
+
// we're currently looking at a customType, that has it's own symbol table
|
|
760
|
+
// use the name of the custom type
|
|
761
|
+
// TODO TYPES: get proper parent name for methods/fields defined in super classes
|
|
762
|
+
tokenText.push(tokenChain.length === 1 ? token.text : symbolType.name);
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
justReturnDynamic = true;
|
|
766
|
+
tokenText.push(token.text);
|
|
767
|
+
}
|
|
768
|
+
symbolContainer = symbolType;
|
|
769
|
+
currentSymbolTable = symbolContainer === null || symbolContainer === void 0 ? void 0 : symbolContainer.memberTable;
|
|
770
|
+
}
|
|
771
|
+
else if ((0, reflection_1.isObjectType)(symbolType) || (0, reflection_1.isArrayType)(symbolType) || (0, reflection_1.isDynamicType)(symbolType)) {
|
|
772
|
+
// this is an object that has no member table
|
|
773
|
+
// this could happen if a parameter is marked as object
|
|
774
|
+
// assume all fields are dynamic
|
|
775
|
+
symbolContainer = undefined;
|
|
776
|
+
tokenText.push(token.text);
|
|
777
|
+
justReturnDynamic = true;
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
// No further symbol tables were found
|
|
782
|
+
symbolContainer = undefined;
|
|
783
|
+
tokenText.push(token.text);
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
if (tokenText.length > 2) {
|
|
787
|
+
tokenText.shift(); // only care about last two symbols
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
let expandedTokenText = tokenText.join('.');
|
|
791
|
+
let backUpReturnType;
|
|
792
|
+
if (tokenFoundCount === tokenChain.length) {
|
|
793
|
+
// did we complete the chain? if so, we have a valid token at the end
|
|
794
|
+
const symbolData = { type: symbolTypeBeforeReference, expandedTokenText: tokenText.join('.'), symbolContainer: symbolContainer };
|
|
795
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
796
|
+
return symbolData;
|
|
797
|
+
}
|
|
798
|
+
if ((0, reflection_1.isDynamicType)(symbolTypeBeforeReference) || (0, reflection_1.isArrayType)(symbolTypeBeforeReference) || justReturnDynamic) {
|
|
799
|
+
// last type in chain is dynamic... so currentToken could be anything.
|
|
800
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
801
|
+
expandedTokenText = currentToken.text;
|
|
802
|
+
}
|
|
803
|
+
else if ((0, reflection_1.isPrimitiveType)(symbolTypeBeforeReference)) {
|
|
804
|
+
// last type in chain is dynamic... so currentToken could be anything.
|
|
805
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
806
|
+
expandedTokenText = currentToken.text;
|
|
807
|
+
}
|
|
808
|
+
else if (tokenChain.length === 1) {
|
|
809
|
+
// variable that has not been assigned
|
|
810
|
+
expandedTokenText = currentToken.text;
|
|
811
|
+
backUpReturnType = new UninitializedType_1.UninitializedType();
|
|
812
|
+
}
|
|
813
|
+
else if (tokenFoundCount === tokenChain.length - 1) {
|
|
814
|
+
// member field that is not known
|
|
815
|
+
if (symbolContainer) {
|
|
816
|
+
backUpReturnType = new InvalidType_1.InvalidType();
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
// TODO TYPES: once we have stricter object/node member type checking, we could say this is invalid, but until then, call it dynamic
|
|
820
|
+
backUpReturnType = new DynamicType_1.DynamicType();
|
|
821
|
+
expandedTokenText = currentToken.text;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
const symbolData = { type: backUpReturnType, expandedTokenText: expandedTokenText };
|
|
825
|
+
scope.symbolCache.set(currentToken, symbolData);
|
|
826
|
+
return symbolData;
|
|
827
|
+
}
|
|
727
828
|
getGlobalClassStatementCompletions(currentToken, parseMode) {
|
|
728
829
|
var _a;
|
|
729
830
|
if (parseMode === parser_1.ParseMode.BrightScript) {
|
|
@@ -762,7 +863,7 @@ class BrsFile {
|
|
|
762
863
|
//remove any trailing identifer and then any trailing dot, to give us the
|
|
763
864
|
//name of its immediate parent namespace
|
|
764
865
|
let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
|
|
765
|
-
let newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
|
|
866
|
+
let newToken = this.parser.getTokenBefore(currentToken, lexer_1.TokenKind.New);
|
|
766
867
|
let namespaceLookup = scope.namespaceLookup;
|
|
767
868
|
let result = new Map();
|
|
768
869
|
for (let key in namespaceLookup) {
|
|
@@ -821,7 +922,7 @@ class BrsFile {
|
|
|
821
922
|
if (!location && statement.getName(parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
|
|
822
923
|
const namespaceItemStatementHandler = (statement) => {
|
|
823
924
|
if (!location && statement.name.text.toLowerCase() === endName) {
|
|
824
|
-
const uri = util_1.util.pathToUri(file.
|
|
925
|
+
const uri = util_1.util.pathToUri(file.srcPath);
|
|
825
926
|
location = vscode_languageserver_1.Location.create(uri, statement.range);
|
|
826
927
|
}
|
|
827
928
|
};
|
|
@@ -865,64 +966,6 @@ class BrsFile {
|
|
|
865
966
|
return undefined;
|
|
866
967
|
}
|
|
867
968
|
}
|
|
868
|
-
isPositionNextToTokenKind(position, tokenKind) {
|
|
869
|
-
const closestToken = this.getClosestToken(position);
|
|
870
|
-
const previousToken = this.getPreviousToken(closestToken);
|
|
871
|
-
const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
|
|
872
|
-
//next to matched token
|
|
873
|
-
if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
|
|
874
|
-
return false;
|
|
875
|
-
}
|
|
876
|
-
else if (closestToken.kind === tokenKind) {
|
|
877
|
-
return true;
|
|
878
|
-
}
|
|
879
|
-
else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
|
|
880
|
-
return false;
|
|
881
|
-
//next to an identifier, which is next to token kind
|
|
882
|
-
}
|
|
883
|
-
else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
|
|
884
|
-
return true;
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
return false;
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
getTokenBefore(currentToken, tokenKind) {
|
|
891
|
-
const index = this.parser.tokens.indexOf(currentToken);
|
|
892
|
-
for (let i = index - 1; i >= 0; i--) {
|
|
893
|
-
currentToken = this.parser.tokens[i];
|
|
894
|
-
if (currentToken.kind === lexer_1.TokenKind.Newline) {
|
|
895
|
-
break;
|
|
896
|
-
}
|
|
897
|
-
else if (currentToken.kind === tokenKind) {
|
|
898
|
-
return currentToken;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
return undefined;
|
|
902
|
-
}
|
|
903
|
-
tokenFollows(currentToken, tokenKind) {
|
|
904
|
-
const index = this.parser.tokens.indexOf(currentToken);
|
|
905
|
-
if (index > 0) {
|
|
906
|
-
return this.parser.tokens[index - 1].kind === tokenKind;
|
|
907
|
-
}
|
|
908
|
-
return false;
|
|
909
|
-
}
|
|
910
|
-
getTokensUntil(currentToken, tokenKind, direction = -1) {
|
|
911
|
-
let tokens = [];
|
|
912
|
-
for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
|
|
913
|
-
currentToken = this.parser.tokens[i];
|
|
914
|
-
if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
tokens.push(currentToken);
|
|
918
|
-
}
|
|
919
|
-
return tokens;
|
|
920
|
-
}
|
|
921
|
-
getPreviousToken(token) {
|
|
922
|
-
const parser = this.parser;
|
|
923
|
-
let idx = parser.tokens.indexOf(token);
|
|
924
|
-
return parser.tokens[idx - 1];
|
|
925
|
-
}
|
|
926
969
|
/**
|
|
927
970
|
* Find the first scope that has a namespace with this name.
|
|
928
971
|
* Returns false if no namespace was found with that name
|
|
@@ -964,28 +1007,6 @@ class BrsFile {
|
|
|
964
1007
|
}
|
|
965
1008
|
return false;
|
|
966
1009
|
}
|
|
967
|
-
/**
|
|
968
|
-
* Get the token closest to the position. if no token is found, the previous token is returned
|
|
969
|
-
* @param position
|
|
970
|
-
* @param tokens
|
|
971
|
-
*/
|
|
972
|
-
getClosestToken(position) {
|
|
973
|
-
let tokens = this.parser.tokens;
|
|
974
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
975
|
-
let token = tokens[i];
|
|
976
|
-
if (util_1.util.rangeContains(token.range, position)) {
|
|
977
|
-
return token;
|
|
978
|
-
}
|
|
979
|
-
//if the position less than this token range, then this position touches no token,
|
|
980
|
-
if (util_1.util.positionIsGreaterThanRange(position, token.range) === false) {
|
|
981
|
-
let t = tokens[i - 1];
|
|
982
|
-
//return the token or the first token
|
|
983
|
-
return t ? t : tokens[0];
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
//return the last token
|
|
987
|
-
return tokens[tokens.length - 1];
|
|
988
|
-
}
|
|
989
1010
|
/**
|
|
990
1011
|
* Builds a list of document symbols for this file. Used by LanguageServer's onDocumentSymbol functionality
|
|
991
1012
|
*/
|
|
@@ -1090,7 +1111,7 @@ class BrsFile {
|
|
|
1090
1111
|
return symbols;
|
|
1091
1112
|
}
|
|
1092
1113
|
const name = statement.getName(parser_1.ParseMode.BrighterScript);
|
|
1093
|
-
const uri = util_1.util.pathToUri(this.
|
|
1114
|
+
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1094
1115
|
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));
|
|
1095
1116
|
symbols.push(symbol);
|
|
1096
1117
|
return symbols;
|
|
@@ -1102,7 +1123,7 @@ class BrsFile {
|
|
|
1102
1123
|
getDefinition(position) {
|
|
1103
1124
|
let results = [];
|
|
1104
1125
|
//get the token at the position
|
|
1105
|
-
const token = this.getTokenAt(position);
|
|
1126
|
+
const token = this.parser.getTokenAt(position);
|
|
1106
1127
|
// 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
|
|
1107
1128
|
let definitionTokenTypes = [
|
|
1108
1129
|
lexer_1.TokenKind.Identifier,
|
|
@@ -1113,25 +1134,25 @@ class BrsFile {
|
|
|
1113
1134
|
return results;
|
|
1114
1135
|
}
|
|
1115
1136
|
let textToSearchFor = token.text.toLowerCase();
|
|
1116
|
-
const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
1137
|
+
const previousToken = this.parser.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
|
|
1117
1138
|
if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Callfunc) {
|
|
1118
1139
|
for (const scope of this.program.getScopes()) {
|
|
1119
1140
|
//to only get functions defined in interface methods
|
|
1120
1141
|
const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
|
|
1121
1142
|
if (callable) {
|
|
1122
|
-
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(callable.callable.file.
|
|
1143
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(callable.callable.file.srcPath), callable.callable.functionStatement.range));
|
|
1123
1144
|
}
|
|
1124
1145
|
}
|
|
1125
1146
|
return results;
|
|
1126
1147
|
}
|
|
1127
|
-
let classToken = this.getTokenBefore(token, lexer_1.TokenKind.Class);
|
|
1148
|
+
let classToken = this.parser.getTokenBefore(token, lexer_1.TokenKind.Class);
|
|
1128
1149
|
if (classToken) {
|
|
1129
1150
|
let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
|
|
1130
1151
|
if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
|
|
1131
1152
|
const nameParts = cs.parentClassName.getNameParts();
|
|
1132
1153
|
let extendedClass = this.getClassFileLink(nameParts[nameParts.length - 1], nameParts.slice(0, -1).join('.'));
|
|
1133
1154
|
if (extendedClass) {
|
|
1134
|
-
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(extendedClass.file.
|
|
1155
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(extendedClass.file.srcPath), extendedClass.item.range));
|
|
1135
1156
|
}
|
|
1136
1157
|
}
|
|
1137
1158
|
return results;
|
|
@@ -1145,23 +1166,21 @@ class BrsFile {
|
|
|
1145
1166
|
}
|
|
1146
1167
|
textToSearchFor = textToSearchFor.substring(startIndex, endIndex);
|
|
1147
1168
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
results.push(vscode_languageserver_1.Location.create(uri, label.nameRange));
|
|
1164
|
-
}
|
|
1169
|
+
const func = this.getFunctionExpressionAtPosition(position);
|
|
1170
|
+
//look through local variables first
|
|
1171
|
+
//find any variable with this name
|
|
1172
|
+
for (const symbol of func.symbolTable.getOwnSymbols()) {
|
|
1173
|
+
//we found a variable declaration with this token text
|
|
1174
|
+
if (symbol.name.toLowerCase() === textToSearchFor) {
|
|
1175
|
+
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1176
|
+
results.push(vscode_languageserver_1.Location.create(uri, symbol.range));
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (this.parser.tokenFollows(token, lexer_1.TokenKind.Goto)) {
|
|
1180
|
+
for (const label of func.labelStatements) {
|
|
1181
|
+
if (label.tokens.identifier.text.toLocaleLowerCase() === textToSearchFor) {
|
|
1182
|
+
const uri = util_1.util.pathToUri(this.srcPath);
|
|
1183
|
+
results.push(vscode_languageserver_1.Location.create(uri, label.tokens.identifier.range));
|
|
1165
1184
|
}
|
|
1166
1185
|
}
|
|
1167
1186
|
}
|
|
@@ -1182,7 +1201,7 @@ class BrsFile {
|
|
|
1182
1201
|
}
|
|
1183
1202
|
const statementHandler = (statement) => {
|
|
1184
1203
|
if (statement.getName(this.parseMode).toLowerCase() === textToSearchFor) {
|
|
1185
|
-
const uri = util_1.util.pathToUri(file.
|
|
1204
|
+
const uri = util_1.util.pathToUri(file.srcPath);
|
|
1186
1205
|
results.push(vscode_languageserver_1.Location.create(uri, statement.range));
|
|
1187
1206
|
}
|
|
1188
1207
|
};
|
|
@@ -1200,12 +1219,12 @@ class BrsFile {
|
|
|
1200
1219
|
//get class fields and members
|
|
1201
1220
|
const statementHandler = (statement) => {
|
|
1202
1221
|
if (statement.getName(file.parseMode).toLowerCase() === textToSearchFor) {
|
|
1203
|
-
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.
|
|
1222
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), statement.range));
|
|
1204
1223
|
}
|
|
1205
1224
|
};
|
|
1206
1225
|
const fieldStatementHandler = (statement) => {
|
|
1207
1226
|
if (statement.name.text.toLowerCase() === textToSearchFor) {
|
|
1208
|
-
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.
|
|
1227
|
+
results.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), statement.range));
|
|
1209
1228
|
}
|
|
1210
1229
|
};
|
|
1211
1230
|
file.parser.ast.walk((0, visitors_1.createVisitor)({
|
|
@@ -1217,8 +1236,9 @@ class BrsFile {
|
|
|
1217
1236
|
return results;
|
|
1218
1237
|
}
|
|
1219
1238
|
getHover(position) {
|
|
1239
|
+
var _a, _b, _c;
|
|
1220
1240
|
//get the token at the position
|
|
1221
|
-
let token = this.getTokenAt(position);
|
|
1241
|
+
let token = this.parser.getTokenAt(position);
|
|
1222
1242
|
let hoverTokenTypes = [
|
|
1223
1243
|
lexer_1.TokenKind.Identifier,
|
|
1224
1244
|
lexer_1.TokenKind.Function,
|
|
@@ -1233,35 +1253,45 @@ class BrsFile {
|
|
|
1233
1253
|
let lowerTokenText = token.text.toLowerCase();
|
|
1234
1254
|
//look through local variables first
|
|
1235
1255
|
{
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
//we found a variable declaration with this token text!
|
|
1242
|
-
if (varDeclaration.name.toLowerCase() === lowerTokenText) {
|
|
1243
|
-
let typeText;
|
|
1244
|
-
if ((0, reflection_1.isFunctionType)(varDeclaration.type)) {
|
|
1245
|
-
typeText = varDeclaration.type.toString();
|
|
1246
|
-
}
|
|
1247
|
-
else {
|
|
1248
|
-
typeText = `${varDeclaration.name} as ${varDeclaration.type.toString()}`;
|
|
1249
|
-
}
|
|
1256
|
+
const func = this.getFunctionExpressionAtPosition(position);
|
|
1257
|
+
if (func) {
|
|
1258
|
+
// this identifier could possibly be a class field, so no function expression is available
|
|
1259
|
+
for (const labelStatement of (_a = func === null || func === void 0 ? void 0 : func.labelStatements) !== null && _a !== void 0 ? _a : []) {
|
|
1260
|
+
if (labelStatement.tokens.identifier.text.toLocaleLowerCase() === lowerTokenText) {
|
|
1250
1261
|
return {
|
|
1251
1262
|
range: token.range,
|
|
1252
|
-
|
|
1253
|
-
contents: typeText
|
|
1263
|
+
contents: `${labelStatement.tokens.identifier.text}: label`
|
|
1254
1264
|
};
|
|
1255
1265
|
}
|
|
1256
1266
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1267
|
+
}
|
|
1268
|
+
const typeTexts = [];
|
|
1269
|
+
for (const scope of this.program.getScopesForFile(this)) {
|
|
1270
|
+
scope.linkSymbolTable();
|
|
1271
|
+
const typeTextPair = this.getSymbolTypeFromToken(token, func, scope);
|
|
1272
|
+
if (typeTextPair) {
|
|
1273
|
+
let scopeTypeText = '';
|
|
1274
|
+
if ((0, reflection_1.isFunctionType)(typeTextPair.type)) {
|
|
1275
|
+
scopeTypeText = (_b = typeTextPair.type) === null || _b === void 0 ? void 0 : _b.toString();
|
|
1276
|
+
}
|
|
1277
|
+
else if (typeTextPair.useExpandedTextOnly) {
|
|
1278
|
+
scopeTypeText = typeTextPair.expandedTokenText;
|
|
1279
|
+
}
|
|
1280
|
+
else {
|
|
1281
|
+
scopeTypeText = `${typeTextPair.expandedTokenText} as ${(_c = typeTextPair.type) === null || _c === void 0 ? void 0 : _c.toString()}`;
|
|
1282
|
+
}
|
|
1283
|
+
if (scopeTypeText && !typeTexts.includes(scopeTypeText)) {
|
|
1284
|
+
typeTexts.push(scopeTypeText);
|
|
1263
1285
|
}
|
|
1264
1286
|
}
|
|
1287
|
+
scope.unlinkSymbolTable();
|
|
1288
|
+
}
|
|
1289
|
+
const typeText = typeTexts.join(' | ');
|
|
1290
|
+
if (typeText) {
|
|
1291
|
+
return {
|
|
1292
|
+
range: token.range,
|
|
1293
|
+
contents: typeText
|
|
1294
|
+
};
|
|
1265
1295
|
}
|
|
1266
1296
|
}
|
|
1267
1297
|
//look through all callables in relevant scopes
|
|
@@ -1313,10 +1343,10 @@ class BrsFile {
|
|
|
1313
1343
|
const func = statement.func;
|
|
1314
1344
|
const funcStartPosition = func.range.start;
|
|
1315
1345
|
// Get function comments in reverse order
|
|
1316
|
-
let currentToken = this.getTokenAt(funcStartPosition);
|
|
1346
|
+
let currentToken = this.parser.getTokenAt(funcStartPosition);
|
|
1317
1347
|
let functionComments = [];
|
|
1318
1348
|
while (currentToken) {
|
|
1319
|
-
currentToken = this.getPreviousToken(currentToken);
|
|
1349
|
+
currentToken = this.parser.getPreviousToken(currentToken);
|
|
1320
1350
|
if (!currentToken) {
|
|
1321
1351
|
break;
|
|
1322
1352
|
}
|
|
@@ -1360,7 +1390,8 @@ class BrsFile {
|
|
|
1360
1390
|
}
|
|
1361
1391
|
getClassMethod(classStatement, name, walkParents = true) {
|
|
1362
1392
|
var _a;
|
|
1363
|
-
//TODO - would like to write this with
|
|
1393
|
+
//TODO - would like to write this with getClassHierarchy; but got stuck on working out the scopes to use... :(
|
|
1394
|
+
//TODO types - this could be solved with symbolTable?
|
|
1364
1395
|
let statement;
|
|
1365
1396
|
const statementHandler = (e) => {
|
|
1366
1397
|
if (!statement && e.name.text.toLowerCase() === name.toLowerCase()) {
|
|
@@ -1396,7 +1427,7 @@ class BrsFile {
|
|
|
1396
1427
|
return sigHelp;
|
|
1397
1428
|
}
|
|
1398
1429
|
getReferences(position) {
|
|
1399
|
-
const callSiteToken = this.getTokenAt(position);
|
|
1430
|
+
const callSiteToken = this.parser.getTokenAt(position);
|
|
1400
1431
|
let locations = [];
|
|
1401
1432
|
const searchFor = callSiteToken.text.toLowerCase();
|
|
1402
1433
|
const scopes = this.program.getScopesForFile(this);
|
|
@@ -1410,7 +1441,7 @@ class BrsFile {
|
|
|
1410
1441
|
file.ast.walk((0, visitors_1.createVisitor)({
|
|
1411
1442
|
VariableExpression: (e) => {
|
|
1412
1443
|
if (e.name.text.toLowerCase() === searchFor) {
|
|
1413
|
-
locations.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.
|
|
1444
|
+
locations.push(vscode_languageserver_1.Location.create(util_1.util.pathToUri(file.srcPath), e.range));
|
|
1414
1445
|
}
|
|
1415
1446
|
}
|
|
1416
1447
|
}), {
|
|
@@ -1454,7 +1485,7 @@ class BrsFile {
|
|
|
1454
1485
|
getTypedef() {
|
|
1455
1486
|
const state = new BrsTranspileState_1.BrsTranspileState(this);
|
|
1456
1487
|
const typedef = this.ast.getTypedef(state);
|
|
1457
|
-
const programNode = new source_map_1.SourceNode(null, null, this.
|
|
1488
|
+
const programNode = new source_map_1.SourceNode(null, null, this.srcPath, typedef);
|
|
1458
1489
|
return programNode.toString();
|
|
1459
1490
|
}
|
|
1460
1491
|
dispose() {
|