blob: d514d605f3d872f829a8e1f4a296c1fb9ee08b13 [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.
part of dds;
/// 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 {
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(null) != null) {
params['scope'] = parameters['scope'].asMap;
}
return await dds._vmServiceClient.sendRequest(
'_buildExpressionEvaluationScope',
params,
);
}
Future<String> _compileExpression(String isolateId, String expression,
Map<String, dynamic> buildScopeResponseResult) async {
_DartDevelopmentServiceClient externalClient =
dds.clientManager.findFirstClientThatHandlesService(
'compileExpression',
);
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;
}
// TODO(bkonyi): handle service disappeared case?
try {
if (externalClient != null) {
return (await externalClient.sendRequest(
'compileExpression',
compileParams,
))['kernelBytes'];
} else {
// Fallback to compiling using the kernel service.
return (await dds._vmServiceClient.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(null) != null) {
params['scope'] = parameters['scope'].asMap;
}
return await dds._vmServiceClient.sendRequest(
'_evaluateCompiledExpression',
params,
);
}
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 _DartDevelopmentService dds;
}