computeCompoundValue method

Object? computeCompoundValue(
  1. Object? currentValue,
  2. Object? rhsValue,
  3. TokenType operatorType
)

Implementation

Object? computeCompoundValue(
    Object? currentValue, Object? rhsValue, TokenType operatorType) {
  // Unwrap BridgedInstance if necessary
  final bridgedInstance = toBridgedInstance(currentValue);
  final left =
      bridgedInstance.$2 ? bridgedInstance.$1!.nativeObject : currentValue;
  final right = rhsValue;

  if (operatorType == TokenType.PLUS_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      return left + right;
    } else if (left is String && right != null) {
      return left + stringify(right);
    } else if (left is List && right is List) {
      // For List += List, create a new list with both elements
      // This is how Dart's List + operator works
      return [...left, ...right];
    }
    // Fall through to extension check if standard types don't match
  } else if (operatorType == TokenType.MINUS_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      return left - right;
    }
    // Fall through
  } else if (operatorType == TokenType.STAR_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      return left * right;
    }
    // Fall through
  } else if (operatorType == TokenType.SLASH_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      if (right == 0) throw RuntimeD4rtException("Division by zero in '/='.");
      return left.toDouble() / right.toDouble();
    }
    // Fall through
  } else if (operatorType == TokenType.TILDE_SLASH_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      if (rhsValue == 0) {
        throw RuntimeD4rtException("Integer division by zero in '~/='.");
      }
      return left ~/ right;
    }
    // Fall through
  } else if (operatorType == TokenType.PERCENT_EQ) {
    // Use unwrapped left/right for calculation
    if (left is num && right is num) {
      if (right == 0) throw RuntimeD4rtException("Modulo by zero in '%='.");
      return left % right;
    }
    // Fall through
  } else if (operatorType == TokenType.QUESTION_QUESTION_EQ) {
    // Note: Uses original currentValue, not unwrapped 'left'
    if (currentValue == null) {
      return rhsValue; // If left is null, assign right
    } else {
      return currentValue; // If left is not null, keep left
    }
  } else if (operatorType == TokenType.AMPERSAND_EQ) {
    // Bitwise AND assignment (&=)
    if (left is int && right is int) {
      return left & right;
    } else if (left is BigInt && right is BigInt) {
      return left & right;
    }
    // Fall through to extension search
  } else if (operatorType == TokenType.BAR_EQ) {
    // Bitwise OR assignment (|=)
    if (left is int && right is int) {
      return left | right;
    } else if (left is BigInt && right is BigInt) {
      return left | right;
    }
    // Fall through to extension search
  } else if (operatorType == TokenType.CARET_EQ) {
    // Bitwise XOR assignment (^=)
    if (left is int && right is int) {
      return left ^ right;
    } else if (left is BigInt && right is BigInt) {
      return left ^ right;
    }
    // Fall through to extension search
  } else if (operatorType == TokenType.GT_GT_EQ) {
    // Right shift assignment (>>=)
    if (left is int && right is int) {
      return left >> right;
    } else if (left is BigInt && right is int) {
      return left >> right;
    }
    // Fall through to extension search
  } else if (operatorType == TokenType.LT_LT_EQ) {
    // Left shift assignment (<<=)
    if (left is int && right is int) {
      return left << right;
    } else if (left is BigInt && right is int) {
      return left << right;
    }
    // Fall through to extension search
  } else if (operatorType == TokenType.GT_GT_GT_EQ) {
    // Unsigned right shift assignment (>>>=)
    if (left is int && right is int) {
      return left >>> right;
    }
    // Note: BigInt doesn't support >>> operator
    // Fall through to extension search
  }

  Logger.debug(
      "[CompoundAssign] Standard op failed for $operatorType. Trying extension operator.");
  final String? operatorName = _mapCompoundToOperatorName(operatorType);

  if (operatorName != null) {
    try {
      final extensionOperator =
          environment.findExtensionMember(currentValue, operatorName);

      if (extensionOperator is ExtensionMemberCallable &&
          extensionOperator.isOperator) {
        Logger.debug(
            "[CompoundAssign] Found extension operator '$operatorName' for type ${currentValue?.runtimeType}. Calling...");
        // Call the extension operator method
        // Args: receiver (currentValue), right-hand-side (rhsValue)
        final extensionPositionalArgs = [currentValue, rhsValue];
        try {
          return extensionOperator.call(this, extensionPositionalArgs, {});
        } on ReturnException catch (e) {
          return e.value; // Should not happen for operators, but handle
        } catch (e) {
          throw RuntimeD4rtException(
              "Error executing extension operator '$operatorName' for compound assignment: $e");
        }
      }
      Logger.debug(
          "[CompoundAssign] No suitable extension operator '$operatorName' found for type ${currentValue?.runtimeType}.");
    } on RuntimeD4rtException catch (findError) {
      Logger.debug(
          "[CompoundAssign] No extension member '$operatorName' found for type ${currentValue?.runtimeType}. Error: ${findError.message}");
      // Fall through to the final unimplemented error
    }
  }

  throw UnimplementedD4rtException(
      'Compound assignment operator $operatorType not handled for types ${currentValue?.runtimeType} and ${rhsValue?.runtimeType}');
}