Skip to content

Fix recursive const and enum resolution during transpilation#1578

Merged
TwitchBronBron merged 5 commits intomasterfrom
copilot/fix-nested-consts-transpilation
Oct 31, 2025
Merged

Fix recursive const and enum resolution during transpilation#1578
TwitchBronBron merged 5 commits intomasterfrom
copilot/fix-nested-consts-transpilation

Conversation

Copy link
Contributor

Copilot AI commented Oct 22, 2025

Fixes an issue where nested const and enum references were not being fully resolved during transpilation, resulting in incorrect output with extra parentheses or unresolved namespace references instead of the final literal values.

Problem

When a const references another const or enum (either directly or through namespace paths), the transpiler was only performing single-level resolution. This caused issues like:

const FLAG_A = "A"
const FLAG_B = FLAG_A
const AD_BREAK_START = { a: FLAG_A, b: FLAG_B }

Would transpile to:

print ({
    a: "A"
    b: ("A")  // Extra parentheses instead of just "A"
})

Additionally, enums used in consts were not being resolved at all, especially across files. As shown in the provided screenshots, Theming_Color_BLUE and Theming_PRIMARY_COLOR were not being resolved to their final literal values when definitions were spread across multiple files.

Solution

Implemented recursive const and enum resolution in BrsFilePreTranspileProcessor.ts:

  1. Enhanced resolveConstValue() method to recursively follow both const and enum references until reaching a final literal value
  2. Added circular reference detection using a visited set and isCircular flag to prevent infinite loops
  3. Modified processExpression() to use recursive resolution for both consts and enums

The fix ensures that:

  • const FLAG_B = FLAG_A resolves to the final value of FLAG_A
  • Namespace references like aa.bb.FLAG_A are fully resolved
  • Enums used in consts are resolved to their literal values
  • Cross-file const and enum references work correctly
  • Const→enum→const→enum chains are fully resolved
  • Circular references are detected and handled gracefully without infinite loops

Test Coverage

Added comprehensive test cases covering:

  • Simple recursive const references within the same scope
  • Cross-namespace const references (aa.bb.FLAG_A)
  • Cross-file const references
  • Cyclical const references (without infinite loops)
  • Consts inside array literals
  • Enum used in const (same file and cross-file)
  • Complex const→enum→const→enum chains across multiple files
  • The exact scenarios described in the issue and review comments

All existing const functionality continues to work unchanged, ensuring backward compatibility.

Fixes #1506

Original prompt

This section details on the original issue you should resolve

<issue_title>Nested consts without a full namespace path are transpiled as-is</issue_title>
<issue_description>Nested consts without a full namespace path are transpiled as-is, but they should be recursively resolved.

This seems to happen in both v0.69.* and v1. Relevant slack conversation: https://rokudevelopers.slack.com/archives/CKF1QQGTY/p1745222320238079

const AD_BREAK_START = { a: aa.bb.FLAG_A, b: FLAG_B }

</issue_description>

<agent_instructions>we need several good unit tetsts to prove this is happening first (by the unit tests failing). then, fix the problem and verify the unit tests pass. would love to see as little code changed for this fix as possible. can we resolve these things in a loop, until we run out of things to resolve? </agent_instructions>

Comments on the Issue (you are @copilot in this section)

@luis-j-soares I've seen a similar issue happen as well. Seems like the resolver for consts doesn't work when the value of that const resides in a different file.

Works fine:
Image

Does not work:
Image</comment_new>

Fixes #1506


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Fix nested consts transpilation to resolve recursively Fix recursive const resolution during transpilation Oct 22, 2025
Copilot AI requested a review from TwitchBronBron October 22, 2025 19:29
Copy link
Member

