Expression evaluator architecture

Important

In Visual Studio 2015, this way of implementing expression evaluators is deprecated. For information about implementing CLR expression evaluators, see CLR expression evaluators and Managed expression evaluator sample.

Integrating a proprietary language into the Visual Studio debug package means you must set up the required expression evaluator (EE) interfaces and call the common language run-time symbol provider (SP) and binder interfaces. The SP and binder objects, together with the current execution address, are the context in which expressions are evaluated. The information that these interfaces produce and consume represents the key concepts in the architecture of an EE.

Parse the Expression

When you are debugging a program, expressions are evaluated for a number of reasons but always when the program being debugged has been stopped at a breakpoint (either a breakpoint placed by the user or one caused by an exception). It is at this moment when Visual Studio obtains a stack frame, as represented by the IDebugStackFrame2 interface, from the debug engine (DE). Visual Studio then calls GetExpressionContext to get the IDebugExpressionContext2 interface. This interface represents a context in which expressions can be evaluated; ParseText is the entry point to the evaluation process. Up until this point, all interfaces are implemented by the DE.

When IDebugExpressionContext2::ParseText is called, the DE instantiates the EE associated with the language of the source file where the breakpoint occurred (the DE also instantiates the SH at this point). The EE is represented by the IDebugExpressionEvaluator interface. The DE then calls Parse to convert the expression (in text form) to a parsed expression, ready for evaluation. This parsed expression is represented by the IDebugParsedExpression interface. The expression is typically parsed and not evaluated at this point.

The DE creates an object that implements the IDebugExpression2 interface, puts the IDebugParsedExpression object into the IDebugExpression2 object, and returns the IDebugExpression2 object from IDebugExpressionContext2::ParseText.

Evaluate the expression

Visual Studio calls either EvaluateSync or EvaluateAsync to evaluate the parsed expression. Both of these methods call EvaluateSync (IDebugExpression2::EvaluateSync calls the method immediately, while IDebugExpression2::EvaluateAsync calls the method through a background thread) to evaluate the parsed expression and return an IDebugProperty2 interface that represents the value and type of the parsed expression. IDebugParsedExpression::EvaluateSync uses the supplied SH, address, and binder to convert the parsed expression into an actual value, represented by the IDebugProperty2 interface.

For example

After a breakpoint is hit in a running program, the user chooses to view a variable in the QuickWatch dialog box. This dialog box shows the variable's name, its value, and its type. The user can typically change the value.

When the QuickWatch dialog box is shown, the name of the variable being examined is sent as text to ParseText. This returns an IDebugExpression2 object representing the parsed expression, in this case, the variable. EvaluateSync is then called to produce an IDebugProperty2 object that represents the variable's value and type, as well as its name. It is this information that is displayed.

If the user changes the variable's value, SetValueAsString is called with the new value, which changes the value of the variable in memory so it will be used when the program resumes running.

See Displaying locals for more details on this process of displaying the values of variables. See Changing the value of a local for more details on how a variable's value is changed.

In this section

Evaluation context Provides the arguments that are passed when the DE calls the EE.

Key expression evaluator interfaces Describes the crucial interfaces needed when writing an EE, along with the evaluation context.