safeEval method

Future<InstanceRef> safeEval(
  1. String expression, {
  2. required Disposable? isAlive,
  3. Map<String, String>? scope,
})

An eval that throws when a Sentinel/error occurs or if isAlive was disposed while the request was pending.

If isAlive was disposed while the request was pending, will throw a CancelledException.

Implementation

Future<InstanceRef> safeEval(
  String expression, {
  required Disposable? isAlive,
  Map<String, String>? scope,
}) async {
  Object? result;

  try {
    if (disposed) {
      throw StateError(
        'Called `safeEval` on a disposed `EvalOnDartLibrary` instance',
      );
    }

    result = await addRequest(isAlive, () async {
      final libraryRef = await _waitForLibraryRef();

      return await service.evaluate(
        isolateRef!.id!,
        libraryRef.id!,
        expression,
        scope: scope,
        disableBreakpoints: disableBreakpoints,
      );
    });

    if (result is! InstanceRef) {
      if (result is ErrorRef) {
        throw EvalErrorException(
          expression: expression,
          scope: scope,
          errorRef: result,
        );
      }
      if (result is Sentinel) {
        throw EvalSentinelException(
          expression: expression,
          scope: scope,
          sentinel: result,
        );
      }
      throw UnknownEvalException(
        expression: expression,
        scope: scope,
        exception: result,
      );
    }
  } catch (err, stack) {
    /// Throwing when the request is cancelled instead of returning `null`
    /// allows easily chaining eval calls, without having to check "disposed"
    /// between each request.
    /// It also removes the need for using `!` once the devtool is migrated to NNBD
    if (isAlive?.disposed ?? true) {
      // throw before _handleError as we don't want to log cancellations.
      core.Error.throwWithStackTrace(CancelledException(), stack);
    }

    _handleError(err, stack);
    rethrow;
  }

  return result;
}