blob: 5e2f48499d5e8446fe1fd5c85ca4e14d58f4fb34 [file] [log] [blame] [edit]
// Copyright (c) 2023, 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 'package:dap/dap.dart';
import 'package:vm_service/vm_service.dart';
/// A wrapper around variables for use in `variablesRequest` that can hold
/// additional data, such as a formatting information supplied in an evaluation
/// request.
class VariableData {
final Object data;
final VariableFormat? format;
VariableData(this.data, this.format);
}
/// Data used to lazily evaluate a getter in a Variables request.
class VariableGetter {
final Instance instance;
final String getterName;
final String? parentEvaluateName;
final bool allowCallingToString;
VariableGetter({
required this.instance,
required this.getterName,
required this.parentEvaluateName,
required this.allowCallingToString,
});
}
/// A wrapper around variables for use in `variablesRequest` that can hold
/// additional data, such as a formatting information supplied in an evaluation
/// request.
class FrameScopeData {
final Frame frame;
final FrameScopeDataKind kind;
FrameScopeData(this.frame, this.kind);
}
enum FrameScopeDataKind {
locals,
globals,
}
/// A wrapper around a variable for use in `variablesRequest` that holds
/// an instance sent for inspection.
class InspectData {
final InstanceRef? instance;
InspectData(this.instance);
}
/// A wrapper around an Instance ID that will result in a variable with a single
/// field `value` that can be used by DAP-over-DDS clients wanting to use
/// variables requests for variable display.
class WrappedInstanceVariable {
final String instanceId;
WrappedInstanceVariable(this.instanceId);
}
/// Formatting preferences for a variable.
class VariableFormat {
/// Whether to supress quotes around [String]s.
final bool noQuotes;
/// Whether to render integers as hex.
final bool hex;
/// Whether to force rendering integers as decimal (base 10).
final bool decimal;
const VariableFormat({
this.noQuotes = false,
this.hex = false,
this.decimal = false,
});
factory VariableFormat.from(
VariableFormat base, {
bool? noQuotes,
bool? hex,
bool? decimal,
}) {
return VariableFormat(
noQuotes: noQuotes ?? base.noQuotes,
hex: hex ?? base.hex,
decimal: decimal ?? base.decimal,
);
}
const VariableFormat.noQuotes() : this(noQuotes: true);
const VariableFormat.hex() : this(hex: true);
String formatInt(int? value) {
return value != null && hex
? '0x${value.toRadixString(16)}'
: value.toString();
}
String formatString(String value) {
return noQuotes ? value : '"$value"';
}
String format(Object? value) {
return switch (value) {
int() => formatInt(value),
String() => formatString(value),
_ => value.toString(),
};
}
/// Converts a DAP ValueFormat into our own formatting class used by our
/// debug adapters.
///
/// Returns `null` if the desired format does not require special handling
/// (or is something we don't support).
static VariableFormat? fromDapValueFormat(ValueFormat? format) {
return (format?.hex ?? false) ? VariableFormat.hex() : null;
}
}
/// An evaluation expression and optional formatting preferences that were
/// supplied as a trailing format specifier in expression evaluations.
class EvaluationExpression {
final String expression;
final VariableFormat? format;
EvaluationExpression._(this.expression, {this.format});
/// A regular expression that extracts format specifiers from an evaluation
/// expression.
static final _expressionWithFormatSpecifierRegex =
RegExp(r'(.*?)(?:,([\w,]+))$');
/// Parse an expression that may end with a format specifier to dictate the
/// format a value should be presented in.
factory EvaluationExpression.parse(String expression) {
final match = _expressionWithFormatSpecifierRegex.firstMatch(expression);
expression = match?.group(1) ?? expression;
final formatSpecifiers = match?.group(2)?.split(',').toSet() ?? const {};
final format = formatSpecifiers.isEmpty
? null
: VariableFormat(
noQuotes: formatSpecifiers.contains('nq'),
hex: formatSpecifiers.contains('h'),
decimal: formatSpecifiers.contains('d'),
);
return EvaluationExpression._(expression, format: format);
}
}