Environment class

Represents a scope for variable bindings in the interpreter.

An Environment maintains a mapping of variable names to their values and can be chained to parent environments to implement lexical scoping. It supports variable definition, assignment, and lookup through the scope chain.

Variable Management Methods Overview

This class provides four main methods for variable operations, each serving specific use cases to correctly implement Lua's variable scoping semantics:

1. get(name) - Variable Lookup

  • Purpose: Read variable values
  • Behavior: Searches environment chain from current to root
  • Usage: x in expressions like print(x) or y = x + 1

2. declare(name, value) - Local Variable Declaration

  • Purpose: Create new local variables (local x = value)
  • Behavior: Always creates new binding with isLocal: true, shadows existing variables
  • Usage: Local variable declarations in Lua code

3. updateLocal(name, value) - Local Variable Assignment

  • Purpose: Update existing local variables only
  • Behavior: Searches for isLocal: true variables, updates first match
  • Returns: true if local found and updated, false otherwise
  • Usage: Assignments when local variable should take precedence
  • Why needed: Prevents accidental global creation when local exists

4. defineGlobal(name, value) - Global Variable Assignment

  • Purpose: Create/update global variables specifically
  • Behavior: Always operates on root environment, ignores local variables
  • Usage: When assignment should target global environment
  • Why needed: Ensures globals can be created even when locals exist

5. define(name, value) - Legacy General Assignment

  • Purpose: Original assignment method (has scoping issues)
  • Behavior: Searches chain, updates first match, creates in root if none found
  • Status: Still used but being phased out in favor of precise methods

Design Rationale

The multiple methods exist because Lua has complex variable scoping rules:

  • Local variables shadow globals with the same name
  • Assignments to existing locals should update the local, not create globals
  • Assignments when no local exists should create/update globals
  • Environment isolation (like load() with custom env) needs special handling

The original define() method couldn't distinguish these cases correctly, leading to bugs where local variables in main scripts affected globals. The newer methods provide precise control over each scenario.

Constructors

Environment({Environment? parent, LuaRuntime? interpreter, bool isClosure = false, bool isLoadIsolated = false})
Creates a new Environment.

Properties

declaredGlobals Map<String, Box>
Names explicitly declared as globals in this lexical scope.
final
estimatedSize int
Estimated memory footprint for this object expressed in GC "credits".
no setter
gcSpace ↔ GCGenerationSpace?
Which GC generation space this object is tracked in, or null if untracked. Stored directly on the object to avoid Expando lookups on hot paths.
getter/setter pairinherited
hashCode int
The hash code for this object.
no setterinherited
implicitToBeClosedValues List<Value>
Stores implicit to-be-closed resources that must stay GC-reachable even when they are not ordinary local bindings.
final
interpreter LuaRuntime?
The interpreter associated with this environment.
getter/setter pair
isClosure bool
Whether this environment represents a closure scope.
final
isLoadIsolated bool
Whether this environment was created by load() with a custom environment.
getter/setter pair
isOld bool
Whether this object belongs to the old generation. Used in generational collection to determine which generation the object belongs to.
getter/setter pairinherited
marked bool
Whether this object has been marked during the current GC cycle. Used in mark-and-sweep collection to identify live objects.
getter/setter pairinherited
parent Environment?
The parent environment in the scope chain, if any.
final
pendingImplicitToBeClosed int
Tracks pending implicit to-be-closed resources that are active for this scope but are not represented as normal local bindings.
getter/setter pair
root Environment
Gets the root environment (the one with no parent).
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
toBeClosedVars List<String>
Tracks the order in which to-be-closed variables were declared
final
values Map<String, Box>
Storage for variable bindings in this scope.
final

Methods

clearGlobal(String name) → void
Removes the root global binding for name and keeps the backing _G table in sync.
clone({LuaRuntime? interpreter}) Environment
Creates a clone of this environment
closeVariables([dynamic error]) Future<void>
Closes all to-be-closed variables in this environment in reverse order of declaration.
contains(String name) bool
Checks if a variable exists in this environment or any of its ancestors.
declare(String name, dynamic value, {bool trackToBeClosed = false}) → void
Declares a new local variable in the current environment.
declareGlobalBinding(String name) → void
Declares name as an explicit global in this lexical scope.
define(String name, dynamic value) → void
Defines or updates a variable named name with value.
defineAll(Map<String, dynamic> values) → void
Defines multiple variables in the current environment.
defineGlobal(String name, dynamic value) → void
Defines or updates a global variable in the root environment.
findBox(String name) Box?
Finds the Box associated with name in this environment chain. Returns null if no binding exists.
findDeclaredGlobalBox(String name) Box?
Finds the nearest explicit-global binding for name in this lexical chain.
free() → void
Free any resources (for debugging or finalization).
inherited
get(String name) → dynamic
Looks up the value of a variable named name in this environment.
getReferences() List<GCObject>
Return direct references so the GC can traverse the object graph.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
readRootGlobal(String name) → dynamic
Reads the root global binding for name, ignoring local variables.
resolvesThroughDeclaredGlobal(String name) bool
Returns whether name resolves through an explicit global declaration before any local binding when walking the lexical scope chain.
toString() String
A string representation of this object.
inherited
updateLocal(String name, dynamic value) bool
Updates only local variables in the current scope chain.

Operators

operator ==(Object other) bool
The equality operator.
inherited

Static Properties

maxActive int
getter/setter pair
totalCreated int
getter/setter pair
totalFreed int
getter/setter pair

Static Methods

createModuleEnvironment(Environment globalEnv) Environment
Creates a new module environment.