Repository: rokucommunity/brighterscript
Pull request #985 (2023-12-08 16:24:05)

Fix transpile for non-namespaced enums in namespaced functions
Fixes a critical transpile bug where non-namespaced enums used in namespaced function blocks would be left untranspiled!

![image](https://github.com/rokucommunity/brighterscript/assets/2544493/5d47b4ad-5285-4548-9212-a0c5be5926ef)



Patch:
diff --git a/src/Scope.ts b/src/Scope.ts
index 2f1e3cc6..932bef47 100644
--- a/src/Scope.ts
+++ b/src/Scope.ts
@@ -181,7 +181,6 @@ export class Scope {
             let member = enumeration.item.findChild<EnumMemberStatement>((child) => isEnumMemberStatement(child) && child.name?.toLowerCase() === memberName);
             return member ? { item: member, file: enumeration.file } : undefined;
         }
-        return enumeration;
     }
 
     /**
diff --git a/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts b/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
index f19107e5..2e7f6058 100644
--- a/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
+++ b/src/bscPlugin/transpile/BrsFilePreTranspileProcessor.ts
@@ -39,25 +39,13 @@ export class BrsFilePreTranspileProcessor {
      * For example, all of these would return the enum: `SomeNamespace.SomeEnum.SomeMember`, SomeEnum.SomeMember, `SomeEnum`
      */
     private getEnumInfo(name: string, containingNamespace: string, scope: Scope) {
-        //look for the enum directly
-        let result = scope?.getEnumFileLink(name, containingNamespace);
 
-        if (result) {
+        //do we have an enum MEMBER reference? (i.e. SomeEnum.someMember or SomeNamespace.SomeEnum.SomeMember)
+        let memberLink = scope.getEnumMemberFileLink(name, containingNamespace);
+        if (memberLink) {
+            const value = memberLink.item.getValue();
             return {
-                enum: result.item
-            };
-        }
-        //assume we've been given the enum.member syntax, so pop the member and try again
-        const parts = name.toLowerCase().split('.');
-        const memberName = parts.pop();
-        if (containingNamespace && parts[0] !== containingNamespace.toLowerCase()) {
-            parts.unshift(containingNamespace.toLowerCase());
-        }
-        result = scope?.getEnumMap().get(parts.join('.'));
-        if (result) {
-            const value = result.item.getMemberValue(memberName);
-            return {
-                enum: result.item,
+                enum: memberLink.item.parent,
                 value: new LiteralExpression(createToken(
                     //just use float literal for now...it will transpile properly with any literal value
                     value.startsWith('"') ? TokenKind.StringLiteral : TokenKind.FloatLiteral,
@@ -65,6 +53,16 @@ export class BrsFilePreTranspileProcessor {
                 ))
             };
         }
+
+        //do we have an enum reference? (i.e. SomeEnum or SomeNamespace.SomeEnum)
+        let enumLink = scope?.getEnumFileLink(name, containingNamespace);
+
+        if (enumLink) {
+            return {
+                enum: enumLink.item
+            };
+        }
+
     }
 
     private processExpression(expression: Expression, scope: Scope) {
diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts
index 5f2fd7fc..c98284f2 100644
--- a/src/parser/Statement.ts
+++ b/src/parser/Statement.ts
@@ -2574,6 +2574,13 @@ export class EnumMemberStatement extends Statement implements TypedefProvider {
         );
     }
 
+    /**
+     * Get the value of this enum. Requires that `.parent` is set
+     */
+    public getValue() {
+        return (this.parent as EnumStatement).getMemberValue(this.name);
+    }
+
     public transpile(state: BrsTranspileState): TranspileResult {
         return [];
     }


Test patch:
diff --git a/src/parser/tests/statement/Enum.spec.ts b/src/parser/tests/statement/Enum.spec.ts
index 806bb226..5a11f176 100644
--- a/src/parser/tests/statement/Enum.spec.ts
+++ b/src/parser/tests/statement/Enum.spec.ts
@@ -519,6 +519,24 @@ describe('EnumStatement', () => {
     });
 
     describe('transpile', () => {
+        it('supports non-namespaced enum from within a namespace', () => {
+            program.options.autoImportComponentScript = true;
+            testTranspile(`
+                namespace alpha
+                    sub test()
+                        print Direction.up
+                    end sub
+                end namespace
+                enum Direction
+                    up = "up"
+                end enum
+            `, `
+                sub alpha_test()
+                    print "up"
+                end sub
+            `);
+        });
+
         it('transpiles negative number', () => {
             testTranspile(`
                 sub main()