Repository: rokucommunity/brighterscript
Pull request #1054 (2024-02-01 18:49:43)

Indexed get set multi index
#1050 fixed the indexedGet and indexedSet AST parsing in a backwards compatible way (`additionalIndexes`). But this PR refactors that in a breaking way for v1 into a single prop called `.indexes`. 


Patch:
diff --git a/src/astUtils/reflection.spec.ts b/src/astUtils/reflection.spec.ts
index 563f5c71..1e23edb5 100644
--- a/src/astUtils/reflection.spec.ts
+++ b/src/astUtils/reflection.spec.ts
@@ -57,7 +57,7 @@ describe('reflection', () => {
         const foreach = new ForEachStatement({ forEach: token, in: token, endFor: token, item: token, target: expr, body: block });
         const whiles = new WhileStatement({ while: token, endWhile: token, condition: expr, body: block });
         const dottedSet = new DottedSetStatement({ obj: expr, name: ident, value: expr });
-        const indexedSet = new IndexedSetStatement({ obj: expr, index: expr, value: expr, openingSquare: token, closingSquare: token, additionalIndexes: [] });
+        const indexedSet = new IndexedSetStatement({ obj: expr, indexes: [expr], value: expr, openingSquare: token, closingSquare: token });
         const library = new LibraryStatement({ library: token, filePath: token });
         const namespace = new NamespaceStatement({ namespace: token, nameExpression: createVariableExpression('a', range), body: body, endNamespace: token });
         const cls = new ClassStatement({ class: token, name: ident, body: [], endClass: token });
@@ -218,7 +218,7 @@ describe('reflection', () => {
         });
         const dottedGet = new DottedGetExpression({ obj: expr, name: ident, dot: token });
         const xmlAttrGet = new XmlAttributeGetExpression({ obj: expr, name: ident, at: token });
-        const indexedGet = new IndexedGetExpression({ obj: expr, index: expr, openingSquare: token, closingSquare: token, additionalIndexes: [] });
+        const indexedGet = new IndexedGetExpression({ obj: expr, indexes: [expr], openingSquare: token, closingSquare: token });
         const grouping = new GroupingExpression({ leftParen: token, rightParen: token, expression: expr });
         const literal = createStringLiteral('test');
         const escapedCarCode = new EscapedCharCodeLiteralExpression({ value: charCode });
diff --git a/src/bscPlugin/validation/BrsFileValidator.ts b/src/bscPlugin/validation/BrsFileValidator.ts
index f48c00a0..f784fd28 100644
--- a/src/bscPlugin/validation/BrsFileValidator.ts
+++ b/src/bscPlugin/validation/BrsFileValidator.ts
@@ -405,7 +405,7 @@ export class BrsFileValidator {
                 if (isDottedSetStatement(parent)) {
                     range = util.createBoundingRange(parent.obj, parent.tokens.dot, parent.tokens.name);
                 } else if (isIndexedSetStatement(parent)) {
-                    range = util.createBoundingRange(parent.obj, parent.tokens.openingSquare, parent.index, parent.tokens.closingSquare);
+                    range = util.createBoundingRange(parent.obj, parent.tokens.openingSquare, ...parent.indexes, parent.tokens.closingSquare);
                 } else {
                     range = node.range;
                 }
diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts
index 11838481..bcf0d5f0 100644
--- a/src/parser/Expression.ts
+++ b/src/parser/Expression.ts
@@ -603,14 +603,13 @@ export class XmlAttributeGetExpression extends Expression {
 export class IndexedGetExpression extends Expression {
     constructor(options: {
         obj: Expression;
-        index: Expression;
+        indexes: Expression[];
         /**
          * Can either be `[` or `?[`. If `?.[` is used, this will be `[` and `optionalChainingToken` will be `?.` - defaults to '[' in transpile
          */
         openingSquare?: Token;
         closingSquare?: Token;
         questionDot?: Token;//  ? or ?.
-        additionalIndexes: Expression[];
     }) {
         super();
         this.tokens = {
@@ -619,16 +618,14 @@ export class IndexedGetExpression extends Expression {
             questionDot: options.questionDot
         };
         this.obj = options.obj;
-        this.index = options.index;
-        this.additionalIndexes = options.additionalIndexes;
-        this.range = util.createBoundingRange(this.obj, this.tokens.openingSquare, this.tokens.questionDot, this.tokens.openingSquare, this.index, ...this.additionalIndexes, this.tokens.closingSquare);
+        this.indexes = options.indexes;
+        this.range = util.createBoundingRange(this.obj, this.tokens.openingSquare, this.tokens.questionDot, this.tokens.openingSquare, ...this.indexes, this.tokens.closingSquare);
     }
 
     public readonly kind = AstNodeKind.IndexedGetExpression;
 
     public obj: Expression;
-    public index: Expression;
-    public additionalIndexes: Expression[];
+    public indexes: Expression[];
 
     public tokens: {
         /**
@@ -648,13 +645,12 @@ export class IndexedGetExpression extends Expression {
             this.tokens.questionDot ? state.transpileToken(this.tokens.questionDot) : '',
             state.transpileToken(this.tokens.openingSquare, '[')
         );
-        const indexes = [this.index, ...this.additionalIndexes];
-        for (let i = 0; i < indexes.length; i++) {
+        for (let i = 0; i < this.indexes.length; i++) {
             //add comma between indexes
             if (i > 0) {
                 result.push(', ');
             }
-            let index = indexes[i];
+            let index = this.indexes[i];
             result.push(
                 ...(index?.transpile(state) ?? [])
             );
@@ -668,8 +664,7 @@ export class IndexedGetExpression extends Expression {
     walk(visitor: WalkVisitor, options: WalkOptions) {
         if (options.walkMode & InternalWalkMode.walkExpressions) {
             walk(this, 'obj', visitor, options);
-            walk(this, 'index', visitor, options);
-            walkArray(this.additionalIndexes, visitor, options, this);
+            walkArray(this.indexes, visitor, options, this);
         }
     }
 
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index 5b48c8d0..e07ab59e 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -2041,13 +2041,12 @@ export class Parser {
             if (isIndexedGetExpression(left)) {
                 return new IndexedSetStatement({
                     obj: left.obj,
-                    index: left.index,
+                    indexes: left.indexes,
                     value: operator.kind === TokenKind.Equal
                         ? right
                         : new BinaryExpression({ left: left, operator: operator, right: right }),
                     openingSquare: left.tokens.openingSquare,
-                    closingSquare: left.tokens.closingSquare,
-                    additionalIndexes: left.additionalIndexes
+                    closingSquare: left.tokens.closingSquare
                 });
             } else if (isDottedGetExpression(left)) {
                 return new DottedSetStatement({
@@ -2449,11 +2448,10 @@ export class Parser {
 
         return new IndexedGetExpression({
             obj: expr,
-            index: indexes.shift(),
+            indexes: indexes,
             openingSquare: openingSquare,
             closingSquare: closingSquare,
-            questionDot: questionDotToken,
-            additionalIndexes: indexes
+            questionDot: questionDotToken
         });
     }
 
diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts
index d9bccb73..39969380 100644
--- a/src/parser/Statement.ts
+++ b/src/parser/Statement.ts
@@ -1305,11 +1305,10 @@ export class DottedSetStatement extends Statement {
 export class IndexedSetStatement extends Statement {
     constructor(options: {
         obj: Expression;
-        index: Expression;
+        indexes: Expression[];
         value: Expression;
         openingSquare?: Token;
         closingSquare?: Token;
-        additionalIndexes: Expression[];
     }) {
         super();
         this.tokens = {
@@ -1317,14 +1316,12 @@ export class IndexedSetStatement extends Statement {
             closingSquare: options.closingSquare
         };
         this.obj = options.obj;
-        this.index = options.index;
-        this.additionalIndexes = options.additionalIndexes ?? [];
+        this.indexes = options.indexes;
         this.value = options.value;
         this.range = util.createBoundingRange(
             this.obj,
             this.tokens.openingSquare,
-            this.index,
-            ...this.additionalIndexes,
+            ...this.indexes,
             this.tokens.closingSquare,
             this.value
         );
@@ -1335,8 +1332,7 @@ export class IndexedSetStatement extends Statement {
         closingSquare?: Token;
     };
     readonly obj: Expression;
-    readonly index: Expression;
-    readonly additionalIndexes: Expression[];
+    readonly indexes: Expression[];
     readonly value: Expression;
 
     public readonly kind = AstNodeKind.IndexedSetStatement;
@@ -1355,13 +1351,12 @@ export class IndexedSetStatement extends Statement {
                 //   [
                 state.transpileToken(this.tokens.openingSquare)
             );
-            const indexes = [this.index, ...this.additionalIndexes];
-            for (let i = 0; i < indexes.length; i++) {
+            for (let i = 0; i < this.indexes.length; i++) {
                 //add comma between indexes
                 if (i > 0) {
                     result.push(', ');
                 }
-                let index = indexes[i];
+                let index = this.indexes[i];
                 result.push(
                     ...(index?.transpile(state) ?? [])
                 );
@@ -1378,8 +1373,7 @@ export class IndexedSetStatement extends Statement {
     walk(visitor: WalkVisitor, options: WalkOptions) {
         if (options.walkMode & InternalWalkMode.walkExpressions) {
             walk(this, 'obj', visitor, options);
-            walk(this, 'index', visitor, options);
-            walkArray(this.additionalIndexes, visitor, options, this);
+            walkArray(this.indexes, visitor, options, this);
             walk(this, 'value', visitor, options);
         }
     }


Test patch:
diff --git a/src/parser/tests/expression/Indexing.spec.ts b/src/parser/tests/expression/Indexing.spec.ts
index 93d854eb..d8f5f9d5 100644
--- a/src/parser/tests/expression/Indexing.spec.ts
+++ b/src/parser/tests/expression/Indexing.spec.ts
@@ -281,8 +281,8 @@ describe('parser indexing', () => {
             expect(isIndexedGetExpression(assignStmt.value)).to.be.true;
             const indexedGetExpr = assignStmt.value as IndexedGetExpression;
             expect((indexedGetExpr.obj as VariableExpression).tokens.name.text).to.equal('foo');
-            expect(isDottedGetExpression(indexedGetExpr.index)).to.be.true;
-            const dottedGetExpr = indexedGetExpr.index as DottedGetExpression;
+            expect(isDottedGetExpression(indexedGetExpr.indexes[0])).to.be.true;
+            const dottedGetExpr = indexedGetExpr.indexes[0] as DottedGetExpression;
             expect(dottedGetExpr.tokens.name.text).to.equal('baz');
             expect(isVariableExpression(dottedGetExpr.obj)).to.be.true;
         });