Repository: rokucommunity/brighterscript
Pull request #559 (2022-04-06 15:58:04)

Fix enum transpile bug for binary expressions
Fixes a bug when transpiling enums used within binary expressions that wouldn't actually move the values inline. 


Patch:
diff --git a/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts b/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
index 3c7ef717..3e41f260 100644
--- a/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
+++ b/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
@@ -1,6 +1,8 @@
+import { isBinaryExpression } from '../../astUtils/reflection';
 import { Cache } from '../../Cache';
 import type { BrsFile } from '../../files/BrsFile';
 import type { BeforeFileTranspileEvent } from '../../interfaces';
+import type { Expression } from '../../parser/Expression';
 import util from '../../util';
 
 export class BrsFilePreTranspileProcessor {
@@ -21,19 +23,29 @@ export class BrsFilePreTranspileProcessor {
         if ((enumLookup?.size ?? 0) === 0) {
             return;
         }
-        for (const expression of this.event.file.parser.references.expressions) {
-            const parts = util.getAllDottedGetParts(expression)?.map(x => x.toLowerCase());
-            if (parts) {
-                //get the name of the enum member
-                const memberName = parts.pop();
-                //get the name of the enum (including leading namespace if applicable)
-                const enumName = parts.join('.');
-                const lowerEnumName = enumName.toLowerCase();
-                const theEnum = enumLookup.get(lowerEnumName)?.item;
-                if (theEnum) {
-                    const members = membersByEnum.getOrAdd(lowerEnumName, () => theEnum.getMemberValueMap());
-                    const value = members?.get(memberName);
-                    this.event.editor.overrideTranspileResult(expression, value);
+        for (const referenceExpression of this.event.file.parser.references.expressions) {
+            const actualExpressions: Expression[] = [];
+            //binary expressions actually have two expressions (left and right), so handle them independently
+            if (isBinaryExpression(referenceExpression)) {
+                actualExpressions.push(referenceExpression.left, referenceExpression.right);
+            } else {
+                //assume all other expressions are a single chain
+                actualExpressions.push(referenceExpression);
+            }
+            for (const expression of actualExpressions) {
+                const parts = util.getAllDottedGetParts(expression)?.map(x => x.toLowerCase());
+                if (parts) {
+                    //get the name of the enum member
+                    const memberName = parts.pop();
+                    //get the name of the enum (including leading namespace if applicable)
+                    const enumName = parts.join('.');
+                    const lowerEnumName = enumName.toLowerCase();
+                    const theEnum = enumLookup.get(lowerEnumName)?.item;
+                    if (theEnum) {
+                        const members = membersByEnum.getOrAdd(lowerEnumName, () => theEnum.getMemberValueMap());
+                        const value = members?.get(memberName);
+                        this.event.editor.overrideTranspileResult(expression, value);
+                    }
                 }
             }
         }


Test patch:
diff --git a/src/parser/tests/statement/Enum.spec.ts b/src/parser/tests/statement/Enum.spec.ts
index 7aecfcc2..2606942a 100644
--- a/src/parser/tests/statement/Enum.spec.ts
+++ b/src/parser/tests/statement/Enum.spec.ts
@@ -868,6 +868,76 @@ describe('EnumStatement', () => {
                 kind: CompletionItemKind.Enum
             }]);
         });
+
+        it('handles both sides of a logical expression', () => {
+            testTranspile(`
+                sub main()
+                    dir = m.direction = Direction.up
+                    dir = Direction.up = m.direction
+                end sub
+                enum Direction
+                    up = "up"
+                    down = "down"
+                end enum
+            `, `
+                sub main()
+                    dir = m.direction = "up"
+                    dir = "up" = m.direction
+                end sub
+            `);
+        });
+
+        it('replaces enum values in if statements', () => {
+            testTranspile(`
+                sub main()
+                    if m.direction = Direction.up
+                        print Direction.up
+                    end if
+                end sub
+                enum Direction
+                    up = "up"
+                    down = "down"
+                end enum
+            `, `
+                sub main()
+                    if m.direction = "up"
+                        print "up"
+                    end if
+                end sub
+            `);
+        });
+
+        it('replaces enum values in function default parameter value expressions', () => {
+            testTranspile(`
+                sub speak(dir = Direction.up)
+                end sub
+                enum Direction
+                    up = "up"
+                end enum
+            `, `
+                sub speak(dir = "up")
+                end sub
+            `);
+        });
+
+        it('replaces enum values in for loops', () => {
+            testTranspile(`
+                sub main()
+                    for i = Loop.start to Loop.end step Loop.step
+                    end for
+                end sub
+                enum Loop
+                    start = 0
+                    end = 10
+                    step = 1
+                end enum
+            `, `
+                sub main()
+                    for i = 0 to 10 step 1
+                    end for
+                end sub
+            `);
+        });
     });
 
 });