brighterscript 1.0.0-alpha.13 → 1.0.0-alpha.14
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 +46 -2
- package/dist/Cache.d.ts +3 -3
- package/dist/Cache.js +10 -6
- package/dist/Cache.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 +106 -43
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.js +3 -3
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +15 -6
- package/dist/Scope.js +39 -25
- package/dist/Scope.js.map +1 -1
- package/dist/SymbolTable.d.ts +1 -1
- package/dist/astUtils/reflection.spec.js +6 -6
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +8 -8
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.js +5 -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 +8 -0
- package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.js → BrsFileSemanticTokensProcessor.js} +12 -14
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.d.ts → BrsFileSemanticTokensProcessor.spec.d.ts} +0 -0
- package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.js → BrsFileSemanticTokensProcessor.spec.js} +2 -2
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/files/BrsFile.Class.spec.js +389 -238
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +17 -11
- package/dist/files/BrsFile.js +160 -91
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +442 -109
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/XmlFile.d.ts +6 -5
- package/dist/files/XmlFile.js +13 -8
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +57 -55
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +8 -6
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +21 -4
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +46 -10
- package/dist/lexer/Lexer.js +1 -2
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +462 -462
- package/dist/lexer/Lexer.spec.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 +17 -5
- package/dist/parser/Parser.js +403 -288
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +157 -35
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGTypes.spec.js +9 -9
- package/dist/parser/SGTypes.spec.js.map +1 -1
- package/dist/parser/Statement.d.ts +3 -3
- package/dist/parser/Statement.js +8 -8
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +3 -3
- package/dist/parser/tests/Parser.spec.js +4 -4
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +40 -40
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +22 -21
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +100 -99
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +25 -25
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +21 -21
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +91 -91
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +102 -102
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +15 -15
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +22 -21
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +11 -11
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +171 -171
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +50 -50
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +25 -25
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +26 -26
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +27 -27
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +3 -2
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/Relational.spec.js +25 -25
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +7 -7
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +6 -6
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/Declaration.spec.js +20 -20
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/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/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 +15 -9
- package/dist/util.js +93 -50
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js +17 -24
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +2 -1
- 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.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/parser/Parser.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getBscTypeFromExpression = exports.TokenUsage = exports.References = exports.ParseMode = exports.Parser = void 0;
|
|
4
|
-
const
|
|
4
|
+
const Token_1 = require("../lexer/Token");
|
|
5
|
+
const Lexer_1 = require("../lexer/Lexer");
|
|
6
|
+
const TokenKind_1 = require("../lexer/TokenKind");
|
|
5
7
|
const Statement_1 = require("./Statement");
|
|
6
8
|
const DiagnosticMessages_1 = require("../DiagnosticMessages");
|
|
7
9
|
const util_1 = require("../util");
|
|
@@ -10,12 +12,11 @@ const Logger_1 = require("../Logger");
|
|
|
10
12
|
const reflection_1 = require("../astUtils/reflection");
|
|
11
13
|
const visitors_1 = require("../astUtils/visitors");
|
|
12
14
|
const creators_1 = require("../astUtils/creators");
|
|
13
|
-
const DynamicType_1 = require("../types/DynamicType");
|
|
14
15
|
const SymbolTable_1 = require("../SymbolTable");
|
|
16
|
+
const DynamicType_1 = require("../types/DynamicType");
|
|
15
17
|
const ObjectType_1 = require("../types/ObjectType");
|
|
16
18
|
const ArrayType_1 = require("../types/ArrayType");
|
|
17
19
|
const helpers_1 = require("../types/helpers");
|
|
18
|
-
const _1 = require(".");
|
|
19
20
|
class Parser {
|
|
20
21
|
constructor() {
|
|
21
22
|
/**
|
|
@@ -61,7 +62,7 @@ class Parser {
|
|
|
61
62
|
this._references = undefined;
|
|
62
63
|
}
|
|
63
64
|
addPropertyHints(item) {
|
|
64
|
-
if ((0,
|
|
65
|
+
if ((0, Token_1.isToken)(item)) {
|
|
65
66
|
const name = item.text;
|
|
66
67
|
this._references.propertyHints[name.toLowerCase()] = name;
|
|
67
68
|
}
|
|
@@ -93,7 +94,7 @@ class Parser {
|
|
|
93
94
|
static parse(toParse, options) {
|
|
94
95
|
let tokens;
|
|
95
96
|
if (typeof toParse === 'string') {
|
|
96
|
-
tokens =
|
|
97
|
+
tokens = Lexer_1.Lexer.scan(toParse).tokens;
|
|
97
98
|
}
|
|
98
99
|
else {
|
|
99
100
|
tokens = toParse;
|
|
@@ -111,9 +112,9 @@ class Parser {
|
|
|
111
112
|
this.tokens = tokens;
|
|
112
113
|
this.options = this.sanitizeParseOptions(options);
|
|
113
114
|
this.allowedLocalIdentifiers = [
|
|
114
|
-
...
|
|
115
|
+
...TokenKind_1.AllowedLocalIdentifiers,
|
|
115
116
|
//when in plain brightscript mode, the BrighterScript source literals can be used as regular variables
|
|
116
|
-
...(this.options.mode === ParseMode.BrightScript ?
|
|
117
|
+
...(this.options.mode === ParseMode.BrightScript ? TokenKind_1.BrighterScriptSourceLiterals : [])
|
|
117
118
|
];
|
|
118
119
|
this.current = 0;
|
|
119
120
|
this.diagnostics = [];
|
|
@@ -184,16 +185,16 @@ class Parser {
|
|
|
184
185
|
}
|
|
185
186
|
declaration() {
|
|
186
187
|
try {
|
|
187
|
-
if (this.checkAny(
|
|
188
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
188
189
|
return this.functionDeclaration(false);
|
|
189
190
|
}
|
|
190
191
|
if (this.checkLibrary()) {
|
|
191
192
|
return this.libraryStatement();
|
|
192
193
|
}
|
|
193
|
-
if (this.check(
|
|
194
|
+
if (this.check(TokenKind_1.TokenKind.At) && this.checkNext(TokenKind_1.TokenKind.Identifier)) {
|
|
194
195
|
return this.annotationExpression();
|
|
195
196
|
}
|
|
196
|
-
if (this.check(
|
|
197
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
197
198
|
return this.commentStatement();
|
|
198
199
|
}
|
|
199
200
|
//catch certain global terminators to prevent unnecessary lookahead (i.e. like `end namespace`, no need to continue)
|
|
@@ -211,17 +212,17 @@ class Parser {
|
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
214
|
identifier(...additionalTokenKinds) {
|
|
214
|
-
const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
215
|
+
const identifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...additionalTokenKinds);
|
|
215
216
|
// force the name into an identifier so the AST makes some sense
|
|
216
|
-
identifier.kind =
|
|
217
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
217
218
|
return identifier;
|
|
218
219
|
}
|
|
219
220
|
/**
|
|
220
221
|
* Create a new InterfaceMethodStatement. This should only be called from within `interfaceDeclaration`
|
|
221
222
|
*/
|
|
222
223
|
interfaceFieldStatement() {
|
|
223
|
-
const name = this.identifier(...
|
|
224
|
-
let asToken = this.consumeToken(
|
|
224
|
+
const name = this.identifier(...TokenKind_1.AllowedProperties);
|
|
225
|
+
let asToken = this.consumeToken(TokenKind_1.TokenKind.As);
|
|
225
226
|
let typeToken = this.typeToken();
|
|
226
227
|
const type = util_1.util.tokenToBscType(typeToken);
|
|
227
228
|
if (!type) {
|
|
@@ -235,13 +236,13 @@ class Parser {
|
|
|
235
236
|
*/
|
|
236
237
|
interfaceMethodStatement() {
|
|
237
238
|
const functionType = this.advance();
|
|
238
|
-
const name = this.identifier(...
|
|
239
|
-
const leftParen = this.consumeToken(
|
|
239
|
+
const name = this.identifier(...TokenKind_1.AllowedProperties);
|
|
240
|
+
const leftParen = this.consumeToken(TokenKind_1.TokenKind.LeftParen);
|
|
240
241
|
const params = [];
|
|
241
|
-
const rightParen = this.consumeToken(
|
|
242
|
+
const rightParen = this.consumeToken(TokenKind_1.TokenKind.RightParen);
|
|
242
243
|
let asToken = null;
|
|
243
244
|
let returnTypeToken = null;
|
|
244
|
-
if (this.check(
|
|
245
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
245
246
|
asToken = this.advance();
|
|
246
247
|
returnTypeToken = this.typeToken();
|
|
247
248
|
const returnType = util_1.util.tokenToBscType(returnTypeToken);
|
|
@@ -255,7 +256,7 @@ class Parser {
|
|
|
255
256
|
interfaceDeclaration() {
|
|
256
257
|
this.warnIfNotBrighterScriptMode('interface declarations');
|
|
257
258
|
const parentAnnotations = this.enterAnnotationBlock();
|
|
258
|
-
const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(
|
|
259
|
+
const interfaceToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Interface), TokenKind_1.TokenKind.Interface);
|
|
259
260
|
const nameToken = this.identifier(...this.allowedLocalIdentifiers);
|
|
260
261
|
let extendsToken;
|
|
261
262
|
let parentInterfaceName;
|
|
@@ -266,23 +267,23 @@ class Parser {
|
|
|
266
267
|
this.consumeStatementSeparators();
|
|
267
268
|
//gather up all interface members (Fields, Methods)
|
|
268
269
|
let body = [];
|
|
269
|
-
while (this.checkAny(
|
|
270
|
+
while (this.checkAny(TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
|
|
270
271
|
try {
|
|
271
272
|
let decl;
|
|
272
273
|
//collect leading annotations
|
|
273
|
-
if (this.check(
|
|
274
|
+
if (this.check(TokenKind_1.TokenKind.At)) {
|
|
274
275
|
this.annotationExpression();
|
|
275
276
|
}
|
|
276
277
|
//fields
|
|
277
|
-
if (this.checkAny(
|
|
278
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.As)) {
|
|
278
279
|
decl = this.interfaceFieldStatement();
|
|
279
280
|
//methods (function/sub keyword followed by opening paren)
|
|
280
281
|
}
|
|
281
|
-
else if (this.checkAny(
|
|
282
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) && this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
282
283
|
decl = this.interfaceMethodStatement();
|
|
283
284
|
//comments
|
|
284
285
|
}
|
|
285
|
-
else if (this.check(
|
|
286
|
+
else if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
286
287
|
decl = this.commentStatement();
|
|
287
288
|
}
|
|
288
289
|
if (decl) {
|
|
@@ -291,23 +292,22 @@ class Parser {
|
|
|
291
292
|
}
|
|
292
293
|
else {
|
|
293
294
|
//we didn't find a declaration...flag tokens until next line
|
|
294
|
-
this.flagUntil(
|
|
295
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
catch (e) {
|
|
298
299
|
//throw out any failed members and move on to the next line
|
|
299
|
-
this.flagUntil(
|
|
300
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
300
301
|
}
|
|
301
302
|
//ensure statement separator
|
|
302
303
|
this.consumeStatementSeparators();
|
|
303
304
|
//break out of this loop if we encountered the `EndInterface` token not followed by `as`
|
|
304
|
-
if (this.check(
|
|
305
|
+
if (this.check(TokenKind_1.TokenKind.EndInterface) && !this.checkNext(TokenKind_1.TokenKind.As)) {
|
|
305
306
|
break;
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
//consume the final `end interface` token
|
|
309
|
-
const endInterfaceToken = this.consumeToken(
|
|
310
|
-
this.consumeStatementSeparators();
|
|
310
|
+
const endInterfaceToken = this.consumeToken(TokenKind_1.TokenKind.EndInterface);
|
|
311
311
|
const statement = new Statement_1.InterfaceStatement(interfaceToken, nameToken, extendsToken, parentInterfaceName, body, endInterfaceToken, this.currentNamespaceName);
|
|
312
312
|
this._references.interfaceStatements.push(statement);
|
|
313
313
|
this.exitAnnotationBlock(parentAnnotations);
|
|
@@ -319,11 +319,11 @@ class Parser {
|
|
|
319
319
|
classDeclaration() {
|
|
320
320
|
this.warnIfNotBrighterScriptMode('class declarations');
|
|
321
321
|
const parentAnnotations = this.enterAnnotationBlock();
|
|
322
|
-
let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(
|
|
322
|
+
let classKeyword = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedKeyword(TokenKind_1.TokenKind.Class), TokenKind_1.TokenKind.Class);
|
|
323
323
|
let extendsKeyword;
|
|
324
324
|
let parentClassName;
|
|
325
325
|
//get the class name
|
|
326
|
-
let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'),
|
|
326
|
+
let className = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('class'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
327
327
|
//see if the class inherits from parent
|
|
328
328
|
if (this.peek().text.toLowerCase() === 'extends') {
|
|
329
329
|
extendsKeyword = this.advance();
|
|
@@ -333,14 +333,14 @@ class Parser {
|
|
|
333
333
|
this.consumeStatementSeparators();
|
|
334
334
|
//gather up all class members (Fields, Methods)
|
|
335
335
|
let body = [];
|
|
336
|
-
while (this.checkAny(
|
|
336
|
+
while (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private, TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Identifier, TokenKind_1.TokenKind.At, ...TokenKind_1.AllowedProperties)) {
|
|
337
337
|
try {
|
|
338
338
|
let decl;
|
|
339
339
|
let accessModifier;
|
|
340
|
-
if (this.check(
|
|
340
|
+
if (this.check(TokenKind_1.TokenKind.At)) {
|
|
341
341
|
this.annotationExpression();
|
|
342
342
|
}
|
|
343
|
-
if (this.checkAny(
|
|
343
|
+
if (this.checkAny(TokenKind_1.TokenKind.Public, TokenKind_1.TokenKind.Protected, TokenKind_1.TokenKind.Private)) {
|
|
344
344
|
//use actual access modifier
|
|
345
345
|
accessModifier = this.advance();
|
|
346
346
|
}
|
|
@@ -349,7 +349,7 @@ class Parser {
|
|
|
349
349
|
overrideKeyword = this.advance();
|
|
350
350
|
}
|
|
351
351
|
//methods (function/sub keyword OR identifier followed by opening paren)
|
|
352
|
-
if (this.checkAny(
|
|
352
|
+
if (this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub) || (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties) && this.checkNext(TokenKind_1.TokenKind.LeftParen))) {
|
|
353
353
|
const funcDeclaration = this.functionDeclaration(false, false, true);
|
|
354
354
|
//remove this function from the lists because it's not a callable
|
|
355
355
|
const functionStatement = this._references.functionStatements.pop();
|
|
@@ -362,7 +362,7 @@ class Parser {
|
|
|
362
362
|
functionStatement.func.functionStatement = decl;
|
|
363
363
|
//fields
|
|
364
364
|
}
|
|
365
|
-
else if (this.checkAny(
|
|
365
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
366
366
|
decl = this.classFieldDeclaration(accessModifier);
|
|
367
367
|
//class fields cannot be overridden
|
|
368
368
|
if (overrideKeyword) {
|
|
@@ -370,7 +370,7 @@ class Parser {
|
|
|
370
370
|
}
|
|
371
371
|
//comments
|
|
372
372
|
}
|
|
373
|
-
else if (this.check(
|
|
373
|
+
else if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
374
374
|
decl = this.commentStatement();
|
|
375
375
|
}
|
|
376
376
|
if (decl) {
|
|
@@ -380,13 +380,13 @@ class Parser {
|
|
|
380
380
|
}
|
|
381
381
|
catch (e) {
|
|
382
382
|
//throw out any failed members and move on to the next line
|
|
383
|
-
this.flagUntil(
|
|
383
|
+
this.flagUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
384
384
|
}
|
|
385
385
|
//ensure statement separator
|
|
386
386
|
this.consumeStatementSeparators();
|
|
387
387
|
}
|
|
388
388
|
let endingKeyword = this.advance();
|
|
389
|
-
if (endingKeyword.kind !==
|
|
389
|
+
if (endingKeyword.kind !== TokenKind_1.TokenKind.EndClass) {
|
|
390
390
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('class')), { range: endingKeyword.range }));
|
|
391
391
|
}
|
|
392
392
|
const result = new Statement_1.ClassStatement(classKeyword, className, body, endingKeyword, extendsKeyword, parentClassName, this.currentNamespaceName, this.currentSymbolTable);
|
|
@@ -398,11 +398,11 @@ class Parser {
|
|
|
398
398
|
return result;
|
|
399
399
|
}
|
|
400
400
|
classFieldDeclaration(accessModifier) {
|
|
401
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(),
|
|
401
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedClassFieldIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
402
402
|
let asToken;
|
|
403
403
|
let fieldType;
|
|
404
404
|
//look for `as SOME_TYPE`
|
|
405
|
-
if (this.check(
|
|
405
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
406
406
|
asToken = this.advance();
|
|
407
407
|
fieldType = this.typeToken();
|
|
408
408
|
//no field type specified
|
|
@@ -413,7 +413,7 @@ class Parser {
|
|
|
413
413
|
let initialValue;
|
|
414
414
|
let equal;
|
|
415
415
|
//if there is a field initializer
|
|
416
|
-
if (this.check(
|
|
416
|
+
if (this.check(TokenKind_1.TokenKind.Equal)) {
|
|
417
417
|
equal = this.advance();
|
|
418
418
|
initialValue = this.expression();
|
|
419
419
|
}
|
|
@@ -427,14 +427,14 @@ class Parser {
|
|
|
427
427
|
//track depth to help certain statements need to know if they are contained within a function body
|
|
428
428
|
this.namespaceAndFunctionDepth++;
|
|
429
429
|
let functionType;
|
|
430
|
-
if (this.checkAny(
|
|
430
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
431
431
|
functionType = this.advance();
|
|
432
432
|
}
|
|
433
433
|
else {
|
|
434
434
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingCallableKeyword()), { range: this.peek().range }));
|
|
435
435
|
functionType = {
|
|
436
436
|
isReserved: true,
|
|
437
|
-
kind:
|
|
437
|
+
kind: TokenKind_1.TokenKind.Function,
|
|
438
438
|
text: 'function',
|
|
439
439
|
//zero-length location means derived
|
|
440
440
|
range: {
|
|
@@ -444,16 +444,16 @@ class Parser {
|
|
|
444
444
|
leadingWhitespace: ''
|
|
445
445
|
};
|
|
446
446
|
}
|
|
447
|
-
let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) ===
|
|
447
|
+
let isSub = (functionType === null || functionType === void 0 ? void 0 : functionType.kind) === TokenKind_1.TokenKind.Sub;
|
|
448
448
|
let functionTypeText = isSub ? 'sub' : 'function';
|
|
449
449
|
let name;
|
|
450
450
|
let leftParen;
|
|
451
451
|
if (isAnonymous) {
|
|
452
|
-
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText),
|
|
452
|
+
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), TokenKind_1.TokenKind.LeftParen);
|
|
453
453
|
}
|
|
454
454
|
else {
|
|
455
|
-
name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText),
|
|
456
|
-
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText),
|
|
455
|
+
name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedNameAfterCallableKeyword(functionTypeText), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
456
|
+
leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLeftParenAfterCallableName(functionTypeText), TokenKind_1.TokenKind.LeftParen);
|
|
457
457
|
//prevent functions from ending with type designators
|
|
458
458
|
let lastChar = name.text[name.text.length - 1];
|
|
459
459
|
if (['$', '%', '!', '#', '&'].includes(lastChar)) {
|
|
@@ -461,23 +461,23 @@ class Parser {
|
|
|
461
461
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.functionNameCannotEndWithTypeDesignator(functionTypeText, name.text, lastChar)), { range: name.range }));
|
|
462
462
|
}
|
|
463
463
|
//flag functions with keywords for names (only for standard functions)
|
|
464
|
-
if (checkIdentifier &&
|
|
464
|
+
if (checkIdentifier && TokenKind_1.DisallowedFunctionIdentifiersText.has(name.text.toLowerCase())) {
|
|
465
465
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
let params = [];
|
|
469
469
|
let asToken;
|
|
470
470
|
let typeToken;
|
|
471
|
-
if (!this.check(
|
|
471
|
+
if (!this.check(TokenKind_1.TokenKind.RightParen)) {
|
|
472
472
|
do {
|
|
473
473
|
if (params.length >= Expression_1.CallExpression.MaximumArguments) {
|
|
474
474
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableParameters(params.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
|
|
475
475
|
}
|
|
476
476
|
params.push(this.functionParameter());
|
|
477
|
-
} while (this.match(
|
|
477
|
+
} while (this.match(TokenKind_1.TokenKind.Comma));
|
|
478
478
|
}
|
|
479
479
|
let rightParen = this.advance();
|
|
480
|
-
if (this.check(
|
|
480
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
481
481
|
asToken = this.advance();
|
|
482
482
|
typeToken = this.typeToken();
|
|
483
483
|
if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
|
|
@@ -529,7 +529,7 @@ class Parser {
|
|
|
529
529
|
}
|
|
530
530
|
// consume 'end sub' or 'end function'
|
|
531
531
|
func.end = this.advance();
|
|
532
|
-
let expectedEndKind = isSub ?
|
|
532
|
+
let expectedEndKind = isSub ? TokenKind_1.TokenKind.EndSub : TokenKind_1.TokenKind.EndFunction;
|
|
533
533
|
//if `function` is ended with `end sub`, or `sub` is ended with `end function`, then
|
|
534
534
|
//add an error but don't hard-fail so the AST can continue more gracefully
|
|
535
535
|
if (func.end.kind !== expectedEndKind) {
|
|
@@ -553,22 +553,22 @@ class Parser {
|
|
|
553
553
|
}
|
|
554
554
|
}
|
|
555
555
|
functionParameter() {
|
|
556
|
-
if (!this.checkAny(
|
|
556
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
|
|
557
557
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedParameterNameButFound(this.peek().text)), { range: this.peek().range }));
|
|
558
558
|
throw this.lastDiagnosticAsError();
|
|
559
559
|
}
|
|
560
|
-
const name = this.identifier(...
|
|
560
|
+
const name = this.identifier(...TokenKind_1.AllowedLocalIdentifiers);
|
|
561
561
|
let typeToken;
|
|
562
562
|
let defaultValue;
|
|
563
563
|
let equalsToken;
|
|
564
564
|
// parse argument default value
|
|
565
|
-
if (this.match(
|
|
565
|
+
if (this.match(TokenKind_1.TokenKind.Equal)) {
|
|
566
566
|
equalsToken = this.previous();
|
|
567
567
|
// it seems any expression is allowed here -- including ones that operate on other arguments!
|
|
568
568
|
defaultValue = this.expression();
|
|
569
569
|
}
|
|
570
570
|
let asToken = null;
|
|
571
|
-
if (this.check(
|
|
571
|
+
if (this.check(TokenKind_1.TokenKind.As)) {
|
|
572
572
|
asToken = this.advance();
|
|
573
573
|
typeToken = this.typeToken();
|
|
574
574
|
if (!util_1.util.tokenToBscType(typeToken, this.options.mode === ParseMode.BrighterScript, this.currentNamespaceName)) {
|
|
@@ -594,17 +594,20 @@ class Parser {
|
|
|
594
594
|
assignment() {
|
|
595
595
|
let name = this.identifier(...this.allowedLocalIdentifiers);
|
|
596
596
|
//add diagnostic if name is a reserved word that cannot be used as an identifier
|
|
597
|
-
if (
|
|
597
|
+
if (TokenKind_1.DisallowedLocalIdentifiersText.has(name.text.toLowerCase())) {
|
|
598
598
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.cannotUseReservedWordAsIdentifier(name.text)), { range: name.range }));
|
|
599
599
|
}
|
|
600
|
-
let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(
|
|
600
|
+
let operator = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOperatorAfterIdentifier(TokenKind_1.AssignmentOperators, name.text), ...TokenKind_1.AssignmentOperators);
|
|
601
601
|
let value = this.expression();
|
|
602
602
|
let result;
|
|
603
|
-
if (operator.kind ===
|
|
603
|
+
if (operator.kind === TokenKind_1.TokenKind.Equal) {
|
|
604
604
|
result = new Statement_1.AssignmentStatement(name, operator, value, this.currentFunctionExpression);
|
|
605
605
|
}
|
|
606
606
|
else {
|
|
607
607
|
result = new Statement_1.AssignmentStatement(name, operator, new Expression_1.BinaryExpression(new Expression_1.VariableExpression(name, this.currentNamespaceName), operator, value), this.currentFunctionExpression);
|
|
608
|
+
//remove the right-hand-side expression from this assignment operator, and replace with the full assignment expression
|
|
609
|
+
this._references.expressions.delete(value);
|
|
610
|
+
this._references.expressions.add(result);
|
|
608
611
|
}
|
|
609
612
|
this._references.assignmentStatements.push(result);
|
|
610
613
|
const assignmentType = getBscTypeFromExpression(result.value, this.currentFunctionExpression);
|
|
@@ -612,14 +615,14 @@ class Parser {
|
|
|
612
615
|
return result;
|
|
613
616
|
}
|
|
614
617
|
checkLibrary() {
|
|
615
|
-
let isLibraryToken = this.check(
|
|
618
|
+
let isLibraryToken = this.check(TokenKind_1.TokenKind.Library);
|
|
616
619
|
//if we are at the top level, any line that starts with "library" should be considered a library statement
|
|
617
620
|
if (this.isAtRootLevel() && isLibraryToken) {
|
|
618
621
|
return true;
|
|
619
622
|
//not at root level, library statements are all invalid here, but try to detect if the tokens look
|
|
620
623
|
//like a library statement (and let the libraryStatement function handle emitting the diagnostics)
|
|
621
624
|
}
|
|
622
|
-
else if (isLibraryToken && this.checkNext(
|
|
625
|
+
else if (isLibraryToken && this.checkNext(TokenKind_1.TokenKind.StringLiteral)) {
|
|
623
626
|
return true;
|
|
624
627
|
//definitely not a library statement
|
|
625
628
|
}
|
|
@@ -631,54 +634,54 @@ class Parser {
|
|
|
631
634
|
if (this.checkLibrary()) {
|
|
632
635
|
return this.libraryStatement();
|
|
633
636
|
}
|
|
634
|
-
if (this.check(
|
|
637
|
+
if (this.check(TokenKind_1.TokenKind.Import)) {
|
|
635
638
|
return this.importStatement();
|
|
636
639
|
}
|
|
637
|
-
if (this.check(
|
|
640
|
+
if (this.check(TokenKind_1.TokenKind.Stop)) {
|
|
638
641
|
return this.stopStatement();
|
|
639
642
|
}
|
|
640
|
-
if (this.check(
|
|
643
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
641
644
|
return this.ifStatement();
|
|
642
645
|
}
|
|
643
646
|
//`try` must be followed by a block, otherwise it could be a local variable
|
|
644
|
-
if (this.check(
|
|
647
|
+
if (this.check(TokenKind_1.TokenKind.Try) && this.checkAnyNext(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
|
|
645
648
|
return this.tryCatchStatement();
|
|
646
649
|
}
|
|
647
|
-
if (this.check(
|
|
650
|
+
if (this.check(TokenKind_1.TokenKind.Throw)) {
|
|
648
651
|
return this.throwStatement();
|
|
649
652
|
}
|
|
650
|
-
if (this.checkAny(
|
|
653
|
+
if (this.checkAny(TokenKind_1.TokenKind.Print, TokenKind_1.TokenKind.Question)) {
|
|
651
654
|
return this.printStatement();
|
|
652
655
|
}
|
|
653
|
-
if (this.check(
|
|
656
|
+
if (this.check(TokenKind_1.TokenKind.Dim)) {
|
|
654
657
|
return this.dimStatement();
|
|
655
658
|
}
|
|
656
|
-
if (this.check(
|
|
659
|
+
if (this.check(TokenKind_1.TokenKind.While)) {
|
|
657
660
|
return this.whileStatement();
|
|
658
661
|
}
|
|
659
|
-
if (this.check(
|
|
662
|
+
if (this.check(TokenKind_1.TokenKind.ExitWhile)) {
|
|
660
663
|
return this.exitWhile();
|
|
661
664
|
}
|
|
662
|
-
if (this.check(
|
|
665
|
+
if (this.check(TokenKind_1.TokenKind.For)) {
|
|
663
666
|
return this.forStatement();
|
|
664
667
|
}
|
|
665
|
-
if (this.check(
|
|
668
|
+
if (this.check(TokenKind_1.TokenKind.ForEach)) {
|
|
666
669
|
return this.forEachStatement();
|
|
667
670
|
}
|
|
668
|
-
if (this.check(
|
|
671
|
+
if (this.check(TokenKind_1.TokenKind.ExitFor)) {
|
|
669
672
|
return this.exitFor();
|
|
670
673
|
}
|
|
671
|
-
if (this.check(
|
|
674
|
+
if (this.check(TokenKind_1.TokenKind.End)) {
|
|
672
675
|
return this.endStatement();
|
|
673
676
|
}
|
|
674
|
-
if (this.match(
|
|
677
|
+
if (this.match(TokenKind_1.TokenKind.Return)) {
|
|
675
678
|
return this.returnStatement();
|
|
676
679
|
}
|
|
677
|
-
if (this.check(
|
|
680
|
+
if (this.check(TokenKind_1.TokenKind.Goto)) {
|
|
678
681
|
return this.gotoStatement();
|
|
679
682
|
}
|
|
680
683
|
//does this line look like a label? (i.e. `someIdentifier:` )
|
|
681
|
-
if (this.check(
|
|
684
|
+
if (this.check(TokenKind_1.TokenKind.Identifier) && this.checkNext(TokenKind_1.TokenKind.Colon) && this.checkPrevious(TokenKind_1.TokenKind.Newline)) {
|
|
682
685
|
try {
|
|
683
686
|
return this.labelStatement();
|
|
684
687
|
}
|
|
@@ -692,18 +695,18 @@ class Parser {
|
|
|
692
695
|
// BrightScript is like python, in that variables can be declared without a `var`,
|
|
693
696
|
// `let`, (...) keyword. As such, we must check the token *after* an identifier to figure
|
|
694
697
|
// out what to do with it.
|
|
695
|
-
if (this.checkAny(
|
|
696
|
-
this.checkAnyNext(...
|
|
698
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers) &&
|
|
699
|
+
this.checkAnyNext(...TokenKind_1.AssignmentOperators)) {
|
|
697
700
|
return this.assignment();
|
|
698
701
|
}
|
|
699
702
|
//some BrighterScript keywords are allowed as a local identifiers, so we need to check for them AFTER the assignment check
|
|
700
|
-
if (this.check(
|
|
703
|
+
if (this.check(TokenKind_1.TokenKind.Interface)) {
|
|
701
704
|
return this.interfaceDeclaration();
|
|
702
705
|
}
|
|
703
|
-
if (this.check(
|
|
706
|
+
if (this.check(TokenKind_1.TokenKind.Class)) {
|
|
704
707
|
return this.classDeclaration();
|
|
705
708
|
}
|
|
706
|
-
if (this.check(
|
|
709
|
+
if (this.check(TokenKind_1.TokenKind.Namespace)) {
|
|
707
710
|
return this.namespaceStatement();
|
|
708
711
|
}
|
|
709
712
|
// TODO: support multi-statements
|
|
@@ -713,9 +716,9 @@ class Parser {
|
|
|
713
716
|
const whileKeyword = this.advance();
|
|
714
717
|
const condition = this.expression();
|
|
715
718
|
this.consumeStatementSeparators();
|
|
716
|
-
const whileBlock = this.block(
|
|
719
|
+
const whileBlock = this.block(TokenKind_1.TokenKind.EndWhile);
|
|
717
720
|
let endWhile;
|
|
718
|
-
if (!whileBlock || this.peek().kind !==
|
|
721
|
+
if (!whileBlock || this.peek().kind !== TokenKind_1.TokenKind.EndWhile) {
|
|
719
722
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.couldNotFindMatchingEndKeyword('while')), { range: this.peek().range }));
|
|
720
723
|
if (!whileBlock) {
|
|
721
724
|
throw this.lastDiagnosticAsError();
|
|
@@ -738,7 +741,7 @@ class Parser {
|
|
|
738
741
|
const finalValue = this.expression();
|
|
739
742
|
let incrementExpression;
|
|
740
743
|
let stepToken;
|
|
741
|
-
if (this.check(
|
|
744
|
+
if (this.check(TokenKind_1.TokenKind.Step)) {
|
|
742
745
|
stepToken = this.advance();
|
|
743
746
|
incrementExpression = this.expression();
|
|
744
747
|
}
|
|
@@ -746,9 +749,9 @@ class Parser {
|
|
|
746
749
|
// BrightScript for/to/step loops default to a step of 1 if no `step` is provided
|
|
747
750
|
}
|
|
748
751
|
this.consumeStatementSeparators();
|
|
749
|
-
let body = this.block(
|
|
752
|
+
let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
|
|
750
753
|
let endForToken;
|
|
751
|
-
if (!body || !this.checkAny(
|
|
754
|
+
if (!body || !this.checkAny(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next)) {
|
|
752
755
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
|
|
753
756
|
if (!body) {
|
|
754
757
|
throw this.lastDiagnosticAsError();
|
|
@@ -765,7 +768,7 @@ class Parser {
|
|
|
765
768
|
let forEach = this.advance();
|
|
766
769
|
let name = this.identifier(...this.allowedLocalIdentifiers);
|
|
767
770
|
let maybeIn = this.peek();
|
|
768
|
-
if (this.check(
|
|
771
|
+
if (this.check(TokenKind_1.TokenKind.Identifier) && maybeIn.text.toLowerCase() === 'in') {
|
|
769
772
|
this.advance();
|
|
770
773
|
}
|
|
771
774
|
else {
|
|
@@ -778,14 +781,17 @@ class Parser {
|
|
|
778
781
|
throw this.lastDiagnosticAsError();
|
|
779
782
|
}
|
|
780
783
|
this.consumeStatementSeparators();
|
|
781
|
-
let body = this.block(
|
|
784
|
+
let body = this.block(TokenKind_1.TokenKind.EndFor, TokenKind_1.TokenKind.Next);
|
|
782
785
|
if (!body) {
|
|
783
786
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndForOrNextToTerminateForLoop()), { range: this.peek().range }));
|
|
784
787
|
throw this.lastDiagnosticAsError();
|
|
785
788
|
}
|
|
786
789
|
let endFor = this.advance();
|
|
787
|
-
|
|
788
|
-
const
|
|
790
|
+
let itemType = new DynamicType_1.DynamicType();
|
|
791
|
+
const targetType = getBscTypeFromExpression(target, this.currentFunctionExpression);
|
|
792
|
+
if ((0, reflection_1.isArrayType)(targetType)) {
|
|
793
|
+
itemType = targetType.getDefaultType();
|
|
794
|
+
}
|
|
789
795
|
this.currentSymbolTable.addSymbol(name.text, name.range, itemType);
|
|
790
796
|
return new Statement_1.ForEachStatement(forEach, name, maybeIn, target, body, endFor);
|
|
791
797
|
}
|
|
@@ -802,7 +808,7 @@ class Parser {
|
|
|
802
808
|
}
|
|
803
809
|
else {
|
|
804
810
|
let comments = [this.advance()];
|
|
805
|
-
while (this.check(
|
|
811
|
+
while (this.check(TokenKind_1.TokenKind.Newline) && this.checkNext(TokenKind_1.TokenKind.Comment)) {
|
|
806
812
|
this.advance();
|
|
807
813
|
comments.push(this.advance());
|
|
808
814
|
}
|
|
@@ -820,13 +826,13 @@ class Parser {
|
|
|
820
826
|
//set the current namespace name
|
|
821
827
|
let result = new Statement_1.NamespaceStatement(keyword, name, null, null, this.currentSymbolTable);
|
|
822
828
|
this.currentNamespace = result;
|
|
823
|
-
this.globalTerminators.push([
|
|
829
|
+
this.globalTerminators.push([TokenKind_1.TokenKind.EndNamespace]);
|
|
824
830
|
let body = this.body();
|
|
825
831
|
this.globalTerminators.pop();
|
|
826
832
|
//unset the current namespace name
|
|
827
833
|
this.currentNamespace = undefined;
|
|
828
834
|
let endKeyword;
|
|
829
|
-
if (this.check(
|
|
835
|
+
if (this.check(TokenKind_1.TokenKind.EndNamespace)) {
|
|
830
836
|
endKeyword = this.advance();
|
|
831
837
|
}
|
|
832
838
|
else {
|
|
@@ -843,24 +849,24 @@ class Parser {
|
|
|
843
849
|
* Get an expression with identifiers separated by periods. Useful for namespaces and class extends
|
|
844
850
|
*/
|
|
845
851
|
getNamespacedVariableNameExpression() {
|
|
846
|
-
let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text),
|
|
852
|
+
let firstIdentifier = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword(this.previous().text), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
847
853
|
let expr;
|
|
848
854
|
if (firstIdentifier) {
|
|
849
855
|
// force it into an identifier so the AST makes some sense
|
|
850
|
-
firstIdentifier.kind =
|
|
856
|
+
firstIdentifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
851
857
|
expr = new Expression_1.VariableExpression(firstIdentifier, null);
|
|
852
858
|
//consume multiple dot identifiers (i.e. `Name.Space.Can.Have.Many.Parts`)
|
|
853
|
-
while (this.check(
|
|
854
|
-
let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text),
|
|
859
|
+
while (this.check(TokenKind_1.TokenKind.Dot)) {
|
|
860
|
+
let dot = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.Dot);
|
|
855
861
|
if (!dot) {
|
|
856
862
|
break;
|
|
857
863
|
}
|
|
858
|
-
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
864
|
+
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers, ...TokenKind_1.AllowedProperties);
|
|
859
865
|
if (!identifier) {
|
|
860
866
|
break;
|
|
861
867
|
}
|
|
862
868
|
// force it into an identifier so the AST makes some sense
|
|
863
|
-
identifier.kind =
|
|
869
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
864
870
|
expr = new Expression_1.DottedGetExpression(expr, identifier, dot);
|
|
865
871
|
}
|
|
866
872
|
}
|
|
@@ -892,7 +898,7 @@ class Parser {
|
|
|
892
898
|
let libStatement = new Statement_1.LibraryStatement({
|
|
893
899
|
library: this.advance(),
|
|
894
900
|
//grab the next token only if it's a string
|
|
895
|
-
filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'),
|
|
901
|
+
filePath: this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('library'), TokenKind_1.TokenKind.StringLiteral)
|
|
896
902
|
});
|
|
897
903
|
this._references.libraryStatements.push(libStatement);
|
|
898
904
|
return libStatement;
|
|
@@ -901,20 +907,20 @@ class Parser {
|
|
|
901
907
|
this.warnIfNotBrighterScriptMode('import statements');
|
|
902
908
|
let importStatement = new Statement_1.ImportStatement(this.advance(),
|
|
903
909
|
//grab the next token only if it's a string
|
|
904
|
-
this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'),
|
|
910
|
+
this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedStringLiteralAfterKeyword('import'), TokenKind_1.TokenKind.StringLiteral));
|
|
905
911
|
this._references.importStatements.push(importStatement);
|
|
906
912
|
return importStatement;
|
|
907
913
|
}
|
|
908
914
|
annotationExpression() {
|
|
909
915
|
const atToken = this.advance();
|
|
910
|
-
const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
916
|
+
const identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
911
917
|
if (identifier) {
|
|
912
|
-
identifier.kind =
|
|
918
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
913
919
|
}
|
|
914
920
|
let annotation = new Expression_1.AnnotationExpression(atToken, identifier);
|
|
915
921
|
this.pendingAnnotations.push(annotation);
|
|
916
922
|
//optional arguments
|
|
917
|
-
if (this.check(
|
|
923
|
+
if (this.check(TokenKind_1.TokenKind.LeftParen)) {
|
|
918
924
|
let leftParen = this.advance();
|
|
919
925
|
annotation.call = this.finishCall(leftParen, annotation, false);
|
|
920
926
|
}
|
|
@@ -927,7 +933,7 @@ class Parser {
|
|
|
927
933
|
}
|
|
928
934
|
const questionMarkToken = this.advance();
|
|
929
935
|
//consume newlines or comments
|
|
930
|
-
while (this.checkAny(
|
|
936
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
931
937
|
this.advance();
|
|
932
938
|
}
|
|
933
939
|
let consequent;
|
|
@@ -936,12 +942,12 @@ class Parser {
|
|
|
936
942
|
}
|
|
937
943
|
catch (_a) { }
|
|
938
944
|
//consume newlines or comments
|
|
939
|
-
while (this.checkAny(
|
|
945
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
940
946
|
this.advance();
|
|
941
947
|
}
|
|
942
|
-
const colonToken = this.tryConsumeToken(
|
|
948
|
+
const colonToken = this.tryConsumeToken(TokenKind_1.TokenKind.Colon);
|
|
943
949
|
//consume newlines
|
|
944
|
-
while (this.checkAny(
|
|
950
|
+
while (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
945
951
|
this.advance();
|
|
946
952
|
}
|
|
947
953
|
let alternate;
|
|
@@ -959,7 +965,7 @@ class Parser {
|
|
|
959
965
|
}
|
|
960
966
|
regexLiteralExpression() {
|
|
961
967
|
this.warnIfNotBrighterScriptMode('regular expression literal');
|
|
962
|
-
return new
|
|
968
|
+
return new Expression_1.RegexLiteralExpression({
|
|
963
969
|
regexLiteral: this.advance()
|
|
964
970
|
});
|
|
965
971
|
}
|
|
@@ -968,23 +974,23 @@ class Parser {
|
|
|
968
974
|
//get the tag name
|
|
969
975
|
let tagName;
|
|
970
976
|
if (isTagged) {
|
|
971
|
-
tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
977
|
+
tagName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
972
978
|
// force it into an identifier so the AST makes some sense
|
|
973
|
-
tagName.kind =
|
|
979
|
+
tagName.kind = TokenKind_1.TokenKind.Identifier;
|
|
974
980
|
}
|
|
975
981
|
let quasis = [];
|
|
976
982
|
let expressions = [];
|
|
977
983
|
let openingBacktick = this.peek();
|
|
978
984
|
this.advance();
|
|
979
985
|
let currentQuasiExpressionParts = [];
|
|
980
|
-
while (!this.isAtEnd() && !this.check(
|
|
986
|
+
while (!this.isAtEnd() && !this.check(TokenKind_1.TokenKind.BackTick)) {
|
|
981
987
|
let next = this.peek();
|
|
982
|
-
if (next.kind ===
|
|
988
|
+
if (next.kind === TokenKind_1.TokenKind.TemplateStringQuasi) {
|
|
983
989
|
//a quasi can actually be made up of multiple quasis when it includes char literals
|
|
984
990
|
currentQuasiExpressionParts.push(new Expression_1.LiteralExpression(next));
|
|
985
991
|
this.advance();
|
|
986
992
|
}
|
|
987
|
-
else if (next.kind ===
|
|
993
|
+
else if (next.kind === TokenKind_1.TokenKind.EscapedCharCodeLiteral) {
|
|
988
994
|
currentQuasiExpressionParts.push(new Expression_1.EscapedCharCodeLiteralExpression(next));
|
|
989
995
|
this.advance();
|
|
990
996
|
}
|
|
@@ -992,12 +998,12 @@ class Parser {
|
|
|
992
998
|
//finish up the current quasi
|
|
993
999
|
quasis.push(new Expression_1.TemplateStringQuasiExpression(currentQuasiExpressionParts));
|
|
994
1000
|
currentQuasiExpressionParts = [];
|
|
995
|
-
if (next.kind ===
|
|
1001
|
+
if (next.kind === TokenKind_1.TokenKind.TemplateStringExpressionBegin) {
|
|
996
1002
|
this.advance();
|
|
997
1003
|
}
|
|
998
1004
|
//now keep this expression
|
|
999
1005
|
expressions.push(this.expression());
|
|
1000
|
-
if (!this.isAtEnd() && this.check(
|
|
1006
|
+
if (!this.isAtEnd() && this.check(TokenKind_1.TokenKind.TemplateStringExpressionEnd)) {
|
|
1001
1007
|
//TODO is it an error if this is not present?
|
|
1002
1008
|
this.advance();
|
|
1003
1009
|
}
|
|
@@ -1029,12 +1035,12 @@ class Parser {
|
|
|
1029
1035
|
const statement = new Statement_1.TryCatchStatement(tryToken);
|
|
1030
1036
|
//ensure statement separator
|
|
1031
1037
|
this.consumeStatementSeparators();
|
|
1032
|
-
statement.tryBranch = this.block(
|
|
1038
|
+
statement.tryBranch = this.block(TokenKind_1.TokenKind.Catch, TokenKind_1.TokenKind.EndTry);
|
|
1033
1039
|
const peek = this.peek();
|
|
1034
|
-
if (peek.kind !==
|
|
1040
|
+
if (peek.kind !== TokenKind_1.TokenKind.Catch) {
|
|
1035
1041
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedCatchBlockInTryCatch()), { range: this.peek().range }));
|
|
1036
1042
|
//gracefully handle end-try
|
|
1037
|
-
if (peek.kind ===
|
|
1043
|
+
if (peek.kind === TokenKind_1.TokenKind.EndTry) {
|
|
1038
1044
|
statement.endTryToken = this.advance();
|
|
1039
1045
|
}
|
|
1040
1046
|
return statement;
|
|
@@ -1042,16 +1048,16 @@ class Parser {
|
|
|
1042
1048
|
else {
|
|
1043
1049
|
statement.catchToken = this.advance();
|
|
1044
1050
|
}
|
|
1045
|
-
const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(),
|
|
1051
|
+
const exceptionVarToken = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingExceptionVarToFollowCatch(), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
1046
1052
|
if (exceptionVarToken) {
|
|
1047
1053
|
// force it into an identifier so the AST makes some sense
|
|
1048
|
-
exceptionVarToken.kind =
|
|
1054
|
+
exceptionVarToken.kind = TokenKind_1.TokenKind.Identifier;
|
|
1049
1055
|
statement.exceptionVariable = exceptionVarToken;
|
|
1050
1056
|
}
|
|
1051
1057
|
//ensure statement sepatator
|
|
1052
1058
|
this.consumeStatementSeparators();
|
|
1053
|
-
statement.catchBranch = this.block(
|
|
1054
|
-
if (this.peek().kind !==
|
|
1059
|
+
statement.catchBranch = this.block(TokenKind_1.TokenKind.EndTry);
|
|
1060
|
+
if (this.peek().kind !== TokenKind_1.TokenKind.EndTry) {
|
|
1055
1061
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedEndTryToTerminateTryCatch()), { range: this.peek().range }));
|
|
1056
1062
|
}
|
|
1057
1063
|
else {
|
|
@@ -1062,7 +1068,7 @@ class Parser {
|
|
|
1062
1068
|
throwStatement() {
|
|
1063
1069
|
const throwToken = this.advance();
|
|
1064
1070
|
let expression;
|
|
1065
|
-
if (this.checkAny(
|
|
1071
|
+
if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
1066
1072
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword()), { range: throwToken.range }));
|
|
1067
1073
|
}
|
|
1068
1074
|
else {
|
|
@@ -1072,19 +1078,19 @@ class Parser {
|
|
|
1072
1078
|
}
|
|
1073
1079
|
dimStatement() {
|
|
1074
1080
|
const dim = this.advance();
|
|
1075
|
-
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'),
|
|
1081
|
+
let identifier = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifierAfterKeyword('dim'), TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers);
|
|
1076
1082
|
// force to an identifier so the AST makes some sense
|
|
1077
1083
|
if (identifier) {
|
|
1078
|
-
identifier.kind =
|
|
1084
|
+
identifier.kind = TokenKind_1.TokenKind.Identifier;
|
|
1079
1085
|
}
|
|
1080
|
-
let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(),
|
|
1086
|
+
let leftSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingLeftSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.LeftSquareBracket);
|
|
1081
1087
|
let expressions = [];
|
|
1082
1088
|
let expression;
|
|
1083
1089
|
do {
|
|
1084
1090
|
try {
|
|
1085
1091
|
expression = this.expression();
|
|
1086
1092
|
expressions.push(expression);
|
|
1087
|
-
if (this.check(
|
|
1093
|
+
if (this.check(TokenKind_1.TokenKind.Comma)) {
|
|
1088
1094
|
this.advance();
|
|
1089
1095
|
}
|
|
1090
1096
|
else {
|
|
@@ -1098,15 +1104,15 @@ class Parser {
|
|
|
1098
1104
|
if (expressions.length === 0) {
|
|
1099
1105
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.missingExpressionsInDimStatement()), { range: this.peek().range }));
|
|
1100
1106
|
}
|
|
1101
|
-
let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(),
|
|
1107
|
+
let rightSquareBracket = this.tryConsume(DiagnosticMessages_1.DiagnosticMessages.missingRightSquareBracketAfterDimIdentifier(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
1102
1108
|
return new Statement_1.DimStatement(dim, identifier, leftSquareBracket, expressions, rightSquareBracket);
|
|
1103
1109
|
}
|
|
1104
1110
|
ifStatement() {
|
|
1105
1111
|
// colon before `if` is usually not allowed, unless it's after `then`
|
|
1106
1112
|
if (this.current > 0) {
|
|
1107
1113
|
const prev = this.previous();
|
|
1108
|
-
if (prev.kind ===
|
|
1109
|
-
if (this.current > 1 && this.tokens[this.current - 2].kind !==
|
|
1114
|
+
if (prev.kind === TokenKind_1.TokenKind.Colon) {
|
|
1115
|
+
if (this.current > 1 && this.tokens[this.current - 2].kind !== TokenKind_1.TokenKind.Then) {
|
|
1110
1116
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedColonBeforeIfStatement()), { range: prev.range }));
|
|
1111
1117
|
}
|
|
1112
1118
|
}
|
|
@@ -1120,14 +1126,14 @@ class Parser {
|
|
|
1120
1126
|
let endIfToken;
|
|
1121
1127
|
let elseToken;
|
|
1122
1128
|
//optional `then`
|
|
1123
|
-
if (this.check(
|
|
1129
|
+
if (this.check(TokenKind_1.TokenKind.Then)) {
|
|
1124
1130
|
thenToken = this.advance();
|
|
1125
1131
|
}
|
|
1126
1132
|
//is it inline or multi-line if?
|
|
1127
|
-
const isInlineIfThen = !this.checkAny(
|
|
1133
|
+
const isInlineIfThen = !this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment);
|
|
1128
1134
|
if (isInlineIfThen) {
|
|
1129
1135
|
/*** PARSE INLINE IF STATEMENT ***/
|
|
1130
|
-
thenBranch = this.inlineConditionalBranch(
|
|
1136
|
+
thenBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
|
|
1131
1137
|
if (!thenBranch) {
|
|
1132
1138
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedStatementToFollowConditionalCondition(ifToken.text)), { range: this.peek().range }));
|
|
1133
1139
|
throw this.lastDiagnosticAsError();
|
|
@@ -1136,9 +1142,9 @@ class Parser {
|
|
|
1136
1142
|
this.ensureInline(thenBranch.statements);
|
|
1137
1143
|
}
|
|
1138
1144
|
//else branch
|
|
1139
|
-
if (this.check(
|
|
1145
|
+
if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1140
1146
|
elseToken = this.advance();
|
|
1141
|
-
if (this.check(
|
|
1147
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
1142
1148
|
// recurse-read `else if`
|
|
1143
1149
|
elseBranch = this.ifStatement();
|
|
1144
1150
|
//no multi-line if chained with an inline if
|
|
@@ -1146,13 +1152,13 @@ class Parser {
|
|
|
1146
1152
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: elseBranch.range }));
|
|
1147
1153
|
}
|
|
1148
1154
|
}
|
|
1149
|
-
else if (this.checkAny(
|
|
1155
|
+
else if (this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
1150
1156
|
//expecting inline else branch
|
|
1151
1157
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedInlineIfStatement()), { range: this.peek().range }));
|
|
1152
1158
|
throw this.lastDiagnosticAsError();
|
|
1153
1159
|
}
|
|
1154
1160
|
else {
|
|
1155
|
-
elseBranch = this.inlineConditionalBranch(
|
|
1161
|
+
elseBranch = this.inlineConditionalBranch(TokenKind_1.TokenKind.Else, TokenKind_1.TokenKind.EndIf);
|
|
1156
1162
|
if (elseBranch) {
|
|
1157
1163
|
this.ensureInline(elseBranch.statements);
|
|
1158
1164
|
}
|
|
@@ -1166,9 +1172,9 @@ class Parser {
|
|
|
1166
1172
|
if (!elseBranch || !(0, reflection_1.isIfStatement)(elseBranch)) {
|
|
1167
1173
|
//enforce newline at the end of the inline if statement
|
|
1168
1174
|
const peek = this.peek();
|
|
1169
|
-
if (peek.kind !==
|
|
1175
|
+
if (peek.kind !== TokenKind_1.TokenKind.Newline && peek.kind !== TokenKind_1.TokenKind.Comment && !this.isAtEnd()) {
|
|
1170
1176
|
//ignore last error if it was about a colon
|
|
1171
|
-
if (this.previous().kind ===
|
|
1177
|
+
if (this.previous().kind === TokenKind_1.TokenKind.Colon) {
|
|
1172
1178
|
this.diagnostics.pop();
|
|
1173
1179
|
this.current--;
|
|
1174
1180
|
}
|
|
@@ -1183,9 +1189,9 @@ class Parser {
|
|
|
1183
1189
|
//ensure newline/colon before next keyword
|
|
1184
1190
|
this.ensureNewLineOrColon();
|
|
1185
1191
|
//else branch
|
|
1186
|
-
if (this.check(
|
|
1192
|
+
if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1187
1193
|
elseToken = this.advance();
|
|
1188
|
-
if (this.check(
|
|
1194
|
+
if (this.check(TokenKind_1.TokenKind.If)) {
|
|
1189
1195
|
// recurse-read `else if`
|
|
1190
1196
|
elseBranch = this.ifStatement();
|
|
1191
1197
|
}
|
|
@@ -1196,7 +1202,7 @@ class Parser {
|
|
|
1196
1202
|
}
|
|
1197
1203
|
}
|
|
1198
1204
|
if (!(0, reflection_1.isIfStatement)(elseBranch)) {
|
|
1199
|
-
if (this.check(
|
|
1205
|
+
if (this.check(TokenKind_1.TokenKind.EndIf)) {
|
|
1200
1206
|
endIfToken = this.advance();
|
|
1201
1207
|
}
|
|
1202
1208
|
else {
|
|
@@ -1219,7 +1225,7 @@ class Parser {
|
|
|
1219
1225
|
let diagnosticsLengthBeforeBlock = this.diagnostics.length;
|
|
1220
1226
|
// we're parsing a multi-line ("block") form of the BrightScript if/then and must find
|
|
1221
1227
|
// a trailing "end if" or "else if"
|
|
1222
|
-
let branch = this.block(
|
|
1228
|
+
let branch = this.block(TokenKind_1.TokenKind.EndIf, TokenKind_1.TokenKind.Else);
|
|
1223
1229
|
if (!branch) {
|
|
1224
1230
|
//throw out any new diagnostics created as a result of a `then` block parse failure.
|
|
1225
1231
|
//the block() function will discard the current line, so any discarded diagnostics will
|
|
@@ -1233,7 +1239,7 @@ class Parser {
|
|
|
1233
1239
|
}
|
|
1234
1240
|
ensureNewLineOrColon(silent = false) {
|
|
1235
1241
|
const prev = this.previous().kind;
|
|
1236
|
-
if (prev !==
|
|
1242
|
+
if (prev !== TokenKind_1.TokenKind.Newline && prev !== TokenKind_1.TokenKind.Colon) {
|
|
1237
1243
|
if (!silent) {
|
|
1238
1244
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()), { range: this.peek().range }));
|
|
1239
1245
|
}
|
|
@@ -1262,12 +1268,12 @@ class Parser {
|
|
|
1262
1268
|
const startingRange = statement.range;
|
|
1263
1269
|
//look for colon statement separator
|
|
1264
1270
|
let foundColon = false;
|
|
1265
|
-
while (this.match(
|
|
1271
|
+
while (this.match(TokenKind_1.TokenKind.Colon)) {
|
|
1266
1272
|
foundColon = true;
|
|
1267
1273
|
}
|
|
1268
1274
|
//if a colon was found, add the next statement or err if unexpected
|
|
1269
1275
|
if (foundColon) {
|
|
1270
|
-
if (!this.checkAny(
|
|
1276
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Newline, ...additionalTerminators)) {
|
|
1271
1277
|
//if not an ending keyword, add next statement
|
|
1272
1278
|
let extra = this.inlineConditionalBranch(...additionalTerminators);
|
|
1273
1279
|
if (!extra) {
|
|
@@ -1285,9 +1291,9 @@ class Parser {
|
|
|
1285
1291
|
}
|
|
1286
1292
|
expressionStatement(expr) {
|
|
1287
1293
|
let expressionStart = this.peek();
|
|
1288
|
-
if (this.checkAny(
|
|
1294
|
+
if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
|
|
1289
1295
|
let operator = this.advance();
|
|
1290
|
-
if (this.checkAny(
|
|
1296
|
+
if (this.checkAny(TokenKind_1.TokenKind.PlusPlus, TokenKind_1.TokenKind.MinusMinus)) {
|
|
1291
1297
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.consecutiveIncrementDecrementOperatorsAreNotAllowed()), { range: this.peek().range }));
|
|
1292
1298
|
throw this.lastDiagnosticAsError();
|
|
1293
1299
|
}
|
|
@@ -1295,7 +1301,9 @@ class Parser {
|
|
|
1295
1301
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.incrementDecrementOperatorsAreNotAllowedAsResultOfFunctionCall()), { range: expressionStart.range }));
|
|
1296
1302
|
throw this.lastDiagnosticAsError();
|
|
1297
1303
|
}
|
|
1298
|
-
|
|
1304
|
+
const result = new Statement_1.IncrementStatement(expr, operator);
|
|
1305
|
+
this._references.expressions.add(result);
|
|
1306
|
+
return result;
|
|
1299
1307
|
}
|
|
1300
1308
|
if ((0, reflection_1.isCallExpression)(expr) || (0, reflection_1.isCallfuncExpression)(expr)) {
|
|
1301
1309
|
return new Statement_1.ExpressionStatement(expr);
|
|
@@ -1312,18 +1320,18 @@ class Parser {
|
|
|
1312
1320
|
* priority as standalone function calls though, so we can parse them in the same way.
|
|
1313
1321
|
*/
|
|
1314
1322
|
let expr = this.call();
|
|
1315
|
-
if (this.checkAny(...
|
|
1323
|
+
if (this.checkAny(...TokenKind_1.AssignmentOperators) && !((0, reflection_1.isCallExpression)(expr))) {
|
|
1316
1324
|
let left = expr;
|
|
1317
1325
|
let operator = this.advance();
|
|
1318
1326
|
let right = this.expression();
|
|
1319
1327
|
// Create a dotted or indexed "set" based on the left-hand side's type
|
|
1320
1328
|
if ((0, reflection_1.isIndexedGetExpression)(left)) {
|
|
1321
|
-
return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind ===
|
|
1329
|
+
return new Statement_1.IndexedSetStatement(left.obj, left.index, operator.kind === TokenKind_1.TokenKind.Equal
|
|
1322
1330
|
? right
|
|
1323
1331
|
: new Expression_1.BinaryExpression(left, operator, right), left.openingSquare, left.closingSquare);
|
|
1324
1332
|
}
|
|
1325
1333
|
else if ((0, reflection_1.isDottedGetExpression)(left)) {
|
|
1326
|
-
const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind ===
|
|
1334
|
+
const dottedSetStmt = new Statement_1.DottedSetStatement(left.obj, left.name, operator.kind === TokenKind_1.TokenKind.Equal
|
|
1327
1335
|
? right
|
|
1328
1336
|
: new Expression_1.BinaryExpression(left, operator, right));
|
|
1329
1337
|
this._references.dottedSetStatements.push(dottedSetStmt);
|
|
@@ -1336,13 +1344,13 @@ class Parser {
|
|
|
1336
1344
|
let printKeyword = this.advance();
|
|
1337
1345
|
let values = [];
|
|
1338
1346
|
while (!this.checkEndOfStatement()) {
|
|
1339
|
-
if (this.check(
|
|
1347
|
+
if (this.check(TokenKind_1.TokenKind.Semicolon)) {
|
|
1340
1348
|
values.push(this.advance());
|
|
1341
1349
|
}
|
|
1342
|
-
else if (this.check(
|
|
1350
|
+
else if (this.check(TokenKind_1.TokenKind.Comma)) {
|
|
1343
1351
|
values.push(this.advance());
|
|
1344
1352
|
}
|
|
1345
|
-
else if (this.check(
|
|
1353
|
+
else if (this.check(TokenKind_1.TokenKind.Else)) {
|
|
1346
1354
|
break; // inline branch
|
|
1347
1355
|
}
|
|
1348
1356
|
else {
|
|
@@ -1355,7 +1363,7 @@ class Parser {
|
|
|
1355
1363
|
values.push(emptyStringLiteral);
|
|
1356
1364
|
}
|
|
1357
1365
|
let last = values[values.length - 1];
|
|
1358
|
-
if ((0,
|
|
1366
|
+
if ((0, Token_1.isToken)(last)) {
|
|
1359
1367
|
// TODO: error, expected value
|
|
1360
1368
|
}
|
|
1361
1369
|
return new Statement_1.PrintStatement({ print: printKeyword }, values);
|
|
@@ -1369,7 +1377,7 @@ class Parser {
|
|
|
1369
1377
|
if (this.checkEndOfStatement()) {
|
|
1370
1378
|
return new Statement_1.ReturnStatement(tokens);
|
|
1371
1379
|
}
|
|
1372
|
-
let toReturn = this.check(
|
|
1380
|
+
let toReturn = this.check(TokenKind_1.TokenKind.Else) ? undefined : this.expression();
|
|
1373
1381
|
return new Statement_1.ReturnStatement(tokens, toReturn);
|
|
1374
1382
|
}
|
|
1375
1383
|
/**
|
|
@@ -1382,7 +1390,7 @@ class Parser {
|
|
|
1382
1390
|
colon: this.advance()
|
|
1383
1391
|
};
|
|
1384
1392
|
//label must be alone on its line, this is probably not a label
|
|
1385
|
-
if (!this.checkAny(
|
|
1393
|
+
if (!this.checkAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
1386
1394
|
//rewind and cancel
|
|
1387
1395
|
this.current -= 2;
|
|
1388
1396
|
throw new CancelStatementError();
|
|
@@ -1398,7 +1406,7 @@ class Parser {
|
|
|
1398
1406
|
gotoStatement() {
|
|
1399
1407
|
let tokens = {
|
|
1400
1408
|
goto: this.advance(),
|
|
1401
|
-
label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(),
|
|
1409
|
+
label: this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedLabelIdentifierAfterGotoKeyword(), TokenKind_1.TokenKind.Identifier)
|
|
1402
1410
|
};
|
|
1403
1411
|
return new Statement_1.GotoStatement(tokens);
|
|
1404
1412
|
}
|
|
@@ -1429,7 +1437,7 @@ class Parser {
|
|
|
1429
1437
|
this.consumeStatementSeparators(true);
|
|
1430
1438
|
let startingToken = this.peek();
|
|
1431
1439
|
const statements = [];
|
|
1432
|
-
while (!this.isAtEnd() && !this.checkAny(
|
|
1440
|
+
while (!this.isAtEnd() && !this.checkAny(TokenKind_1.TokenKind.EndSub, TokenKind_1.TokenKind.EndFunction, ...terminators)) {
|
|
1433
1441
|
//grab the location of the current token
|
|
1434
1442
|
let loopCurrent = this.current;
|
|
1435
1443
|
let dec = this.declaration();
|
|
@@ -1445,7 +1453,7 @@ class Parser {
|
|
|
1445
1453
|
//something went wrong. reset to the top of the loop
|
|
1446
1454
|
this.current = loopCurrent;
|
|
1447
1455
|
//scrap the entire line (hopefully whatever failed has added a diagnostic)
|
|
1448
|
-
this.consumeUntil(
|
|
1456
|
+
this.consumeUntil(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Eof);
|
|
1449
1457
|
//trash the next token. this prevents an infinite loop. not exactly sure why we need this,
|
|
1450
1458
|
//but there's already an error in the file being parsed, so just leave this line here
|
|
1451
1459
|
this.advance();
|
|
@@ -1462,8 +1470,8 @@ class Parser {
|
|
|
1462
1470
|
//if so, we need to restore the statement separator
|
|
1463
1471
|
let prev = this.previous().kind;
|
|
1464
1472
|
let peek = this.peek().kind;
|
|
1465
|
-
if ((peek ===
|
|
1466
|
-
(prev ===
|
|
1473
|
+
if ((peek === TokenKind_1.TokenKind.EndSub || peek === TokenKind_1.TokenKind.EndFunction) &&
|
|
1474
|
+
(prev === TokenKind_1.TokenKind.Newline || prev === TokenKind_1.TokenKind.Colon)) {
|
|
1467
1475
|
this.current--;
|
|
1468
1476
|
}
|
|
1469
1477
|
}
|
|
@@ -1495,13 +1503,15 @@ class Parser {
|
|
|
1495
1503
|
this.pendingAnnotations = parentAnnotations;
|
|
1496
1504
|
}
|
|
1497
1505
|
expression() {
|
|
1498
|
-
|
|
1506
|
+
const expression = this.anonymousFunction();
|
|
1507
|
+
this._references.expressions.add(expression);
|
|
1508
|
+
return expression;
|
|
1499
1509
|
}
|
|
1500
1510
|
anonymousFunction() {
|
|
1501
|
-
if (this.checkAny(
|
|
1511
|
+
if (this.checkAny(TokenKind_1.TokenKind.Sub, TokenKind_1.TokenKind.Function)) {
|
|
1502
1512
|
const func = this.functionDeclaration(true);
|
|
1503
1513
|
//if there's an open paren after this, this is an IIFE
|
|
1504
|
-
if (this.check(
|
|
1514
|
+
if (this.check(TokenKind_1.TokenKind.LeftParen)) {
|
|
1505
1515
|
return this.finishCall(this.advance(), func);
|
|
1506
1516
|
}
|
|
1507
1517
|
else {
|
|
@@ -1509,10 +1519,10 @@ class Parser {
|
|
|
1509
1519
|
}
|
|
1510
1520
|
}
|
|
1511
1521
|
let expr = this.boolean();
|
|
1512
|
-
if (this.check(
|
|
1522
|
+
if (this.check(TokenKind_1.TokenKind.Question)) {
|
|
1513
1523
|
return this.ternaryExpression(expr);
|
|
1514
1524
|
}
|
|
1515
|
-
else if (this.check(
|
|
1525
|
+
else if (this.check(TokenKind_1.TokenKind.QuestionQuestion)) {
|
|
1516
1526
|
return this.nullCoalescingExpression(expr);
|
|
1517
1527
|
}
|
|
1518
1528
|
else {
|
|
@@ -1521,7 +1531,7 @@ class Parser {
|
|
|
1521
1531
|
}
|
|
1522
1532
|
boolean() {
|
|
1523
1533
|
let expr = this.relational();
|
|
1524
|
-
while (this.matchAny(
|
|
1534
|
+
while (this.matchAny(TokenKind_1.TokenKind.And, TokenKind_1.TokenKind.Or)) {
|
|
1525
1535
|
let operator = this.previous();
|
|
1526
1536
|
let right = this.relational();
|
|
1527
1537
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1530,7 +1540,7 @@ class Parser {
|
|
|
1530
1540
|
}
|
|
1531
1541
|
relational() {
|
|
1532
1542
|
let expr = this.additive();
|
|
1533
|
-
while (this.matchAny(
|
|
1543
|
+
while (this.matchAny(TokenKind_1.TokenKind.Equal, TokenKind_1.TokenKind.LessGreater, TokenKind_1.TokenKind.Greater, TokenKind_1.TokenKind.GreaterEqual, TokenKind_1.TokenKind.Less, TokenKind_1.TokenKind.LessEqual)) {
|
|
1534
1544
|
let operator = this.previous();
|
|
1535
1545
|
let right = this.additive();
|
|
1536
1546
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1540,7 +1550,7 @@ class Parser {
|
|
|
1540
1550
|
// TODO: bitshift
|
|
1541
1551
|
additive() {
|
|
1542
1552
|
let expr = this.multiplicative();
|
|
1543
|
-
while (this.matchAny(
|
|
1553
|
+
while (this.matchAny(TokenKind_1.TokenKind.Plus, TokenKind_1.TokenKind.Minus)) {
|
|
1544
1554
|
let operator = this.previous();
|
|
1545
1555
|
let right = this.multiplicative();
|
|
1546
1556
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1549,7 +1559,7 @@ class Parser {
|
|
|
1549
1559
|
}
|
|
1550
1560
|
multiplicative() {
|
|
1551
1561
|
let expr = this.exponential();
|
|
1552
|
-
while (this.matchAny(
|
|
1562
|
+
while (this.matchAny(TokenKind_1.TokenKind.Forwardslash, TokenKind_1.TokenKind.Backslash, TokenKind_1.TokenKind.Star, TokenKind_1.TokenKind.Mod, TokenKind_1.TokenKind.LeftShift, TokenKind_1.TokenKind.RightShift)) {
|
|
1553
1563
|
let operator = this.previous();
|
|
1554
1564
|
let right = this.exponential();
|
|
1555
1565
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1558,7 +1568,7 @@ class Parser {
|
|
|
1558
1568
|
}
|
|
1559
1569
|
exponential() {
|
|
1560
1570
|
let expr = this.prefixUnary();
|
|
1561
|
-
while (this.match(
|
|
1571
|
+
while (this.match(TokenKind_1.TokenKind.Caret)) {
|
|
1562
1572
|
let operator = this.previous();
|
|
1563
1573
|
let right = this.prefixUnary();
|
|
1564
1574
|
expr = new Expression_1.BinaryExpression(expr, operator, right);
|
|
@@ -1567,7 +1577,7 @@ class Parser {
|
|
|
1567
1577
|
}
|
|
1568
1578
|
prefixUnary() {
|
|
1569
1579
|
const nextKind = this.peek().kind;
|
|
1570
|
-
if (nextKind ===
|
|
1580
|
+
if (nextKind === TokenKind_1.TokenKind.Not || nextKind === TokenKind_1.TokenKind.Minus) {
|
|
1571
1581
|
this.current++; //advance
|
|
1572
1582
|
let operator = this.previous();
|
|
1573
1583
|
let right = this.prefixUnary();
|
|
@@ -1577,17 +1587,17 @@ class Parser {
|
|
|
1577
1587
|
}
|
|
1578
1588
|
indexedGet(expr) {
|
|
1579
1589
|
let openingSquare = this.previous();
|
|
1580
|
-
while (this.match(
|
|
1590
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1581
1591
|
let index = this.expression();
|
|
1582
|
-
while (this.match(
|
|
1583
|
-
let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(),
|
|
1592
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1593
|
+
let closingSquare = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightSquareBraceAfterArrayOrObjectIndex(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
1584
1594
|
return new Expression_1.IndexedGetExpression(expr, index, openingSquare, closingSquare);
|
|
1585
1595
|
}
|
|
1586
1596
|
newExpression() {
|
|
1587
1597
|
this.warnIfNotBrighterScriptMode(`using 'new' keyword to construct a class`);
|
|
1588
1598
|
let newToken = this.advance();
|
|
1589
1599
|
let nameExpr = this.getNamespacedVariableNameExpression();
|
|
1590
|
-
let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text),
|
|
1600
|
+
let leftParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.unexpectedToken(this.peek().text), TokenKind_1.TokenKind.LeftParen);
|
|
1591
1601
|
let call = this.finishCall(leftParen, nameExpr);
|
|
1592
1602
|
//pop the call from the callExpressions list because this is technically something else
|
|
1593
1603
|
this.callExpressions.pop();
|
|
@@ -1601,46 +1611,52 @@ class Parser {
|
|
|
1601
1611
|
callfunc(callee) {
|
|
1602
1612
|
this.warnIfNotBrighterScriptMode('callfunc operator');
|
|
1603
1613
|
let operator = this.previous();
|
|
1604
|
-
let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(),
|
|
1614
|
+
let methodName = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedIdentifier(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1605
1615
|
// force it into an identifier so the AST makes some sense
|
|
1606
|
-
methodName.kind =
|
|
1607
|
-
let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(),
|
|
1616
|
+
methodName.kind = TokenKind_1.TokenKind.Identifier;
|
|
1617
|
+
let openParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedOpenParenToFollowCallfuncIdentifier(), TokenKind_1.TokenKind.LeftParen);
|
|
1608
1618
|
let call = this.finishCall(openParen, callee, false);
|
|
1609
1619
|
return new Expression_1.CallfuncExpression(callee, operator, methodName, openParen, call.args, call.closingParen);
|
|
1610
1620
|
}
|
|
1611
1621
|
call() {
|
|
1612
|
-
if (this.check(
|
|
1622
|
+
if (this.check(TokenKind_1.TokenKind.New) && this.checkAnyNext(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
|
|
1613
1623
|
return this.newExpression();
|
|
1614
1624
|
}
|
|
1615
1625
|
let expr = this.primary();
|
|
1626
|
+
//an expression to keep for _references
|
|
1627
|
+
let referenceCallExpression;
|
|
1616
1628
|
while (true) {
|
|
1617
|
-
if (this.match(
|
|
1629
|
+
if (this.match(TokenKind_1.TokenKind.LeftParen)) {
|
|
1618
1630
|
expr = this.finishCall(this.previous(), expr);
|
|
1631
|
+
//store this call expression in references
|
|
1632
|
+
referenceCallExpression = expr;
|
|
1619
1633
|
}
|
|
1620
|
-
else if (this.match(
|
|
1634
|
+
else if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1621
1635
|
expr = this.indexedGet(expr);
|
|
1622
1636
|
}
|
|
1623
|
-
else if (this.match(
|
|
1637
|
+
else if (this.match(TokenKind_1.TokenKind.Callfunc)) {
|
|
1624
1638
|
expr = this.callfunc(expr);
|
|
1639
|
+
//store this callfunc expression in references
|
|
1640
|
+
referenceCallExpression = expr;
|
|
1625
1641
|
}
|
|
1626
|
-
else if (this.match(
|
|
1627
|
-
if (this.match(
|
|
1642
|
+
else if (this.match(TokenKind_1.TokenKind.Dot)) {
|
|
1643
|
+
if (this.match(TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1628
1644
|
expr = this.indexedGet(expr);
|
|
1629
1645
|
}
|
|
1630
1646
|
else {
|
|
1631
1647
|
let dot = this.previous();
|
|
1632
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(),
|
|
1648
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedPropertyNameAfterPeriod(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1633
1649
|
// force it into an identifier so the AST makes some sense
|
|
1634
|
-
name.kind =
|
|
1650
|
+
name.kind = TokenKind_1.TokenKind.Identifier;
|
|
1635
1651
|
expr = new Expression_1.DottedGetExpression(expr, name, dot);
|
|
1636
1652
|
this.addPropertyHints(name);
|
|
1637
1653
|
}
|
|
1638
1654
|
}
|
|
1639
|
-
else if (this.check(
|
|
1655
|
+
else if (this.check(TokenKind_1.TokenKind.At)) {
|
|
1640
1656
|
let dot = this.advance();
|
|
1641
|
-
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(),
|
|
1657
|
+
let name = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedAttributeNameAfterAtSymbol(), TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties);
|
|
1642
1658
|
// force it into an identifier so the AST makes some sense
|
|
1643
|
-
name.kind =
|
|
1659
|
+
name.kind = TokenKind_1.TokenKind.Identifier;
|
|
1644
1660
|
expr = new Expression_1.XmlAttributeGetExpression(expr, name, dot);
|
|
1645
1661
|
//only allow a single `@` expression
|
|
1646
1662
|
break;
|
|
@@ -1649,24 +1665,28 @@ class Parser {
|
|
|
1649
1665
|
break;
|
|
1650
1666
|
}
|
|
1651
1667
|
}
|
|
1668
|
+
//if we found a callExpression, add it to `expressions` in references
|
|
1669
|
+
if (referenceCallExpression) {
|
|
1670
|
+
this._references.expressions.add(referenceCallExpression);
|
|
1671
|
+
}
|
|
1652
1672
|
return expr;
|
|
1653
1673
|
}
|
|
1654
1674
|
finishCall(openingParen, callee, addToCallExpressionList = true) {
|
|
1655
1675
|
let args = [];
|
|
1656
|
-
while (this.match(
|
|
1676
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1657
1677
|
}
|
|
1658
|
-
if (!this.check(
|
|
1678
|
+
if (!this.check(TokenKind_1.TokenKind.RightParen)) {
|
|
1659
1679
|
do {
|
|
1660
|
-
while (this.match(
|
|
1680
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1661
1681
|
if (args.length >= Expression_1.CallExpression.MaximumArguments) {
|
|
1662
1682
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.tooManyCallableArguments(args.length, Expression_1.CallExpression.MaximumArguments)), { range: this.peek().range }));
|
|
1663
1683
|
throw this.lastDiagnosticAsError();
|
|
1664
1684
|
}
|
|
1665
1685
|
args.push(this.expression());
|
|
1666
|
-
} while (this.match(
|
|
1686
|
+
} while (this.match(TokenKind_1.TokenKind.Comma));
|
|
1667
1687
|
}
|
|
1668
|
-
while (this.match(
|
|
1669
|
-
const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(),
|
|
1688
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) { }
|
|
1689
|
+
const closingParen = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(), TokenKind_1.TokenKind.RightParen);
|
|
1670
1690
|
if ((0, reflection_1.isVariableExpression)(callee)) {
|
|
1671
1691
|
callee.isCalled = true;
|
|
1672
1692
|
}
|
|
@@ -1683,15 +1703,15 @@ class Parser {
|
|
|
1683
1703
|
*/
|
|
1684
1704
|
typeToken() {
|
|
1685
1705
|
let typeToken;
|
|
1686
|
-
if (this.checkAny(...
|
|
1706
|
+
if (this.checkAny(...TokenKind_1.DeclarableTypes)) {
|
|
1687
1707
|
// Token is a built in type
|
|
1688
1708
|
typeToken = this.advance();
|
|
1689
1709
|
}
|
|
1690
1710
|
else if (this.options.mode === ParseMode.BrighterScript) {
|
|
1691
1711
|
try {
|
|
1692
|
-
// see if we can get a namespaced
|
|
1712
|
+
// see if we can get a namespaced identifier
|
|
1693
1713
|
const qualifiedType = this.getNamespacedVariableNameExpression();
|
|
1694
|
-
typeToken = (0, creators_1.createToken)(
|
|
1714
|
+
typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, qualifiedType.getName(this.options.mode), qualifiedType.range);
|
|
1695
1715
|
}
|
|
1696
1716
|
catch (_a) {
|
|
1697
1717
|
//could not get an identifier - just get whatever's next
|
|
@@ -1702,57 +1722,68 @@ class Parser {
|
|
|
1702
1722
|
// just get whatever's next
|
|
1703
1723
|
typeToken = this.advance();
|
|
1704
1724
|
}
|
|
1725
|
+
if (typeToken && this.options.mode === ParseMode.BrighterScript) {
|
|
1726
|
+
// Check if it is an array - that is, if it has `[]` after the type
|
|
1727
|
+
// eg. `string[]` or `SomeKlass[]`
|
|
1728
|
+
if (this.check(TokenKind_1.TokenKind.LeftSquareBracket)) {
|
|
1729
|
+
this.advance();
|
|
1730
|
+
if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1731
|
+
const rightBracket = this.advance();
|
|
1732
|
+
typeToken = (0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, typeToken.text + '[]', util_1.util.getRange(typeToken, rightBracket));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1705
1736
|
return typeToken;
|
|
1706
1737
|
}
|
|
1707
1738
|
primary() {
|
|
1708
1739
|
switch (true) {
|
|
1709
|
-
case this.matchAny(
|
|
1740
|
+
case this.matchAny(TokenKind_1.TokenKind.False, TokenKind_1.TokenKind.True, TokenKind_1.TokenKind.Invalid, TokenKind_1.TokenKind.IntegerLiteral, TokenKind_1.TokenKind.LongIntegerLiteral, TokenKind_1.TokenKind.FloatLiteral, TokenKind_1.TokenKind.DoubleLiteral, TokenKind_1.TokenKind.StringLiteral):
|
|
1710
1741
|
return new Expression_1.LiteralExpression(this.previous());
|
|
1711
1742
|
//capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript)
|
|
1712
|
-
case this.matchAny(
|
|
1743
|
+
case this.matchAny(TokenKind_1.TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : TokenKind_1.BrighterScriptSourceLiterals)):
|
|
1713
1744
|
return new Expression_1.SourceLiteralExpression(this.previous());
|
|
1714
1745
|
//template string
|
|
1715
|
-
case this.check(
|
|
1746
|
+
case this.check(TokenKind_1.TokenKind.BackTick):
|
|
1716
1747
|
return this.templateString(false);
|
|
1717
1748
|
//tagged template string (currently we do not support spaces between the identifier and the backtick)
|
|
1718
|
-
case this.checkAny(
|
|
1749
|
+
case this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers) && this.checkNext(TokenKind_1.TokenKind.BackTick):
|
|
1719
1750
|
return this.templateString(true);
|
|
1720
|
-
case this.matchAny(
|
|
1751
|
+
case this.matchAny(TokenKind_1.TokenKind.Identifier, ...this.allowedLocalIdentifiers):
|
|
1721
1752
|
return new Expression_1.VariableExpression(this.previous(), this.currentNamespaceName);
|
|
1722
|
-
case this.match(
|
|
1753
|
+
case this.match(TokenKind_1.TokenKind.LeftParen):
|
|
1723
1754
|
let left = this.previous();
|
|
1724
1755
|
let expr = this.expression();
|
|
1725
|
-
let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(),
|
|
1756
|
+
let right = this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftParenAfterExpression(), TokenKind_1.TokenKind.RightParen);
|
|
1726
1757
|
return new Expression_1.GroupingExpression({ left: left, right: right }, expr);
|
|
1727
|
-
case this.match(
|
|
1758
|
+
case this.match(TokenKind_1.TokenKind.LeftSquareBracket):
|
|
1728
1759
|
let elements = [];
|
|
1729
1760
|
let openingSquare = this.previous();
|
|
1730
1761
|
//add any comment found right after the opening square
|
|
1731
|
-
if (this.check(
|
|
1762
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1732
1763
|
elements.push(new Statement_1.CommentStatement([this.advance()]));
|
|
1733
1764
|
}
|
|
1734
|
-
while (this.match(
|
|
1765
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1735
1766
|
}
|
|
1736
|
-
if (!this.match(
|
|
1767
|
+
if (!this.match(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1737
1768
|
elements.push(this.expression());
|
|
1738
|
-
while (this.matchAny(
|
|
1739
|
-
if (this.checkPrevious(
|
|
1740
|
-
let comment = this.check(
|
|
1769
|
+
while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment)) {
|
|
1770
|
+
if (this.checkPrevious(TokenKind_1.TokenKind.Comment) || this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1771
|
+
let comment = this.check(TokenKind_1.TokenKind.Comment) ? this.advance() : this.previous();
|
|
1741
1772
|
elements.push(new Statement_1.CommentStatement([comment]));
|
|
1742
1773
|
}
|
|
1743
|
-
while (this.match(
|
|
1774
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1744
1775
|
}
|
|
1745
|
-
if (this.check(
|
|
1776
|
+
if (this.check(TokenKind_1.TokenKind.RightSquareBracket)) {
|
|
1746
1777
|
break;
|
|
1747
1778
|
}
|
|
1748
1779
|
elements.push(this.expression());
|
|
1749
1780
|
}
|
|
1750
|
-
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(),
|
|
1781
|
+
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftSquareBraceAfterArrayLiteral(), TokenKind_1.TokenKind.RightSquareBracket);
|
|
1751
1782
|
}
|
|
1752
1783
|
let closingSquare = this.previous();
|
|
1753
1784
|
//this.consume("Expected newline or ':' after array literal", TokenKind.Newline, TokenKind.Colon, TokenKind.Eof);
|
|
1754
1785
|
return new Expression_1.ArrayLiteralExpression(elements, openingSquare, closingSquare);
|
|
1755
|
-
case this.match(
|
|
1786
|
+
case this.match(TokenKind_1.TokenKind.LeftCurlyBrace):
|
|
1756
1787
|
let openingBrace = this.previous();
|
|
1757
1788
|
let members = [];
|
|
1758
1789
|
let key = () => {
|
|
@@ -1761,25 +1792,25 @@ class Parser {
|
|
|
1761
1792
|
keyToken: null,
|
|
1762
1793
|
range: null
|
|
1763
1794
|
};
|
|
1764
|
-
if (this.checkAny(
|
|
1795
|
+
if (this.checkAny(TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedProperties)) {
|
|
1765
1796
|
result.keyToken = this.advance();
|
|
1766
1797
|
}
|
|
1767
|
-
else if (this.check(
|
|
1798
|
+
else if (this.check(TokenKind_1.TokenKind.StringLiteral)) {
|
|
1768
1799
|
result.keyToken = this.advance();
|
|
1769
1800
|
}
|
|
1770
1801
|
else {
|
|
1771
1802
|
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unexpectedAAKey()), { range: this.peek().range }));
|
|
1772
1803
|
throw this.lastDiagnosticAsError();
|
|
1773
1804
|
}
|
|
1774
|
-
result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(),
|
|
1805
|
+
result.colonToken = this.consume(DiagnosticMessages_1.DiagnosticMessages.expectedColonBetweenAAKeyAndvalue(), TokenKind_1.TokenKind.Colon);
|
|
1775
1806
|
result.range = util_1.util.getRange(result.keyToken, result.colonToken);
|
|
1776
1807
|
return result;
|
|
1777
1808
|
};
|
|
1778
|
-
while (this.match(
|
|
1809
|
+
while (this.match(TokenKind_1.TokenKind.Newline)) {
|
|
1779
1810
|
}
|
|
1780
|
-
if (!this.match(
|
|
1811
|
+
if (!this.match(TokenKind_1.TokenKind.RightCurlyBrace)) {
|
|
1781
1812
|
let lastAAMember;
|
|
1782
|
-
if (this.check(
|
|
1813
|
+
if (this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1783
1814
|
lastAAMember = null;
|
|
1784
1815
|
members.push(new Statement_1.CommentStatement([this.advance()]));
|
|
1785
1816
|
}
|
|
@@ -1789,26 +1820,26 @@ class Parser {
|
|
|
1789
1820
|
lastAAMember = new Expression_1.AAMemberExpression(k.keyToken, k.colonToken, expr, getBscTypeFromExpression(expr, this.currentFunctionExpression));
|
|
1790
1821
|
members.push(lastAAMember);
|
|
1791
1822
|
}
|
|
1792
|
-
while (this.matchAny(
|
|
1823
|
+
while (this.matchAny(TokenKind_1.TokenKind.Comma, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Comment)) {
|
|
1793
1824
|
// collect comma at end of expression
|
|
1794
|
-
if (lastAAMember && this.checkPrevious(
|
|
1825
|
+
if (lastAAMember && this.checkPrevious(TokenKind_1.TokenKind.Comma)) {
|
|
1795
1826
|
lastAAMember.commaToken = this.previous();
|
|
1796
1827
|
}
|
|
1797
1828
|
//check for comment at the end of the current line
|
|
1798
|
-
if (this.check(
|
|
1799
|
-
let token = this.checkPrevious(
|
|
1829
|
+
if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
|
|
1830
|
+
let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
|
|
1800
1831
|
members.push(new Statement_1.CommentStatement([token]));
|
|
1801
1832
|
}
|
|
1802
1833
|
else {
|
|
1803
1834
|
this.consumeStatementSeparators(true);
|
|
1804
1835
|
//check for a comment on its own line
|
|
1805
|
-
if (this.check(
|
|
1806
|
-
let token = this.checkPrevious(
|
|
1836
|
+
if (this.check(TokenKind_1.TokenKind.Comment) || this.checkPrevious(TokenKind_1.TokenKind.Comment)) {
|
|
1837
|
+
let token = this.checkPrevious(TokenKind_1.TokenKind.Comment) ? this.previous() : this.advance();
|
|
1807
1838
|
lastAAMember = null;
|
|
1808
1839
|
members.push(new Statement_1.CommentStatement([token]));
|
|
1809
1840
|
continue;
|
|
1810
1841
|
}
|
|
1811
|
-
if (this.check(
|
|
1842
|
+
if (this.check(TokenKind_1.TokenKind.RightCurlyBrace)) {
|
|
1812
1843
|
break;
|
|
1813
1844
|
}
|
|
1814
1845
|
let k = key();
|
|
@@ -1817,23 +1848,23 @@ class Parser {
|
|
|
1817
1848
|
members.push(lastAAMember);
|
|
1818
1849
|
}
|
|
1819
1850
|
}
|
|
1820
|
-
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(),
|
|
1851
|
+
this.consume(DiagnosticMessages_1.DiagnosticMessages.unmatchedLeftCurlyAfterAALiteral(), TokenKind_1.TokenKind.RightCurlyBrace);
|
|
1821
1852
|
}
|
|
1822
1853
|
let closingBrace = this.previous();
|
|
1823
1854
|
const aaExpr = new Expression_1.AALiteralExpression(members, openingBrace, closingBrace, this.currentFunctionExpression);
|
|
1824
1855
|
this._references.aaLiterals.push(aaExpr);
|
|
1825
1856
|
this.addPropertyHints(aaExpr);
|
|
1826
1857
|
return aaExpr;
|
|
1827
|
-
case this.matchAny(
|
|
1858
|
+
case this.matchAny(TokenKind_1.TokenKind.Pos, TokenKind_1.TokenKind.Tab):
|
|
1828
1859
|
let token = Object.assign(this.previous(), {
|
|
1829
|
-
kind:
|
|
1860
|
+
kind: TokenKind_1.TokenKind.Identifier
|
|
1830
1861
|
});
|
|
1831
1862
|
return new Expression_1.VariableExpression(token, this.currentNamespaceName);
|
|
1832
|
-
case this.checkAny(
|
|
1863
|
+
case this.checkAny(TokenKind_1.TokenKind.Function, TokenKind_1.TokenKind.Sub):
|
|
1833
1864
|
return this.anonymousFunction();
|
|
1834
|
-
case this.check(
|
|
1865
|
+
case this.check(TokenKind_1.TokenKind.RegexLiteral):
|
|
1835
1866
|
return this.regexLiteralExpression();
|
|
1836
|
-
case this.check(
|
|
1867
|
+
case this.check(TokenKind_1.TokenKind.Comment):
|
|
1837
1868
|
return new Statement_1.CommentStatement([this.advance()]);
|
|
1838
1869
|
default:
|
|
1839
1870
|
//if we found an expected terminator, don't throw a diagnostic...just return undefined
|
|
@@ -1903,12 +1934,12 @@ class Parser {
|
|
|
1903
1934
|
}
|
|
1904
1935
|
consumeStatementSeparators(optional = false) {
|
|
1905
1936
|
//a comment or EOF mark the end of the statement
|
|
1906
|
-
if (this.isAtEnd() || this.check(
|
|
1937
|
+
if (this.isAtEnd() || this.check(TokenKind_1.TokenKind.Comment)) {
|
|
1907
1938
|
return true;
|
|
1908
1939
|
}
|
|
1909
1940
|
let consumed = false;
|
|
1910
1941
|
//consume any newlines and colons
|
|
1911
|
-
while (this.matchAny(
|
|
1942
|
+
while (this.matchAny(TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Colon)) {
|
|
1912
1943
|
consumed = true;
|
|
1913
1944
|
}
|
|
1914
1945
|
if (!optional && !consumed) {
|
|
@@ -1924,7 +1955,7 @@ class Parser {
|
|
|
1924
1955
|
}
|
|
1925
1956
|
checkEndOfStatement() {
|
|
1926
1957
|
const nextKind = this.peek().kind;
|
|
1927
|
-
return [
|
|
1958
|
+
return [TokenKind_1.TokenKind.Colon, TokenKind_1.TokenKind.Newline, TokenKind_1.TokenKind.Comment, TokenKind_1.TokenKind.Eof].includes(nextKind);
|
|
1928
1959
|
}
|
|
1929
1960
|
checkPrevious(tokenKind) {
|
|
1930
1961
|
var _a;
|
|
@@ -1932,14 +1963,14 @@ class Parser {
|
|
|
1932
1963
|
}
|
|
1933
1964
|
check(tokenKind) {
|
|
1934
1965
|
const nextKind = this.peek().kind;
|
|
1935
|
-
if (nextKind ===
|
|
1966
|
+
if (nextKind === TokenKind_1.TokenKind.Eof) {
|
|
1936
1967
|
return false;
|
|
1937
1968
|
}
|
|
1938
1969
|
return nextKind === tokenKind;
|
|
1939
1970
|
}
|
|
1940
1971
|
checkAny(...tokenKinds) {
|
|
1941
1972
|
const nextKind = this.peek().kind;
|
|
1942
|
-
if (nextKind ===
|
|
1973
|
+
if (nextKind === TokenKind_1.TokenKind.Eof) {
|
|
1943
1974
|
return false;
|
|
1944
1975
|
}
|
|
1945
1976
|
return tokenKinds.includes(nextKind);
|
|
@@ -1958,7 +1989,7 @@ class Parser {
|
|
|
1958
1989
|
return tokenKinds.includes(nextKind);
|
|
1959
1990
|
}
|
|
1960
1991
|
isAtEnd() {
|
|
1961
|
-
return this.peek().kind ===
|
|
1992
|
+
return this.peek().kind === TokenKind_1.TokenKind.Eof;
|
|
1962
1993
|
}
|
|
1963
1994
|
peekNext() {
|
|
1964
1995
|
if (this.isAtEnd()) {
|
|
@@ -1980,16 +2011,16 @@ class Parser {
|
|
|
1980
2011
|
return;
|
|
1981
2012
|
}
|
|
1982
2013
|
switch (this.peek().kind) { //eslint-disable-line @typescript-eslint/switch-exhaustiveness-check
|
|
1983
|
-
case
|
|
1984
|
-
case
|
|
1985
|
-
case
|
|
1986
|
-
case
|
|
1987
|
-
case
|
|
1988
|
-
case
|
|
1989
|
-
case
|
|
1990
|
-
case
|
|
1991
|
-
case
|
|
1992
|
-
case
|
|
2014
|
+
case TokenKind_1.TokenKind.Namespace:
|
|
2015
|
+
case TokenKind_1.TokenKind.Class:
|
|
2016
|
+
case TokenKind_1.TokenKind.Function:
|
|
2017
|
+
case TokenKind_1.TokenKind.Sub:
|
|
2018
|
+
case TokenKind_1.TokenKind.If:
|
|
2019
|
+
case TokenKind_1.TokenKind.For:
|
|
2020
|
+
case TokenKind_1.TokenKind.ForEach:
|
|
2021
|
+
case TokenKind_1.TokenKind.While:
|
|
2022
|
+
case TokenKind_1.TokenKind.Print:
|
|
2023
|
+
case TokenKind_1.TokenKind.Return:
|
|
1993
2024
|
// start parsing again from the next block starter or obvious
|
|
1994
2025
|
// expression start
|
|
1995
2026
|
return;
|
|
@@ -2035,17 +2066,17 @@ class Parser {
|
|
|
2035
2066
|
const previousToken = this.getPreviousToken(closestToken);
|
|
2036
2067
|
const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
|
|
2037
2068
|
//next to matched token
|
|
2038
|
-
if (!closestToken || closestToken.kind ===
|
|
2069
|
+
if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
|
|
2039
2070
|
return false;
|
|
2040
2071
|
}
|
|
2041
2072
|
else if (closestToken.kind === tokenKind) {
|
|
2042
2073
|
return true;
|
|
2043
2074
|
}
|
|
2044
|
-
else if (closestToken.kind ===
|
|
2075
|
+
else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
|
|
2045
2076
|
return false;
|
|
2046
2077
|
//next to an identifier, which is next to token kind
|
|
2047
2078
|
}
|
|
2048
|
-
else if (closestToken.kind ===
|
|
2079
|
+
else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
|
|
2049
2080
|
return true;
|
|
2050
2081
|
}
|
|
2051
2082
|
else {
|
|
@@ -2056,7 +2087,7 @@ class Parser {
|
|
|
2056
2087
|
const index = this.tokens.indexOf(currentToken);
|
|
2057
2088
|
for (let i = index - 1; i >= 0; i--) {
|
|
2058
2089
|
currentToken = this.tokens[i];
|
|
2059
|
-
if (currentToken.kind ===
|
|
2090
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
|
|
2060
2091
|
break;
|
|
2061
2092
|
}
|
|
2062
2093
|
else if (currentToken.kind === tokenKind) {
|
|
@@ -2076,7 +2107,7 @@ class Parser {
|
|
|
2076
2107
|
let tokens = [];
|
|
2077
2108
|
for (let i = this.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.tokens.length; i += direction) {
|
|
2078
2109
|
currentToken = this.tokens[i];
|
|
2079
|
-
if (currentToken.kind ===
|
|
2110
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
|
|
2080
2111
|
break;
|
|
2081
2112
|
}
|
|
2082
2113
|
tokens.push(currentToken);
|
|
@@ -2147,12 +2178,12 @@ class Parser {
|
|
|
2147
2178
|
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2148
2179
|
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2149
2180
|
}
|
|
2150
|
-
if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) ===
|
|
2181
|
+
if ((currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind) === TokenKind_1.TokenKind.Dot) {
|
|
2151
2182
|
previousTokenResult = this.getPreviousTokenFromIndex(currentTokenIndex);
|
|
2152
2183
|
currentToken = previousTokenResult.token;
|
|
2153
2184
|
currentTokenIndex = previousTokenResult.index;
|
|
2154
2185
|
}
|
|
2155
|
-
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex,
|
|
2186
|
+
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftParen, TokenKind_1.TokenKind.RightParen);
|
|
2156
2187
|
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2157
2188
|
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2158
2189
|
if (previousTokenResult.hasBrackets) {
|
|
@@ -2160,7 +2191,7 @@ class Parser {
|
|
|
2160
2191
|
}
|
|
2161
2192
|
let tokenTypeIsNotKnowable = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.tokenTypeIsNotKnowable;
|
|
2162
2193
|
if (currentTokenIndex) {
|
|
2163
|
-
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex,
|
|
2194
|
+
previousTokenResult = this.getPreviousTokenIgnoreNests(currentTokenIndex, TokenKind_1.TokenKind.LeftSquareBracket, TokenKind_1.TokenKind.RightSquareBracket);
|
|
2164
2195
|
currentToken = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.token;
|
|
2165
2196
|
currentTokenIndex = previousTokenResult === null || previousTokenResult === void 0 ? void 0 : previousTokenResult.index;
|
|
2166
2197
|
if (previousTokenResult.hasBrackets) {
|
|
@@ -2178,15 +2209,15 @@ class Parser {
|
|
|
2178
2209
|
if (!currentToken || lastTokenHasWhitespace) {
|
|
2179
2210
|
return false;
|
|
2180
2211
|
}
|
|
2181
|
-
if (currentToken.kind ===
|
|
2212
|
+
if (currentToken.kind === TokenKind_1.TokenKind.Identifier) {
|
|
2182
2213
|
return true;
|
|
2183
2214
|
}
|
|
2184
2215
|
if (currentToken.leadingWhitespace.length === 0) {
|
|
2185
2216
|
// start of the chain
|
|
2186
|
-
return
|
|
2217
|
+
return TokenKind_1.AllowedLocalIdentifiers.includes(currentToken.kind);
|
|
2187
2218
|
}
|
|
2188
2219
|
// not the start of the chain
|
|
2189
|
-
return
|
|
2220
|
+
return TokenKind_1.AllowedProperties.includes(currentToken.kind);
|
|
2190
2221
|
}
|
|
2191
2222
|
/**
|
|
2192
2223
|
* Builds up a chain of tokens, starting with the first in the chain, and ending with currentToken
|
|
@@ -2233,32 +2264,67 @@ class Parser {
|
|
|
2233
2264
|
*/
|
|
2234
2265
|
findReferences() {
|
|
2235
2266
|
this._references = new References();
|
|
2267
|
+
const excludedExpressions = new Set();
|
|
2268
|
+
const visitCallExpression = (e) => {
|
|
2269
|
+
for (const p of e.args) {
|
|
2270
|
+
this._references.expressions.add(p);
|
|
2271
|
+
}
|
|
2272
|
+
//add calls that were not excluded (from loop below)
|
|
2273
|
+
if (!excludedExpressions.has(e)) {
|
|
2274
|
+
this._references.expressions.add(e);
|
|
2275
|
+
}
|
|
2276
|
+
//if this call is part of a longer expression that includes a call higher up, find that higher one and remove it
|
|
2277
|
+
if (e.callee) {
|
|
2278
|
+
let node = e.callee;
|
|
2279
|
+
while (node) {
|
|
2280
|
+
//the primary goal for this loop. If we found a parent call expression, remove it from `references`
|
|
2281
|
+
if ((0, reflection_1.isCallExpression)(node)) {
|
|
2282
|
+
this.references.expressions.delete(node);
|
|
2283
|
+
excludedExpressions.add(node);
|
|
2284
|
+
//stop here. even if there are multiple calls in the chain, each child will find and remove its closest parent, so that reduces excess walking.
|
|
2285
|
+
break;
|
|
2286
|
+
//when we hit a variable expression, we're definitely at the leftmost expression so stop
|
|
2287
|
+
}
|
|
2288
|
+
else if ((0, reflection_1.isVariableExpression)(node)) {
|
|
2289
|
+
break;
|
|
2290
|
+
//if
|
|
2291
|
+
}
|
|
2292
|
+
else if ((0, reflection_1.isDottedGetExpression)(node) || (0, reflection_1.isIndexedGetExpression)(node)) {
|
|
2293
|
+
node = node.obj;
|
|
2294
|
+
}
|
|
2295
|
+
else {
|
|
2296
|
+
//some expression we don't understand. log it and quit the loop
|
|
2297
|
+
this.logger.info('Encountered unknown expression while calculating function expression chain', node);
|
|
2298
|
+
break;
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2236
2303
|
//gather up all the top-level statements
|
|
2237
2304
|
this.ast.walk((0, visitors_1.createVisitor)({
|
|
2305
|
+
AssignmentStatement: s => {
|
|
2306
|
+
this._references.assignmentStatements.push(s);
|
|
2307
|
+
this.references.expressions.add(s.value);
|
|
2308
|
+
},
|
|
2238
2309
|
ClassStatement: s => {
|
|
2239
2310
|
this._references.classStatements.push(s);
|
|
2240
2311
|
},
|
|
2312
|
+
ClassFieldStatement: s => {
|
|
2313
|
+
if (s.initialValue) {
|
|
2314
|
+
this._references.expressions.add(s.initialValue);
|
|
2315
|
+
}
|
|
2316
|
+
},
|
|
2241
2317
|
NamespaceStatement: s => {
|
|
2242
2318
|
this._references.namespaceStatements.push(s);
|
|
2243
2319
|
},
|
|
2244
2320
|
FunctionStatement: s => {
|
|
2245
2321
|
this._references.functionStatements.push(s);
|
|
2246
|
-
//add the initial set of function expressions for function statements
|
|
2247
|
-
this._references.functionExpressions.push(s.func);
|
|
2248
2322
|
},
|
|
2249
2323
|
ImportStatement: s => {
|
|
2250
2324
|
this._references.importStatements.push(s);
|
|
2251
2325
|
},
|
|
2252
2326
|
LibraryStatement: s => {
|
|
2253
2327
|
this._references.libraryStatements.push(s);
|
|
2254
|
-
}
|
|
2255
|
-
}), {
|
|
2256
|
-
walkMode: visitors_1.WalkMode.visitStatements
|
|
2257
|
-
});
|
|
2258
|
-
let func;
|
|
2259
|
-
let visitor = (0, visitors_1.createVisitor)({
|
|
2260
|
-
AssignmentStatement: s => {
|
|
2261
|
-
this._references.assignmentStatements.push(s);
|
|
2262
2328
|
},
|
|
2263
2329
|
FunctionExpression: (expression, parent) => {
|
|
2264
2330
|
if (!(0, reflection_1.isClassMethodStatement)(parent)) {
|
|
@@ -2267,25 +2333,51 @@ class Parser {
|
|
|
2267
2333
|
},
|
|
2268
2334
|
NewExpression: e => {
|
|
2269
2335
|
this._references.newExpressions.push(e);
|
|
2336
|
+
for (const p of e.call.args) {
|
|
2337
|
+
this._references.expressions.add(p);
|
|
2338
|
+
}
|
|
2339
|
+
},
|
|
2340
|
+
ExpressionStatement: s => {
|
|
2341
|
+
this._references.expressions.add(s.expression);
|
|
2342
|
+
},
|
|
2343
|
+
CallfuncExpression: e => {
|
|
2344
|
+
visitCallExpression(e);
|
|
2345
|
+
},
|
|
2346
|
+
CallExpression: e => {
|
|
2347
|
+
visitCallExpression(e);
|
|
2270
2348
|
},
|
|
2271
2349
|
AALiteralExpression: e => {
|
|
2272
2350
|
this.addPropertyHints(e);
|
|
2351
|
+
this._references.expressions.add(e);
|
|
2352
|
+
for (const member of e.elements) {
|
|
2353
|
+
if ((0, reflection_1.isAAMemberExpression)(member)) {
|
|
2354
|
+
this._references.expressions.add(member.value);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
},
|
|
2358
|
+
ArrayLiteralExpression: e => {
|
|
2359
|
+
for (const element of e.elements) {
|
|
2360
|
+
//keep everything except comments
|
|
2361
|
+
if (!(0, reflection_1.isCommentStatement)(element)) {
|
|
2362
|
+
this._references.expressions.add(element);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2273
2365
|
},
|
|
2274
2366
|
DottedGetExpression: e => {
|
|
2275
2367
|
this.addPropertyHints(e.name);
|
|
2276
2368
|
},
|
|
2277
2369
|
DottedSetStatement: e => {
|
|
2278
2370
|
this.addPropertyHints(e.name);
|
|
2371
|
+
},
|
|
2372
|
+
UnaryExpression: e => {
|
|
2373
|
+
this._references.expressions.add(e);
|
|
2374
|
+
},
|
|
2375
|
+
IncrementStatement: e => {
|
|
2376
|
+
this._references.expressions.add(e);
|
|
2279
2377
|
}
|
|
2378
|
+
}), {
|
|
2379
|
+
walkMode: visitors_1.WalkMode.visitAllRecursive
|
|
2280
2380
|
});
|
|
2281
|
-
//walk all function expressions (we'll add new ones as we move along too)
|
|
2282
|
-
for (let i = 0; i < this._references.functionExpressions.length; i++) {
|
|
2283
|
-
func = this._references.functionExpressions[i];
|
|
2284
|
-
//walk this function expression
|
|
2285
|
-
func.body.walk(visitor, {
|
|
2286
|
-
walkMode: visitors_1.WalkMode.visitAll
|
|
2287
|
-
});
|
|
2288
|
-
}
|
|
2289
2381
|
}
|
|
2290
2382
|
getContainingClass(currentToken) {
|
|
2291
2383
|
return this.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
|
|
@@ -2297,7 +2389,10 @@ class Parser {
|
|
|
2297
2389
|
return this.references.namespaceStatements.find((cs) => util_1.util.rangeContains(cs.range, currentToken.range.start));
|
|
2298
2390
|
}
|
|
2299
2391
|
getContainingFunctionExpression(currentToken) {
|
|
2300
|
-
return this.
|
|
2392
|
+
return this.getContainingFunctionExpressionByPosition(currentToken.range.start);
|
|
2393
|
+
}
|
|
2394
|
+
getContainingFunctionExpressionByPosition(position) {
|
|
2395
|
+
return this.references.functionExpressions.find((fe) => util_1.util.rangeContains(fe.range, position));
|
|
2301
2396
|
}
|
|
2302
2397
|
dispose() {
|
|
2303
2398
|
}
|
|
@@ -2317,6 +2412,17 @@ class References {
|
|
|
2317
2412
|
this.functionExpressions = [];
|
|
2318
2413
|
this.functionStatements = [];
|
|
2319
2414
|
this.interfaceStatements = [];
|
|
2415
|
+
/**
|
|
2416
|
+
* A collection of full expressions. This excludes intermediary expressions.
|
|
2417
|
+
*
|
|
2418
|
+
* Example 1:
|
|
2419
|
+
* `a.b.c` is composed of `a` (variableExpression) `.b` (DottedGetExpression) `.c` (DottedGetExpression)
|
|
2420
|
+
* This will only contain the final `.c` DottedGetExpression because `.b` and `a` can both be derived by walking back from the `.c` DottedGetExpression.
|
|
2421
|
+
*
|
|
2422
|
+
* Example 2:
|
|
2423
|
+
* `name.space.doSomething(a.b.c)` will result in 2 entries in this list. the `CallExpression` for `doSomething`, and the `.c` DottedGetExpression.
|
|
2424
|
+
*/
|
|
2425
|
+
this.expressions = new Set();
|
|
2320
2426
|
this.importStatements = [];
|
|
2321
2427
|
this.libraryStatements = [];
|
|
2322
2428
|
this.namespaceStatements = [];
|
|
@@ -2388,7 +2494,10 @@ function getBscTypeFromExpression(expression, functionExpression) {
|
|
|
2388
2494
|
//Array literal
|
|
2389
2495
|
}
|
|
2390
2496
|
else if ((0, reflection_1.isArrayLiteralExpression)(expression)) {
|
|
2391
|
-
|
|
2497
|
+
const innerTypes = expression.elements.filter((element) => !(0, reflection_1.isCommentStatement)(element)).map((element) => {
|
|
2498
|
+
return getBscTypeFromExpression(element, functionExpression);
|
|
2499
|
+
});
|
|
2500
|
+
return new ArrayType_1.ArrayType(...innerTypes);
|
|
2392
2501
|
//function call
|
|
2393
2502
|
}
|
|
2394
2503
|
else if ((0, reflection_1.isNewExpression)(expression)) {
|
|
@@ -2404,6 +2513,12 @@ function getBscTypeFromExpression(expression, functionExpression) {
|
|
|
2404
2513
|
else if ((0, reflection_1.isDottedGetExpression)(expression)) {
|
|
2405
2514
|
return (0, helpers_1.getTypeFromDottedGetExpression)(expression, functionExpression);
|
|
2406
2515
|
}
|
|
2516
|
+
else if ((0, reflection_1.isIndexedGetExpression)(expression)) {
|
|
2517
|
+
const source = getBscTypeFromExpression(expression.obj, functionExpression);
|
|
2518
|
+
if ((0, reflection_1.isArrayType)(source)) {
|
|
2519
|
+
return source.getDefaultType();
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2407
2522
|
}
|
|
2408
2523
|
catch (e) {
|
|
2409
2524
|
//do nothing. Just return dynamic
|