content: import 'dart:async';
  import 'package:analyzer/dart/ast/ast.dart' hide TypeParameter;
  import 'package:analyzer/dart/ast/token.dart';
  import 'package:d4rt/d4rt.dart';
  
  /// Represents a yield operation in a generator function
  class YieldValue {
    final Object? value;
    final bool isYieldStar;
  
    YieldValue(this.value, {this.isYieldStar = false});
  }
  
  /// Unwraps a BridgedInstance to get the native object if it's an exception
  Object _unwrapExceptionForPropagation(Object? thrownValue) {
    if (thrownValue is BridgedInstance) {
      // If it's a bridged instance, return the native object
      return thrownValue.nativeObject;
    }
    // Otherwise, return the value as-is or a default exception
    return thrownValue ?? Exception('Unknown error');
  }
  
  // Interface or base class for all "callable" entities
  abstract class Callable {
    // Number of expected arguments
    int get arity;
    // Method to execute the callable
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments, List<RuntimeType>? typeArguments]);
  }
  
  class _ExecutionPreparationResult {
    final Environment environment;
    final bool redirected;
    _ExecutionPreparationResult(this.environment, this.redirected);
  }
  
  // Represents a function or method defined by the user
  class InterpretedFunction implements Callable {
    final FormalParameterList? _parameters;
    final FunctionBody _body;
    final Environment _closure;
    final String? _name;
    // Add isInitializer flag for constructors
    final bool isInitializer;
    // Store constructor initializers
    final List<ConstructorInitializer>? _constructorInitializers;
    // Flags for getters and setters
    final bool isGetter;
    final bool isSetter;
    // Store the class/enum where this function/method was defined
    final RuntimeType? ownerType; // Nullable for non-class/enum functions
    // Abstract flag for methods
    final bool isAbstract;
    // Async flag for methods/functions
    final bool isAsync;
    // Generator flags
    final bool isGenerator;
    final bool isAsyncGenerator;
    // Factory flag for constructors
    final bool isFactory;
  
    final RuntimeType? declaredReturnType; // Store the declared type
  
    final bool isNullable; // Store if the return type is nullable
  
    // Store type parameter names from the original declaration
    final List<String> typeParameterNames; // e.g., ['T', 'U', 'V']
  
    // Store type parameter bounds (constraints) from the original declaration
    final Map<String, RuntimeType?>
        typeParameterBounds; // e.g., {'T': num, 'U': Object}
  
    // Public getter for the closure environment
    Environment get closure => _closure;
  
    // Helper method to extract type parameter names from a TypeParameterList
    static List<String> _extractTypeParameterNames(
        TypeParameterList? typeParameters) {
      if (typeParameters == null) return [];
      return typeParameters.typeParameters
          .map((param) => param.name.lexeme)
          .toList();
    }
  
    // Helper method to extract type parameter bounds from a TypeParameterList
    static Map<String, RuntimeType?> _extractTypeParameterBounds(
        TypeParameterList? typeParameters, Environment? resolveEnvironment) {
      final bounds = <String, RuntimeType?>{};
      if (typeParameters == null) return bounds;
  
      for (final typeParam in typeParameters.typeParameters) {
        final paramName = typeParam.name.lexeme;
        RuntimeType? bound;
  
        if (typeParam.bound != null && resolveEnvironment != null) {
          // Use dynamic type resolution instead of static hard-coded types
          try {
            Logger.debug(
                "[InterpretedFunction._extractTypeParameterBounds] Resolving bound for type parameter '$paramName'");
  
            // Use dynamic resolution to look up the bound type in the environment
            bound = _resolveTypeAnnotationDynamic(
                typeParam.bound!, resolveEnvironment);
  
            Logger.debug(
                "[InterpretedFunction._extractTypeParameterBounds] Successfully resolved bound for '$paramName' to: ${bound.name}");
          } catch (e) {
            Logger.debug(
                "[InterpretedFunction._extractTypeParameterBounds] Failed to resolve bound for '$paramName': $e");
            // Re-throw the exception instead of silently ignoring it
            rethrow;
          }
        }
  
        bounds[paramName] = bound;
      }
  
      return bounds;
    }
  
    // Helper method for dynamic type resolution (similar to InterpreterVisitor logic)
    static RuntimeType _resolveTypeAnnotationDynamic(
        TypeAnnotation typeNode, Environment env) {
      if (typeNode is NamedType) {
        final typeName = typeNode.name2.lexeme;
  
        Logger.debug(
            "[InterpretedFunction._resolveTypeAnnotationDynamic] Resolving NamedType: $typeName");
  
        final resolved = env.get(typeName);
        if (resolved is RuntimeType) {
          Logger.debug(
              "[InterpretedFunction._resolveTypeAnnotationDynamic] Resolved from environment to RuntimeType: ${resolved.name}");
          return resolved;
        } else {
          throw RuntimeError(
              "Symbol '$typeName' resolved to non-type value: $resolved");
        }
      } else {
        throw RuntimeError(
            "Unsupported type annotation for constraint: ${typeNode.runtimeType}");
      }
    }
  
    // Private constructor for bind
    InterpretedFunction._internal(
      this._parameters,
      this._body,
      this._closure,
      this._name, {
      this.isInitializer = false,
      List<ConstructorInitializer>? constructorInitializers,
      this.isGetter = false,
      this.isSetter = false,
      this.ownerType,
      this.isAbstract = false,
      this.isAsync = false,
      this.isGenerator = false,
      this.isAsyncGenerator = false,
      this.isFactory = false,
      this.declaredReturnType,
      this.isNullable = false,
      this.typeParameterNames = const [],
      this.typeParameterBounds = const {},
    }) : _constructorInitializers = constructorInitializers;
  
    // Constructor for declared functions (top-level or nested, not methods)
    InterpretedFunction.declaration(FunctionDeclaration declaration,
        Environment closure, RuntimeType? declaredReturnType, bool isNullable)
        : this._internal(
            declaration.functionExpression.parameters,
            declaration.functionExpression.body,
            closure,
            declaration.name.lexeme,
            isGetter: declaration.isGetter, // Pass getter flag
            isSetter: declaration.isSetter, // Pass setter flag
            ownerType: null, // Not defined within a class/enum
            isAbstract: false, // Non-method functions cannot be abstract
            isAsync: declaration
                .functionExpression.body.isAsynchronous, // Pass async flag
            isGenerator: declaration
                .functionExpression.body.isGenerator, // Pass generator flag
            isAsyncGenerator:
                declaration.functionExpression.body.isAsynchronous &&
                    declaration.functionExpression.body
                        .isGenerator, // Pass async generator flag
            declaredReturnType: declaredReturnType,
            isNullable: isNullable,
            typeParameterNames: _extractTypeParameterNames(
                declaration.functionExpression.typeParameters),
            typeParameterBounds: _extractTypeParameterBounds(
                declaration.functionExpression.typeParameters, closure),
          );
  
    // Constructor for function expressions (anonymous)
    InterpretedFunction.expression(
        FunctionExpression expression, Environment closure)
        : this._internal(
            expression.parameters, expression.body, closure, null,
            ownerType: null, // Not defined within a class/enum
            isAbstract: false, // Anonymous functions cannot be abstract
            isAsync: expression.body.isAsynchronous, // Pass async flag
            isGenerator: expression.body.isGenerator, // Pass generator flag
            isAsyncGenerator: expression.body.isAsynchronous &&
                expression.body.isGenerator, // Pass async generator flag
            typeParameterNames:
                _extractTypeParameterNames(expression.typeParameters),
            typeParameterBounds:
                _extractTypeParameterBounds(expression.typeParameters, closure),
          );
  
    // Constructor for methods
    InterpretedFunction.method(
        MethodDeclaration declaration, Environment closure, RuntimeType? owner)
        : this._internal(
            declaration.parameters, declaration.body, closure,
            declaration.name.lexeme,
            // Consider factory methods later
            isInitializer: false, // Methods are not initializers (usually)
            isGetter: declaration.isGetter, // Pass getter flag
            isSetter: declaration.isSetter, // Pass setter flag
            ownerType: owner, // Pass the owner type (class or enum)
            isAbstract: declaration.isAbstract, // Set the abstract flag
            isAsync: declaration.body.isAsynchronous, // Pass async flag
            isGenerator: declaration.body.isGenerator, // Pass generator flag
            isAsyncGenerator: declaration.body.isAsynchronous &&
                declaration.body.isGenerator, // Pass async generator flag
            typeParameterNames:
                _extractTypeParameterNames(declaration.typeParameters),
            typeParameterBounds:
                _extractTypeParameterBounds(declaration.typeParameters, closure),
          );
  
    // Constructor for constructors
    InterpretedFunction.constructor(ConstructorDeclaration declaration,
        Environment closure, RuntimeType? owner)
        : this._internal(
            declaration.parameters, declaration.body, closure,
            declaration.name?.lexeme ?? '', // Use '' for unnamed constructor
            isInitializer: declaration.factoryKeyword ==
                null, // Factory constructors are not initializers
            constructorInitializers:
                declaration.initializers, // Pass to renamed param
            ownerType: owner, // Pass the owner type (class or enum)
            isAbstract: false, // Constructors cannot be abstract
            isAsync: false, // Constructors cannot be async
            isFactory:
                declaration.factoryKeyword != null, // Detect factory constructors
            // Constructors don't have their own type parameters - they inherit from their class
            typeParameterNames: const [],
            typeParameterBounds: const {},
          );
  
    @override
    int get arity {
      if (isSetter) return 1; // Setters always take one argument
      // Original logic for required positional parameters
      final params = _parameters?.parameters;
      if (params == null) return 0;
      return params
          .whereType<NormalFormalParameter>()
          .where((p) => p.isRequiredPositional)
          .length;
    }
  
    // Calculate total positional parameters (required + optional)
    int get _totalPositionalArity {
      final params = _parameters?.parameters;
      if (params == null) return 0;
      return params.where((p) => p.isPositional).length;
    }
  
    /// Binds 'this' to a specific instance, returning a new callable
    /// where the closure has 'this' defined.
    Callable bind(RuntimeValue instance) {
      if (ownerType == null) {
        // Check ownerType instead of definingClass
        throw RuntimeError("Cannot bind 'this' to a non-method function.");
      }
      // Create a new environment that encloses the original function closure,
      // but defines 'this' locally.
      final boundEnvironment = Environment(enclosing: closure);
      boundEnvironment.define('this', instance);
  
      // Define class type parameters in bound environment
      if (instance is InterpretedInstance && ownerType is InterpretedClass) {
        final klass = ownerType as InterpretedClass;
        final instTypeArgs = instance.typeArguments ?? [];
        for (int i = 0; i < klass.typeParameterNames.length; i++) {
          final paramName = klass.typeParameterNames[i];
          final typeArg = i < instTypeArgs.length
              ? instTypeArgs[i]
              : TypeParameter(paramName);
          boundEnvironment.define(paramName, typeArg);
        }
      }
  
      // Create a new function *instance* that uses the bound environment
      // Need to ensure all relevant properties (isGetter, isSetter, etc.) are copied.
      final boundFunction = InterpretedFunction._internal(
        _parameters,
        _body,
        boundEnvironment,
        _name,
        isInitializer: isInitializer,
        constructorInitializers: _constructorInitializers,
        isGetter: isGetter,
        isSetter: isSetter,
        ownerType: ownerType, // Pass ownerType
        isAbstract: isAbstract,
        isAsync: isAsync,
        isGenerator: isGenerator,
        isAsyncGenerator: isAsyncGenerator,
        isFactory: isFactory, // Copy the factory flag
        declaredReturnType: declaredReturnType,
        typeParameterNames: typeParameterNames, // Copy type parameter names
        typeParameterBounds: typeParameterBounds, // Copy type parameter bounds
      );
      return boundFunction;
    }
  
    /// Helper to setup environment, bind args, and run initializers.
    /// Returns the execution environment and whether redirection occurred.
    _ExecutionPreparationResult _prepareExecutionEnvironment(
      InterpreterVisitor visitor,
      List<Object?> positionalArguments,
      Map<String, Object?> namedArguments,
      List<RuntimeType>? typeArguments,
    ) {
      final executionEnvironment = Environment(enclosing: _closure);
  
      // For static methods, add static members of the owner class to the execution environment
      // This allows static methods to call other static methods without prefixing the class name
      bool hasThis = false;
      try {
        _closure.get('this');
        hasThis = true;
      } on RuntimeError {
        hasThis = false;
      }
  
      if (ownerType is InterpretedClass && !isInitializer && !hasThis) {
        final ownerClass = ownerType as InterpretedClass;
        Logger.debug(
            "[InterpretedFunction._prepareExecutionEnvironment] Adding static members of class '${ownerClass.name}' to execution environment.");
  
        // Add all static methods
        for (final entry in ownerClass.staticMethods.entries) {
          final methodName = entry.key;
          final method = entry.value;
          executionEnvironment.define(methodName, method);
          Logger.debug(
              "[InterpretedFunction._prepareExecutionEnvironment] Added static method '$methodName' to execution environment.");
        }
  
        // Add all static getters
        for (final entry in ownerClass.staticGetters.entries) {
          final getterName = entry.key;
          final getter = entry.value;
          executionEnvironment.define(getterName, getter);
          Logger.debug(
              "[InterpretedFunction._prepareExecutionEnvironment] Added static getter '$getterName' to execution environment.");
        }
  
        // Add all static setters
        for (final entry in ownerClass.staticSetters.entries) {
          final setterName = entry.key;
          final setter = entry.value;
          executionEnvironment.define(setterName, setter);
          Logger.debug(
              "[InterpretedFunction._prepareExecutionEnvironment] Added static setter '$setterName' to execution environment.");
        }
  
        // Add all static fields
        for (final entry in ownerClass.staticFields.entries) {
          final fieldName = entry.key;
          final fieldValue = entry.value;
          executionEnvironment.define(fieldName, fieldValue);
          Logger.debug(
              "[InterpretedFunction._prepareExecutionEnvironment] Added static field '$fieldName' to execution environment.");
        }
      }
  
      // Handle type parameters (generics) if provided
      if (typeArguments != null && typeArguments.isNotEmpty) {
        // Use the stored type parameter names from the declaration
        for (int i = 0;
            i < typeArguments.length && i < typeParameterNames.length;
            i++) {
          final paramName = typeParameterNames[i];
          final typeArg = typeArguments[i];
  
          // Define the type parameter in the execution environment
          executionEnvironment.define(paramName, typeArg);
  
          Logger.debug(
              "[InterpretedFunction._prepareExecutionEnvironment] Defined type parameter '$paramName' = ${typeArg.name}");
        }
      }
  
      // Also handle declared type parameters without explicit type arguments
      // (needed for cases where a method has type parameters but no explicit type args are provided)
      if (typeParameterNames.isNotEmpty) {
        for (final paramName in typeParameterNames) {
          // Only define if not already defined by type arguments above
          if (!executionEnvironment.isDefinedLocally(paramName)) {
            // Create a placeholder TypeParameter
            final typeParam = TypeParameter(paramName);
            executionEnvironment.define(paramName, typeParam);
  
            Logger.debug(
                "[InterpretedFunction._prepareExecutionEnvironment] Defined placeholder type parameter '$paramName'");
          }
        }
      }
  
      final params = _parameters?.parameters;
      int positionalArgIndex = 0;
      final providedNamedArgs = namedArguments;
      final processedParamNames = <String>{};
  
      if (params != null) {
        for (final param in params) {
          String? paramName;
          Expression? defaultValueExpr;
          bool isRequired = false;
          bool isOptionalPositional = false;
          bool isNamed = false;
          bool isRequiredNamed = false;
          bool isFieldInitializing = false; // NEW flag
  
          // Determine parameter info
          FormalParameter actualParam =
              param; // Handle potential DefaultFormalParameter wrapper
          if (param is DefaultFormalParameter) {
            defaultValueExpr = param.defaultValue;
            actualParam = param.parameter;
          }
  
          if (actualParam is NormalFormalParameter) {
            paramName = actualParam.name?.lexeme;
            isRequired = actualParam.isRequiredPositional;
            isOptionalPositional = actualParam.isOptionalPositional;
            isNamed = actualParam.isNamed;
            isRequiredNamed = actualParam.isRequiredNamed;
            // Check if it's specifically a field-initializing parameter (this.x)
            if (actualParam is FieldFormalParameter) {
              isFieldInitializing = true;
            }
          } else {
            throw UnimplementedError(
                "Unsupported parameter kind after unwrapping DefaultFormalParameter: ${actualParam.runtimeType}");
          }
  
          if (paramName == null) throw StateError("Parameter missing name");
          processedParamNames.add(paramName);
  
          // Find corresponding argument and value
          Object? valueToDefine;
          bool argumentProvided = false;
  
          if (isOptionalPositional || isRequired) {
            if (positionalArgIndex < positionalArguments.length) {
              valueToDefine = positionalArguments[positionalArgIndex++];
              argumentProvided = true;
            }
          } else if (isNamed) {
            if (providedNamedArgs.containsKey(paramName)) {
              valueToDefine = providedNamedArgs[paramName];
              argumentProvided = true;
            }
          } else {
            // This should not happen if logic above is correct
            throw StateError(
                "Parameter '$paramName' is neither positional nor named?");
          }
  
          // Handle defaults and required checks
          if (!argumentProvided) {
            if (defaultValueExpr != null) {
              final previousVisitorEnv = visitor.environment;
              try {
                // Default values evaluated in the *calling* scope (closure of the function)
                visitor.environment = _closure;
                valueToDefine = defaultValueExpr.accept<Object?>(visitor);
              } finally {
                visitor.environment = previousVisitorEnv;
              }
            } else if (isRequired || isRequiredNamed) {
              throw RuntimeError(
                  "Missing required ${isNamed ? 'named' : ''} argument for '$paramName' in function '${_name ?? '<anonymous>'}'.");
            } else {
              // Optional parameters default to null if no default value specified
              valueToDefine = null;
            }
          }
  
          // Define variable in execution scope OR Initialize field
          if (isFieldInitializing) {
            // It's a `this.fieldName` parameter. Initialize the field directly.
            final thisValue = _closure.get('this')
                as RuntimeValue; // Get 'this' as RuntimeValue
            // Directly call set on the RuntimeValue (works for both Instance and EnumValue)
            // We don't need the visitor here, as field init parameters don't call setters.
            Logger.debug(
                "[_prepareEnv] Attempting to set this.$paramName = $valueToDefine for instance ${thisValue.hashCode}");
            thisValue.set(paramName, valueToDefine);
          } else {
            // It's a regular parameter. Define it in the execution environment.
            executionEnvironment.define(paramName, valueToDefine);
          }
        }
  
        // Final Validation
        if (positionalArgIndex < positionalArguments.length) {
          throw RuntimeError(
              "Too many positional arguments. Expected at most $_totalPositionalArity, got ${positionalArguments.length}.");
        }
        for (final providedName in providedNamedArgs.keys) {
          if (!processedParamNames.contains(providedName)) {
            throw RuntimeError(
                "Function '${_name ?? '<anonymous>'}' does not have a parameter named '$providedName'.");
          }
        }
      } else if (positionalArguments.isNotEmpty || providedNamedArgs.isNotEmpty) {
        throw RuntimeError(
            "Function '${_name ?? '<anonymous>'}' takes no arguments, but arguments were provided.");
      }
  
      bool explicitSuperCalled = false; // Track if super() or this() was called
      bool redirected = false;
      if (isInitializer) {
        // Only run initializers for constructors
        // Determine superclass ONLY if owner is a class
        InterpretedClass? superClass;
        if (ownerType is InterpretedClass) {
          final ownerClass = ownerType as InterpretedClass; // Cast to local var
          superClass = ownerClass.superclass;
        }
  
        // Get 'this' which could be InterpretedInstance OR InterpretedEnumValue
        final RuntimeValue thisValue = _closure.get('this') as RuntimeValue;
  
        if (_constructorInitializers != null &&
            _constructorInitializers.isNotEmpty) {
          final originalVisitorEnv = visitor.environment;
          try {
            // Initializers run in the environment of the constructor *body*,
            // which encloses the closure (with 'this') and params.
            visitor.environment = executionEnvironment;
  
            for (final initializer in _constructorInitializers) {
              if (initializer is ConstructorFieldInitializer) {
                // Handles: this.fieldName = expression
                final fieldName = initializer.fieldName.name;
                final value = initializer.expression.accept<Object?>(visitor);
                if (value is AsyncSuspensionRequest) {
                  // Await in constructor field initializers is not allowed in Dart
                  // The parser would normally catch this, but if it gets here we should provide guidance
                  throw RuntimeError(
                      "Dart language does not allow 'await' expressions in constructor field initializers. "
                      "Consider using a static async factory method instead: "
                      "static Future<${ownerType?.name ?? 'YourClass'}> create() async { /* await initialization */ }");
                }
                thisValue.set(
                    fieldName, value); // No visitor needed for direct field init
              } else if (initializer is SuperConstructorInvocation) {
                // Handles: super(...) or super.named(...)
                if (explicitSuperCalled) {
                  throw RuntimeError(
                      "Cannot call 'super' or 'this' multiple times in a constructor initializer list.");
                }
                if (ownerType is! InterpretedClass) {
                  // Should not happen if this is called from a constructor
                  throw StateError(
                      "Super constructor call outside of class context.");
                }
                final ownerClass = ownerType as InterpretedClass;
                final InterpretedClass? dartSuperClass = ownerClass.superclass;
                final BridgedClass? bridgedSuperClass =
                    ownerClass.bridgedSuperclass;
  
                if (dartSuperClass == null && bridgedSuperClass == null) {
                  throw RuntimeError(
                      "Cannot call 'super' in constructor of class '${ownerType?.name}' because it has no superclass."); // Use ownerType?.name
                }
  
                final superConstructorName =
                    initializer.constructorName?.name ?? '';
  
                if (dartSuperClass != null) {
                  final superConstructor =
                      dartSuperClass.findConstructor(superConstructorName);
                  if (superConstructor == null) {
                    throw RuntimeError(
                        "Superclass '${dartSuperClass.name}' does not have a constructor named '$superConstructorName'.");
                  }
                  // Evaluate arguments (existing logic)
                  final (superPositionalArgs, superNamedArgs) =
                      _evaluateArgumentsForInvocation(
                          visitor, initializer.argumentList, "super()");
                  // Call Dart super constructor (existing logic)
                  final superCallResult = superConstructor
                      .bind(thisValue)
                      .call(visitor, superPositionalArgs, superNamedArgs);
                  if (superCallResult is AsyncSuspensionRequest) {
                    throw StateError(
                        "Internal error: Super constructor call returned SuspendedState.");
                  }
                } else if (bridgedSuperClass != null) {
                  final constructorAdapter = bridgedSuperClass
                      .findConstructorAdapter(superConstructorName);
                  if (constructorAdapter == null) {
                    throw RuntimeError(
                        "Bridged superclass '${bridgedSuperClass.name}' does not have a constructor named '$superConstructorName'. Check bridge definition.");
                  }
                  // Evaluate arguments (using helper)
                  final (superPositionalArgs, superNamedArgs) =
                      _evaluateArgumentsForInvocation(
                          visitor, initializer.argumentList, "super()");
                  // Call the bridged constructor adapter
                  try {
                    // Adapter needs the *visitor* and args. It does NOT operate on 'thisValue' directly.
                    // The adapter is responsible for finding/creating the native object.
                    final nativeSuperObject = constructorAdapter(
                        visitor, superPositionalArgs, superNamedArgs);
  
                    // We need to associate this new native object with our current instance.
                    if (thisValue is InterpretedInstance) {
                      // Store the returned native object in the public field
                      thisValue.bridgedSuperObject =
                          nativeSuperObject; // Use the public field
                      Logger.debug(
                          "[SuperCall] Stored native object from bridged super constructor '$superConstructorName' ($nativeSuperObject)");
                    } else {
                      // This case (e.g., calling super() from an enum constructor?) seems unlikely/invalid.
                      throw StateError(
                          "Cannot call super() constructor on non-instance 'this'.");
                    }
                  } on RuntimeError catch (e) {
                    throw RuntimeError(
                        "Error during bridged super constructor '$superConstructorName': ${e.message}");
                  } catch (e) {
                    throw RuntimeError(
                        "Native error during bridged super constructor '$superConstructorName': $e");
                  }
                } else {
                  // Should be impossible given the check at the start
                  throw StateError(
                      "Internal error: No superclass found despite initial check.");
                }
                explicitSuperCalled = true;
              } else if (initializer is RedirectingConstructorInvocation) {
                // Handles: this(...)
                if (explicitSuperCalled) {
                  throw RuntimeError(
                      "Cannot call 'super' or 'this' multiple times in a constructor initializer list.");
                }
  
                final targetConstructorName =
                    initializer.constructorName?.name ?? '';
                InterpretedFunction? targetConstructor;
                if (ownerType is InterpretedClass) {
                  final ownerClass =
                      ownerType as InterpretedClass; // Cast to local var
                  targetConstructor =
                      ownerClass.findConstructor(targetConstructorName);
                }
                if (targetConstructor == null) {
                  throw RuntimeError(
                      "Class '${ownerType?.name ?? '<unknown>'}' does not have a constructor named '$targetConstructorName' for redirection."); // Use ownerType?.name
                }
  
                // Evaluate arguments for this(...) call
                final List<Object?> targetPositionalArgs = [];
                final Map<String, Object?> targetNamedArgs = {};
                bool targetNamedArgsEncountered = false;
                for (final arg in initializer.argumentList.arguments) {
                  final argValue = arg.accept<Object?>(visitor);
                  if (argValue is AsyncSuspensionRequest) {
                    throw RuntimeError(
                        "Dart language does not allow 'await' expressions in redirecting constructor call arguments. "
                        "Consider using a static async factory method instead: "
                        "static Future<${ownerType?.name ?? 'YourClass'}> create() async { /* await initialization */ }");
                  }
  
                  if (arg is NamedExpression) {
                    targetNamedArgsEncountered = true;
                    final name = arg.name.label.name;
                    // Use already evaluated value
                    if (targetNamedArgs.containsKey(name)) {
                      throw RuntimeError(
                          "Named argument '$name' provided multiple times to this().");
                    }
                    targetNamedArgs[name] = argValue;
                  } else {
                    if (targetNamedArgsEncountered) {
                      throw RuntimeError(
                          "Positional arguments cannot follow named arguments in this().");
                    }
                    targetPositionalArgs
                        .add(argValue); // Use already evaluated value
                  }
                }
  
                // Call the target constructor, bound to the *same* instance
                // NOTE: Redirecting constructor call CANNOT suspend
                final redirectCallResult = targetConstructor
                    .bind(thisValue)
                    .call(visitor, targetPositionalArgs, targetNamedArgs);
                if (redirectCallResult is AsyncSuspensionRequest) {
                  // Should not happen as constructors are not async
                  throw StateError(
                      "Internal error: Redirecting constructor call returned SuspendedState.");
                }
  
                explicitSuperCalled = true;
                redirected = true; // Mark that redirection occurred
              } else {
                throw StateError(
                    "Unknown constructor initializer type: ${initializer.runtimeType}");
              }
            }
          } finally {
            visitor.environment =
                originalVisitorEnv; // Restore visitor environment
          }
        }
  
        // If no explicit super() or this() was called, and there IS a superclass,
        // implicitly call the superclass's unnamed constructor with no arguments.
        if (!explicitSuperCalled && superClass != null) {
          final defaultSuperConstructor = superClass.findConstructor('');
          if (defaultSuperConstructor == null) {
            throw RuntimeError(
                "Implicit call to superclass '${superClass.name}' default constructor failed: No default constructor found.");
          }
          // Call the default super constructor, bound to the *current* instance
          // NOTE: Default super constructor call CANNOT suspend
          final defaultSuperResult =
              defaultSuperConstructor.bind(thisValue).call(visitor, [], {});
          if (defaultSuperResult is AsyncSuspensionRequest) {
            // Should not happen as constructors are not async
            throw StateError(
                "Internal error: Implicit super constructor call returned SuspendedState.");
          }
        }
      }
  
      return _ExecutionPreparationResult(executionEnvironment, redirected);
    }
  
    /// Validate type arguments for generic functions/methods
    void _validateTypeArguments(List<RuntimeType>? typeArguments,
        List<Object?> positionalArguments, Map<String, Object?> namedArguments) {
      if (typeArguments == null || typeArguments.isEmpty) {
        return; // No type arguments to validate
      }
  
      // For factory constructors, type arguments come from the class, not the method
      // Skip validation if this is a factory constructor or regular constructor
      if (isFactory || isInitializer) {
        return; // Factory constructors inherit type parameters from their class
      }
  
      // Validate that the number of type arguments matches the number of type parameters
      if (typeArguments.length > typeParameterNames.length) {
        throw RuntimeError(
            "Too many type arguments for function '${_name ?? '<anonymous>'}'. Expected at most ${typeParameterNames.length}, got ${typeArguments.length}.");
      }
  
      // Check type bounds for each type argument
      _validateTypeBounds(typeArguments);
  
      // Validate parameter types against type arguments
      _validateParameterTypes(typeArguments, positionalArguments, namedArguments);
  
      // Check return type constraints (will be validated at return time)
      // Return type validation happens in visitReturnStatement
  
      Logger.debug(
          "[InterpretedFunction._validateTypeArguments] Validated ${typeArguments.length} type arguments for function '${_name ?? '<anonymous>'}'");
    }
  
    /// Validate that type arguments respect their bounds constraints
    void _validateTypeBounds(List<RuntimeType> typeArguments) {
      for (int i = 0;
          i < typeArguments.length && i < typeParameterNames.length;
          i++) {
        final typeArg = typeArguments[i];
        final paramName = typeParameterNames[i];
        final bound = typeParameterBounds[paramName];
  
        Logger.debug(
            "[InterpretedFunction._validateTypeBounds] Type parameter '$paramName' bound check for argument '${typeArg.name}'");
  
        if (bound != null) {
          // Check if the type argument satisfies the bound constraint
          bool satisfiesBound = _checkTypeSatisfiesBound(typeArg, bound);
  
          if (!satisfiesBound) {
            throw RuntimeError(
                "Type argument '${typeArg.name}' for type parameter '$paramName' does not satisfy bound '${bound.name}' in function '${_name ?? '<anonymous>'}'");
          }
  
          Logger.debug(
              "[InterpretedFunction._validateTypeBounds] Type parameter '$paramName' with argument '${typeArg.name}' satisfies bound '${bound.name}'");
        } else {
          Logger.debug(
              "[InterpretedFunction._validateTypeBounds] Type parameter '$paramName' has no bound constraint");
        }
  
        // Example basic validation - could be extended
        if (typeArg.name == 'Null') {
          Logger.debug(
              "[InterpretedFunction._validateTypeBounds] Warning: Null type argument for parameter '$paramName'");
        }
      }
    }
  
    /// Check if a type argument satisfies a bound constraint
    bool _checkTypeSatisfiesBound(RuntimeType typeArg, RuntimeType bound) {
      // If the type argument is the same as the bound, it satisfies the constraint
      if (typeArg == bound || typeArg.name == bound.name) {
        return true;
      }
  
      // Special handling for common native types
      if (bound.name == 'num') {
        // Check if typeArg is a numeric type
        if (typeArg is BridgedClass) {
          return typeArg.nativeType == int ||
              typeArg.nativeType == double ||
              typeArg.nativeType == num;
        }
        // For other types, check the name
        return typeArg.name == 'int' ||
            typeArg.name == 'double' ||
            typeArg.name == 'num';
      }
  
      if (bound.name == 'Object') {
        // Everything extends Object (except possibly void/dynamic)
        return typeArg.name != 'void';
      }
  
      if (bound.name == 'Comparable') {
        // Check if the type implements Comparable
        if (typeArg is BridgedClass) {
          try {
            // Basic check for common comparable types
            return typeArg.nativeType == String ||
                typeArg.nativeType == int ||
                typeArg.nativeType == double ||
                typeArg.nativeType == DateTime;
          } catch (e) {
            return false;
          }
        }
        return typeArg.name == 'String' ||
            typeArg.name == 'int' ||
            typeArg.name == 'double';
      }
  
      // Check if the type argument is a subtype of the bound
      try {
        return typeArg.isSubtypeOf(bound);
      } catch (e) {
        Logger.debug(
            "[InterpretedFunction._checkTypeSatisfiesBound] Error checking subtype relationship: $e");
        // If we can't determine the relationship, default to allowing it
        // In a stricter implementation, this might default to false
        return true;
      }
    }
  
    /// Validate that positional and named arguments match the expected types
    void _validateParameterTypes(List<RuntimeType> typeArguments,
        List<Object?> positionalArguments, Map<String, Object?> namedArguments) {
      // Basic validation - check if arguments are compatible with function signature
      // This is a simplified implementation
  
      Logger.debug(
          "[InterpretedFunction._validateParameterTypes] Validating ${positionalArguments.length} positional and ${namedArguments.length} named arguments");
  
      // For each positional argument, try basic type compatibility check
      for (int i = 0; i < positionalArguments.length; i++) {
        final argument = positionalArguments[i];
  
        if (argument != null) {
          Logger.debug(
              "[InterpretedFunction._validateParameterTypes] Argument $i: ${argument.runtimeType}");
  
          // Additional type checking could be implemented here
          // For example, checking against expected parameter types from function signature
        }
      }
  
      // For each named argument, try basic type compatibility check
      for (final entry in namedArguments.entries) {
        final argName = entry.key;
        final argValue = entry.value;
  
        if (argValue != null) {
          Logger.debug(
              "[InterpretedFunction._validateParameterTypes] Named argument '$argName': ${argValue.runtimeType}");
        }
      }
  
      // More sophisticated validation would require:
      // 1. Access to the function's parameter type annotations
      // 2. Type substitution logic for generic parameters
      // 3. Runtime type compatibility checking
    }
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments]) {
      Logger.debug(
          "[InterpretedFunction.call] Called '${_name ?? 'anonymous'}' with ${positionalArguments.length} positional, ${namedArguments.length} named arguments.");
  
      final previousFunction = visitor.currentFunction;
      final previousAsyncState = visitor.currentAsyncState;
  
      try {
        visitor.currentFunction = this;
  
        final preparationResult = _prepareExecutionEnvironment(
            visitor, positionalArguments, namedArguments, typeArguments);
  
        // Validate generic type arguments if provided
        _validateTypeArguments(
            typeArguments, positionalArguments, namedArguments);
  
        final executionEnvironment = preparationResult.environment;
        final redirected = preparationResult.redirected;
  
        final previousCurrentFunction = visitor.currentFunction; // Save previous
        visitor.currentFunction = this; // Set current function
        final previousAsyncState =
            visitor.currentAsyncState; // Save current async state
  
        try {
          if (isAsyncGenerator) {
            // Handle async* functions - return a Stream
            return _createAsyncGeneratorStream(
                visitor, executionEnvironment, redirected);
          } else if (isGenerator) {
            // Handle sync* functions - return an Iterable
            return _createSyncGeneratorIterable(
                visitor, executionEnvironment, redirected);
          } else if (isAsync) {
            final completer = Completer<Object?>();
  
            // Determine the first state (AST node)
            AstNode? initialStateIdentifier;
            final bodyToExecute = _body;
            if (!redirected) {
              if (bodyToExecute is BlockFunctionBody) {
                initialStateIdentifier =
                    bodyToExecute.block.statements.firstOrNull;
              } else if (bodyToExecute is ExpressionFunctionBody) {
                initialStateIdentifier = bodyToExecute.expression;
              } else if (bodyToExecute is EmptyFunctionBody) {
                initialStateIdentifier =
                    null; // Empty function, completes immediately
              } else {
                throw StateError(
                    "Unhandled function body type for async state machine: ${bodyToExecute.runtimeType}");
              }
            } else {
              // Redirecting constructor, completes with 'this'
              initialStateIdentifier = null;
            }
  
            // Create the initial state
            final asyncState = AsyncExecutionState(
              environment: executionEnvironment,
              completer: completer,
              nextStateIdentifier: initialStateIdentifier,
              function: this,
            );
  
            // Handle cases where the function completes immediately
            if (initialStateIdentifier == null) {
              if (redirected) {
                completer.complete(executionEnvironment.get('this'));
              } else {
                completer.complete(null); // Empty function
              }
            } else {
              // The engine will take care of scheduling (ex: via Future.microtask)
              // Put the visitor in the initial state for the engine
              visitor.currentAsyncState = asyncState;
              _startAsyncStateMachine(visitor, asyncState);
            }
  
            // Return immediately the Future
            return completer.future;
          } else {
            Object? syncResult;
            final previousVisitorEnv = visitor.environment; // Save env
            try {
              if (isAbstract) {
                throw RuntimeError(
                    "Cannot call abstract method '${_name ?? '<abstract>'}'.");
              }
  
              final bodyToExecute = _body;
  
              if (!redirected) {
                if (bodyToExecute is BlockFunctionBody) {
                  syncResult = visitor.executeBlock(
                      bodyToExecute.block.statements, executionEnvironment);
                } else if (bodyToExecute is ExpressionFunctionBody) {
                  visitor.environment = executionEnvironment;
                  syncResult = bodyToExecute.expression.accept<Object?>(visitor);
                } else if (bodyToExecute is EmptyFunctionBody) {
                  if (!isInitializer && _name != null) {
                    throw RuntimeError(
                        "Cannot execute non-constructor function $_name' with empty body.");
                  }
                  syncResult = null;
                } else {
                  throw StateError(
                      "Unhandled function body type: ${bodyToExecute.runtimeType}");
                }
              } else {
                Logger.debug(
                    " [InterpretedFunction.call sync] Body skipped due to redirecting constructor for $_name");
                // If redirected, the value is 'this'
                syncResult = _closure.get('this');
              }
            } on ReturnException catch (returnExc) {
              syncResult = returnExc.value;
            } finally {
              visitor.currentFunction =
                  previousCurrentFunction; // Restore function
              visitor.environment = previousVisitorEnv; // Restore environment
            }
  
            // For initializers (constructors), always return 'this'
            if (isInitializer) {
              try {
                return _closure.get('this');
              } catch (_) {
                throw StateError(
                    "Internal error: 'this' not found in bound constructor environment.");
              }
            } else {
              // Check if the synchronous execution resulted in a suspension (shouldn't happen if await is blocked)
              if (syncResult is AsyncSuspensionRequest) {
                throw StateError(
                    "Internal error: Synchronous function returned SuspendedState.");
              }
              return syncResult; // Return sync result
            }
          }
        } on ReturnException catch (e) {
          // Catch return from synchronous functions
          return e.value;
        } finally {
          visitor.currentFunction = previousCurrentFunction; // Restore previous
  
          // Restaurer l'état asynchrone précédent au lieu de l'écraser
          visitor.currentAsyncState = previousAsyncState;
          Logger.debug(
              " [InterpretedFunction.call FINALLY] Restored currentFunction and currentAsyncState. AsyncState is now: ${visitor.currentAsyncState?.hashCode}");
        }
      } on ReturnException catch (e) {
        // Catch return from asynchronous functions
        return e.value;
      } finally {
        visitor.currentFunction = previousFunction;
        visitor.currentAsyncState = previousAsyncState;
      }
    }
  
    // Main engine of the async state machine
    // Scheduled via Future.microtask to start execution
    static Future<void> _runStateMachine(
        InterpreterVisitor visitor, AsyncExecutionState currentState) async {
      Object? lastResult;
      AstNode? currentNode = currentState.nextStateIdentifier;
  
      // Main loop of state machine execution
      while (currentNode != null) {
        // Save current visitor environment (in case of error)
        final originalVisitorEnv = visitor.environment;
        final previousAsyncState = visitor.currentAsyncState;
  
        // Configure the visitor for the current state
        // Use the top of the loop environment stack if it exists, otherwise the state environment
        if (currentState.loopEnvironmentStack.isNotEmpty) {
          visitor.environment = currentState.loopEnvironmentStack.last;
        } else {
          visitor.environment = currentState.environment;
        }
        visitor.currentAsyncState = currentState;
        // currentFunction is already defined by the call method
  
        Logger.debug(
            " [StateMachine] Executing state: ${currentNode.runtimeType} in state env ${currentState.environment.hashCode}, loop stack depth: ${currentState.loopEnvironmentStack.length}. Visitor env set to: ${visitor.environment.hashCode}");
  
        try {
          // Case: While loop
          if (currentNode is WhileStatement) {
            final whileNode = currentNode;
            Logger.debug("[StateMachine] Handling WhileStatement condition.");
            // Evaluate the condition
            final conditionResult = whileNode.condition.accept<Object?>(visitor);
  
            if (conditionResult is AsyncSuspensionRequest) {
              // The condition itself is asynchronous, suspend
              Logger.debug(
                  " [StateMachine] While condition suspended. Waiting...");
              lastResult =
                  conditionResult; // Update lastResult for the processing below
            } else if (conditionResult is bool) {
              // Synchronous condition
              if (conditionResult) {
                // True condition: the next state is the body of the loop
                Logger.debug(
                    "[StateMachine] While condition TRUE. Next node is body: ${whileNode.body.runtimeType}");
                // If the body is a block, take the first statement
                if (whileNode.body is Block) {
                  currentNode = (whileNode.body as Block).statements.firstOrNull;
                } else {
                  currentNode = whileNode.body;
                }
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the while loop of the state machine with the new node
              } else {
                // False condition: skip the loop, find the next node after the while
                Logger.debug(
                    "[StateMachine] While condition FALSE. Finding node after while.");
                currentNode = _findNextSequentialNode(visitor, whileNode);
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the while loop of the state machine
              }
            } else {
              // The condition did not return a boolean or suspension
              throw RuntimeError(
                  "While loop condition must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
            }
          } else if (currentNode is DoStatement) {
            final doNode = currentNode;
            // The logic of DoStatement is particular:
            // 1. If we arrive on the DoStatement the *first time* (or after a true condition),
            //    we need to execute the body.
            // 2. If we arrive on the DoStatement after having executed the *last* instruction of the body
            //    (detected by _findNextSequentialNode returning the DoStatement),
            //    we need to evaluate the condition.
  
            // To differentiate, we can look at the previous state or add a flag in AsyncExecutionState.
            // Simple approach: if the current state points to DoStatement, we assume we need to evaluate the condition
            // because _findNextSequentialNode led us to the DoStatement from the end of the body.
            // If we entered the loop in a non-standard way, this could fail.
  
            Logger.debug(
                "[StateMachine] Handling DoStatement. Evaluating condition.");
            // Evaluate the condition
            final conditionResult = doNode.condition.accept<Object?>(visitor);
  
            if (conditionResult is AsyncSuspensionRequest) {
              // The condition is asynchronous, suspend
              Logger.debug(
                  " [StateMachine] DoWhile condition suspended. Waiting...");
              lastResult =
                  conditionResult; // Update lastResult for the processing below
            } else if (conditionResult is bool) {
              // Synchronous condition
              if (conditionResult) {
                // True condition: the next state is the beginning of the loop body
                Logger.debug(
                    "[StateMachine] DoWhile condition TRUE. Next node is body: ${doNode.body.runtimeType}");
                if (doNode.body is Block) {
                  currentNode = (doNode.body as Block).statements.firstOrNull;
                } else {
                  currentNode = doNode.body;
                }
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the state machine loop with the beginning of the body
              } else {
                // False condition: exit the loop, find the next node after the do-while
                Logger.debug(
                    "[StateMachine] DoWhile condition FALSE. Finding node after do-while.");
                currentNode = _findNextSequentialNode(visitor, doNode);
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the state machine loop
              }
            } else {
              // The condition did not return a boolean or suspension
              throw RuntimeError(
                  "DoWhile loop condition must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
            }
            // If the condition was suspended, lastResult contains AsyncSuspensionRequest
            // and will be handled by the suspension logic below.
          } else if (currentNode is ForStatement &&
              currentNode.forLoopParts is ForEachParts) {
            final forNode = currentNode;
            final parts = forNode.forLoopParts as ForEachParts;
  
            // Check if this is an await for loop
            if (forNode.awaitKeyword != null) {
              // This is an await for loop - handle it natively in the state machine
              Logger.debug(
                  "[StateMachine] Detected await for loop, handling natively.");
  
              // Check if this await-for loop is already in the stack
              final awaitForLoopIndex =
                  currentState.awaitForNodeStack.indexOf(forNode);
              final bool isExistingAwaitForLoop = awaitForLoopIndex >= 0;
  
              // Get or initialize the state for this specific await-for loop
              List<Object?>? awaitForList;
              int? awaitForIndex;
  
              if (isExistingAwaitForLoop) {
                // This loop is already in the stack, retrieve its state
                awaitForList = currentState.awaitForListStack[awaitForLoopIndex];
                awaitForIndex =
                    currentState.awaitForIndexStack[awaitForLoopIndex];
                Logger.debug(
                    "[StateMachine] AwaitForIn: Resuming existing loop at stack index $awaitForLoopIndex");
              }
  
              // Check if we need to initialize this await-for loop
              if (!isExistingAwaitForLoop && awaitForList == null) {
                // First time: evaluate the stream and convert to list
                Logger.debug("[StateMachine] AwaitForIn: Evaluating stream.");
                final streamResult = parts.iterable.accept<Object?>(visitor);
  
                if (streamResult is AsyncSuspensionRequest) {
                  Logger.debug(
                      "[StateMachine] AwaitForIn stream evaluation suspended. Waiting...");
                  lastResult = streamResult;
                  // The suspension logic below will handle it.
                } else {
                  // We have a stream, convert it to a list asynchronously
                  Object? streamValue;
                  if (visitor.toBridgedInstance(streamResult).$2) {
                    final bridgedInstance =
                        visitor.toBridgedInstance(streamResult).$1!;
                    if (bridgedInstance.nativeObject is Stream) {
                      streamValue = bridgedInstance.nativeObject;
                    } else {
                      throw RuntimeError(
                          'Value used in await for-in loop must be a Stream, but got BridgedInstance containing ${bridgedInstance.nativeObject.runtimeType}');
                    }
                  } else if (streamResult is Stream) {
                    streamValue = streamResult;
                  } else {
                    throw RuntimeError(
                        'Value used in await for-in loop must be a Stream, but got ${streamResult?.runtimeType}');
                  }
  
                  if (streamValue is Stream) {
                    // Create a suspension request to convert stream to list
                    lastResult = AsyncSuspensionRequest(
                      streamValue.toList(),
                      currentState,
                    );
                    // Mark that we're waiting for stream conversion
                    currentState.awaitingStreamConversion = true;
                    // Add this loop to the stack as "pending initialization"
                    currentState.awaitForNodeStack.add(forNode);
                    currentState.awaitForListStack
                        .add([]); // Placeholder until stream converts
                    currentState.awaitForIndexStack.add(0);
                  }
                }
              } else if (currentState.awaitingStreamConversion == true) {
                // We just finished converting the stream to a list
                currentState.awaitingStreamConversion = false;
                final List<Object?> items =
                    currentState.lastAwaitResult as List<Object?>;
  
                // Store in the stack for the current await-for loop
                final stackIndex =
                    currentState.awaitForNodeStack.indexOf(forNode);
                if (stackIndex >= 0) {
                  currentState.awaitForListStack[stackIndex] = items;
                  currentState.awaitForIndexStack[stackIndex] = 0;
                  awaitForList = items;
                  awaitForIndex = 0;
                }
  
                // Keep legacy fields for backward compatibility
                currentState.currentAwaitForList = items;
                currentState.currentAwaitForIndex = 0;
  
                Logger.debug(
                    "[StateMachine] AwaitForIn: Stream converted to list with ${items.length} items at stack index $stackIndex.");
  
                // Set up the loop variable environment - create a dedicated environment
                if (parts is ForEachPartsWithDeclaration) {
                  final loopVariable = parts.loopVariable;
                  // Create an environment for this await-for loop
                  final parentEnv = currentState.loopEnvironmentStack.isNotEmpty
                      ? currentState.loopEnvironmentStack.last
                      : currentState.environment;
                  final awaitForEnv = Environment(enclosing: parentEnv);
                  awaitForEnv.define(loopVariable.name.lexeme, null);
  
                  // Add to the loop environment stack
                  currentState.loopEnvironmentStack.add(awaitForEnv);
                  currentState.loopNodeStack.add(forNode);
                  visitor.environment = awaitForEnv;
  
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Created environment ${awaitForEnv.hashCode} with parent ${parentEnv.hashCode}");
                }
  
                // Continue to process the first item
              }
  
              // Determine which list and index to use
              if (isExistingAwaitForLoop && awaitForList != null) {
                // Use the state from the stack
                final items = awaitForList;
                final currentIndex = awaitForIndex ?? 0;
  
                if (currentIndex < items.length) {
                  // Process current item
                  final currentItem = items[currentIndex];
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Processing item $currentIndex: $currentItem (stack level ${currentState.awaitForNodeStack.length})");
  
                  // Restore the environment for this await-for loop
                  // Find the stack index for this await-for loop
                  final awaitForLoopIndex =
                      currentState.awaitForNodeStack.indexOf(forNode);
                  if (awaitForLoopIndex >= 0 &&
                      awaitForLoopIndex <
                          currentState.loopEnvironmentStack.length) {
                    visitor.environment =
                        currentState.loopEnvironmentStack[awaitForLoopIndex];
                    Logger.debug(
                        "[StateMachine] AwaitForIn: Restored visitor environment to ${visitor.environment.hashCode} (await-for loop index $awaitForLoopIndex)");
                  } else {
                    Logger.debug(
                        "[StateMachine] AwaitForIn: Could NOT find environment for await-for loop at index $awaitForLoopIndex!");
                  }
  
                  if (parts is ForEachPartsWithDeclaration) {
                    visitor.environment
                        .assign(parts.loopVariable.name.lexeme, currentItem);
                  } else if (parts is ForEachPartsWithIdentifier) {
                    visitor.environment
                        .assign(parts.identifier.name, currentItem);
                  }
  
                  // Execute the body through the state machine, not manually
                  // This ensures proper suspension/resumption handling for await expressions
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Executing body for item $currentIndex");
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Next node is body: ${forNode.body.runtimeType}");
  
                  // Increment the index NOW, before executing the body
                  // This way, when the body completes and we return to ForStatement,
                  // we'll move to the next item instead of re-processing the current one
                  currentState.awaitForIndexStack[awaitForLoopIndex] =
                      currentIndex + 1;
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Pre-incremented index to ${currentIndex + 1}");
  
                  if (forNode.body is Block) {
                    currentNode = (forNode.body as Block).statements.firstOrNull;
                  } else {
                    currentNode = forNode.body;
                  }
                  currentState.nextStateIdentifier = currentNode;
                  continue; // Let state machine execute the body
                } else {
                  // End of iteration - remove this loop from the stack
                  Logger.debug(
                      "[StateMachine] AwaitForIn: Iteration finished for stack level ${currentState.awaitForNodeStack.length}.");
  
                  final stackIdx =
                      currentState.awaitForNodeStack.indexOf(forNode);
                  if (stackIdx >= 0) {
                    currentState.awaitForNodeStack.removeAt(stackIdx);
                    currentState.awaitForListStack.removeAt(stackIdx);
                    currentState.awaitForIndexStack.removeAt(stackIdx);
                    Logger.debug(
                        "[StateMachine] AwaitForIn: Removed loop from stack. Remaining depth: ${currentState.awaitForNodeStack.length}");
                  }
  
                  // Clean up the loop environment
                  final loopEnvIndex =
                      currentState.loopNodeStack.indexOf(forNode);
                  if (loopEnvIndex >= 0 &&
                      loopEnvIndex < currentState.loopEnvironmentStack.length) {
                    // Restore the parent environment
                    final loopEnv =
                        currentState.loopEnvironmentStack[loopEnvIndex];
                    visitor.environment =
                        loopEnv.enclosing ?? currentState.environment;
  
                    // Remove from stacks
                    currentState.loopEnvironmentStack.removeAt(loopEnvIndex);
                    currentState.loopNodeStack.removeAt(loopEnvIndex);
                    Logger.debug(
                        "[StateMachine] AwaitForIn: Restored parent environment ${visitor.environment.hashCode}");
                  }
  
                  // Clean up legacy fields if this was the last await-for loop
                  if (currentState.awaitForNodeStack.isEmpty) {
                    currentState.currentAwaitForList = null;
                    currentState.currentAwaitForIndex = null;
                  }
  
                  currentNode = _findNextSequentialNode(visitor, forNode);
                  currentState.nextStateIdentifier = currentNode;
                  continue; // Restart the state machine loop
                }
              }
            } else {
              // Regular for-in loop handling
              // Check if this loop already has an iterator on the stack
              final loopIndex = currentState.loopNodeStack.indexOf(forNode);
              Iterator<Object?>? iterator;
  
              Logger.debug(
                  "[StateMachine] ForIn: Checking for existing loop. loopIndex=$loopIndex, stack size=${currentState.loopNodeStack.length}, forNode hashCode=${forNode.hashCode}");
              Logger.debug(
                  "[StateMachine] ForIn: forInIteratorMap size=${currentState.forInIteratorMap.length}");
              if (currentState.loopNodeStack.isNotEmpty) {
                Logger.debug(
                    "[StateMachine] ForIn: Stack nodes hashCodes: ${currentState.loopNodeStack.map((n) => n.hashCode).join(', ')}");
              }
  
              // Check if iterator exists for this forNode in the map
              if (currentState.forInIteratorMap.containsKey(forNode)) {
                // This loop is already initialized, retrieve its iterator
                iterator = currentState.forInIteratorMap[forNode];
                Logger.debug(
                    "[StateMachine] ForIn: Resumed existing loop at index $loopIndex");
              }
  
              // First time OR node in stack but no iterator yet?
              if (iterator == null && loopIndex == -1) {
                // First time seeing this loop - evaluate iterable and create iterator
                Logger.debug(
                    " [StateMachine] Handling ForIn: Evaluating iterable (first time).");
                final iterableResult = parts.iterable.accept<Object?>(visitor);
  
                // Handle if the iterable evaluation is suspended
                if (iterableResult is AsyncSuspensionRequest) {
                  Logger.debug(
                      "[StateMachine] ForIn iterable suspended. Waiting...");
                  lastResult = iterableResult;
                  // The suspension logic below will handle it.
                } else if (iterableResult is Iterable) {
                  iterator = iterableResult.iterator;
                  currentState.currentForInIterator =
                      iterator; // Save the iterator (keep for compatibility)
                  // Add node and iterator to map/stack immediately
                  currentState.loopNodeStack.add(forNode);
                  currentState.forInIteratorMap[forNode] = iterator;
                  Logger.debug(
                      "[StateMachine] ForIn: Iterator created and added to stacks at index ${currentState.loopNodeStack.length - 1}");
                } else {
                  throw RuntimeError(
                      "The value iterate over in a for-in loop must be an Iterable, but got ${iterableResult?.runtimeType}.");
                }
              }
  
              // If we have an iterator (either created or resumed), we continue the loop
              if (iterator != null && lastResult is! AsyncSuspensionRequest) {
                bool hasNext;
                try {
                  hasNext = iterator.moveNext();
                } catch (e, s) {
                  Logger.warn(
                      "[StateMachine] Error during iterator.moveNext(): $e\n$s");
                  throw RuntimeError("Error during iteration: $e");
                }
  
                if (hasNext) {
                  // Next item available
                  final currentItem = iterator.current;
                  Logger.debug(
                      "[StateMachine] ForIn: Got next item: $currentItem");
  
                  if (parts is ForEachPartsWithDeclaration) {
                    final loopVariable = parts.loopVariable;
                    // Find the environment for this loop
                    final loopIndex = currentState.loopNodeStack.indexOf(forNode);
                    // Check if environment exists at this index
                    if (loopIndex >= 0 &&
                        loopIndex < currentState.loopEnvironmentStack.length) {
                      // Environment already exists, use it and assign the variable
                      visitor.environment =
                          currentState.loopEnvironmentStack[loopIndex];
                      // Assign (not define) the loop variable for the current iteration
                      currentState.loopEnvironmentStack[loopIndex]
                          .assign(loopVariable.name.lexeme, currentItem);
                    } else {
                      // Environment doesn't exist yet - create it
                      // Note: node and iterator were already added to stacks above
                      final parentEnv =
                          currentState.loopEnvironmentStack.isNotEmpty
                              ? currentState.loopEnvironmentStack.last
                              : currentState.environment;
                      final newLoopEnvironment =
                          Environment(enclosing: parentEnv);
                      currentState.forLoopEnvironment = newLoopEnvironment;
                      currentState.loopEnvironmentStack.add(newLoopEnvironment);
                      visitor.environment = newLoopEnvironment;
                      // Define the loop variable in this environment
                      newLoopEnvironment.define(
                          loopVariable.name.lexeme, currentItem);
                      Logger.debug(
                          "[StateMachine] ForIn: Created environment at index ${currentState.loopEnvironmentStack.length - 1}");
                    }
                  } else if (parts is ForEachPartsWithIdentifier) {
                    // No declaration, assign in the current environment
                    currentState.environment
                        .assign(parts.identifier.name, currentItem);
                    // Ensure we don't use a residual loop environment
                    currentState.forLoopEnvironment = null;
                    visitor.environment = currentState.environment;
                  } else {
                    throw StateError(
                        "Unknown ForEachParts type: \\${parts.runtimeType}");
                  }
  
                  // The next state is the body of the loop
                  Logger.debug(
                      "[StateMachine] ForIn: Next node is body: \\${forNode.body.runtimeType}");
                  if (forNode.body is Block) {
                    currentNode = (forNode.body as Block).statements.firstOrNull;
                  } else {
                    currentNode = forNode.body;
                  }
                  currentState.nextStateIdentifier = currentNode;
                  continue; // Restart the state machine loop with the beginning of the body
                } else {
                  // End of iteration
                  Logger.debug(
                      "[StateMachine] ForIn: Iteration finished. Finding node after loop. (forNode: \\${forNode.runtimeType}, parent: \\${forNode.parent?.runtimeType}, env: \\${visitor.environment.hashCode})");
                  currentState.currentForInIterator = null; // Clean the iterator
                  // Clean the loop environment if it existed
                  currentState.forLoopEnvironment = null;
                  // Remove from stacks and map
                  final loopIndex = currentState.loopNodeStack.indexOf(forNode);
                  if (loopIndex >= 0) {
                    currentState.loopNodeStack.removeAt(loopIndex);
                    if (loopIndex < currentState.loopEnvironmentStack.length) {
                      currentState.loopEnvironmentStack.removeAt(loopIndex);
                    }
                    currentState.forInIteratorMap.remove(forNode);
                  }
                  visitor.environment = currentState.environment;
                  currentNode = _findNextSequentialNode(visitor, forNode);
                  Logger.debug(
                      "[StateMachine] ForIn: After _findNextSequentialNode, currentNode: \\${currentNode?.runtimeType}, parent: \\${currentNode?.parent?.runtimeType}");
                  currentState.nextStateIdentifier = currentNode;
                  continue; // Restart the state machine loop
                }
              }
              // If the iterable evaluation was suspended, lastResult contains
              // AsyncSuspensionRequest and will be handled by the logic below.
            } // End of else block for regular for-in loops
          } else if (currentNode is ForStatement &&
              (currentNode.forLoopParts is ForPartsWithDeclarations ||
                  currentNode.forLoopParts is ForPartsWithExpression)) {
            final forNode = currentNode;
            final parts = forNode.forLoopParts;
            bool cameFromBody = false; // Flag to know if we came from the body
  
            // Check if this ForStatement is already on the stack (returning to existing loop)
            // vs a new nested ForStatement (needs initialization)
            bool isExistingLoop = currentState.loopNodeStack.isNotEmpty &&
                currentState.loopNodeStack.contains(forNode);
  
            bool currentLoopInitialized = false;
            if (isExistingLoop) {
              // This is a return to an existing loop, check its initialization status
              currentLoopInitialized =
                  currentState.loopInitializedStack.isNotEmpty
                      ? currentState.loopInitializedStack.last
                      : currentState.forLoopInitialized;
  
              if (currentState.loopEnvironmentStack.isNotEmpty &&
                  currentLoopInitialized &&
                  !currentState.resumedFromInitializer) {
                // We came from the body if the env exists, is initialized, and we didn't resume from the initializer
                cameFromBody = true;
              }
            }
            // Reset the flag after having used it
            currentState.resumedFromInitializer = false;
  
            if (!currentLoopInitialized) {
              Logger.debug(" [StateMachine] Handling For: Initializing.");
              // Create the loop environment once using the currently active environment as parent
              final newLoopEnvironment =
                  Environment(enclosing: visitor.environment);
              currentState.forLoopEnvironment = newLoopEnvironment;
              // Push the new environment, initialization state, and ForStatement node onto the stacks
              currentState.loopEnvironmentStack.add(newLoopEnvironment);
              currentState.loopInitializedStack
                  .add(false); // Start as uninitialized
              currentState.loopNodeStack
                  .add(forNode); // Track which ForStatement this corresponds to
              visitor.environment = newLoopEnvironment;
  
              AstNode? initNode;
              if (parts is ForPartsWithDeclarations) {
                initNode = parts.variables;
              } else if (parts is ForPartsWithExpression) {
                initNode = parts.initialization;
              }
  
              if (initNode != null) {
                lastResult = initNode
                    .accept<Object?>(visitor); // Execute in forLoopEnvironment
  
                if (lastResult is AsyncSuspensionRequest) {
                  // Suspended during initialization
                  Logger.debug(
                      "[StateMachine] For loop initialization suspended. Will resume.");
                  // Mark as initialized so the suspension logic will resume
                  if (currentState.loopInitializedStack.isNotEmpty) {
                    currentState.loopInitializedStack[
                        currentState.loopInitializedStack.length - 1] = true;
                  } else {
                    currentState.forLoopInitialized = true;
                  }
                  // Leave lastResult as is, the general suspension logic will handle it
                  // Do NOT continue to the condition or updaters now.
                  // The 'finally' will restore the env, and the .then() will restart _runStateMachine.
                } else {
                  // Synchronous initialization completed
                  if (currentState.loopInitializedStack.isNotEmpty) {
                    currentState.loopInitializedStack[
                        currentState.loopInitializedStack.length - 1] = true;
                  } else {
                    currentState.forLoopInitialized = true;
                  }
                  cameFromBody = false; // Do NOT go to updaters
                  // Continue to the condition IN THIS SAME ITERATION of the loop
                }
              } else {
                // No initialization
                if (currentState.loopInitializedStack.isNotEmpty) {
                  currentState.loopInitializedStack[
                      currentState.loopInitializedStack.length - 1] = true;
                } else {
                  currentState.forLoopInitialized = true;
                }
                cameFromBody = false;
              }
              // Do NOT restore the environment here, we will need it for the condition/updaters
              // visitor.environment = currentState.environment; // Do NOT restore here
            }
  
            // Runs only if we are not suspended by the initialization
            bool currentLoopInitialized2 =
                currentState.loopInitializedStack.isNotEmpty
                    ? currentState.loopInitializedStack.last
                    : currentState.forLoopInitialized;
            if (cameFromBody &&
                currentLoopInitialized2 &&
                lastResult is! AsyncSuspensionRequest) {
              Logger.debug(" [StateMachine] Handling For: Running updaters.");
              // Use the current loop environment from the stack
              if (currentState.loopEnvironmentStack.isNotEmpty) {
                visitor.environment = currentState.loopEnvironmentStack.last;
                Logger.debug(
                    " [DEBUG] Updater: Using stack environment ${currentState.loopEnvironmentStack.last.hashCode}, stack depth: ${currentState.loopEnvironmentStack.length}");
              } else {
                visitor.environment = currentState.forLoopEnvironment!;
                Logger.debug(
                    " [DEBUG] Updater: Using fallback forLoopEnvironment ${currentState.forLoopEnvironment!.hashCode}");
              }
  
              // Debug: check what variables are available in the current environment
              try {
                final envVars = <String>[];
                Environment? currentEnv = visitor.environment;
                while (currentEnv != null) {
                  envVars.add(
                      "Env ${currentEnv.hashCode}: ${currentEnv.values.keys.join(', ')}");
                  currentEnv = currentEnv.enclosing;
                }
                Logger.debug(
                    " [DEBUG] Environment chain: ${envVars.join(' -> ')}");
              } catch (e) {
                Logger.debug(" [DEBUG] Error checking environment chain: $e");
              }
              NodeList<Expression>? updaters;
              if (parts is ForPartsWithDeclarations) {
                updaters = parts.updaters;
              } else if (parts is ForPartsWithExpression) {
                updaters = parts.updaters;
              }
  
              if (updaters != null) {
                for (final updateExpr in updaters) {
                  lastResult = updateExpr
                      .accept<Object?>(visitor); // Execute in forLoopEnvironment
                  if (lastResult is AsyncSuspensionRequest) {
                    // Suspended during the update
                    Logger.debug("[StateMachine] For loop updater suspended.");
                    // Keep the environment for the suspension logic
                    break; // Exit the updaters loop, the suspension will be handled
                  }
                }
              }
              // Do NOT restore the environment here, we will need it for the condition
              // visitor.environment = currentState.environment;
              // After the updaters (or if there are no updaters), we go to the condition
              cameFromBody =
                  false; // Do NOT consider we came from the body for the condition
            }
  
            // Condition (if initialized and not suspended during init/updater)\
            // Runs after init (if sync) or after updater (if sync)
            bool currentLoopInitialized3 =
                currentState.loopInitializedStack.isNotEmpty
                    ? currentState.loopInitializedStack.last
                    : currentState.forLoopInitialized;
            if (currentLoopInitialized3 &&
                lastResult is! AsyncSuspensionRequest) {
              Logger.debug(" [StateMachine] Handling For: Evaluating condition.");
              // Use the current loop environment from the stack
              if (currentState.loopEnvironmentStack.isNotEmpty) {
                visitor.environment = currentState.loopEnvironmentStack.last;
              } else {
                visitor.environment = currentState.forLoopEnvironment!;
              }
              Expression? condition;
              if (parts is ForPartsWithDeclarations) {
                condition = parts.condition;
              } else if (parts is ForPartsWithExpression) {
                condition = parts.condition;
              }
  
              bool conditionValue = true; // The condition is true if absent
              if (condition != null) {
                lastResult = condition
                    .accept<Object?>(visitor); // Execute in forLoopEnvironment
                if (lastResult is AsyncSuspensionRequest) {
                  // Suspended during the condition
                  Logger.debug("[StateMachine] For loop condition suspended.");
                  // Keep the environment for the suspension logic
                } else if (lastResult is bool) {
                  conditionValue = lastResult;
                } else {
                  // Restore the environment before throwing the error
                  visitor.environment = currentState.environment;
                  throw RuntimeError(
                      "For loop condition must be a boolean, but got ${lastResult?.runtimeType}");
                }
              }
              // Do NOT restore the environment here if we continue in the body
  
              // Decision based on the condition (if not suspended)\
              if (lastResult is! AsyncSuspensionRequest) {
                if (conditionValue) {
                  // Condition true: the next state is the body
                  Logger.debug(
                      "[StateMachine] For condition TRUE. Next node is body: ${forNode.body.runtimeType}");
                  // The loop environment remains active for the body execution
                  if (forNode.body is Block) {
                    currentNode = (forNode.body as Block).statements.firstOrNull;
                  } else {
                    currentNode = forNode.body;
                  }
                  // If the body is empty, we loop directly to the updaters
                  if (currentNode == null) {
                    Logger.debug(
                        "[StateMachine] For loop body is empty. Proceeding to updaters/condition.");
                    // Simulate that we came from the body to trigger the updaters
                    visitor.environment =
                        currentState.environment; // Restore before continuing
                    currentState.nextStateIdentifier =
                        forNode; // Go back to the ForStatement
                    continue;
                  } else {
                    currentState.nextStateIdentifier = currentNode;
                    // Do NOT restore the environment, the body will execute in it
                    continue; // Restart the state machine loop with the body
                  }
                } else {
                  // Condition false: exit the loop
                  Logger.debug(
                      "[StateMachine] For condition FALSE. Finding node after loop.");
                  // Clean the loop state and pop from all stacks
                  if (currentState.loopInitializedStack.isNotEmpty) {
                    currentState.loopInitializedStack.removeLast();
                  } else {
                    currentState.forLoopInitialized = false;
                  }
                  currentState.forLoopEnvironment = null;
                  if (currentState.loopEnvironmentStack.isNotEmpty) {
                    currentState.loopEnvironmentStack.removeLast();
                  }
                  if (currentState.loopNodeStack.isNotEmpty) {
                    currentState.loopNodeStack.removeLast();
                  }
                  visitor.environment =
                      currentState.environment; // Restore the environment
                  currentNode = _findNextSequentialNode(visitor, forNode);
                  currentState.nextStateIdentifier = currentNode;
                  continue; // Restart the state machine loop with the next node
                }
              }
            }
            // If suspended (lastResult is AsyncSuspensionRequest), the general suspension logic takes over.
            // The visitor environment must be restored in the finally of the main loop.
          } else if (currentNode is TryStatement) {
            // When entering a TryStatement, register it
            currentState.activeTryStatement = currentNode;
            Logger.debug(
                "[StateMachine] Entering TryStatement: ${currentNode.offset}. Proceeding to body.");
            // The next state is the first instruction of the try block
            currentNode = currentNode.body.statements.firstOrNull;
            // If the try block is empty, find the next node after the try
            if (currentNode == null) {
              Logger.debug(
                  " [StateMachine] Try block is empty. Finding node after TryStatement.");
              // Is there a finally? If yes, go to it.
              if (currentState.activeTryStatement?.finallyBlock != null) {
                Logger.debug(
                    "[StateMachine] Empty try block, jumping to finally.");
                currentState.pendingFinallyBlock =
                    currentState.activeTryStatement!.finallyBlock;
                currentNode =
                    currentState.pendingFinallyBlock!.statements.firstOrNull;
                currentState.pendingFinallyBlock =
                    null; // Le finally est maintenant en cours
              } else {
                // No finally, find the node after the Try
                currentNode = _findNextSequentialNode(
                    visitor, currentState.activeTryStatement!);
                currentState.activeTryStatement = null; // End of try
              }
            }
            currentState.nextStateIdentifier = currentNode;
            continue; // Continue with the first state of the try (or finally or after)
          } else if (currentNode is IfStatement) {
            final ifNode = currentNode;
            Logger.debug("[StateMachine] Handling IfStatement condition.");
            // Evaluate the condition
            final conditionResult = ifNode.expression.accept<Object?>(visitor);
  
            if (conditionResult is AsyncSuspensionRequest) {
              // The condition is asynchronous, suspend
              Logger.debug(" [StateMachine] If condition suspended. Waiting...");
              lastResult =
                  conditionResult; // Update lastResult for the processing below
              // The general suspension logic will handle the await and resume
            } else if (conditionResult is bool) {
              // Synchronous condition
              if (conditionResult) {
                // Condition true: the next state is the 'then' branch
                Logger.debug(
                    "[StateMachine] If condition TRUE. Next node is thenBranch: ${ifNode.thenStatement.runtimeType}");
                // If then is a block, take the first instruction
                if (ifNode.thenStatement is Block) {
                  currentNode =
                      (ifNode.thenStatement as Block).statements.firstOrNull;
                } else {
                  currentNode = ifNode.thenStatement;
                }
                // If the 'then' branch is empty, go to the next instruction
                if (currentNode == null) {
                  Logger.debug(
                      "[StateMachine] If 'then' branch is empty. Finding node after IfStatement.");
                  currentNode = _findNextSequentialNode(visitor, ifNode);
                }
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the state machine loop with the new node
              } else {
                // Condition false: check the 'else' branch
                if (ifNode.elseStatement != null) {
                  Logger.debug(
                      "[StateMachine] If condition FALSE. Next node is elseBranch: ${ifNode.elseStatement?.runtimeType}");
                  // If else is a block, take the first instruction
                  if (ifNode.elseStatement is Block) {
                    currentNode =
                        (ifNode.elseStatement as Block).statements.firstOrNull;
                  } else {
                    currentNode = ifNode.elseStatement;
                  }
                  // If the 'else' branch is empty, go to the next instruction
                  if (currentNode == null) {
                    Logger.debug(
                        "[StateMachine] If 'else' branch is empty. Finding node after IfStatement.");
                    currentNode = _findNextSequentialNode(visitor, ifNode);
                  }
                } else {
                  // No 'else' branch, find the next instruction after the if
                  Logger.debug(
                      "[StateMachine] If condition FALSE, no else branch. Finding node after IfStatement.");
                  currentNode = _findNextSequentialNode(visitor, ifNode);
                }
                currentState.nextStateIdentifier = currentNode;
                continue; // Restart the state machine loop
              }
            } else {
              // The condition did not return a boolean or a suspension
              throw RuntimeError(
                  "If condition must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
            }
            // If the condition was suspended, lastResult contains AsyncSuspensionRequest
            // and will be handled by the suspension logic below.
          } else {
            if (currentNode is ReturnStatement) {
              try {
                final checkX = visitor.environment.get('x');
                Logger.debug(
                    "[StateMachine] BEFORE ACCEPT ReturnStatement: env=${visitor.environment.hashCode}, x=$checkX (${checkX?.runtimeType})");
              } catch (_) {/* ignore if x not defined */}
            } else if (currentNode is SimpleIdentifier &&
                currentNode.name == 'x') {
              try {
                final checkX = visitor.environment.get('x');
                Logger.debug(
                    "[StateMachine] BEFORE ACCEPT SimpleIdentifier('x'): env=${visitor.environment.hashCode}, x=$checkX (${checkX?.runtimeType})");
              } catch (_) {/* ignore */}
            }
            Logger.debug(
                "[StateMachine] About to accept node ${currentNode.runtimeType}. Visitor env: ${visitor.environment.hashCode}, State env: ${currentState.environment.hashCode}");
            try {
              lastResult = currentNode.accept<Object?>(visitor);
            } on ReturnException {
              rethrow; // Re-throw to be caught by the ReturnException catch below
            } on BreakException {
              rethrow; // Propagate to the outer catch
            } on ContinueException {
              rethrow; // Propagate to the outer catch
            } catch (error, stackTrace) {
              if (error is InternalInterpreterException) {
                // This is a thrown exception (from throw statement). Try to handle it.
                Logger.debug(
                    " [StateMachine] Caught InternalInterpreterException from accept(). Attempting to handle with try/catch.");
                // Store the error and try to find a catch block
                currentState.currentError = error;
                currentState.currentStackTrace = stackTrace;
                _handleAsyncError(visitor, currentState, currentNode);
                return; // Stop this iteration, _handleAsyncError will reschedule if caught
              } else {
                // Standard synchronous error during accept(): store and try to handle
                Logger.debug(
                    " [StateMachine] Caught standard SYNC error during accept(): $error");
                currentState.currentError = error;
                currentState.currentStackTrace = stackTrace;
                _handleAsyncError(visitor, currentState, currentNode);
                return; // Exit, _handleAsyncError will take care of the rest
              }
            }
          }
  
          // Analyze the result (can come from accept() or from condition evaluation in while)
          if (lastResult is AsyncSuspensionRequest) {
            // Check if accept() returned a suspension
            final AsyncSuspensionRequest suspension = lastResult;
  
            Logger.debug(
                "[StateMachine] Suspension requested (from ${currentNode.runtimeType}). Waiting for Future...");
  
            // Attach the callbacks to the Future
            suspension.future.then((futureResult) {
              Logger.debug(
                  " [StateMachine] Future completed successfully with: $futureResult");
              // Update the state with the result
              currentState.lastAwaitResult = futureResult;
              currentState.lastAwaitError = null;
              currentState.lastAwaitStackTrace = null;
              currentState.currentError = null; // Clear any previous error state
              currentState.currentStackTrace = null;
  
              if (currentState.pendingFinallyBlock != null) {
                Logger.debug(
                    "[StateMachine] Resuming after await, pending finally found. Executing finally block first.");
                // The next state is the beginning of the finally block
                final finallyBlock = currentState.pendingFinallyBlock!;
                currentState.pendingFinallyBlock = null; // Consumed
                currentState.nextStateIdentifier =
                    finallyBlock.statements.firstOrNull;
                if (currentState.nextStateIdentifier == null) {
                  // The finally block is empty, find the node after the try
                  Logger.debug(
                      "[StateMachine] Pending finally block was empty. Finding node after TryStatement.");
                  if (currentState.activeTryStatement != null) {
                    currentState.nextStateIdentifier = _findNextSequentialNode(
                        visitor, currentState.activeTryStatement!);
                    currentState.activeTryStatement = null; // End of try handling
                  } else {
                    Logger.warn(
                        "[StateMachine] Cannot find node after empty finally block without active TryStatement.");
                    currentState.nextStateIdentifier = null; // Safe stop
                  }
                }
                _scheduleStateMachineRun(visitor, currentState);
                return; // Do not determine the next normal node
              }
  
              // Determine the next state based on the AST context
              AstNode? nextNodeAfterAwait;
  
              if (suspension.isYieldSuspension) {
                // For yield suspensions, simply continue with the next sequential node
                nextNodeAfterAwait = _findNextSequentialNode(visitor,
                    currentNode!); // The YieldStatement that caused the suspension
                Logger.debug(
                    "[StateMachine] Yield suspension completed. Next node: ${nextNodeAfterAwait?.runtimeType}");
              } else {
                // For await suspensions, use the complex await logic
                nextNodeAfterAwait = _determineNextNodeAfterAwait(
                    visitor,
                    currentState,
                    currentNode!); // The node that caused the suspension
              }
  
              currentState.nextStateIdentifier = nextNodeAfterAwait;
  
              // Reschedule the state machine execution
              _scheduleStateMachineRun(visitor, currentState);
            }).catchError((Object error, StackTrace stackTrace) {
              Logger.debug(
                  " [StateMachine] Future completed with ERROR: $error"); // Do not display stackTrace here, too long
              // Store the error and stack trace in the state
              currentState.lastAwaitError = error; // For info if someone uses it
              currentState.lastAwaitStackTrace = stackTrace;
              currentState.currentError = error; // Active error to handle
              currentState.currentStackTrace = stackTrace;
              currentState.lastAwaitResult = null; // No valid result
  
              // Try to handle the error (find catch/finally)
              _handleAsyncError(visitor, currentState, currentNode!);
              // _handleAsyncError will either find a catch/finally and reschedule,
              // or complete the completer with the error.
            });
  
            // IMPORTANT: Exit the _runStateMachine function.
            // Execution will resume in the .then() or _handleAsyncError
            return;
          } else {
            // Clear error state if we executed successfully
            currentState.currentError = null;
            currentState.currentStackTrace = null;
  
            // Determine the next sequential normal state
            // Use _findNextSequentialNode which now handles try/catch/finally
            final nextNode = _findNextSequentialNode(visitor, currentNode);
            Logger.debug(
                "[StateMachine] Sync execution finished. Next node from _findNext: ${nextNode?.runtimeType}");
            currentNode = nextNode;
            currentState.nextStateIdentifier = currentNode;
          }
        } on ReturnException catch (e) {
          // The function returned a value
          Logger.debug(
              " [StateMachine] Caught ReturnException. Completing with: ${e.value}");
          TryStatement? currentTry =
              currentState.activeTryStatement; // Use currentState
          if (currentTry != null && currentTry.finallyBlock != null) {
            // Check currentTry != null
            Logger.debug(
                "[StateMachine] Return caught inside try with finally. Executing finally first.");
            currentState.returnAfterFinally = e.value; // Use currentState
            // Reset rethrow state if jumping to finally
            currentState.isHandlingErrorForRethrow = false;
            currentState.originalErrorForRethrow = null;
            currentNode =
                currentTry.finallyBlock!.statements.firstOrNull; // Now sure
            currentState.nextStateIdentifier = currentNode; // Use currentState
            continue; // Execute the finally
          }
          if (!currentState.completer.isCompleted) {
            currentState.completer.complete(e.value);
          }
          return; // Stop the state machine
        } on BreakException {
          Logger.debug(
              " [StateMachine] Caught BreakException. Finding node after loop.");
          if (currentState.loopNodeStack.isNotEmpty) {
            final loopNode = currentState.loopNodeStack.removeLast();
            // Also remove the corresponding environment and initialized flag
            if (currentState.loopEnvironmentStack.isNotEmpty) {
              currentState.loopEnvironmentStack.removeLast();
            }
            if (currentState.loopInitializedStack.isNotEmpty) {
              currentState.loopInitializedStack.removeLast();
            }
            currentNode = _findNextSequentialNode(visitor, loopNode);
            currentState.nextStateIdentifier = currentNode;
            continue; // Continue execution after the loop
          } else {
            // This is an error: break outside a loop
            if (!currentState.completer.isCompleted) {
              currentState.completer.completeError(
                  RuntimeError("Break statement outside of a loop."),
                  StackTrace.current);
            }
            return;
          }
        } on ContinueException {
          Logger.debug(
              " [StateMachine] Caught ContinueException. Finding next loop iteration.");
          if (currentState.loopNodeStack.isNotEmpty) {
            final loopNode = currentState.loopNodeStack.last;
            // For all loop types, going back to the loop statement itself
            // will trigger the correct next action (condition check or updaters).
            currentNode = loopNode;
            currentState.nextStateIdentifier = currentNode;
            continue;
          } else {
            // This is an error: continue outside a loop
            if (!currentState.completer.isCompleted) {
              currentState.completer.completeError(
                  RuntimeError("Continue statement outside of a loop."),
                  StackTrace.current);
            }
            return;
          }
        } catch (error, stackTrace) {
          // Other error during state execution (SYNC)
  
          // Check if the error comes from rethrow
          if (error is InternalInterpreterException) {
            // This is an exception rethrown by rethrow. Do not handle it here.
            // Propagate it by completing the Future with the original error.
            Logger.debug(
                " [StateMachine] Caught InternalInterpreterException from rethrow. Propagating.");
            // Reset rethrow state before completing with error
            currentState.isHandlingErrorForRethrow = false;
            currentState.originalErrorForRethrow = null;
            if (!currentState.completer.isCompleted) {
              // Propagate the original error and its associated stack trace (if available in the internal exception)
              // or the current stack trace if the internal one does not have one.
              // Note: InternalInterpreterException does not store the stack trace for now.
              // Using the captured stackTrace here is the best choice.
              final errorToComplete =
                  _unwrapExceptionForPropagation(error.originalThrownValue);
              currentState.completer.completeError(errorToComplete, stackTrace);
            }
            return; // Stop the state machine execution
          } else {
            // Standard synchronous error: Try to handle via internal try/catch/finally
            Logger.debug(
                " [StateMachine] Caught standard SYNC Error during non-accept state execution: $error\\n$stackTrace");
            currentState.currentError = error; // Utiliser currentState
            currentState.currentStackTrace = stackTrace;
            _handleAsyncError(visitor, currentState,
                currentNode ?? currentState.function._body); // Use currentState
            return; // Exit, _handleAsyncError will take care of the rest
          }
        } finally {
          // Restore the visitor environment if it was changed
          visitor.environment = originalVisitorEnv;
          visitor.currentAsyncState = previousAsyncState;
          Logger.debug(
              " [StateMachine] Restored visitor env (${originalVisitorEnv.hashCode}) and async state in finally block.");
        }
      }
  
      // Handle a return that was suspended by a finally
      if (currentState.returnAfterFinally != null &&
          !currentState.completer.isCompleted) {
        Logger.debug(
            " [StateMachine] Completing with stored return value after finally: ${currentState.returnAfterFinally}");
        // Reset rethrow state before completing
        currentState.isHandlingErrorForRethrow = false;
        currentState.originalErrorForRethrow = null;
        currentState.completer.complete(currentState.returnAfterFinally);
        return;
      }
  
      // If the loop ends and there was an error (not caught but after a finally executed)
      if (currentState.currentError != null &&
          !currentState.completer.isCompleted) {
        Logger.debug(
            " [StateMachine] Loop finished, propagating unhandled error after finally: ${currentState.currentError}");
        // Reset rethrow state before completing with error
        currentState.isHandlingErrorForRethrow = false;
        currentState.originalErrorForRethrow = null;
        currentState.completer.completeError(
            currentState.currentError ?? Exception("Unknown error after finally"),
            currentState.currentStackTrace);
      }
      // If the loop ends normally (no more nodes to execute)
      else if (!currentState.completer.isCompleted) {
        Logger.debug(
            " [StateMachine] Loop finished normally. Completing with last result: $lastResult (State has await result: ${currentState.lastAwaitResult})");
        // Reset rethrow state before completing normally
        currentState.isHandlingErrorForRethrow = false;
        currentState.originalErrorForRethrow = null;
  
        Object? finalCompletionValue = lastResult;
        if (lastResult == null && currentState.lastAwaitResult != null) {
          finalCompletionValue = currentState.lastAwaitResult;
          Logger.debug(
              " [StateMachine] Loop finished after await. Using await result for completion: $finalCompletionValue");
        }
        currentState.completer.complete(finalCompletionValue);
      }
    }
  
    // Schedule the state machine execution via microtask
    static void _scheduleStateMachineRun(
        InterpreterVisitor visitor, AsyncExecutionState state) {
      // Check if the completer is already completed to avoid unnecessary executions
      if (state.completer.isCompleted) {
        Logger.debug(
            " [_scheduleStateMachineRun] Completer already completed. Skipping schedule.");
        return;
      }
      Future.microtask(() => _runStateMachine(visitor, state))
          .catchError((error, stackTrace) {
        // Catch errors not caught by the internal logic of _runStateMachine
        if (!state.completer.isCompleted) {
          Logger.error(
              "[StateMachine] Uncaught async error in microtask: $error\n$stackTrace");
          state.completer.completeError(error, stackTrace);
        }
      });
    }
  
    static void _handleAsyncError(InterpreterVisitor visitor,
        AsyncExecutionState state, AstNode nodeWhereErrorOccurred) {
      Object? error = state.currentError;
      if (error is InternalInterpreterException) {
        error = error.originalThrownValue;
      }
      final stackTrace = state.currentStackTrace;
  
      Logger.debug(
          "[_handleAsyncError] Handling error: $error from node: ${nodeWhereErrorOccurred.toSource()}");
  
      // Check if this is a rethrow - if so, skip the current try/catch
      bool isRethrow = state.isCurrentlyRethrowing;
      TryStatement? currentTry = state.activeTryStatement;
  
      // 1. Find an enclosing TryStatement
      TryStatement? enclosingTry =
          _findEnclosingTryStatement(nodeWhereErrorOccurred);
  
      // If this is a rethrow and we found the same try statement, look for an outer one
      if (isRethrow && enclosingTry != null && enclosingTry == currentTry) {
        Logger.debug(
            " [_handleAsyncError] Rethrow detected - skipping current try/catch and looking for outer one");
        // Find the next enclosing try outside of the current one
        enclosingTry = _findEnclosingTryStatement(enclosingTry.parent);
        // Reset the flag after handling
        state.isCurrentlyRethrowing = false;
      }
  
      CatchClause? matchingCatchClause;
      if (enclosingTry != null) {
        Logger.debug(
            " [_handleAsyncError] Found enclosing TryStatement: ${enclosingTry.offset}");
        state.activeTryStatement = enclosingTry; // Marquer comme actif
  
        // 2. Find a matching CatchClause (simplified: take the first one)
        if (enclosingTry.catchClauses.isNotEmpty) {
          matchingCatchClause = enclosingTry.catchClauses.first;
          Logger.debug(
              " [_handleAsyncError] Found matching CatchClause (simplified: first one).");
        } else {
          Logger.debug(
              " [_handleAsyncError] No CatchClauses found in the TryStatement.");
        }
      }
  
      if (matchingCatchClause != null && enclosingTry != null) {
        // 3. Error caught: Prepare the jump to the Catch block
        state.nextStateIdentifier = matchingCatchClause
            .body.statements.firstOrNull; // Start of the catch block
  
        // Update the state for rethrow - store the original error
        final internalError = InternalInterpreterException(
            error ?? Exception("Unknown error caught")); // Pass only the error
        state.originalErrorForRethrow = internalError;
        // NOTE: We set isHandlingErrorForRethrow to true here to indicate we're in a catch block
        // and ready to handle potential rethrow statements
        state.isHandlingErrorForRethrow = true;
  
        // Define the exception variable in the catch environment
        // For now, define in the current environment (can cause collisions)
        final exceptionParameter = matchingCatchClause.exceptionParameter;
        if (exceptionParameter != null) {
          final varName = exceptionParameter.name.lexeme;
          // Use the state environment to define the catch variables
          state.environment.define(varName, error);
          Logger.debug(
              " [_handleAsyncError] Defined exception variable '$varName' in environment.");
  
          // Handle the stack trace parameter if it exists
          final stackTraceParameter = matchingCatchClause.stackTraceParameter;
          if (stackTraceParameter != null) {
            final stackVarName = stackTraceParameter.name.lexeme;
            state.environment.define(stackVarName, stackTrace);
            Logger.debug(
                "[_handleAsyncError] Defined stack trace variable '$stackVarName' in environment.");
          }
        }
  
        // Clear the error state because it is handled
        state.currentError = null;
        state.currentStackTrace = null;
  
        // Reschedule the execution to start the catch block
        Logger.debug(
            " [_handleAsyncError] Scheduling run for CatchClause block.");
        _scheduleStateMachineRun(visitor, state);
      } else {
        // 4. Error not caught or no try:
        //    a) Check if there is a finally to execute anyway
        if (enclosingTry != null && enclosingTry.finallyBlock != null) {
          // Reset rethrow state if jumping to finally
          state.isHandlingErrorForRethrow = false;
          state.originalErrorForRethrow = null;
  
          Logger.debug(
              " [_handleAsyncError] Error not caught, but finally block exists. Jumping to finally.");
          // The next state is the start of the finally block
          state.nextStateIdentifier =
              enclosingTry.finallyBlock!.statements.firstOrNull;
  
          // IMPORTANT: The error remains in state.currentError to be rethrown AFTER the finally.
          // _findNextSequentialNode will handle the transition *after* the finally.
          // The main loop of the state machine will check state.currentError at the end.
          _scheduleStateMachineRun(visitor, state);
        } else {
          //    b) Propagate the error by completing the main Future
          // Reset rethrow state before propagating
          state.isHandlingErrorForRethrow = false;
          state.originalErrorForRethrow = null;
  
          Logger.debug(
              " [_handleAsyncError] Error not caught and no finally block. Propagating error.");
          if (!state.completer.isCompleted) {
            // Unwrap BridgedInstance exceptions to get native objects
            final errorToComplete = _unwrapExceptionForPropagation(
                error ?? Exception("Unknown error"));
            state.completer.completeError(errorToComplete, stackTrace);
          }
        }
      }
    }
  
    static TryStatement? _findEnclosingTryStatement(AstNode? node) {
      AstNode? current = node;
      while (current != null) {
        if (current is TryStatement) {
          return current;
        }
        // Do not search beyond the current function's limit
        if (current is FunctionBody) {
          return null;
        }
        current = current.parent;
      }
      return null;
    }
  
    // Determine the next AST node to execute after the resolution of an awaited Future.
    static AstNode? _determineNextNodeAfterAwait(InterpreterVisitor visitor,
        AsyncExecutionState state, AstNode nodeThatCausedSuspension) {
      Object? futureResult = state.lastAwaitResult;
      final currentExecutionEnvironment = state.loopEnvironmentStack.isNotEmpty
          ? state.loopEnvironmentStack.last
          : state.environment;
      Logger.debug(
          "[_determineNextNodeAfterAwait] Modifying environment: ${currentExecutionEnvironment.hashCode} (state.environment: ${state.environment.hashCode}, loop stack depth: ${state.loopEnvironmentStack.length})");
  
      Logger.debug(
          "[_determineNextNodeAfterAwait] Resuming after await. Node causing suspension: ${nodeThatCausedSuspension.runtimeType}, Result: $futureResult");
  
      // The node that caused the suspension is either the AwaitExpression itself,
      // or a parent node (like WhileStatement) if the await was in its condition.
  
      // Determine the actual context of the await.
      AstNode awaitContextNode;
      Expression? awaitExpression;
  
      if (nodeThatCausedSuspension is AwaitExpression) {
        awaitExpression = nodeThatCausedSuspension;
        awaitContextNode = nodeThatCausedSuspension.parent ??
            nodeThatCausedSuspension; // Use the parent as context
      } else if (nodeThatCausedSuspension is ExpressionStatement &&
          nodeThatCausedSuspension.expression is AwaitExpression) {
        // Case where the await was directly the expression of an ExpressionStatement
        awaitExpression = nodeThatCausedSuspension.expression as AwaitExpression;
        awaitContextNode = nodeThatCausedSuspension;
      } else if (nodeThatCausedSuspension is WhileStatement &&
          nodeThatCausedSuspension.condition is AwaitExpression) {
        // Special case: the await was directly the condition of a WhileStatement
        awaitContextNode =
            nodeThatCausedSuspension; // The WhileStatement is the context
        awaitExpression = nodeThatCausedSuspension.condition as AwaitExpression;
      } else if (nodeThatCausedSuspension is DoStatement &&
          nodeThatCausedSuspension.condition is AwaitExpression) {
        // Special case: the await was directly the condition of a DoStatement
        awaitContextNode =
            nodeThatCausedSuspension; // The DoStatement is the context
        awaitExpression = nodeThatCausedSuspension.condition as AwaitExpression;
      } else if (nodeThatCausedSuspension is MethodInvocation) {
        // Special case: the await was in the arguments of a method invocation
        awaitContextNode = nodeThatCausedSuspension;
        awaitExpression = null; // The await is nested in arguments
        Logger.debug(
            "[_determineNextNodeAfterAwait] Await context is MethodInvocation with arguments containing await.");
      } else if (nodeThatCausedSuspension is FunctionExpressionInvocation) {
        // Special case: the await was in the arguments of a function expression invocation
        awaitContextNode = nodeThatCausedSuspension;
        awaitExpression = null; // The await is nested in arguments
        Logger.debug(
            "[_determineNextNodeAfterAwait] Await context is FunctionExpressionInvocation with arguments containing await.");
      } else if (nodeThatCausedSuspension is InstanceCreationExpression) {
        // Special case: the await was in the arguments of a constructor call
        awaitContextNode = nodeThatCausedSuspension;
        awaitExpression = null; // The await is nested in arguments
        Logger.debug(
            "[_determineNextNodeAfterAwait] Await context is InstanceCreationExpression with arguments containing await.");
      } else {
        // Try to find await context by analyzing the node structure
        AstNode? foundInvocation =
            _findInvocationWithAwaitInArguments(nodeThatCausedSuspension);
        if (foundInvocation != null) {
          Logger.debug(
              "[_determineNextNodeAfterAwait] Found invocation with await in arguments: ${foundInvocation.runtimeType}");
          awaitContextNode = foundInvocation;
          awaitExpression = null; // The await is nested in arguments
        } else {
          // We don't know how to extract the await, use the node directly
          // (may lead to errors if the logic below does not handle this node)
          awaitContextNode = nodeThatCausedSuspension;
          awaitExpression = null; // We don't know where the await was exactly
          Logger.warn(
              "[_determineNextNodeAfterAwait] Could not determine exact await context for node type ${nodeThatCausedSuspension.runtimeType}. Using node as context.");
        }
      }
  
      Logger.debug(
          "[_determineNextNodeAfterAwait] Determined await context: ${awaitContextNode.runtimeType}");
  
      // Logic based on the type of node that contained the await (awaitContextNode)
  
      // Case: Method/Function/Constructor invocation with await in arguments
      if (awaitContextNode is MethodInvocation ||
          awaitContextNode is FunctionExpressionInvocation ||
          awaitContextNode is InstanceCreationExpression) {
        Logger.debug(
            "[_determineNextNodeAfterAwait] Handling ${awaitContextNode.runtimeType} with await in arguments. Re-executing the invocation...");
  
        // Re-execute the invocation with the resolved await value
        try {
          // Temporarily restore the async state to enable await processing
          final previousAsyncState = visitor.currentAsyncState;
          visitor.currentAsyncState = state;
  
          // Enable invocation resumption mode so await expressions return the resolved value
          final previousResumptionMode = state.isInvocationResumptionMode;
          state.isInvocationResumptionMode = true;
  
          final result = awaitContextNode.accept<Object?>(visitor);
  
          // Restore the previous modes
          state.isInvocationResumptionMode = previousResumptionMode;
          visitor.currentAsyncState = previousAsyncState;
  
          if (result is AsyncSuspensionRequest) {
            Logger.debug(
                "[_determineNextNodeAfterAwait] Another await encountered during invocation continuation.");
            return awaitContextNode; // Stay on the same node to handle the next await
          }
  
          // The call completed successfully
          Logger.debug(
              "[_determineNextNodeAfterAwait] Invocation completed successfully with result: $result");
  
          // CRITICAL FIX: Store the invocation result so it can be used as the final completion value
          // This ensures that when the state machine finishes, it uses the correct result
          // instead of falling back to lastAwaitResult
          state.lastAwaitResult = result;
  
          // Now we need to handle the result based on the parent context
          AstNode? parentStatement = awaitContextNode;
          while (parentStatement != null && parentStatement is! Statement) {
            parentStatement = parentStatement.parent;
          }
  
          if (parentStatement is VariableDeclarationStatement) {
            // This is a variable declaration with the invocation as initializer
            Logger.debug(
                "[_determineNextNodeAfterAwait] Completing variable declaration with invocation result: $result");
  
            // Find the variable declaration and assign the result
            final varList = parentStatement.variables;
            if (varList.variables.isNotEmpty) {
              final varDecl = varList.variables.first;
              final varName = varDecl.name.lexeme;
  
              // Set the variable in the current environment
              final currentEnv = state.loopEnvironmentStack.isNotEmpty
                  ? state.loopEnvironmentStack.last
                  : currentExecutionEnvironment;
              currentEnv.define(varName, result);
              Logger.debug(
                  "[_determineNextNodeAfterAwait] Assigned invocation result to variable '$varName' = $result");
            }
  
            // Find the next statement after the variable declaration
            return _findNextSequentialNode(visitor, parentStatement);
          } else if (parentStatement is ExpressionStatement) {
            // This is a standalone expression statement
            Logger.debug(
                "[_determineNextNodeAfterAwait] Completed expression statement with invocation result: $result");
  
            // Find the next statement after the expression statement
            return _findNextSequentialNode(visitor, parentStatement);
          } else {
            // For other cases, continue with finding the next node
            Logger.debug(
                "[_determineNextNodeAfterAwait] Invocation in other context. Finding next node.");
            return _findNextSequentialNode(visitor, awaitContextNode);
          }
        } catch (e, s) {
          Logger.error(
              "[_determineNextNodeAfterAwait] Error during invocation continuation: $e\n$s");
          if (!state.completer.isCompleted) {
            state.completer.completeError(e, s);
          }
          return null; // Stop execution
        }
      }
  
      // Case 1: Variable declaration (var x = await f();)
      if (awaitContextNode is VariableDeclarationStatement) {
        // This case handles when the await occurs directly in the initializer.
        // It's triggered when `visitVariableDeclarationList` returns the suspension.
        // Assign the result to the variable(s)
        final varList = awaitContextNode.variables;
        // Find the *specific* variable whose initializer was the awaitExpression
        // Note: awaitExpression might be null if context couldn't be refined.
        // We assume the *first* variable in the list if awaitExpression is null or not found directly.
        // This might be fragile if multiple variables have initializers.
        VariableDeclaration? targetVar = varList.variables.firstWhereOrNull((v) =>
            v.initializer == awaitExpression ||
            (v.initializer is ParenthesizedExpression &&
                (v.initializer as ParenthesizedExpression).expression ==
                    awaitExpression));
        targetVar ??= varList.variables.first; // Fallback to first
        if (targetVar.initializer is PropertyAccess) {
          final propertyAccess = targetVar.initializer as PropertyAccess;
          if (propertyAccess.target is ParenthesizedExpression) {
            // We want to access the property on the resolved Future value
            final propertyName = propertyAccess.propertyName.name;
            final (bridgedInstance, isBridgedInstance) =
                visitor.toBridgedInstance(futureResult);
            if (isBridgedInstance) {
              final getterAdapter = bridgedInstance!.bridgedClass
                  .findInstanceGetterAdapter(propertyName);
              if (getterAdapter != null) {
                final getterResult =
                    getterAdapter(visitor, bridgedInstance.nativeObject);
  
                futureResult = getterResult;
              }
  
              final methodAdapter = bridgedInstance.bridgedClass
                  .findInstanceMethodAdapter(propertyName);
              if (methodAdapter != null) {
                // Return a callable bound to the instance
                final boundCallable = BridgedMethodCallable(
                    bridgedInstance, methodAdapter, propertyName);
  
                futureResult = boundCallable;
              }
            }
          }
        }
        currentExecutionEnvironment.define(targetVar.name.lexeme, futureResult);
        Logger.debug(
            " [_determineNextNodeAfterAwait] Defined awaited result for variable '${targetVar.name.lexeme}' = $futureResult in env ${currentExecutionEnvironment.hashCode} (Case 1). Finding next node.");
        Logger.debug(
            " [_determineNextNodeAfterAwait] Assigned awaited result to variable '${targetVar.name.lexeme}' (Case 1). Finding next node.");
  
        if (visitor.environment != currentExecutionEnvironment) {
          Logger.debug(
              " [_determineNextNodeAfterAwait] Updating visitor environment from ${visitor.environment.hashCode} to ${currentExecutionEnvironment.hashCode}");
          visitor.environment = currentExecutionEnvironment;
        }
  
        // Find the next sequential node to execute AFTER the await context node.
        return _findNextSequentialNode(visitor, awaitContextNode);
      }
  
      // NEW CASE 1.5: Resume after await in the initializer of a declaration IN a block.
      // This happens when `nodeThatCausedSuspension` is the ExpressionStatement or VariableDeclarationStatement itself,
      // but `_determineNextNodeAfterAwait` is called *after* the Future resolves.
      else if (nodeThatCausedSuspension is VariableDeclarationStatement) {
        final varDeclStatement = nodeThatCausedSuspension;
        final varList = varDeclStatement.variables;
        // Like in Case 1, find the variable that awaited.
        VariableDeclaration? targetVar = varList.variables.firstWhereOrNull(
            (v) => v.initializer is AwaitExpression
            // We need a better way to link the suspension back to the AwaitExpression node
            // For now, assume the FIRST variable with an AwaitExpression initializer in this statement
            );
        targetVar ??=
            varList.variables.first; // Fallback: assume it was the first variable
  
        // Use define() because the variable was not defined during the initial visit
        currentExecutionEnvironment.define(targetVar.name.lexeme, futureResult);
        // SPECULATIVE FIX: Try assigning immediately after defining
        try {
          currentExecutionEnvironment.assign(targetVar.name.lexeme, futureResult);
        } catch (assignError) {
          Logger.warn(
              "[_determineNextNodeAfterAwait] Speculative assign after define failed: $assignError");
        }
        // ADD DEBUG:
        try {
          final checkValue =
              currentExecutionEnvironment.get(targetVar.name.lexeme);
          Logger.debug(
              " [_determineNextNodeAfterAwait] Check after define+assign: '${targetVar.name.lexeme}' in env ${currentExecutionEnvironment.hashCode} is $checkValue (${checkValue?.runtimeType}) <Expected: $futureResult>");
        } catch (e) {
          Logger.debug(
              " [_determineNextNodeAfterAwait] Check after define+assign FAILED for '${targetVar.name.lexeme}': $e");
        }
        // END ADD DEBUG
        Logger.debug(
            " [_determineNextNodeAfterAwait] Defined/Assigned variable '${targetVar.name.lexeme}' = $futureResult (Case 1.5). Finding next node.");
  
        // Find the next instruction AFTER this declaration
        return _findNextSequentialNode(visitor, varDeclStatement);
      }
  
      // Case 2: Expression statement (await f(); or var x = await f(); or x = await f(); etc.)
      else if (awaitContextNode is ExpressionStatement) {
        // Check the type of expression inside the statement
        final expression = awaitContextNode.expression;
  
        if (expression is AwaitExpression) {
          // Simple case: await f(); The result is ignored.
          Logger.debug(
              " [_determineNextNodeAfterAwait] Resumed from ExpressionStatement (AwaitExpression). Finding next sequential node.");
          return _findNextSequentialNode(visitor, awaitContextNode);
        } else if (expression is VariableDeclarationList) {
          // Case: var awaitedValue = await getValue(i);
          // The suspension actually happened *during* the visitVariableDeclarationList call,
          // but _determineNextNodeAfterAwait sees the ExpressionStatement as the context.
          Logger.debug(
              " [_determineNextNodeAfterAwait] Resumed from ExpressionStatement (VariableDeclarationList). Defining variable.");
  
          // Cast expression to VariableDeclarationList to access variables
          final varList = expression as VariableDeclarationList;
  
          // Find the variable that had the await (assuming first with AwaitExpression initializer)
          VariableDeclaration? targetVar = varList.variables
              .firstWhereOrNull((v) => v.initializer is AwaitExpression
                  // Need a reliable way to know which specific await finished
                  // Fallback: assume first variable if none match perfectly
                  );
          targetVar ??= varList.variables.first;
  
          // Assign the result in the correct environment (the loop environment if inside one)
          final currentEnv = state.loopEnvironmentStack.isNotEmpty
              ? state.loopEnvironmentStack.last
              : currentExecutionEnvironment;
          // Use define() because the variable was not defined during the initial visit
          currentEnv.define(targetVar.name.lexeme, futureResult);
          // SPECULATIVE FIX: Try assigning immediately after defining
          try {
            currentEnv.assign(targetVar.name.lexeme, futureResult);
          } catch (assignError) {
            Logger.warn(
                "[_determineNextNodeAfterAwait] Speculative assign after define failed (VarDeclList): $assignError");
          }
          try {
            final checkValue2 = currentEnv.get(targetVar.name.lexeme);
            Logger.debug(
                "[_determineNextNodeAfterAwait] Check after define+assign: '${targetVar.name.lexeme}' in env ${currentEnv.hashCode} is $checkValue2 (${checkValue2?.runtimeType}) <Expected: $futureResult>");
          } catch (e) {
            Logger.debug(
                "[_determineNextNodeAfterAwait] Check after define+assign FAILED for '${targetVar.name.lexeme}': $e");
          }
          Logger.debug(
              " [_determineNextNodeAfterAwait] Defined/Assigned variable '${targetVar.name.lexeme}' = $futureResult (Case 2 - VarDecl). Finding next node.");
  
          // Find the next statement after this ExpressionStatement
          return _findNextSequentialNode(visitor, awaitContextNode);
        } else if (expression is AssignmentExpression) {
          // Case: x += await f(); or x = await f();
          // This is the primary handler now as the context is the ExpressionStatement.
          final assignmentNode = expression; // Already cast
          Object? resolvedRhs = state.lastAwaitResult; // La valeur résolue
          final operatorType = assignmentNode.operator.type;
          final lhs = assignmentNode.leftHandSide;
          final currentEnv = state.loopEnvironmentStack.isNotEmpty
              ? state.loopEnvironmentStack.last
              : currentExecutionEnvironment;
  
          Logger.debug(
              " [_determineNextNodeAfterAwait] Resuming ExpressionStatement(AssignmentExpression Op: $operatorType). RHS: $resolvedRhs (${resolvedRhs?.runtimeType})");
  
          // Determine the next node AFTER the ExpressionStatement
          final AstNode? nextNode =
              _findNextSequentialNode(visitor, awaitContextNode);
          final propertyAccess = expression.childEntities.lastOrNull;
          if (propertyAccess != null && propertyAccess is PropertyAccess) {
            if (propertyAccess.target is ParenthesizedExpression) {
              // We want to access the property on the resolved Future value
              final propertyName = propertyAccess.propertyName.name;
              final (bridgedInstance, isBridgedInstance) =
                  visitor.toBridgedInstance(resolvedRhs);
              if (isBridgedInstance) {
                final getterAdapter = bridgedInstance!.bridgedClass
                    .findInstanceGetterAdapter(propertyName);
                if (getterAdapter != null) {
                  final getterResult =
                      getterAdapter(visitor, bridgedInstance.nativeObject);
  
                  resolvedRhs = getterResult;
                }
  
                final methodAdapter = bridgedInstance.bridgedClass
                    .findInstanceMethodAdapter(propertyName);
                if (methodAdapter != null) {
                  // Return a callable bound to the instance
                  final boundCallable = BridgedMethodCallable(
                      bridgedInstance, methodAdapter, propertyName);
  
                  resolvedRhs = boundCallable;
                }
              }
            }
          }
          if (operatorType == TokenType.EQ) {
            if (lhs is SimpleIdentifier) {
              final varName = lhs.name;
              try {
                currentEnv.assign(varName, resolvedRhs);
                Logger.debug(
                    "[_determineNextNodeAfterAwait] Assigned $varName = $resolvedRhs (Case 2 - Simple Assign)");
              } catch (e) {
                Logger.error("Assigning simple await result: $e");
              }
            } else {
              Logger.warn(
                  "[_determineNextNodeAfterAwait] Resumption for simple assignment to complex LHS not implemented (Case 2).");
              // Attempt: Re-execute the assignment now that RHS is known (may fail)
              // This approach is risky because it re-evaluates the LHS.
              final originalVisitorEnv = visitor.environment;
              try {
                visitor.environment = currentEnv;
                assignmentNode
                    .accept(visitor); // Might re-trigger await if LHS is complex?
              } catch (e) {
                Logger.warn("Re-visiting simple assignment failed: $e");
              } finally {
                visitor.environment = originalVisitorEnv;
              }
            }
          } else {
            final originalVisitorEnv = visitor.environment;
            Object? lhsValue;
            try {
              visitor.environment = currentEnv; // Use correct scope
              // IMPORTANT: Re-evaluating LHS here. Assumes it's safe/idempotent.
              lhsValue = lhs.accept<Object?>(visitor);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Re-evaluated LHS for compound assign to: $lhsValue (${lhsValue?.runtimeType})");
            } catch (e, s) {
              Logger.error("Re-evaluating LHS for compound assign: $e\n$s");
              if (!state.completer.isCompleted) {
                state.completer.completeError(e, s);
              }
              return null; // Stop
            } finally {
              visitor.environment = originalVisitorEnv;
            }
  
            // Calculate the result
            Object? resultValue;
            try {
              // Call computeCompoundValue from the visitor instance
              resultValue = visitor.computeCompoundValue(
                  lhsValue, resolvedRhs, operatorType);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Computed compound value: $resultValue");
            } catch (e, s) {
              Logger.error("Computing compound value after await: $e\n$s");
              if (!state.completer.isCompleted) {
                state.completer.completeError(e, s);
              }
              return null; // Stop
            }
  
            // Assign the computed result back
            if (lhs is SimpleIdentifier) {
              final varName = lhs.name;
              try {
                currentEnv.assign(varName, resultValue);
                Logger.debug(
                    "[_determineNextNodeAfterAwait] Assigned $varName = $resultValue (Case 2 - Compound Assign)");
              } catch (e) {
                Logger.error("Assigning compound await result: $e");
              }
            } else {
              Logger.warn(
                  "[_determineNextNodeAfterAwait] Resumption for compound assignment to complex LHS not fully implemented. Trying standard assign visit.");
              // Tentative: Ré-exécuter l'assignation avec la valeur calculée (peut échouer)
              // Need to fake the RHS with the computed value somehow? This is hard.
              // For now, let it fail or proceed without assigning complex LHS.
            }
          }
          // Return the next node found earlier
          return nextNode;
        } else {
          // Other expression types within ExpressionStatement after await?
          Logger.warn(
              "[_determineNextNodeAfterAwait] Resumed from ExpressionStatement with unexpected inner expression: ${expression.runtimeType}. Finding next sequential node.");
          return _findNextSequentialNode(visitor, awaitContextNode);
        }
      }
  
      // Case 3: Return statement (return await f();)
      else if (awaitContextNode is ReturnStatement && awaitExpression != null) {
      }
  
      // Case 4: Function body expression (=> await f();)
      else if (awaitContextNode is ExpressionFunctionBody &&
          awaitExpression != null) {
      }
  
      // Case 5: Assignment (x = await f(); or x += await f();)
      else if (awaitContextNode is AssignmentExpression) {
        final assignmentNode = awaitContextNode;
        final resolvedRhs = state.lastAwaitResult; // The resolved Future value
        final operatorType = assignmentNode.operator.type;
        final lhs = assignmentNode.leftHandSide;
        // Use the correct environment (the loop environment if applicable)
        final currentEnv = state.loopEnvironmentStack.isNotEmpty
            ? state.loopEnvironmentStack.last
            : currentExecutionEnvironment;
  
        Logger.debug(
            " [_determineNextNodeAfterAwait] Resuming AssignmentExpression (Operator: $operatorType). RHS resolved to: $resolvedRhs (${resolvedRhs?.runtimeType})");
  
        // Determine the next node BEFORE making the assignment (because _findNext may depend on the parent)
        AstNode? parentStatement = assignmentNode;
        while (parentStatement != null && parentStatement is! Statement) {
          parentStatement = parentStatement.parent;
        }
        final AstNode? nextNode = (parentStatement is Statement)
            ? _findNextSequentialNode(visitor, parentStatement)
            : null; // If we don't find the parent statement, we'll stop
  
        if (operatorType == TokenType.EQ) {
          if (lhs is SimpleIdentifier) {
            final varName = lhs.name;
            try {
              currentEnv.assign(varName, resolvedRhs);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Assigned $varName = $resolvedRhs (Simple Assign)");
            } catch (e) {
              Logger.error("Assigning simple await result: $e");
            }
          } else {
            Logger.warn(
                "[_determineNextNodeAfterAwait] Resumption for simple assignment to complex LHS not fully implemented. Trying standard assign visit.");
  
            final originalVisitorEnv = visitor.environment;
            try {
              visitor.environment = currentEnv;
              assignmentNode
                  .accept(visitor); // Might re-trigger await if LHS is complex?
            } catch (e) {
              Logger.error("Re-visiting simple assignment failed: $e");
            } finally {
              visitor.environment = originalVisitorEnv;
            }
          }
        } else {
          final originalVisitorEnv = visitor.environment;
          Object? lhsValue;
          try {
            visitor.environment = currentEnv; // Use correct scope for LHS
            lhsValue = lhs.accept<Object?>(visitor);
            Logger.debug(
                "[_determineNextNodeAfterAwait] Re-evaluated LHS for compound assignment to: $lhsValue (${lhsValue?.runtimeType})");
          } catch (e, s) {
            Logger.error("Re-evaluating LHS for compound assign: $e\n$s");
            // Cannot proceed without LHS value
            if (!state.completer.isCompleted) state.completer.completeError(e, s);
            return null; // Stop
          } finally {
            visitor.environment = originalVisitorEnv;
          }
  
          // Calculate the result using computeCompoundValue
          Object? resultValue;
          try {
            // computeCompoundValue needs the visitor for potential extension methods
            resultValue =
                visitor.computeCompoundValue(lhsValue, resolvedRhs, operatorType);
          } catch (e, s) {
            Logger.error("Computing compound value after await: $e\n$s");
            if (!state.completer.isCompleted) state.completer.completeError(e, s);
            return null; // Stop
          }
  
          // Assign the computed result back to the LHS target
          if (lhs is SimpleIdentifier) {
            final varName = lhs.name;
            try {
              currentEnv.assign(varName, resultValue);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Assigned $varName = $resultValue (Compound Assign)");
            } catch (e) {
              Logger.error("Assigning compound await result: $e");
            }
          } else {
            Logger.warn(
                "[_determineNextNodeAfterAwait] Resumption for compound assignment to complex LHS not fully implemented. Trying standard assign visit.");
            // Tentative: Ré-exécuter l'assignation avec la valeur calculée (peut échouer)
            // Need to fake the RHS with the computed value somehow? This is hard.
            // For now, let it fail or proceed without assigning complex LHS.
          }
        }
  
        // Return the next node determined earlier
        if (nextNode == null && parentStatement is! Statement) {
          Logger.warn(
              "[_determineNextNodeAfterAwait] Could not find parent statement or next node for AssignmentExpression after await. Stopping.");
        }
        return nextNode;
      }
  
      // Case 6: If condition (if (await f()))
      else if (awaitContextNode is IfStatement && awaitExpression != null) {
        // ... (unchanged logic, but ensure it uses awaitContextNode) ...
      } else if (awaitContextNode is WhileStatement) {
        // The await was in the condition
        final conditionResult = state.lastAwaitResult;
        Logger.debug(
            " [_determineNextNodeAfterAwait] Resuming While condition with awaited result: $conditionResult");
  
        if (conditionResult is! bool) {
          final error = RuntimeError(
              "While condition (after await) must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
          if (!state.completer.isCompleted) {
            state.completer.completeError(error);
          }
          return null;
        }
  
        if (conditionResult) {
          // Condition true -> Go to body
          Logger.debug(
              " [_determineNextNodeAfterAwait] While condition TRUE. Next node is body: ${awaitContextNode.body.runtimeType}");
          if (awaitContextNode.body is Block) {
            return (awaitContextNode.body as Block).statements.firstOrNull;
          } else {
            return awaitContextNode.body;
          }
        } else {
          // Condition false -> Exit loop
          Logger.debug(
              " [_determineNextNodeAfterAwait] While condition FALSE. Finding node after loop.");
          return _findNextSequentialNode(visitor, awaitContextNode);
        }
      } else if (awaitContextNode is DoStatement) {
        // The await was in the condition
        final conditionResult = state.lastAwaitResult;
        Logger.debug(
            " [_determineNextNodeAfterAwait] Resuming DoWhile condition with awaited result: $conditionResult");
  
        if (conditionResult is! bool) {
          final error = RuntimeError(
              "DoWhile condition (after await) must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
          if (!state.completer.isCompleted) {
            state.completer.completeError(error);
          }
          return null;
        }
  
        if (conditionResult) {
          // Condition true: the next state is the beginning of the loop body
          Logger.debug(
              " [_determineNextNodeAfterAwait] DoWhile condition TRUE. Next node is body: ${awaitContextNode.body.runtimeType}");
          if (awaitContextNode.body is Block) {
            return (awaitContextNode.body as Block).statements.firstOrNull;
          } else {
            return awaitContextNode.body;
          }
        } else {
          // Condition false: find the next instruction after the do-while
          Logger.debug(
              " [_determineNextNodeAfterAwait] DoWhile condition FALSE. Finding node after do-while.");
          return _findNextSequentialNode(visitor, awaitContextNode);
        }
      } else if (awaitContextNode is IfStatement) {
        // The await was in the condition
        final ifNode = awaitContextNode;
        final conditionResult = state.lastAwaitResult;
        Logger.debug(
            " [_determineNextNodeAfterAwait] Resuming If condition with awaited result: $conditionResult");
  
        if (conditionResult is! bool) {
          final error = RuntimeError(
              "If condition (after await) must evaluate to a boolean, but got ${conditionResult?.runtimeType}.");
          if (!state.completer.isCompleted) {
            state.completer.completeError(error);
          }
          return null; // Arrêter
        }
  
        if (conditionResult) {
          // Condition true: the next state is the 'then' branch
          Logger.debug(
              " [_determineNextNodeAfterAwait] If condition TRUE. Next node is thenBranch: ${ifNode.thenStatement.runtimeType}");
          if (ifNode.thenStatement is Block) {
            return (ifNode.thenStatement as Block).statements.firstOrNull;
          } else {
            return ifNode.thenStatement;
          }
        } else {
          // Condition false: check the 'else' branch
          if (ifNode.elseStatement != null) {
            Logger.debug(
                "[_determineNextNodeAfterAwait] If condition FALSE. Next node is elseBranch: ${ifNode.elseStatement?.runtimeType}");
            if (ifNode.elseStatement is Block) {
              return (ifNode.elseStatement as Block).statements.firstOrNull;
            } else {
              return ifNode.elseStatement;
            }
          } else {
            // No 'else' branch, find the next instruction after the if
            Logger.debug(
                "[_determineNextNodeAfterAwait] If condition FALSE, no else branch. Finding node after IfStatement.");
            return _findNextSequentialNode(visitor, ifNode);
          }
        }
      } else if (awaitContextNode is ForStatement &&
          (awaitContextNode.forLoopParts is ForPartsWithDeclarations ||
              awaitContextNode.forLoopParts is ForPartsWithExpression)) {
        final forNode = awaitContextNode;
        // Use nodeThatCausedSuspension to find where the await occurred
        // AstNode? nodeThatContainedAwait = nodeThatCausedSuspension; // Can be AwaitExpression or ForStatement if await in condition/updater
        final awaitResult = state.lastAwaitResult;
  
        Logger.debug(
            " [_determineNextNodeAfterAwait] Resuming For loop. Suspension node: ${nodeThatCausedSuspension.runtimeType}, Context node: ${awaitContextNode.runtimeType}, Result: $awaitResult");
  
        // Check if we are resuming specifically from initializer suspension
        // We know we suspended during initialization if:
        // 1. The context node is the ForStatement itself.
        // 2. The loop environment exists (currentState.loopEnvironmentStack is not empty).
        // 3. The loop is marked as initialized (currentState.forLoopInitialized == true or stack indicates initialized)
        //    (because the SM marks it initialized *before* waiting on the init suspension).
        // 4. We haven't already processed the initializer resumption (currentState.resumedFromInitializer == false).
        bool isLoopInitialized = state.loopInitializedStack.isNotEmpty
            ? state.loopInitializedStack.last
            : state.forLoopInitialized;
        bool resumingFromInitializer = (awaitContextNode ==
                forNode) && // Suspended *while processing* the ForStatement node
            state.loopEnvironmentStack.isNotEmpty &&
            isLoopInitialized && // Was set before waiting
            !state.resumedFromInitializer; // Haven't resumed the init part yet
  
        if (resumingFromInitializer) {
          Logger.debug(
              " [_determineNextNodeAfterAwait] Detected resumption from For initializer. Assigning result and proceeding to condition.");
  
          // Assign the result to the loop variable
          if (state.loopEnvironmentStack.isEmpty) {
            throw StateError(
                "Internal error: For loop environment stack empty after initializer await resumption.");
          }
          final parts = forNode.forLoopParts;
          if (parts is ForPartsWithDeclarations) {
            // Assuming a single variable declaration for now, as before
            if (parts.variables.variables.length == 1) {
              final loopVarName = parts.variables.variables.first.name.lexeme;
              // Assign the actual result now. The var was defined as null previously by visitVariableDeclarationList.
              state.loopEnvironmentStack.last.assign(loopVarName, awaitResult);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Assigned awaited result $awaitResult to for loop variable '$loopVarName' in env ${currentExecutionEnvironment.hashCode}.");
            } else {
              throw UnimplementedError(
                  "Async initialization for multiple variables in a single 'for' declaration not yet supported.");
            }
          } else if (parts is ForPartsWithExpression) {
            // If init is an expression like `i = await f()`, AssignmentExpression should handle it.
            // If init is just `await f()`, the result is discarded, just proceed.
            Logger.debug(
                "[_determineNextNodeAfterAwait] Resumed from ForPartsWithExpression initializer (await result ignored or handled by AssignmentExpression).");
          }
  
          // Mark that we have now processed the initializer resumption
          state.resumedFromInitializer = true;
  
          // Next state is the ForStatement itself to evaluate the condition
          return forNode;
        } else {
          // Resumption wasn't from initializer, try condition/updater/body logic
          AstNode? nodeThatContainedAwait =
              nodeThatCausedSuspension; // Where did the await physically occur?
          bool inCondition = false;
          bool inUpdater = false;
          final parts = forNode.forLoopParts;
  
          // Try detecting condition await more reliably
          if ((parts is ForPartsWithDeclarations &&
                  parts.condition == nodeThatContainedAwait) ||
              (parts is ForPartsWithExpression &&
                  parts.condition == nodeThatContainedAwait)) {
            inCondition = true;
          }
          // Try detecting updater await more reliably
          else if ((parts is ForPartsWithDeclarations) ||
              (parts is ForPartsWithExpression)) {
            final NodeList<Expression> currentUpdaters =
                (parts is ForPartsWithDeclarations)
                    ? parts.updaters
                    : (parts as ForPartsWithExpression).updaters;
            AstNode? current = nodeThatContainedAwait;
            while (current != null &&
                !(current.parent is NodeList<Expression> &&
                    (current.parent as NodeList<Expression>) ==
                        currentUpdaters)) {
              current = current.parent;
            }
            if (current != null) {
              // Found the await expression within the updaters list
              inUpdater = true;
            }
          }
  
          if (inCondition) {
            Logger.debug(
                "[_determineNextNodeAfterAwait] Resumed from For condition. Result: $awaitResult");
            if (awaitResult is! bool) {
              final error = RuntimeError(
                  "For loop condition (after await) must be a boolean, but got ${awaitResult?.runtimeType}");
              if (!state.completer.isCompleted) {
                state.completer.completeError(error);
              }
              return null; // Arrêter
            }
            if (awaitResult) {
              // Condition true -> Go to body
              Logger.debug(
                  " [_determineNextNodeAfterAwait] For condition TRUE. Next node is body.");
              if (forNode.body is Block) {
                return (forNode.body as Block).statements.firstOrNull;
              } else {
                return forNode.body;
              }
            } else {
              // Condition false -> Exit loop
              Logger.debug(
                  " [_determineNextNodeAfterAwait] For condition FALSE. Finding node after loop.");
              state.forLoopInitialized = false; // Clean up state
              state.forLoopEnvironment = null;
              if (state.loopEnvironmentStack.isNotEmpty) {
                state.loopEnvironmentStack.removeLast();
              }
              if (state.loopNodeStack.isNotEmpty) {
                state.loopNodeStack.removeLast();
              }
              return _findNextSequentialNode(visitor, forNode);
            }
          } else if (inUpdater) {
            Logger.debug(
                "[_determineNextNodeAfterAwait] Resumed from For updater. Proceeding to condition check.");
            // After updater, always go back to ForStatement for condition check
            return forNode;
          } else {
            // If not initializer, condition, or updater, assume it was in the body.
            Logger.debug(
                "[_determineNextNodeAfterAwait] Assuming await was in For loop body. Finding next node after suspension point: ${nodeThatCausedSuspension.runtimeType}. Visitor env: ${visitor.environment.hashCode}");
            // Reset the initializer flag just in case
            state.resumedFromInitializer = false;
            // Find the node *after* the statement that contained the await
            AstNode? parentStatement = nodeThatCausedSuspension;
            // Climb up until we find the Statement that is a direct child of the loop's body Block,
            // or the body itself if it's not a Block.
            while (parentStatement != null &&
                parentStatement.parent !=
                    forNode
                        .body && // Stop if parent is the body itself (non-block)
                !(parentStatement.parent is Block &&
                    parentStatement.parent ==
                        forNode.body)) // Stop if parent is the body block
            {
              parentStatement = parentStatement.parent;
            }
  
            if (parentStatement != null && parentStatement is Statement) {
              // Found the statement within the body that contained the await
              AstNode? nextInBody =
                  _findNextSequentialNode(visitor, parentStatement);
              Logger.debug(
                  " [_determineNextNodeAfterAwait] Found parent statement in body: ${parentStatement.runtimeType}. Next sequential node is: ${nextInBody?.runtimeType}");
              // If _findNextSequentialNode returns the ForStatement, it means we finished the body
              return nextInBody;
            } else {
              // Could not find the statement in the body, maybe await was the body itself?
              if (forNode.body == nodeThatCausedSuspension) {
                Logger.debug(
                    "[_determineNextNodeAfterAwait] Await was the single statement body of the For loop.");
                // After single statement body, go back to ForStatement for updater/condition
                return forNode;
              } else {
                // Fallback / Error case
                Logger.warn(
                    "[_determineNextNodeAfterAwait] Could not determine sequence after await in For loop body. Context: ${awaitContextNode.runtimeType}, Suspension: ${nodeThatCausedSuspension.runtimeType}. Stopping.");
                state.forLoopInitialized = false;
                state.forLoopEnvironment = null;
                if (state.loopEnvironmentStack.isNotEmpty) {
                  state.loopEnvironmentStack.removeLast();
                }
                if (state.loopNodeStack.isNotEmpty) {
                  state.loopNodeStack.removeLast();
                }
                return null;
              }
            }
          }
        }
      }
  
      // Handle await for loops specifically
      if (awaitContextNode is ForStatement &&
          awaitContextNode.awaitKeyword != null) {
        Logger.debug(
            "[_determineNextNodeAfterAwait] Handling await for loop suspension.");
  
        // If we just finished converting stream to list, set up the list and start iteration
        if (state.awaitingStreamConversion == true) {
          Logger.debug(
              "[_determineNextNodeAfterAwait] Setting up await for list iteration.");
          state.awaitingStreamConversion = false;
          final List<Object?> items = futureResult as List<Object?>;
  
          // Update the stack for this await-for loop
          final stackIndex = state.awaitForNodeStack.indexOf(awaitContextNode);
          if (stackIndex >= 0) {
            state.awaitForListStack[stackIndex] = items;
            state.awaitForIndexStack[stackIndex] = 0;
            Logger.debug(
                "[_determineNextNodeAfterAwait] Updated stack index $stackIndex with ${items.length} items");
          }
  
          // Also update legacy fields for backward compatibility
          state.currentAwaitForList = items;
          state.currentAwaitForIndex = 0;
  
          final parts = awaitContextNode.forLoopParts as ForEachParts;
          if (parts is ForEachPartsWithDeclaration) {
            final loopVariable = parts.loopVariable;
            visitor.environment.define(loopVariable.name.lexeme, null);
          }
  
          // Return the ForStatement itself to continue processing
          return awaitContextNode;
        } else {
          // If we're in the middle of await for iteration but got suspended (e.g., body had async operation)
          // Increment the index in the stack for this specific await-for loop
          final stackIndex = state.awaitForNodeStack.indexOf(awaitContextNode);
          if (stackIndex >= 0) {
            final currentIndex = state.awaitForIndexStack[stackIndex];
            state.awaitForIndexStack[stackIndex] = currentIndex + 1;
            Logger.debug(
                "[_determineNextNodeAfterAwait] Continuing await for iteration at stack level $stackIndex. Moving to index ${state.awaitForIndexStack[stackIndex]}");
          } else {
            // Fallback to legacy approach
            final currentIndex = state.currentAwaitForIndex ?? 0;
            state.currentAwaitForIndex = currentIndex + 1;
            Logger.debug(
                "[_determineNextNodeAfterAwait] Continuing await for iteration (legacy). Moving to index ${state.currentAwaitForIndex}");
          }
          // Continue back to the ForStatement to process next item
          return awaitContextNode;
        }
      }
  
      Logger.warn(
          "_determineNextNodeAfterAwait - Unhandled await context: ${awaitContextNode.runtimeType} (suspension from: ${nodeThatCausedSuspension.runtimeType}). Stopping state machine.");
      return null; // Default stop state machine
    }
  
    // Implementation of the logic to find the next sequential node
    static AstNode? _findNextSequentialNode(
        InterpreterVisitor visitor, AstNode currentNode) {
      AstNode? parent = currentNode.parent;
      AsyncExecutionState? state =
          visitor.currentAsyncState; // Can be null if not async
  
      Logger.debug(
          "[_findNextSequentialNode] Finding next node after: ${currentNode.runtimeType} (parent: ${parent?.runtimeType})");
  
      // Handle the end of an instruction in a block
      if (currentNode is Statement && parent is Block) {
        final block = parent;
        final index = block.statements.indexOf(currentNode);
        bool isLastStatement =
            (index != -1 && index == block.statements.length - 1);
  
        if (!isLastStatement && index != -1) {
          // Simple case: next instruction in the same block
          Logger.debug(
              " [_findNextSequentialNode] Next sequential node in block: ${block.statements[index + 1].runtimeType}");
          return block.statements[index + 1];
        } else if (isLastStatement) {
          // It was the last instruction in the block. What next?
          Logger.debug(" [_findNextSequentialNode] Reached end of a Block.");
  
          AstNode? blockParent = block.parent;
  
          // Case 1: End of a Try block
          if (blockParent is TryStatement && blockParent.body == block) {
            Logger.debug("[_findNextSequentialNode] End of Try block.");
            // Are there any catch clauses?
            if (blockParent.catchClauses.isNotEmpty) {
              // If there are catch clauses, normal execution skips them.
              // They are only reached by an exception handled by _handleAsyncError.
              // So, after the try, we look for the finally or the next code.
              Logger.debug(
                  " [_findNextSequentialNode] Try block finished normally, skipping catches.");
            }
            // Check if there is a finally block
            if (blockParent.finallyBlock != null) {
              Logger.debug(
                  " [_findNextSequentialNode] Found finally block after Try. Jumping to finally.");
              // The next node is the beginning of the finally block
              final firstFinallyStmt =
                  blockParent.finallyBlock!.statements.firstOrNull;
              if (firstFinallyStmt != null) {
                return firstFinallyStmt;
              } else {
                // Finally block is empty, find what follows the TryStatement
                Logger.debug(
                    "[_findNextSequentialNode] Finally block is empty. Finding node after TryStatement.");
                if (state != null) {
                  state.activeTryStatement = null; // End of try handling
                }
                return _findNextSequentialNode(visitor, blockParent);
              }
            } else {
              // No catch (normally skipped) and no finally, skip after the TryStatement
              Logger.debug(
                  " [_findNextSequentialNode] No finally block after Try. Finding node after TryStatement.");
              if (state != null) {
                state.activeTryStatement = null; // End of try handling
              }
              return _findNextSequentialNode(visitor, blockParent);
            }
          }
          // Case 2: End of a Catch block
          else if (blockParent is CatchClause) {
            Logger.debug("[_findNextSequentialNode] End of Catch block.");
            TryStatement? tryStatement = _findEnclosingTryStatement(blockParent);
            // After a catch, we must ALWAYS execute the finally if it exists
            if (tryStatement != null && tryStatement.finallyBlock != null) {
              Logger.debug(
                  " [_findNextSequentialNode] Found finally block after Catch. Jumping to finally.");
              // The next node is the beginning of the finally block
              final firstFinallyStmt =
                  tryStatement.finallyBlock!.statements.firstOrNull;
              if (firstFinallyStmt != null) {
                return firstFinallyStmt;
              } else {
                // Finally block is empty, find what follows the TryStatement
                Logger.debug(
                    "[_findNextSequentialNode] Finally block is empty (after catch). Finding node after TryStatement.");
                if (state != null) {
                  state.activeTryStatement = null; // End of try handling
                }
                return _findNextSequentialNode(visitor, tryStatement);
              }
            } else {
              // No finally, skip after the TryStatement
              Logger.debug(
                  " [_findNextSequentialNode] No finally block after Catch. Finding node after TryStatement.");
              if (state != null) {
                state.activeTryStatement = null; // End of try handling
              }
              return _findNextSequentialNode(visitor,
                  tryStatement ?? blockParent); // Go back to the Try or Catch
            }
          }
          // Case 3: End of a Finally block
          else if (blockParent is TryStatement &&
              blockParent.finallyBlock == block) {
            Logger.debug("[_findNextSequentialNode] End of Finally block.");
            // After a finally, we look for the next node after the TryStatement
            // If an error was in progress, it will be rethrown by the main loop.
            if (state != null) {
              state.activeTryStatement = null; // End of try handling
            }
            return _findNextSequentialNode(visitor, blockParent);
          }
          // Case 4: End of a loop block (While, DoWhile, For, ForIn)
          else if (blockParent is WhileStatement && blockParent.body == block) {
            Logger.debug(
                "[_findNextSequentialNode] End of While body Block. Returning WhileStatement node.");
            return blockParent; // Go back to the WhileStatement to re-evaluate the condition
          } else if (blockParent is DoStatement && blockParent.body == block) {
            Logger.debug(
                "[_findNextSequentialNode] End of DoWhile body Block. Returning DoStatement node.");
            return blockParent; // Go back to the DoStatement to re-evaluate the condition
          } else if (blockParent is ForStatement && blockParent.body == block) {
            // Applies to both standard For and For-In
            Logger.debug(
                "[_findNextSequentialNode] End of For/For-In body Block. Returning ForStatement node.");
            return blockParent; // Go back to the ForStatement to evaluate the next iteration/condition
          }
  
          // Case 5: End of an If/Else block
          else if (blockParent is IfStatement) {
            // Whether it's the end of the 'then' or the 'else', we look after the entire IfStatement
            Logger.debug(
                "[_findNextSequentialNode] End of If/Else Block. Finding node after IfStatement.");
            return _findNextSequentialNode(visitor, blockParent);
          }
  
          // Generic case: end of an unhandled block
          else {
            Logger.debug(
                "[_findNextSequentialNode] End of generic Block (parent: ${blockParent?.runtimeType}). Finding node after parent Block.");
            // Go back to the parent of the block to find the next node
            return _findNextSequentialNode(visitor, block);
          }
        }
        // If index == -1 (should not happen unless internal error), go back
        else {
          Logger.warn(
              "[_findNextSequentialNode] Statement not found in parent block? Finding node after parent block.");
          return _findNextSequentialNode(visitor, parent);
        }
      }
  
      AstNode? currentSearchNode = currentNode;
      while (currentSearchNode != null) {
        parent = currentSearchNode.parent;
  
        // Handle the end of the body (single statement) of a While loop
        if (currentSearchNode is Statement &&
            parent is WhileStatement &&
            parent.body == currentSearchNode) {
          Logger.debug(
              " [_findNextSequentialNode] End of While body (single statement). Returning WhileStatement node.");
          return parent;
        }
  
        // Handle the end of the body (single statement) of a DoWhile loop
        if (currentSearchNode is Statement &&
            parent is DoStatement &&
            parent.body == currentSearchNode) {
          Logger.debug(
              " [_findNextSequentialNode] End of DoWhile body (single statement). Returning DoStatement node.");
          return parent;
        }
  
        // Handle the end of the body (single statement) of a standard For loop or For-In loop
        if (currentSearchNode is Statement &&
            parent is ForStatement &&
            parent.body == currentSearchNode) {
          Logger.debug(
              " [_findNextSequentialNode] End of standard For/For-In body (single statement). Returning ForStatement node.");
          return parent;
        }
  
        // Handle the end of the 'then' branch (single statement) of an IfStatement
        if (currentSearchNode is Statement &&
            parent is IfStatement &&
            parent.thenStatement == currentSearchNode) {
          // If there is an 'else' branch, do nothing (execution stops here for this branch)
          // If there is NO 'else' branch, find the node AFTER the IfStatement.
          if (parent.elseStatement == null) {
            Logger.debug(
                "[_findNextSequentialNode] End of If 'then' (single statement, no else). Finding node after IfStatement.");
            return _findNextSequentialNode(visitor, parent);
          } else {
            Logger.debug(
                "[_findNextSequentialNode] End of If 'then' (single statement, with else). Stopping this path.");
            // There is no "next sequential node" after the then if there is an else.
            return null;
          }
        }
  
        // Handle the end of the 'else' branch (single statement) of an IfStatement
        if (currentSearchNode is Statement &&
            parent is IfStatement &&
            parent.elseStatement == currentSearchNode) {
          // After the 'else', we always look for the node AFTER the entire IfStatement.
          Logger.debug(
              " [_findNextSequentialNode] End of If 'else' (single statement). Finding node after IfStatement.");
          return _findNextSequentialNode(visitor, parent);
        }
  
        // If we didn't find a specific control structure parent,
        // check if the parent is a statement that can be sequenced.
  
        if (parent is Block) {
          // If the parent is a Block, the logic at the beginning (block handling) applies.
          // Call recursively so that this logic takes over.
          Logger.debug(
              " [_findNextSequentialNode] Ascending into a Block. Re-evaluating block logic for the parent Block.");
          return _findNextSequentialNode(visitor, parent);
        } else if (parent is Statement) {
          // If the parent is another statement, continue ascending
          // to find the enclosing block or function.
          Logger.debug(
              " [_findNextSequentialNode] Ascending from Statement (${currentSearchNode.runtimeType}) to parent (${parent.runtimeType}).");
          currentSearchNode = parent;
        } else if (parent is FunctionBody || parent is CompilationUnit) {
          // Reached the limit of the function or file
          Logger.debug(
              " [_findNextSequentialNode] Reached FunctionBody or CompilationUnit. Returning null.");
          return null;
        } else if (parent == null) {
          // Reached the root of the AST
          Logger.debug(
              " [_findNextSequentialNode] Reached top level (null parent). Returning null.");
          return null;
        } else {
          // Unhandled parent (Expression, etc.) - continue ascending
          Logger.debug(
              " [_findNextSequentialNode] Ascending from non-statement parent (${parent.runtimeType}).");
          currentSearchNode = parent;
        }
      }
  
      Logger.debug(
          "[_findNextSequentialNode] Could not determine next sequential node (fell through). Returning null.");
      return null; // Fallback
    }
  
    // Replace the old placeholder _startAsyncStateMachine
    void _startAsyncStateMachine(
        InterpreterVisitor visitor, AsyncExecutionState initialState) {
      Logger.debug(
          "[_startAsyncStateMachine] Scheduling state machine run for initial state: ${initialState.nextStateIdentifier?.runtimeType}");
      _scheduleStateMachineRun(visitor, initialState);
    }
  
    @override
    String toString() => '<fn ${_name ?? '<anonymous>'}>';
  
    // Helper to recursively search for invocations with await in arguments
    static AstNode? _findInvocationWithAwaitInArguments(AstNode node) {
      // Check if this node is an invocation with await in arguments
      if (node is MethodInvocation ||
          node is FunctionExpressionInvocation ||
          node is InstanceCreationExpression) {
        if (_hasAwaitInArguments(node)) {
          return node;
        }
      }
  
      // Recursively search in child nodes
      for (final child in node.childEntities) {
        if (child is AstNode) {
          final found = _findInvocationWithAwaitInArguments(child);
          if (found != null) {
            return found;
          }
        }
      }
  
      return null;
    }
  
    // Helper to check if an invocation has await in its arguments
    static bool _hasAwaitInArguments(AstNode invocation) {
      ArgumentList? argumentList;
  
      if (invocation is MethodInvocation) {
        argumentList = invocation.argumentList;
      } else if (invocation is FunctionExpressionInvocation) {
        argumentList = invocation.argumentList;
      } else if (invocation is InstanceCreationExpression) {
        argumentList = invocation.argumentList;
      }
  
      if (argumentList == null) return false;
  
      // Check each argument for await expressions
      for (final arg in argumentList.arguments) {
        if (_containsAwait(arg)) {
          return true;
        }
      }
  
      return false;
    }
  
    // Helper to recursively check if a node contains await
    static bool _containsAwait(AstNode node) {
      if (node is AwaitExpression) {
        return true;
      }
  
      // Recursively check child nodes
      for (final child in node.childEntities) {
        if (child is AstNode && _containsAwait(child)) {
          return true;
        }
      }
  
      return false;
    }
  
    // Helper to evaluate arguments for constructor/super/this invocations
    (List<Object?>, Map<String, Object?>) _evaluateArgumentsForInvocation(
        InterpreterVisitor visitor,
        ArgumentList argumentList,
        String invocationType // e.g., "super()", "this()"
        ) {
      final List<Object?> positionalArgs = [];
      final Map<String, Object?> namedArgs = {};
      bool namedArgsEncountered = false;
  
      for (final arg in argumentList.arguments) {
        // Evaluate argument, disallow await for now in constructor contexts
        final argValue = arg.accept<Object?>(visitor);
        if (argValue is AsyncSuspensionRequest) {
          throw UnimplementedError(
              "'await' is not yet supported within $invocationType call arguments.");
        }
  
        if (arg is NamedExpression) {
          namedArgsEncountered = true;
          final name = arg.name.label.name;
          final value = arg.expression
              .accept<Object?>(visitor); // Evaluate the expression part
          Logger.debug(
              " [_evalArgs] Evaluated NAMED arg expression '$name' = $value (${value?.runtimeType})");
          if (value is AsyncSuspensionRequest) {
            throw UnimplementedError(
                "'await' is not yet supported within $invocationType call arguments.");
          }
          if (namedArgs.containsKey(name)) {
            throw RuntimeError(
                "Named argument '$name' provided multiple times to $invocationType.");
          }
          namedArgs[name] = value;
        } else {
          if (namedArgsEncountered) {
            throw RuntimeError(
                "Positional arguments cannot follow named arguments in $invocationType.");
          }
          positionalArgs.add(argValue);
          Logger.debug(
              " [_evalArgs] Evaluated POSITIONAL arg = $argValue (${argValue?.runtimeType})");
        }
      }
      return (positionalArgs, namedArgs);
    }
  
    // Create a Stream for async* generator functions using real async state machine
    Stream<Object?> _createAsyncGeneratorStream(InterpreterVisitor visitor,
        Environment executionEnvironment, bool redirected) {
      late StreamController<Object?> controller;
  
      controller = StreamController<Object?>(onListen: () async {
        try {
          final previousVisitorEnv = visitor.environment;
          final previousCurrentFunction = visitor.currentFunction;
          final previousAsyncState = visitor.currentAsyncState;
  
          try {
            visitor.environment = executionEnvironment;
            visitor.currentFunction = this;
  
            if (isAbstract) {
              controller.addError(RuntimeError(
                  "Cannot call abstract method '${_name ?? '<abstract>'}'."));
              return;
            }
  
            final bodyToExecute = _body;
            if (!redirected && bodyToExecute is BlockFunctionBody) {
              // Use the real async state machine for generators
              await _runAsyncGenerator(
                  visitor, bodyToExecute, controller, executionEnvironment);
            } else if (bodyToExecute is ExpressionFunctionBody) {
              final result = bodyToExecute.expression.accept<Object?>(visitor);
              if (result is YieldValue) {
                if (result.isYieldStar) {
                  await _handleYieldStar(result.value, controller);
                } else {
                  controller.add(result.value);
                }
              }
            }
          } on ReturnException catch (_) {
            // Generator completed with return
          } finally {
            visitor.environment = previousVisitorEnv;
            visitor.currentFunction = previousCurrentFunction;
            visitor.currentAsyncState = previousAsyncState;
          }
        } catch (e, stackTrace) {
          controller.addError(e, stackTrace);
        } finally {
          if (!controller.isClosed) controller.close();
        }
      });
  
      return controller.stream;
    }
  
    // Run async* generator using the real async state machine
    Future<void> _runAsyncGenerator(
        InterpreterVisitor visitor,
        BlockFunctionBody body,
        StreamController<Object?> controller,
        Environment executionEnvironment) async {
      final completer = Completer<Object?>();
  
      // Determine the first state (AST node)
      AstNode? initialStateIdentifier = body.block.statements.firstOrNull;
  
      // Create the async state with generator support
      final asyncState = AsyncExecutionState(
        environment: executionEnvironment,
        completer: completer,
        nextStateIdentifier: initialStateIdentifier,
        function: this,
        generatorStreamController: controller, // Enable generator mode
      );
  
      // Set the async state in visitor
      final previousAsyncState = visitor.currentAsyncState;
      visitor.currentAsyncState = asyncState;
  
      try {
        // Schedule the real state machine to run
        _scheduleStateMachineRun(visitor, asyncState);
  
        // Wait for the generator to complete
        await completer.future;
      } finally {
        visitor.currentAsyncState = previousAsyncState;
      }
    }
  
    // Create an Iterable for sync* generator functions
    Iterable<Object?> _createSyncGeneratorIterable(InterpreterVisitor visitor,
        Environment executionEnvironment, bool redirected) {
      return _SyncGeneratorIterable(
          this, visitor, executionEnvironment, redirected);
    }
  
    // Handle yield* expressions
    Future<void> _handleYieldStar(
        Object? value, StreamController<Object?> controller) async {
      if (value is Stream) {
        await for (final item in value) {
          controller.add(item);
        }
      } else if (value is Iterable) {
        for (final item in value) {
          controller.add(item);
        }
      } else {
        throw RuntimeError(
            "yield* expression must be a Stream or Iterable, got ${value.runtimeType}");
      }
    }
  }
  
  // Iterable implementation for sync* generators
  class _SyncGeneratorIterable extends Iterable<Object?> {
    final InterpretedFunction function;
    final InterpreterVisitor visitor;
    final Environment executionEnvironment;
    final bool redirected;
  
    _SyncGeneratorIterable(
        this.function, this.visitor, this.executionEnvironment, this.redirected);
  
    @override
    Iterator<Object?> get iterator => _SyncGeneratorIterator(
        function, visitor, executionEnvironment, redirected);
  }
  
  // Iterator implementation for sync* generators
  class _SyncGeneratorIterator implements Iterator<Object?> {
    final InterpretedFunction function;
    final InterpreterVisitor visitor;
    final Environment executionEnvironment;
    final bool redirected;
  
    List<Object?>? _values;
    int _currentIndex = -1;
    bool _initialized = false;
  
    _SyncGeneratorIterator(
        this.function, this.visitor, this.executionEnvironment, this.redirected);
  
    @override
    Object? get current =>
        (_currentIndex >= 0 && _values != null && _currentIndex < _values!.length)
            ? _values![_currentIndex]
            : null;
  
    @override
    bool moveNext() {
      if (!_initialized) {
        _initialized = true;
        _values = _collectAllValues();
      }
  
      if (_values == null || _values!.isEmpty) {
        return false;
      }
  
      _currentIndex++;
      return _currentIndex < _values!.length;
    }
  
    List<Object?> _collectAllValues() {
      final values = <Object?>[];
      final previousVisitorEnv = visitor.environment;
      final previousCurrentFunction = visitor.currentFunction;
  
      try {
        visitor.environment = executionEnvironment;
        visitor.currentFunction = function;
  
        if (function.isAbstract) {
          throw RuntimeError(
              "Cannot call abstract method '${function._name ?? '<abstract>'}'.");
        }
  
        final bodyToExecute = function._body;
        if (!redirected) {
          if (bodyToExecute is BlockFunctionBody) {
            _executeGeneratorBlockSync(bodyToExecute.block.statements, values);
          } else if (bodyToExecute is ExpressionFunctionBody) {
            final result = bodyToExecute.expression.accept<Object?>(visitor);
            if (result is YieldValue) {
              if (result.isYieldStar) {
                _handleYieldStarSync(result.value, values);
              } else {
                values.add(result.value);
              }
            }
          } else if (bodyToExecute is EmptyFunctionBody) {
            // Empty generator - no yields
          }
        }
      } on ReturnException catch (_) {
        // Generator completed with return
      } finally {
        visitor.environment = previousVisitorEnv;
        visitor.currentFunction = previousCurrentFunction;
      }
  
      return values;
    }
  
    void _executeGeneratorBlockSync(
        List<Statement> statements, List<Object?> values) {
      for (final statement in statements) {
        try {
          final result = statement.accept<Object?>(visitor);
          if (result is YieldValue) {
            if (result.isYieldStar) {
              _handleYieldStarSync(result.value, values);
            } else {
              values.add(result.value);
            }
          }
        } on ReturnException catch (_) {
          break; // Exit generator
        } on BreakException catch (_) {
          break; // Exit generator
        } on ContinueException catch (_) {
          continue; // Continue to next iteration
        }
      }
    }
  
    void _handleYieldStarSync(Object? value, List<Object?> values) {
      if (value is Iterable) {
        values.addAll(value);
      } else if (value is Stream) {
        throw RuntimeError("Cannot yield* a Stream in a sync* generator");
      } else {
        throw RuntimeError(
            "yield* expression must be an Iterable, got ${value.runtimeType}");
      }
    }
  }
  
  // Represents a function implemented natively in the interpreter host (Dart)
  typedef NativeFunctionImpl = Object? Function(
      InterpreterVisitor visitor,
      List<Object?> arguments,
      Map<String, Object?> namedArguments,
      List<RuntimeType>? typeArguments);
  
  class NativeFunction implements Callable, RuntimeType {
    final NativeFunctionImpl _function;
    @override
    final int arity;
    final String _name;
  
    NativeFunction(this._function, {required this.arity, String? name})
        : _name = name ?? "<native>";
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments]) {
      return _function(
          visitor, positionalArguments, namedArguments, typeArguments);
    }
  
    @override
    String toString() => '<native fn $_name>';
  
    @override
    bool isSubtypeOf(RuntimeType other, {Object? value}) {
      final f1 = _function;
      if (other is NativeFunction) {
        final f2 = other._function;
        if (name == 'num') {
          final isSubtype = switch (other._name) {
            'num' => true,
            'int' => true,
            'double' => true,
            _ => false,
          };
          return isSubtype;
        }
        return f1 == f2;
      }
  
      return false;
    }
  
    @override
    String get name => _name;
  }
  
  // Represents a bridged instance method that has been bound to a specific instance.
  class BridgedMethodCallable implements Callable {
    final BridgedInstance _instance; // The native target instance
    final BridgedMethodAdapter _adapter; // The adapter function
    final String _methodName;
  
    BridgedMethodCallable(this._instance, this._adapter, this._methodName);
  
    @override
    int get arity {
      // The arity is complex to determine statically for native adapters.
      // For now, return 0, but the adapter itself will do the validation.
      // We could improve this if the adapters provide metadata.
      return 0;
    }
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments]) {
      try {
        // Call the adapter with the native object of the instance and the arguments
        return _adapter(
            visitor, _instance.nativeObject, positionalArguments, namedArguments);
      } on ArgumentError catch (e) {
        // Convert native ArgumentError to RuntimeError
        throw RuntimeError(
            "Invalid arguments for bridged method '${_instance.bridgedClass.name}.$_methodName': ${e.message}");
      } catch (e, s) {
        // Handle other native errors
        Logger.error(
            "[BridgedMethodCallable] Native exception during call to '${_instance.bridgedClass.name}.$_methodName': $e\n$s");
        throw RuntimeError(
            "Native error in bridged method '${_instance.bridgedClass.name}.$_methodName': $e");
      }
    }
  
    @override
    String toString() =>
        '<bridged method ${_instance.bridgedClass.name}.$_methodName>';
  }
  
  /// Represents a static method from a bridged class that can be passed as a value
  class BridgedStaticMethodCallable implements Callable {
    final BridgedClass _bridgedClass;
    final BridgedStaticMethodAdapter _adapter;
    final String _methodName;
  
    BridgedStaticMethodCallable(
        this._bridgedClass, this._adapter, this._methodName);
  
    @override
    int get arity {
      // The arity is complex to determine statically for native adapters.
      // For now, return 0, but the adapter itself will do the validation.
      return 0;
    }
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments]) {
      try {
        // Call the adapter with the visitor and arguments
        return _adapter(visitor, positionalArguments, namedArguments);
      } on ArgumentError catch (e) {
        // Convert native ArgumentError to RuntimeError
        throw RuntimeError(
            "Invalid arguments for bridged static method '${_bridgedClass.name}.$_methodName': ${e.message}");
      } catch (e, s) {
        // Handle other native errors
        Logger.error(
            "[BridgedStaticMethodCallable] Native exception during call to '${_bridgedClass.name}.$_methodName': $e\n$s");
        throw RuntimeError(
            "Native error in bridged static method '${_bridgedClass.name}.$_methodName': $e");
      }
    }
  
    @override
    String toString() =>
        '<bridged static method ${_bridgedClass.name}.$_methodName>';
  }
  
  // Represents an extension method during interpretation.
  class InterpretedExtensionMethod implements Callable {
    final MethodDeclaration declaration; // The AST node for the method
    final Environment closure; // Environment where the extension was declared
    // Store the 'on' type to potentially check 'this' type during call?
    final RuntimeType onType;
  
    InterpretedExtensionMethod(this.declaration, this.closure, this.onType);
  
    // Add getters for method type
    bool get isGetter => declaration.isGetter;
    bool get isSetter => declaration.isSetter;
    bool get isOperator => declaration.isOperator;
  
    @override
    int get arity =>
        // Arity is based on the *declared* parameters, not including implicit 'this'
        declaration.parameters?.parameters.length ?? 0;
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments]) {
      // 1. Extract the target instance (first argument)
      if (positionalArguments.isEmpty) {
        throw RuntimeError(
            "Internal error: Extension method '${declaration.name.lexeme}' called without target instance ('this').");
      }
      final targetInstance =
          positionalArguments.removeAt(0); // Consomme le premier argument
  
      // 2. Create the execution environment
      final executionEnvironment = Environment(enclosing: closure);
      // Define 'this' in this environment
      executionEnvironment.define('this', targetInstance);
      Logger.debug(
          "[InterpretedExtensionMethod.call] Created execution env (${executionEnvironment.hashCode}) for '${declaration.name.lexeme}', defining 'this'=${targetInstance?.runtimeType}");
  
      // 3. Bind the declared parameters (explicit arguments)
      final params = declaration.parameters?.parameters;
      int positionalArgIndex = 0;
      final providedNamedArgs = namedArguments;
      final processedParamNames = <String>{};
  
      if (params != null) {
        for (final param in params) {
          String? paramName;
          Expression? defaultValueExpr;
          bool isRequired = false;
          bool isOptionalPositional = false;
          bool isNamed = false;
          bool isRequiredNamed = false;
  
          // Determine the parameter info (copied from InterpretedFunction)
          FormalParameter actualParam = param;
          if (param is DefaultFormalParameter) {
            defaultValueExpr = param.defaultValue;
            actualParam = param.parameter;
          }
          if (actualParam is NormalFormalParameter) {
            paramName = actualParam.name?.lexeme;
            isRequired = actualParam.isRequiredPositional;
            isOptionalPositional = actualParam.isOptionalPositional;
            isNamed = actualParam.isNamed;
            isRequiredNamed = actualParam.isRequiredNamed;
          } else {
            throw UnimplementedError(
                "Unsupported parameter kind in extension method: ${actualParam.runtimeType}");
          }
          if (paramName == null) {
            throw StateError("Extension parameter missing name");
          }
          processedParamNames.add(paramName);
  
          // Find the corresponding argument and value
          Object? valueToDefine;
          bool argumentProvided = false;
          if (isOptionalPositional || isRequired) {
            if (positionalArgIndex < positionalArguments.length) {
              valueToDefine = positionalArguments[positionalArgIndex++];
              argumentProvided = true;
            }
          } else if (isNamed) {
            if (providedNamedArgs.containsKey(paramName)) {
              valueToDefine = providedNamedArgs[paramName];
              argumentProvided = true;
            }
          }
  
          // Handle default values and required checks
          if (!argumentProvided) {
            if (defaultValueExpr != null) {
              final previousVisitorEnv = visitor.environment;
              try {
                visitor.environment =
                    closure; // Defaults evaluated in declaration scope
                valueToDefine = defaultValueExpr.accept<Object?>(visitor);
              } finally {
                visitor.environment = previousVisitorEnv;
              }
            } else if (isRequired || isRequiredNamed) {
              throw RuntimeError(
                  "Missing required ${isNamed ? 'named' : ''} argument for '$paramName' in extension method '${declaration.name.lexeme}'.");
            } else {
              valueToDefine = null;
            }
          }
          // Define the variable in the execution environment
          executionEnvironment.define(paramName, valueToDefine);
          Logger.debug(
              " [InterpretedExtensionMethod.call] Bound param '$paramName' = $valueToDefine");
        }
  
        // Final argument checks (copied from InterpretedFunction)
        final int totalPositionalDeclared =
            params.where((p) => p.isPositional).length;
        if (positionalArgIndex < positionalArguments.length) {
          throw RuntimeError(
              "Too many positional arguments for extension method '${declaration.name.lexeme}'. Expected at most $totalPositionalDeclared, got ${positionalArguments.length}.");
        }
        for (final providedName in providedNamedArgs.keys) {
          if (!processedParamNames.contains(providedName)) {
            throw RuntimeError(
                "Extension method '${declaration.name.lexeme}' does not have a parameter named '$providedName'.");
          }
        }
      } else if (positionalArguments.isNotEmpty || providedNamedArgs.isNotEmpty) {
        throw RuntimeError(
            "Extension method '${declaration.name.lexeme}' takes no arguments (besides 'this'), but arguments were provided.");
      }
  
      // 4. Execute the body in the new environment
      final previousEnvironment = visitor.environment;
      final previousFunction = visitor.currentFunction;
      // visitor.currentFunction = ???;
      visitor.environment = executionEnvironment; // USE THE NEW ENVIRONMENT
      Logger.debug(
          "[InterpretedExtensionMethod.call] Set visitor environment to executionEnvironment (${executionEnvironment.hashCode}) before executing body.");
  
      try {
        final body = declaration.body;
        if (body is BlockFunctionBody) {
          // executeBlock already handles ReturnException correctly
          return visitor.executeBlock(
              body.block.statements, executionEnvironment);
        } else if (body is ExpressionFunctionBody) {
          // For an expression body, evaluate and return the value
          final result = body.expression.accept<Object?>(visitor);
          // No need to raise ReturnException here, we return directly
          return result;
        } else if (body is EmptyFunctionBody) {
          throw RuntimeError(
              "Cannot execute empty body for extension method '${declaration.name.lexeme}'.");
        } else {
          throw UnimplementedError(
              'Function body type not handled in extension method: ${body.runtimeType}');
        }
      } on ReturnException catch (e) {
        // Catch in case executeBlock (or other) still raises ReturnException
        Logger.debug(
            " [InterpretedExtensionMethod.call] Caught ReturnException, returning value: ${e.value}");
        return e.value;
      } finally {
        Logger.debug(
            " [InterpretedExtensionMethod.call] Restoring visitor environment from (${visitor.environment.hashCode}) to (${previousEnvironment.hashCode}).");
        visitor.environment = previousEnvironment;
        visitor.currentFunction =
            previousFunction; // Restaurer aussi currentFunction
      }
    }
  }
  
  /// Represents an extension method bound to a target instance.
  ///
  /// Stores the instance (`target`) and the extension method (`extensionMethod`).
  /// When `call` is invoked, it calls the underlying extension method,
  /// automatically inserting the target instance as the first positional argument.
  class BoundExtensionMethodCallable implements Callable {
    final Object? target; // The 'this' instance to which the method is bound.
    final InterpretedExtensionMethod extensionMethod;
  
    BoundExtensionMethodCallable(this.target, this.extensionMethod);
  
    // The arity of the bound method is the arity of the original extension method.
    @override
    int get arity => extensionMethod.arity;
  
    @override
    Object? call(InterpreterVisitor visitor, List<Object?> positionalArguments,
        [Map<String, Object?> namedArguments = const {},
        List<RuntimeType>? typeArguments = const []]) {
      // Prepare the arguments for the actual call to the InterpretedExtensionMethod:
      // The first argument is ALWAYS the target instance.
      final actualPositionalArgs = [target, ...positionalArguments];
  
      Logger.debug(
          "[BoundExtensionMethodCallable] Calling extension method '${extensionMethod.declaration.name.lexeme}' bound to ${target?.runtimeType}");
  
      // Call the original extension method with the adjusted arguments.
      // It will handle ReturnException, etc.
      return extensionMethod.call(
          visitor, actualPositionalArgs, namedArguments, typeArguments);
    }
  }
  