createModuleEnvironment static method

Environment createModuleEnvironment(
  1. Environment globalEnv
)

Creates a new module environment.

This creates an environment suitable for module execution, where local variables are scoped to the module but globals are inherited.

Implementation

static Environment createModuleEnvironment(Environment globalEnv) {
  final rootEnv = globalEnv.root;
  Logger.debugLazy(
    () =>
        "Creating new module environment with global env (${rootEnv.hashCode})",
    category: 'Env',
  );

  final moduleEnv = Environment(parent: rootEnv, interpreter: null);

  final envTable = <dynamic, dynamic>{};
  final envValue = Value(envTable, interpreter: rootEnv.interpreter);
  final inheritedEnvValue = switch (globalEnv.get('_ENV')) {
    final Value value => value,
    final Object? value? => cachedPrimitiveOrValue(
      rootEnv.interpreter,
      value,
    ),
    _ => null,
  };

  final proxyHandler = <String, Function>{
    '__index': (List<Object?> args) {
      final key = args[1] as Value;
      final keyStr = rawLuaSlot(key).toString();
      Logger.debugLazy(
        () => "Module env __index: looking up '$keyStr'",
        category: 'Env',
      );
      if (envTable.containsKey(keyStr)) {
        return envTable[keyStr];
      }
      final inheritedRaw = rawLuaSlot(inheritedEnvValue);
      if (inheritedEnvValue != null && inheritedRaw is Map) {
        final inheritedTable = inheritedRaw;
        if (inheritedTable.containsKey(keyStr)) {
          return inheritedTable[keyStr];
        }
      }
      return rootEnv.get(keyStr);
    },
    '__newindex': (List<Object?> args) {
      final key = args[1] as Value;
      final value = args[2] as Value;
      final keyStr = rawLuaSlot(key).toString();
      final gc = rootEnv.interpreter?.gc ?? GCAccess.defaultManager;
      Logger.debugLazy(
        () => "Module env __newindex: setting '$keyStr' to $value",
        category: 'Env',
      );
      envTable[keyStr] = value;
      gc?.ensureTracked(value);
      gc?.noteReferenceWrite(envValue, keyStr);
      gc?.noteReferenceWrite(envValue, value);
      envValue.markTableModified();
      final inheritedRaw = rawLuaSlot(inheritedEnvValue);
      if (inheritedEnvValue != null && inheritedRaw is Map) {
        final inheritedTable = inheritedRaw;
        inheritedTable[keyStr] = value;
        gc?.noteReferenceWrite(inheritedEnvValue, keyStr);
        gc?.noteReferenceWrite(inheritedEnvValue, value);
        inheritedEnvValue.markTableModified();
      } else {
        rootEnv.defineGlobal(keyStr, value);
      }
      return rootEnv.interpreter?.constantPrimitiveValue(null) ??
          Value.primitive(null);
    },
  };

  envValue.setMetatable(proxyHandler);
  moduleEnv.declare("_ENV", envValue);

  Logger.debugLazy(
    () => "Module environment created with id (${moduleEnv.hashCode})",
    category: 'Env',
  );
  return moduleEnv;
}