Skip to main content

Scope Manager and Variable Transformation

One of the transpiler's most critical jobs is managing variable scope and state persistence across bar iterations.

The Problem

In standard JavaScript:

let x = 10; // Re-initialized every time the function runs?

If the entire indicator function runs for every bar, let x = 10 would reset x every time. Pine Script variables need to maintain history (x[1]).

The Solution: Context Object

The transpiler moves all variables into a persistent context object ($).

User Code:

let ema9 = ta.ema(close, 9);

Transformed Code:

$.let.glb1_ema9 = $.init($.let.glb1_ema9, temp_result);

Variable Renaming

To prevent naming collisions between scopes (e.g., a variable x in the global scope vs x in a function), the ScopeManager assigns unique prefixes:

  • glb1_: Global scope variables.
  • fn{id}_: Function scope variables.
  • if{id}_: If-block scope variables.
  • for{id}_: For-loop scope variables.

This ensures that even if the user reuses variable names, they map to distinct properties on the context object.

ID Generation

The transpiler generates unique IDs for:

  1. Parameters (p0, p1...): Passed to param() to cache Series objects.
  2. Function Calls (_ta0, _ta1...): Passed to namespace functions to maintain internal state (like prevEma).
  3. Cache Keys: For caching intermediate results.

This allows functions like ta.ema to identify which call they are handling, even if called multiple times with the same parameters.