defineGlobal method
Defines or updates a global variable in the root environment.
This method provides precise control for global variable assignments by always operating on the root (global) environment, completely ignoring any local variables with the same name in the current scope chain.
Behavior:
- Always operates on the root environment (
root) - Updates existing global variable if it exists
- Creates new global variable if it doesn't exist
- Completely ignores local variables with same name
- Respects const variable restrictions for globals
- Handles to-be-closed variable tracking in root environment
Usage: When we specifically want to create or update a global variable, regardless of whether local variables with the same name exist.
Why needed: The original define() method would find local variables
first and update them instead of creating/updating globals. This method
ensures we can always target the global environment specifically.
Example scenario:
local x = 1 -- Local variable exists
_G.x = 2 -- defineGlobal() should update global, not local
Note: This is used when assignment logic determines that a global assignment is intended (e.g., no local variable exists to update).
Implementation
void defineGlobal(String name, dynamic value) {
Logger.debugLazy(
() => "Defining global variable '$name' = $value",
category: 'Env',
);
final rootEnv = root;
// Check if global variable already exists
if (rootEnv.values.containsKey(name)) {
final box = rootEnv.values[name]!;
if (box.preventsAssignment) {
Logger.debugLazy(
() => "Attempt to modify const global variable '$name'",
category: 'Env',
);
throw LuaError("attempt to assign to const variable '$name'");
}
if (!_tryFastReplaceBoxValue(box, value)) {
box.value = value;
}
Logger.debugLazy(
() =>
"Updated global variable '$name' to $value in root env "
'(${rootEnv.hashCode})',
category: 'Env',
);
} else {
// Create new global variable
Logger.debugLazy(
() =>
"Creating new global variable '$name' with value type "
'${value.runtimeType} (is GCObject: ${value is GCObject})',
category: 'Env',
);
final box = Box(value, interpreter: rootEnv.interpreter);
rootEnv.values[name] = box;
rootEnv._noteChildReference(box);
Logger.debugLazy(
() =>
"Created new global variable '$name' = $value in root env "
'(${rootEnv.hashCode})',
category: 'Env',
);
}
rootEnv._updateCredits();
// Keep the underlying _G table in sync so reads via _G[k] see updates
_syncGlobalTableEntry(name, rootEnv.values[name]!.value);
// Track to-be-closed variables in root environment
if (rootEnv.values[name]!.isToBeClose) {
rootEnv.toBeClosedVars.add(name);
Logger.debugLazy(
() => "Added '$name' to to-be-closed variables list in root env",
category: 'Env',
);
}
}