blob: 76026b66a873cbc7d31c11478a76973dd2da85ff [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
import 'client.dart';
import 'dds_impl.dart';
import 'rpc_error_codes.dart';
/// A helper class which handles `evaluate` and `evaluateInFrame` calls by
/// potentially forwarding compilation requests to an external compilation
/// service like Flutter Tools.
class ExpressionEvaluator {
ExpressionEvaluator(this.dds);
Future<Map<String, dynamic>> execute(json_rpc.Parameters parameters) async {
DartDevelopmentServiceClient? externalClient =
dds.clientManager.findFirstClientThatHandlesService(
'compileExpression',
);
// If no compilation service is registered, just forward to the VM service.
if (externalClient == null) {
return (await dds.vmServiceClient.sendRequest(
parameters.method,
parameters.value,
)) as Map<String, dynamic>;
}
final isolateId = parameters['isolateId'].asString;
final expression = parameters['expression'].asString;
Map<String, dynamic> buildScopeResponse;
try {
buildScopeResponse = await _buildScope(parameters);
} on json_rpc.RpcException catch (e) {
throw RpcErrorCodes.buildRpcException(
RpcErrorCodes.kExpressionCompilationError,
data: e.data,
);
}
String kernelBase64;
try {
kernelBase64 =
await _compileExpression(isolateId, expression, buildScopeResponse);
} on json_rpc.RpcException catch (e) {
throw RpcErrorCodes.buildRpcException(
RpcErrorCodes.kExpressionCompilationError,
data: e.data,
);
}
return await _evaluateCompiledExpression(
parameters, isolateId, kernelBase64);
}
Future<Map<String, dynamic>> _buildScope(
json_rpc.Parameters parameters) async {
final params = _setupParams(parameters);
params['isolateId'] = parameters['isolateId'].asString;
if (parameters['scope'].asMapOr({}).isNotEmpty) {
params['scope'] = parameters['scope'].asMap;
}
return (await dds.vmServiceClient.sendRequest(
'_buildExpressionEvaluationScope',
params,
)) as Map<String, dynamic>;
}
Future<String> _compileExpression(String isolateId, String expression,
Map<String, dynamic> buildScopeResponseResult) async {
DartDevelopmentServiceClient? externalClient =
dds.clientManager.findFirstClientThatHandlesService(
'compileExpression',
);
if (externalClient == null) {
throw RpcErrorCodes.buildRpcException(
RpcErrorCodes.kExpressionCompilationError,
data: 'compileExpression service disappeared.');
}
final compileParams = <String, dynamic>{
'isolateId': isolateId,
'expression': expression,
'definitions': buildScopeResponseResult['param_names'],
'typeDefinitions': buildScopeResponseResult['type_params_names'],
'libraryUri': buildScopeResponseResult['libraryUri'],
'isStatic': buildScopeResponseResult['isStatic'],
};
final klass = buildScopeResponseResult['klass'];
if (klass != null) {
compileParams['klass'] = klass;
}
try {
return (await externalClient.sendRequest(
'compileExpression',
compileParams,
))['kernelBytes'];
} on json_rpc.RpcException catch (e) {
throw RpcErrorCodes.buildRpcException(
RpcErrorCodes.kExpressionCompilationError,
data: e.data,
);
}
}
Future<Map<String, dynamic>> _evaluateCompiledExpression(
json_rpc.Parameters parameters,
String isolateId,
String kernelBase64,
) async {
final params = _setupParams(parameters);
params['isolateId'] = isolateId;
params['kernelBytes'] = kernelBase64;
params['disableBreakpoints'] =
parameters['disableBreakpoints'].asBoolOr(false);
if (parameters['scope'].asMapOr({}).isNotEmpty) {
params['scope'] = parameters['scope'].asMap;
}
return (await dds.vmServiceClient.sendRequest(
'_evaluateCompiledExpression',
params,
)) as Map<String, dynamic>;
}
Map<String, dynamic> _setupParams(json_rpc.Parameters parameters) {
if (parameters.method == 'evaluateInFrame') {
return <String, dynamic>{
'frameIndex': parameters['frameIndex'].asInt,
};
} else {
assert(parameters.method == 'evaluate');
return <String, dynamic>{
'targetId': parameters['targetId'].asString,
};
}
}
final DartDevelopmentServiceImpl dds;
}