1ac7ddfbfSEd Maste //===-- CommandObjectExpression.cpp -----------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
104bb0738eSEd Maste #include "llvm/ADT/STLExtras.h"
114bb0738eSEd Maste #include "llvm/ADT/StringRef.h"
124bb0738eSEd Maste 
134bb0738eSEd Maste #include "CommandObjectExpression.h"
14435933ddSDimitry Andric #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
15435933ddSDimitry Andric #include "lldb/Core/Debugger.h"
16ac7ddfbfSEd Maste #include "lldb/Core/Value.h"
17ac7ddfbfSEd Maste #include "lldb/Core/ValueObjectVariable.h"
1835617911SEd Maste #include "lldb/DataFormatters/ValueObjectPrinter.h"
19ac7ddfbfSEd Maste #include "lldb/Expression/DWARFExpression.h"
209f2f44ceSEd Maste #include "lldb/Expression/REPL.h"
21435933ddSDimitry Andric #include "lldb/Expression/UserExpression.h"
22ac7ddfbfSEd Maste #include "lldb/Host/Host.h"
23f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h"
24ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
25ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
264ba319b5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
27ac7ddfbfSEd Maste #include "lldb/Symbol/ObjectFile.h"
28ac7ddfbfSEd Maste #include "lldb/Symbol/Variable.h"
29435933ddSDimitry Andric #include "lldb/Target/Language.h"
30ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
31ac7ddfbfSEd Maste #include "lldb/Target/StackFrame.h"
32ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
33ac7ddfbfSEd Maste #include "lldb/Target/Thread.h"
34ac7ddfbfSEd Maste 
35ac7ddfbfSEd Maste using namespace lldb;
36ac7ddfbfSEd Maste using namespace lldb_private;
37ac7ddfbfSEd Maste 
CommandOptions()38435933ddSDimitry Andric CommandObjectExpression::CommandOptions::CommandOptions() : OptionGroup() {}
39ac7ddfbfSEd Maste 
404bb0738eSEd Maste CommandObjectExpression::CommandOptions::~CommandOptions() = default;
41ac7ddfbfSEd Maste 
42*b5893f02SDimitry Andric static constexpr OptionEnumValueElement g_description_verbosity_type[] = {
43435933ddSDimitry Andric     {eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact",
44435933ddSDimitry Andric      "Only show the description string"},
45435933ddSDimitry Andric     {eLanguageRuntimeDescriptionDisplayVerbosityFull, "full",
46*b5893f02SDimitry Andric      "Show the full output, including persistent variable's name and type"} };
4735617911SEd Maste 
DescriptionVerbosityTypes()48*b5893f02SDimitry Andric static constexpr OptionEnumValues DescriptionVerbosityTypes() {
49*b5893f02SDimitry Andric   return OptionEnumValues(g_description_verbosity_type);
50*b5893f02SDimitry Andric }
51*b5893f02SDimitry Andric 
52*b5893f02SDimitry Andric static constexpr OptionDefinition g_expression_options[] = {
53435933ddSDimitry Andric     // clang-format off
54*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",           'a', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Should we run all threads if the execution doesn't complete on one thread."},
55*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints",    'i', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Ignore breakpoint hits while running expressions"},
56*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",               't', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeUnsignedInteger,      "Timeout value (in microseconds) for running the expression."},
57*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",       'u', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Clean up program state if the expression causes a crash, or raises a signal.  "
58435933ddSDimitry Andric                                                                                                                                                                                   "Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
59*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug",                 'g', OptionParser::eNoArgument,       nullptr, {},                          0, eArgTypeNone,                 "When specified, debug the JIT code by setting a breakpoint on the first instruction "
60435933ddSDimitry Andric                                                                                                                                                                                   "and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
61*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language",              'l', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeLanguage,             "Specifies the Language to use when parsing the expression.  If not set the target.language "
62435933ddSDimitry Andric                                                                                                                                                                                   "setting is used." },
63*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "apply-fixits",          'X', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeLanguage,             "If true, simple fix-it hints will be automatically applied to the expression." },
64*b5893f02SDimitry Andric   {LLDB_OPT_SET_1,                  false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, DescriptionVerbosityTypes(), 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."},
65*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "top-level",             'p', OptionParser::eNoArgument,       nullptr, {},                          0, eArgTypeNone,                 "Interpret the expression as a complete translation unit, without injecting it into the local "
66435933ddSDimitry Andric                                                                                                                                                                                   "context.  Allows declaration of persistent, top-level entities without a $ prefix."},
67*b5893f02SDimitry Andric   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "allow-jit",             'j', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Controls whether the expression can fall back to being JITted if it's not supported by "
68435933ddSDimitry Andric                                                                                                                                                                                   "the interpreter (defaults to true)."}
69435933ddSDimitry Andric     // clang-format on
70ac7ddfbfSEd Maste };
71ac7ddfbfSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)725517e702SDimitry Andric Status CommandObjectExpression::CommandOptions::SetOptionValue(
73435933ddSDimitry Andric     uint32_t option_idx, llvm::StringRef option_arg,
74435933ddSDimitry Andric     ExecutionContext *execution_context) {
755517e702SDimitry Andric   Status error;
76ac7ddfbfSEd Maste 
77435933ddSDimitry Andric   const int short_option = GetDefinitions()[option_idx].short_option;
78ac7ddfbfSEd Maste 
79435933ddSDimitry Andric   switch (short_option) {
809f2f44ceSEd Maste   case 'l':
819f2f44ceSEd Maste     language = Language::GetLanguageTypeFromString(option_arg);
829f2f44ceSEd Maste     if (language == eLanguageTypeUnknown)
83435933ddSDimitry Andric       error.SetErrorStringWithFormat(
84435933ddSDimitry Andric           "unknown language type: '%s' for expression",
85435933ddSDimitry Andric           option_arg.str().c_str());
869f2f44ceSEd Maste     break;
87ac7ddfbfSEd Maste 
88435933ddSDimitry Andric   case 'a': {
89ac7ddfbfSEd Maste     bool success;
90ac7ddfbfSEd Maste     bool result;
914ba319b5SDimitry Andric     result = OptionArgParser::ToBoolean(option_arg, true, &success);
92ac7ddfbfSEd Maste     if (!success)
93435933ddSDimitry Andric       error.SetErrorStringWithFormat(
94435933ddSDimitry Andric           "invalid all-threads value setting: \"%s\"",
95435933ddSDimitry Andric           option_arg.str().c_str());
96ac7ddfbfSEd Maste     else
97ac7ddfbfSEd Maste       try_all_threads = result;
98435933ddSDimitry Andric   } break;
99ac7ddfbfSEd Maste 
100435933ddSDimitry Andric   case 'i': {
101ac7ddfbfSEd Maste     bool success;
1024ba319b5SDimitry Andric     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
103ac7ddfbfSEd Maste     if (success)
104ac7ddfbfSEd Maste       ignore_breakpoints = tmp_value;
105ac7ddfbfSEd Maste     else
106435933ddSDimitry Andric       error.SetErrorStringWithFormat(
107435933ddSDimitry Andric           "could not convert \"%s\" to a boolean value.",
108435933ddSDimitry Andric           option_arg.str().c_str());
109ac7ddfbfSEd Maste     break;
110ac7ddfbfSEd Maste   }
1114bb0738eSEd Maste 
112435933ddSDimitry Andric   case 'j': {
1134bb0738eSEd Maste     bool success;
1144ba319b5SDimitry Andric     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
1154bb0738eSEd Maste     if (success)
1164bb0738eSEd Maste       allow_jit = tmp_value;
1174bb0738eSEd Maste     else
118435933ddSDimitry Andric       error.SetErrorStringWithFormat(
119435933ddSDimitry Andric           "could not convert \"%s\" to a boolean value.",
120435933ddSDimitry Andric           option_arg.str().c_str());
1214bb0738eSEd Maste     break;
1224bb0738eSEd Maste   }
1234bb0738eSEd Maste 
124ac7ddfbfSEd Maste   case 't':
125435933ddSDimitry Andric     if (option_arg.getAsInteger(0, timeout)) {
126435933ddSDimitry Andric       timeout = 0;
127435933ddSDimitry Andric       error.SetErrorStringWithFormat("invalid timeout setting \"%s\"",
128435933ddSDimitry Andric                                      option_arg.str().c_str());
129ac7ddfbfSEd Maste     }
130ac7ddfbfSEd Maste     break;
131ac7ddfbfSEd Maste 
132435933ddSDimitry Andric   case 'u': {
133ac7ddfbfSEd Maste     bool success;
1344ba319b5SDimitry Andric     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
135ac7ddfbfSEd Maste     if (success)
136ac7ddfbfSEd Maste       unwind_on_error = tmp_value;
137ac7ddfbfSEd Maste     else
138435933ddSDimitry Andric       error.SetErrorStringWithFormat(
139435933ddSDimitry Andric           "could not convert \"%s\" to a boolean value.",
140435933ddSDimitry Andric           option_arg.str().c_str());
141ac7ddfbfSEd Maste     break;
142ac7ddfbfSEd Maste   }
14335617911SEd Maste 
14435617911SEd Maste   case 'v':
145435933ddSDimitry Andric     if (option_arg.empty()) {
14635617911SEd Maste       m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
14735617911SEd Maste       break;
14835617911SEd Maste     }
1494ba319b5SDimitry Andric     m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity)
1504ba319b5SDimitry Andric         OptionArgParser::ToOptionEnum(
151435933ddSDimitry Andric             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
15235617911SEd Maste     if (!error.Success())
153435933ddSDimitry Andric       error.SetErrorStringWithFormat(
154435933ddSDimitry Andric           "unrecognized value for description-verbosity '%s'",
155435933ddSDimitry Andric           option_arg.str().c_str());
15635617911SEd Maste     break;
15735617911SEd Maste 
15835617911SEd Maste   case 'g':
15935617911SEd Maste     debug = true;
16035617911SEd Maste     unwind_on_error = false;
16135617911SEd Maste     ignore_breakpoints = false;
16235617911SEd Maste     break;
16335617911SEd Maste 
1644bb0738eSEd Maste   case 'p':
1654bb0738eSEd Maste     top_level = true;
1664bb0738eSEd Maste     break;
1674bb0738eSEd Maste 
168435933ddSDimitry Andric   case 'X': {
1694bb0738eSEd Maste     bool success;
1704ba319b5SDimitry Andric     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
1714bb0738eSEd Maste     if (success)
1724bb0738eSEd Maste       auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;
1734bb0738eSEd Maste     else
174435933ddSDimitry Andric       error.SetErrorStringWithFormat(
175435933ddSDimitry Andric           "could not convert \"%s\" to a boolean value.",
176435933ddSDimitry Andric           option_arg.str().c_str());
1774bb0738eSEd Maste     break;
1784bb0738eSEd Maste   }
1794bb0738eSEd Maste 
180ac7ddfbfSEd Maste   default:
181435933ddSDimitry Andric     error.SetErrorStringWithFormat("invalid short option character '%c'",
182435933ddSDimitry Andric                                    short_option);
183ac7ddfbfSEd Maste     break;
184ac7ddfbfSEd Maste   }
185ac7ddfbfSEd Maste 
186ac7ddfbfSEd Maste   return error;
187ac7ddfbfSEd Maste }
188ac7ddfbfSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)189435933ddSDimitry Andric void CommandObjectExpression::CommandOptions::OptionParsingStarting(
190435933ddSDimitry Andric     ExecutionContext *execution_context) {
191435933ddSDimitry Andric   auto process_sp =
192435933ddSDimitry Andric       execution_context ? execution_context->GetProcessSP() : ProcessSP();
193435933ddSDimitry Andric   if (process_sp) {
194435933ddSDimitry Andric     ignore_breakpoints = process_sp->GetIgnoreBreakpointsInExpressions();
195435933ddSDimitry Andric     unwind_on_error = process_sp->GetUnwindOnErrorInExpressions();
196435933ddSDimitry Andric   } else {
1970127ef0fSEd Maste     ignore_breakpoints = true;
198ac7ddfbfSEd Maste     unwind_on_error = true;
199ac7ddfbfSEd Maste   }
200ac7ddfbfSEd Maste 
201ac7ddfbfSEd Maste   show_summary = true;
202ac7ddfbfSEd Maste   try_all_threads = true;
203ac7ddfbfSEd Maste   timeout = 0;
20435617911SEd Maste   debug = false;
2059f2f44ceSEd Maste   language = eLanguageTypeUnknown;
20635617911SEd Maste   m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
2074bb0738eSEd Maste   auto_apply_fixits = eLazyBoolCalculate;
2084bb0738eSEd Maste   top_level = false;
2094bb0738eSEd Maste   allow_jit = true;
210ac7ddfbfSEd Maste }
211ac7ddfbfSEd Maste 
212435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition>
GetDefinitions()213435933ddSDimitry Andric CommandObjectExpression::CommandOptions::GetDefinitions() {
214435933ddSDimitry Andric   return llvm::makeArrayRef(g_expression_options);
215ac7ddfbfSEd Maste }
216ac7ddfbfSEd Maste 
CommandObjectExpression(CommandInterpreter & interpreter)217435933ddSDimitry Andric CommandObjectExpression::CommandObjectExpression(
218435933ddSDimitry Andric     CommandInterpreter &interpreter)
2194bb0738eSEd Maste     : CommandObjectRaw(
220435933ddSDimitry Andric           interpreter, "expression", "Evaluate an expression on the current "
221435933ddSDimitry Andric                                      "thread.  Displays any returned value "
222435933ddSDimitry Andric                                      "with LLDB's default formatting.",
223435933ddSDimitry Andric           "", eCommandProcessMustBePaused | eCommandTryTargetAPILock),
22412b93ac6SEd Maste       IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
225435933ddSDimitry Andric       m_option_group(), m_format_options(eFormatDefault),
226435933ddSDimitry Andric       m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
227435933ddSDimitry Andric                     true),
228435933ddSDimitry Andric       m_command_options(), m_expr_line_count(0), m_expr_lines() {
229ac7ddfbfSEd Maste   SetHelpLong(
230b91a7dfcSDimitry Andric       R"(
231acac075bSDimitry Andric Single and multi-line expressions:
232acac075bSDimitry Andric 
233acac075bSDimitry Andric )"
234acac075bSDimitry Andric       "    The expression provided on the command line must be a complete expression \
235acac075bSDimitry Andric with no newlines.  To evaluate a multi-line expression, \
236acac075bSDimitry Andric hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
237acac075bSDimitry Andric Hit return on an empty line to end the multi-line expression."
238acac075bSDimitry Andric 
239acac075bSDimitry Andric       R"(
240acac075bSDimitry Andric 
241b91a7dfcSDimitry Andric Timeouts:
242b91a7dfcSDimitry Andric 
243435933ddSDimitry Andric )"
244435933ddSDimitry Andric       "    If the expression can be evaluated statically (without running code) then it will be.  \
245b91a7dfcSDimitry Andric Otherwise, by default the expression will run on the current thread with a short timeout: \
246b91a7dfcSDimitry Andric currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted \
247b91a7dfcSDimitry Andric and resumed with all threads running.  You can use the -a option to disable retrying on all \
248435933ddSDimitry Andric threads.  You can use the -t option to set a shorter timeout."
249435933ddSDimitry Andric       R"(
250b91a7dfcSDimitry Andric 
251b91a7dfcSDimitry Andric User defined variables:
252b91a7dfcSDimitry Andric 
253435933ddSDimitry Andric )"
254435933ddSDimitry Andric       "    You can define your own variables for convenience or to be used in subsequent expressions.  \
255b91a7dfcSDimitry Andric You define them the same way you would define variables in C.  If the first character of \
256b91a7dfcSDimitry Andric your user defined variable is a $, then the variable's value will be available in future \
257435933ddSDimitry Andric expressions, otherwise it will just be available in the current expression."
258435933ddSDimitry Andric       R"(
259b91a7dfcSDimitry Andric 
260b91a7dfcSDimitry Andric Continuing evaluation after a breakpoint:
261b91a7dfcSDimitry Andric 
262435933ddSDimitry Andric )"
263435933ddSDimitry Andric       "    If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
264b91a7dfcSDimitry Andric you are done with your investigation, you can either remove the expression execution frames \
265b91a7dfcSDimitry Andric from the stack with \"thread return -x\" or if you are still interested in the expression result \
266b91a7dfcSDimitry Andric you can issue the \"continue\" command and the expression evaluation will complete and the \
267b91a7dfcSDimitry Andric expression result will be available using the \"thread.completed-expression\" key in the thread \
268435933ddSDimitry Andric format."
269acac075bSDimitry Andric 
270435933ddSDimitry Andric       R"(
271b91a7dfcSDimitry Andric 
272b91a7dfcSDimitry Andric Examples:
273b91a7dfcSDimitry Andric 
274b91a7dfcSDimitry Andric     expr my_struct->a = my_array[3]
275b91a7dfcSDimitry Andric     expr -f bin -- (index * 8) + 5
276b91a7dfcSDimitry Andric     expr unsigned int $foo = 5
277435933ddSDimitry Andric     expr char c[] = \"foo\"; c[0])");
278ac7ddfbfSEd Maste 
279ac7ddfbfSEd Maste   CommandArgumentEntry arg;
280ac7ddfbfSEd Maste   CommandArgumentData expression_arg;
281ac7ddfbfSEd Maste 
282ac7ddfbfSEd Maste   // Define the first (and only) variant of this arg.
283ac7ddfbfSEd Maste   expression_arg.arg_type = eArgTypeExpression;
284ac7ddfbfSEd Maste   expression_arg.arg_repetition = eArgRepeatPlain;
285ac7ddfbfSEd Maste 
286435933ddSDimitry Andric   // There is only one variant this argument could be; put it into the argument
287435933ddSDimitry Andric   // entry.
288ac7ddfbfSEd Maste   arg.push_back(expression_arg);
289ac7ddfbfSEd Maste 
290ac7ddfbfSEd Maste   // Push the data for the first argument into the m_arguments vector.
291ac7ddfbfSEd Maste   m_arguments.push_back(arg);
292ac7ddfbfSEd Maste 
293ac7ddfbfSEd Maste   // Add the "--format" and "--gdb-format"
294435933ddSDimitry Andric   m_option_group.Append(&m_format_options,
295435933ddSDimitry Andric                         OptionGroupFormat::OPTION_GROUP_FORMAT |
296435933ddSDimitry Andric                             OptionGroupFormat::OPTION_GROUP_GDB_FMT,
297435933ddSDimitry Andric                         LLDB_OPT_SET_1);
298ac7ddfbfSEd Maste   m_option_group.Append(&m_command_options);
299435933ddSDimitry Andric   m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
300435933ddSDimitry Andric                         LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
3019f2f44ceSEd Maste   m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
302ac7ddfbfSEd Maste   m_option_group.Finalize();
303ac7ddfbfSEd Maste }
304ac7ddfbfSEd Maste 
3054bb0738eSEd Maste CommandObjectExpression::~CommandObjectExpression() = default;
306ac7ddfbfSEd Maste 
GetOptions()307435933ddSDimitry Andric Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
308ac7ddfbfSEd Maste 
HandleCompletion(CompletionRequest & request)309*b5893f02SDimitry Andric int CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
310*b5893f02SDimitry Andric   EvaluateExpressionOptions options;
311*b5893f02SDimitry Andric   options.SetCoerceToId(m_varobj_options.use_objc);
312*b5893f02SDimitry Andric   options.SetLanguage(m_command_options.language);
313*b5893f02SDimitry Andric   options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
314*b5893f02SDimitry Andric   options.SetAutoApplyFixIts(false);
315*b5893f02SDimitry Andric   options.SetGenerateDebugInfo(false);
316*b5893f02SDimitry Andric 
317*b5893f02SDimitry Andric   // We need a valid execution context with a frame pointer for this
318*b5893f02SDimitry Andric   // completion, so if we don't have one we should try to make a valid
319*b5893f02SDimitry Andric   // execution context.
320*b5893f02SDimitry Andric   if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
321*b5893f02SDimitry Andric     m_interpreter.UpdateExecutionContext(nullptr);
322*b5893f02SDimitry Andric 
323*b5893f02SDimitry Andric   // This didn't work, so let's get out before we start doing things that
324*b5893f02SDimitry Andric   // expect a valid frame pointer.
325*b5893f02SDimitry Andric   if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
326*b5893f02SDimitry Andric     return 0;
327*b5893f02SDimitry Andric 
328*b5893f02SDimitry Andric   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
329*b5893f02SDimitry Andric 
330*b5893f02SDimitry Andric   Target *target = exe_ctx.GetTargetPtr();
331*b5893f02SDimitry Andric 
332*b5893f02SDimitry Andric   if (!target)
333*b5893f02SDimitry Andric     target = GetDummyTarget();
334*b5893f02SDimitry Andric 
335*b5893f02SDimitry Andric   if (!target)
336*b5893f02SDimitry Andric     return 0;
337*b5893f02SDimitry Andric 
338*b5893f02SDimitry Andric   unsigned cursor_pos = request.GetRawCursorPos();
339*b5893f02SDimitry Andric   llvm::StringRef code = request.GetRawLine();
340*b5893f02SDimitry Andric 
341*b5893f02SDimitry Andric   const std::size_t original_code_size = code.size();
342*b5893f02SDimitry Andric 
343*b5893f02SDimitry Andric   // Remove the first token which is 'expr' or some alias/abbreviation of that.
344*b5893f02SDimitry Andric   code = llvm::getToken(code).second.ltrim();
345*b5893f02SDimitry Andric   OptionsWithRaw args(code);
346*b5893f02SDimitry Andric   code = args.GetRawPart();
347*b5893f02SDimitry Andric 
348*b5893f02SDimitry Andric   // The position where the expression starts in the command line.
349*b5893f02SDimitry Andric   assert(original_code_size >= code.size());
350*b5893f02SDimitry Andric   std::size_t raw_start = original_code_size - code.size();
351*b5893f02SDimitry Andric 
352*b5893f02SDimitry Andric   // Check if the cursor is actually in the expression string, and if not, we
353*b5893f02SDimitry Andric   // exit.
354*b5893f02SDimitry Andric   // FIXME: We should complete the options here.
355*b5893f02SDimitry Andric   if (cursor_pos < raw_start)
356*b5893f02SDimitry Andric     return 0;
357*b5893f02SDimitry Andric 
358*b5893f02SDimitry Andric   // Make the cursor_pos again relative to the start of the code string.
359*b5893f02SDimitry Andric   assert(cursor_pos >= raw_start);
360*b5893f02SDimitry Andric   cursor_pos -= raw_start;
361*b5893f02SDimitry Andric 
362*b5893f02SDimitry Andric   auto language = exe_ctx.GetFrameRef().GetLanguage();
363*b5893f02SDimitry Andric 
364*b5893f02SDimitry Andric   Status error;
365*b5893f02SDimitry Andric   lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage(
366*b5893f02SDimitry Andric       code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
367*b5893f02SDimitry Andric       options, error));
368*b5893f02SDimitry Andric   if (error.Fail())
369*b5893f02SDimitry Andric     return 0;
370*b5893f02SDimitry Andric 
371*b5893f02SDimitry Andric   expr->Complete(exe_ctx, request, cursor_pos);
372*b5893f02SDimitry Andric   return request.GetNumberOfMatches();
373*b5893f02SDimitry Andric }
374*b5893f02SDimitry Andric 
3755517e702SDimitry Andric static lldb_private::Status
CanBeUsedForElementCountPrinting(ValueObject & valobj)376435933ddSDimitry Andric CanBeUsedForElementCountPrinting(ValueObject &valobj) {
3774bb0738eSEd Maste   CompilerType type(valobj.GetCompilerType());
3784bb0738eSEd Maste   CompilerType pointee;
3794bb0738eSEd Maste   if (!type.IsPointerType(&pointee))
3805517e702SDimitry Andric     return Status("as it does not refer to a pointer");
3814bb0738eSEd Maste   if (pointee.IsVoidType())
3825517e702SDimitry Andric     return Status("as it refers to a pointer to void");
3835517e702SDimitry Andric   return Status();
3844bb0738eSEd Maste }
3854bb0738eSEd Maste 
EvaluateExpression(llvm::StringRef expr,Stream * output_stream,Stream * error_stream,CommandReturnObject * result)3864ba319b5SDimitry Andric bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
387ac7ddfbfSEd Maste                                                  Stream *output_stream,
388ac7ddfbfSEd Maste                                                  Stream *error_stream,
389435933ddSDimitry Andric                                                  CommandReturnObject *result) {
3904ba319b5SDimitry Andric   // Don't use m_exe_ctx as this might be called asynchronously after the
3914ba319b5SDimitry Andric   // command object DoExecute has finished when doing multi-line expression
3924ba319b5SDimitry Andric   // that use an input reader...
393ac7ddfbfSEd Maste   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
394ac7ddfbfSEd Maste 
395ac7ddfbfSEd Maste   Target *target = exe_ctx.GetTargetPtr();
396ac7ddfbfSEd Maste 
397ac7ddfbfSEd Maste   if (!target)
3987aa51b79SEd Maste     target = GetDummyTarget();
399ac7ddfbfSEd Maste 
400435933ddSDimitry Andric   if (target) {
401ac7ddfbfSEd Maste     lldb::ValueObjectSP result_valobj_sp;
402ac7ddfbfSEd Maste     bool keep_in_memory = true;
4039f2f44ceSEd Maste     StackFrame *frame = exe_ctx.GetFramePtr();
404ac7ddfbfSEd Maste 
405ac7ddfbfSEd Maste     EvaluateExpressionOptions options;
406b952cd58SEd Maste     options.SetCoerceToId(m_varobj_options.use_objc);
407b952cd58SEd Maste     options.SetUnwindOnError(m_command_options.unwind_on_error);
408b952cd58SEd Maste     options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
409b952cd58SEd Maste     options.SetKeepInMemory(keep_in_memory);
410b952cd58SEd Maste     options.SetUseDynamic(m_varobj_options.use_dynamic);
411b952cd58SEd Maste     options.SetTryAllThreads(m_command_options.try_all_threads);
412b952cd58SEd Maste     options.SetDebug(m_command_options.debug);
4139f2f44ceSEd Maste     options.SetLanguage(m_command_options.language);
414435933ddSDimitry Andric     options.SetExecutionPolicy(
415435933ddSDimitry Andric         m_command_options.allow_jit
416435933ddSDimitry Andric             ? EvaluateExpressionOptions::default_execution_policy
417435933ddSDimitry Andric             : lldb_private::eExecutionPolicyNever);
4184bb0738eSEd Maste 
4194bb0738eSEd Maste     bool auto_apply_fixits;
4204bb0738eSEd Maste     if (m_command_options.auto_apply_fixits == eLazyBoolCalculate)
4214bb0738eSEd Maste       auto_apply_fixits = target->GetEnableAutoApplyFixIts();
4224bb0738eSEd Maste     else
423*b5893f02SDimitry Andric       auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes;
4244bb0738eSEd Maste 
4254bb0738eSEd Maste     options.SetAutoApplyFixIts(auto_apply_fixits);
4264bb0738eSEd Maste 
4274bb0738eSEd Maste     if (m_command_options.top_level)
4284bb0738eSEd Maste       options.SetExecutionPolicy(eExecutionPolicyTopLevel);
42935617911SEd Maste 
4304ba319b5SDimitry Andric     // If there is any chance we are going to stop and want to see what went
4314ba319b5SDimitry Andric     // wrong with our expression, we should generate debug info
4320127ef0fSEd Maste     if (!m_command_options.ignore_breakpoints ||
4330127ef0fSEd Maste         !m_command_options.unwind_on_error)
4340127ef0fSEd Maste       options.SetGenerateDebugInfo(true);
4350127ef0fSEd Maste 
43635617911SEd Maste     if (m_command_options.timeout > 0)
437435933ddSDimitry Andric       options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
43812b93ac6SEd Maste     else
439435933ddSDimitry Andric       options.SetTimeout(llvm::None);
440ac7ddfbfSEd Maste 
441435933ddSDimitry Andric     ExpressionResults success = target->EvaluateExpression(
442435933ddSDimitry Andric         expr, frame, result_valobj_sp, options, &m_fixed_expression);
4434bb0738eSEd Maste 
444435933ddSDimitry Andric     // We only tell you about the FixIt if we applied it.  The compiler errors
445435933ddSDimitry Andric     // will suggest the FixIt if it parsed.
446435933ddSDimitry Andric     if (error_stream && !m_fixed_expression.empty() &&
447435933ddSDimitry Andric         target->GetEnableNotifyAboutFixIts()) {
4484bb0738eSEd Maste       if (success == eExpressionCompleted)
449435933ddSDimitry Andric         error_stream->Printf(
450435933ddSDimitry Andric             "  Fix-it applied, fixed expression was: \n    %s\n",
451435933ddSDimitry Andric             m_fixed_expression.c_str());
4524bb0738eSEd Maste     }
453ac7ddfbfSEd Maste 
454435933ddSDimitry Andric     if (result_valobj_sp) {
455ac7ddfbfSEd Maste       Format format = m_format_options.GetFormat();
456ac7ddfbfSEd Maste 
457435933ddSDimitry Andric       if (result_valobj_sp->GetError().Success()) {
458435933ddSDimitry Andric         if (format != eFormatVoid) {
459ac7ddfbfSEd Maste           if (format != eFormatDefault)
460ac7ddfbfSEd Maste             result_valobj_sp->SetFormat(format);
461ac7ddfbfSEd Maste 
462435933ddSDimitry Andric           if (m_varobj_options.elem_count > 0) {
4635517e702SDimitry Andric             Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
464435933ddSDimitry Andric             if (error.Fail()) {
465435933ddSDimitry Andric               result->AppendErrorWithFormat(
466435933ddSDimitry Andric                   "expression cannot be used with --element-count %s\n",
467435933ddSDimitry Andric                   error.AsCString(""));
4684bb0738eSEd Maste               result->SetStatus(eReturnStatusFailed);
4694bb0738eSEd Maste               return false;
4704bb0738eSEd Maste             }
4714bb0738eSEd Maste           }
4724bb0738eSEd Maste 
473435933ddSDimitry Andric           DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
474435933ddSDimitry Andric               m_command_options.m_verbosity, format));
475435933ddSDimitry Andric           options.SetVariableFormatDisplayLanguage(
476435933ddSDimitry Andric               result_valobj_sp->GetPreferredDisplayLanguage());
477ac7ddfbfSEd Maste 
47835617911SEd Maste           result_valobj_sp->Dump(*output_stream, options);
47935617911SEd Maste 
480ac7ddfbfSEd Maste           if (result)
481ac7ddfbfSEd Maste             result->SetStatus(eReturnStatusSuccessFinishResult);
482ac7ddfbfSEd Maste         }
483435933ddSDimitry Andric       } else {
484435933ddSDimitry Andric         if (result_valobj_sp->GetError().GetError() ==
485435933ddSDimitry Andric             UserExpression::kNoResult) {
486435933ddSDimitry Andric           if (format != eFormatVoid &&
487435933ddSDimitry Andric               m_interpreter.GetDebugger().GetNotifyVoid()) {
488ac7ddfbfSEd Maste             error_stream->PutCString("(void)\n");
489ac7ddfbfSEd Maste           }
490ac7ddfbfSEd Maste 
491ac7ddfbfSEd Maste           if (result)
492ac7ddfbfSEd Maste             result->SetStatus(eReturnStatusSuccessFinishResult);
493435933ddSDimitry Andric         } else {
494ac7ddfbfSEd Maste           const char *error_cstr = result_valobj_sp->GetError().AsCString();
495435933ddSDimitry Andric           if (error_cstr && error_cstr[0]) {
496ac7ddfbfSEd Maste             const size_t error_cstr_len = strlen(error_cstr);
497435933ddSDimitry Andric             const bool ends_with_newline =
498435933ddSDimitry Andric                 error_cstr[error_cstr_len - 1] == '\n';
499ac7ddfbfSEd Maste             if (strstr(error_cstr, "error:") != error_cstr)
500ac7ddfbfSEd Maste               error_stream->PutCString("error: ");
501ac7ddfbfSEd Maste             error_stream->Write(error_cstr, error_cstr_len);
502ac7ddfbfSEd Maste             if (!ends_with_newline)
503ac7ddfbfSEd Maste               error_stream->EOL();
504435933ddSDimitry Andric           } else {
505ac7ddfbfSEd Maste             error_stream->PutCString("error: unknown error\n");
506ac7ddfbfSEd Maste           }
507ac7ddfbfSEd Maste 
508ac7ddfbfSEd Maste           if (result)
509ac7ddfbfSEd Maste             result->SetStatus(eReturnStatusFailed);
510ac7ddfbfSEd Maste         }
511ac7ddfbfSEd Maste       }
512ac7ddfbfSEd Maste     }
513435933ddSDimitry Andric   } else {
514ac7ddfbfSEd Maste     error_stream->Printf("error: invalid execution context for expression\n");
515ac7ddfbfSEd Maste     return false;
516ac7ddfbfSEd Maste   }
517ac7ddfbfSEd Maste 
518ac7ddfbfSEd Maste   return true;
519ac7ddfbfSEd Maste }
520ac7ddfbfSEd Maste 
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)521435933ddSDimitry Andric void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
522435933ddSDimitry Andric                                                      std::string &line) {
52312b93ac6SEd Maste   io_handler.SetIsDone(true);
524435933ddSDimitry Andric   //    StreamSP output_stream =
525435933ddSDimitry Andric   //    io_handler.GetDebugger().GetAsyncOutputStream();
52612b93ac6SEd Maste   //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
52712b93ac6SEd Maste   StreamFileSP output_sp(io_handler.GetOutputStreamFile());
52812b93ac6SEd Maste   StreamFileSP error_sp(io_handler.GetErrorStreamFile());
52912b93ac6SEd Maste 
530435933ddSDimitry Andric   EvaluateExpression(line.c_str(), output_sp.get(), error_sp.get());
53112b93ac6SEd Maste   if (output_sp)
53212b93ac6SEd Maste     output_sp->Flush();
53312b93ac6SEd Maste   if (error_sp)
53412b93ac6SEd Maste     error_sp->Flush();
53512b93ac6SEd Maste }
53612b93ac6SEd Maste 
IOHandlerIsInputComplete(IOHandler & io_handler,StringList & lines)537435933ddSDimitry Andric bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
538435933ddSDimitry Andric                                                        StringList &lines) {
5394bb0738eSEd Maste   // An empty lines is used to indicate the end of input
5404bb0738eSEd Maste   const size_t num_lines = lines.GetSize();
541435933ddSDimitry Andric   if (num_lines > 0 && lines[num_lines - 1].empty()) {
5424ba319b5SDimitry Andric     // Remove the last empty line from "lines" so it doesn't appear in our
5434ba319b5SDimitry Andric     // resulting input and return true to indicate we are done getting lines
54412b93ac6SEd Maste     lines.PopBack();
5454bb0738eSEd Maste     return true;
54612b93ac6SEd Maste   }
5474bb0738eSEd Maste   return false;
54812b93ac6SEd Maste }
54912b93ac6SEd Maste 
GetMultilineExpression()550435933ddSDimitry Andric void CommandObjectExpression::GetMultilineExpression() {
5510127ef0fSEd Maste   m_expr_lines.clear();
5520127ef0fSEd Maste   m_expr_line_count = 0;
5530127ef0fSEd Maste 
5540127ef0fSEd Maste   Debugger &debugger = GetCommandInterpreter().GetDebugger();
5557aa51b79SEd Maste   bool color_prompt = debugger.GetUseColor();
5560127ef0fSEd Maste   const bool multiple_lines = true; // Get multiple lines
557435933ddSDimitry Andric   IOHandlerSP io_handler_sp(
558435933ddSDimitry Andric       new IOHandlerEditline(debugger, IOHandler::Type::Expression,
5590127ef0fSEd Maste                             "lldb-expr", // Name of input reader for history
560435933ddSDimitry Andric                             llvm::StringRef(), // No prompt
561435933ddSDimitry Andric                             llvm::StringRef(), // Continuation prompt
562435933ddSDimitry Andric                             multiple_lines, color_prompt,
5630127ef0fSEd Maste                             1, // Show line numbers starting at 1
5640127ef0fSEd Maste                             *this));
5650127ef0fSEd Maste 
5660127ef0fSEd Maste   StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
567435933ddSDimitry Andric   if (output_sp) {
568435933ddSDimitry Andric     output_sp->PutCString(
569435933ddSDimitry Andric         "Enter expressions, then terminate with an empty line to evaluate:\n");
5700127ef0fSEd Maste     output_sp->Flush();
5710127ef0fSEd Maste   }
5720127ef0fSEd Maste   debugger.PushIOHandler(io_handler_sp);
5730127ef0fSEd Maste }
5740127ef0fSEd Maste 
DoExecute(llvm::StringRef command,CommandReturnObject & result)5754ba319b5SDimitry Andric bool CommandObjectExpression::DoExecute(llvm::StringRef command,
576435933ddSDimitry Andric                                         CommandReturnObject &result) {
5774bb0738eSEd Maste   m_fixed_expression.clear();
578435933ddSDimitry Andric   auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
579435933ddSDimitry Andric   m_option_group.NotifyOptionParsingStarting(&exe_ctx);
580ac7ddfbfSEd Maste 
5814ba319b5SDimitry Andric   if (command.empty()) {
5820127ef0fSEd Maste     GetMultilineExpression();
583ac7ddfbfSEd Maste     return result.Succeeded();
584ac7ddfbfSEd Maste   }
585ac7ddfbfSEd Maste 
5864ba319b5SDimitry Andric   OptionsWithRaw args(command);
5874ba319b5SDimitry Andric   llvm::StringRef expr = args.GetRawPart();
588ac7ddfbfSEd Maste 
5894ba319b5SDimitry Andric   if (args.HasArgs()) {
5904ba319b5SDimitry Andric     if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
591ac7ddfbfSEd Maste       return false;
592ac7ddfbfSEd Maste 
593435933ddSDimitry Andric     if (m_repl_option.GetOptionValue().GetCurrentValue()) {
5949f2f44ceSEd Maste       Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
595435933ddSDimitry Andric       if (target) {
5969f2f44ceSEd Maste         // Drop into REPL
5979f2f44ceSEd Maste         m_expr_lines.clear();
5989f2f44ceSEd Maste         m_expr_line_count = 0;
5999f2f44ceSEd Maste 
6009f2f44ceSEd Maste         Debugger &debugger = target->GetDebugger();
6019f2f44ceSEd Maste 
602435933ddSDimitry Andric         // Check if the LLDB command interpreter is sitting on top of a REPL
6034ba319b5SDimitry Andric         // that launched it...
6044ba319b5SDimitry Andric         if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
6054ba319b5SDimitry Andric                                             IOHandler::Type::REPL)) {
606435933ddSDimitry Andric           // the LLDB command interpreter is sitting on top of a REPL that
6074ba319b5SDimitry Andric           // launched it, so just say the command interpreter is done and
6084ba319b5SDimitry Andric           // fall back to the existing REPL
6099f2f44ceSEd Maste           m_interpreter.GetIOHandler(false)->SetIsDone(true);
610435933ddSDimitry Andric         } else {
611435933ddSDimitry Andric           // We are launching the REPL on top of the current LLDB command
6124ba319b5SDimitry Andric           // interpreter, so just push one
6139f2f44ceSEd Maste           bool initialize = false;
6145517e702SDimitry Andric           Status repl_error;
6154ba319b5SDimitry Andric           REPLSP repl_sp(target->GetREPL(repl_error, m_command_options.language,
6164ba319b5SDimitry Andric                                          nullptr, false));
6179f2f44ceSEd Maste 
618435933ddSDimitry Andric           if (!repl_sp) {
6199f2f44ceSEd Maste             initialize = true;
620435933ddSDimitry Andric             repl_sp = target->GetREPL(repl_error, m_command_options.language,
621435933ddSDimitry Andric                                       nullptr, true);
622435933ddSDimitry Andric             if (!repl_error.Success()) {
6239f2f44ceSEd Maste               result.SetError(repl_error);
6249f2f44ceSEd Maste               return result.Succeeded();
6259f2f44ceSEd Maste             }
6269f2f44ceSEd Maste           }
6279f2f44ceSEd Maste 
628435933ddSDimitry Andric           if (repl_sp) {
629435933ddSDimitry Andric             if (initialize) {
6309f2f44ceSEd Maste               repl_sp->SetCommandOptions(m_command_options);
6319f2f44ceSEd Maste               repl_sp->SetFormatOptions(m_format_options);
6329f2f44ceSEd Maste               repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
6339f2f44ceSEd Maste             }
6349f2f44ceSEd Maste 
6359f2f44ceSEd Maste             IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
6369f2f44ceSEd Maste 
6379f2f44ceSEd Maste             io_handler_sp->SetIsDone(false);
6389f2f44ceSEd Maste 
6399f2f44ceSEd Maste             debugger.PushIOHandler(io_handler_sp);
640435933ddSDimitry Andric           } else {
641435933ddSDimitry Andric             repl_error.SetErrorStringWithFormat(
642435933ddSDimitry Andric                 "Couldn't create a REPL for %s",
643435933ddSDimitry Andric                 Language::GetNameForLanguageType(m_command_options.language));
6449f2f44ceSEd Maste             result.SetError(repl_error);
6459f2f44ceSEd Maste             return result.Succeeded();
6469f2f44ceSEd Maste           }
6479f2f44ceSEd Maste         }
6489f2f44ceSEd Maste       }
6499f2f44ceSEd Maste     }
6500127ef0fSEd Maste     // No expression following options
6514ba319b5SDimitry Andric     else if (expr.empty()) {
6520127ef0fSEd Maste       GetMultilineExpression();
6530127ef0fSEd Maste       return result.Succeeded();
6540127ef0fSEd Maste     }
655ac7ddfbfSEd Maste   }
656ac7ddfbfSEd Maste 
6574ba319b5SDimitry Andric   Target *target = GetSelectedOrDummyTarget();
658435933ddSDimitry Andric   if (EvaluateExpression(expr, &(result.GetOutputStream()),
659435933ddSDimitry Andric                          &(result.GetErrorStream()), &result)) {
660435933ddSDimitry Andric 
661435933ddSDimitry Andric     if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) {
6624bb0738eSEd Maste       CommandHistory &history = m_interpreter.GetCommandHistory();
663435933ddSDimitry Andric       // FIXME: Can we figure out what the user actually typed (e.g. some alias
664435933ddSDimitry Andric       // for expr???)
6654bb0738eSEd Maste       // If we can it would be nice to show that.
6664bb0738eSEd Maste       std::string fixed_command("expression ");
6674ba319b5SDimitry Andric       if (args.HasArgs()) {
6684bb0738eSEd Maste         // Add in any options that might have been in the original command:
6694ba319b5SDimitry Andric         fixed_command.append(args.GetArgStringWithDelimiter());
6704bb0738eSEd Maste         fixed_command.append(m_fixed_expression);
6714ba319b5SDimitry Andric       } else
6724ba319b5SDimitry Andric         fixed_command.append(m_fixed_expression);
6734bb0738eSEd Maste       history.AppendString(fixed_command);
6744bb0738eSEd Maste     }
6754ba319b5SDimitry Andric     // Increment statistics to record this expression evaluation success.
6764ba319b5SDimitry Andric     target->IncrementStats(StatisticKind::ExpressionSuccessful);
677ac7ddfbfSEd Maste     return true;
6784bb0738eSEd Maste   }
679ac7ddfbfSEd Maste 
6804ba319b5SDimitry Andric   // Increment statistics to record this expression evaluation failure.
6814ba319b5SDimitry Andric   target->IncrementStats(StatisticKind::ExpressionFailure);
682ac7ddfbfSEd Maste   result.SetStatus(eReturnStatusFailed);
683ac7ddfbfSEd Maste   return false;
684ac7ddfbfSEd Maste }
685