@TwitchBronBron TwitchBronBron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Can you please add unit tests that prove cyclical const references are mitigated? (something like
const a = b
const b = c
const c = a

also consts inside array literal consts.

@TwitchBronBron TwitchBronBron marked this pull request as ready for review October 28, 2025 16:06
@TwitchBronBron TwitchBronBron added the create-package create a temporary npm package on every commit label Oct 28, 2025
@rokucommunity-bot
Copy link
Contributor

Hey there! I just built a new temporary npm package based on 167b20b. You can download it here or install it by running the following command:

npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.2-copilot-fix-nested-consts-transpilation.20251028160636.tgz

Copy link
Member

@TwitchBronBron TwitchBronBron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the situation where enums are not resolved when used in consts. Make a few tests where the items are all spread across multiple files, and prove it still recursively resolves them all. Like this:

'source/theming1.bs
namespace Themeing
    const BACKGROUND_COLOR = Theming.Color.BLACK
end namespace
'source/theming2.bs
namespace Theming
    enum Color
        BLACK = "#000000"
    end enum
end namespace
'source/test.bs
sub test()
    aa = {
        backgroundOverlay: {
            color: Themeing.BACKGROUND_COLOR
        }
    }
end sub

Also handle a const using an enum using a const using an enum. (like const a, enum b, const c, enum d)

@TwitchBronBron TwitchBronBron marked this pull request as draft October 29, 2025 13:12
@TwitchBronBron
Copy link
Member

@copilot can you please implement my latest review comment with code changes to fix the issue?

…ains

- Enhanced resolveConstValue to recursively resolve both consts and enums
- Added circular reference detection with isCircular flag to prevent infinite loops
- Added tests for cyclical const references
- Added tests for consts inside array literals
- Added tests for enum used in const (same file and cross-file)
- Added tests for const->enum->const->enum chains across multiple files
- All 26 ConstStatement tests passing

Co-authored-by: TwitchBronBron <[email protected]>
Copy link
Contributor Author

Copilot AI commented Oct 29, 2025

This looks great! Can you please add unit tests that prove cyclical const references are mitigated? (something like
const a = b
const b = c...

Added comprehensive tests for cyclical const references and consts inside array literals. The cyclical reference test verifies that infinite loops are prevented - when circular references are detected, the transpiler leaves the reference as-is rather than entering an infinite resolution loop. Commit: 5e1e9f8

Please fix the situation where enums are not resolved when used in consts. Make a few tests where the items are all spread across multiple files, and prove it still recursively resolves them all. Like...

Enhanced the recursive resolution to handle enums in addition to consts. Added comprehensive multi-file tests covering:

  • Enum used in const (same file and cross-file)
  • Const→enum→const→enum chains across multiple files
  • Complex scenarios matching the examples you provided

All scenarios now correctly resolve to their final literal values, including when definitions are spread across multiple files. Commit: 5e1e9f8

Copilot AI changed the title Fix recursive const resolution during transpilation Fix recursive const and enum resolution during transpilation Oct 29, 2025
Copilot AI requested a review from TwitchBronBron October 29, 2025 13:32
@rokucommunity-bot
Copy link
Contributor

Hey there! I just built a new temporary npm package based on 5e1e9f8. You can download it here or install it by running the following command:

npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.2-copilot-fix-nested-consts-transpilation.20251029143045.tgz

@rokucommunity-bot
Copy link
Contributor

Hey there! I just built a new temporary npm package based on 5e1e9f8. You can download it here or install it by running the following command:

npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.2-copilot-fix-nested-consts-transpilation.20251029143046.tgz

@TwitchBronBron TwitchBronBron marked this pull request as ready for review October 29, 2025 16:52
@TwitchBronBron TwitchBronBron enabled auto-merge (squash) October 31, 2025 13:25
@rokucommunity-bot
Copy link
Contributor

Hey there! I just built a new temporary npm package based on 1150bec. You can download it here or install it by running the following command:

npm install https://github.com/rokucommunity/brighterscript/releases/download/v0.0.0-packages/brighterscript-0.70.2-copilot-fix-nested-consts-transpilation.20251031132538.tgz

@TwitchBronBron TwitchBronBron merged commit 6a008df into master Oct 31, 2025
7 checks passed
@TwitchBronBron TwitchBronBron deleted the copilot/fix-nested-consts-transpilation branch October 31, 2025 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create-package create a temporary npm package on every commit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested consts without a full namespace path are transpiled as-is

2 participants