1//===-- CommandObjectExpression.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ADT/StringRef.h"
10
11#include "CommandObjectExpression.h"
12#include "lldb/Core/Debugger.h"
13#include "lldb/Expression/ExpressionVariable.h"
14#include "lldb/Expression/REPL.h"
15#include "lldb/Expression/UserExpression.h"
16#include "lldb/Host/OptionParser.h"
17#include "lldb/Interpreter/CommandInterpreter.h"
18#include "lldb/Interpreter/CommandOptionArgumentTable.h"
19#include "lldb/Interpreter/CommandReturnObject.h"
20#include "lldb/Interpreter/OptionArgParser.h"
21#include "lldb/Target/Language.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Target/StackFrame.h"
24#include "lldb/Target/Target.h"
25#include "lldb/lldb-enumerations.h"
26#include "lldb/lldb-private-enumerations.h"
27
28using namespace lldb;
29using namespace lldb_private;
30
31CommandObjectExpression::CommandOptions::CommandOptions() = default;
32
33CommandObjectExpression::CommandOptions::~CommandOptions() = default;
34
35#define LLDB_OPTIONS_expression
36#include "CommandOptions.inc"
37
38Status CommandObjectExpression::CommandOptions::SetOptionValue(
39    uint32_t option_idx, llvm::StringRef option_arg,
40    ExecutionContext *execution_context) {
41  Status error;
42
43  const int short_option = GetDefinitions()[option_idx].short_option;
44
45  switch (short_option) {
46  case 'l':
47    language = Language::GetLanguageTypeFromString(option_arg);
48    if (language == eLanguageTypeUnknown) {
49      StreamString sstr;
50      sstr.Printf("unknown language type: '%s' for expression. "
51                  "List of supported languages:\n",
52                  option_arg.str().c_str());
53
54      Language::PrintSupportedLanguagesForExpressions(sstr, "  ", "\n");
55      error.SetErrorString(sstr.GetString());
56    }
57    break;
58
59  case 'a': {
60    bool success;
61    bool result;
62    result = OptionArgParser::ToBoolean(option_arg, true, &success);
63    if (!success)
64      error.SetErrorStringWithFormat(
65          "invalid all-threads value setting: \"%s\"",
66          option_arg.str().c_str());
67    else
68      try_all_threads = result;
69  } break;
70
71  case 'i': {
72    bool success;
73    bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
74    if (success)
75      ignore_breakpoints = tmp_value;
76    else
77      error.SetErrorStringWithFormat(
78          "could not convert \"%s\" to a boolean value.",
79          option_arg.str().c_str());
80    break;
81  }
82
83  case 'j': {
84    bool success;
85    bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
86    if (success)
87      allow_jit = tmp_value;
88    else
89      error.SetErrorStringWithFormat(
90          "could not convert \"%s\" to a boolean value.",
91          option_arg.str().c_str());
92    break;
93  }
94
95  case 't':
96    if (option_arg.getAsInteger(0, timeout)) {
97      timeout = 0;
98      error.SetErrorStringWithFormat("invalid timeout setting \"%s\"",
99                                     option_arg.str().c_str());
100    }
101    break;
102
103  case 'u': {
104    bool success;
105    bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
106    if (success)
107      unwind_on_error = tmp_value;
108    else
109      error.SetErrorStringWithFormat(
110          "could not convert \"%s\" to a boolean value.",
111          option_arg.str().c_str());
112    break;
113  }
114
115  case 'v':
116    if (option_arg.empty()) {
117      m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
118      break;
119    }
120    m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity)
121        OptionArgParser::ToOptionEnum(
122            option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
123    if (!error.Success())
124      error.SetErrorStringWithFormat(
125          "unrecognized value for description-verbosity '%s'",
126          option_arg.str().c_str());
127    break;
128
129  case 'g':
130    debug = true;
131    unwind_on_error = false;
132    ignore_breakpoints = false;
133    break;
134
135  case 'p':
136    top_level = true;
137    break;
138
139  case 'X': {
140    bool success;
141    bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
142    if (success)
143      auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;
144    else
145      error.SetErrorStringWithFormat(
146          "could not convert \"%s\" to a boolean value.",
147          option_arg.str().c_str());
148    break;
149  }
150
151  case '\x01': {
152    bool success;
153    bool persist_result =
154        OptionArgParser::ToBoolean(option_arg, true, &success);
155    if (success)
156      suppress_persistent_result = !persist_result ? eLazyBoolYes : eLazyBoolNo;
157    else
158      error.SetErrorStringWithFormat(
159          "could not convert \"%s\" to a boolean value.",
160          option_arg.str().c_str());
161    break;
162  }
163
164  default:
165    llvm_unreachable("Unimplemented option");
166  }
167
168  return error;
169}
170
171void CommandObjectExpression::CommandOptions::OptionParsingStarting(
172    ExecutionContext *execution_context) {
173  auto process_sp =
174      execution_context ? execution_context->GetProcessSP() : ProcessSP();
175  if (process_sp) {
176    ignore_breakpoints = process_sp->GetIgnoreBreakpointsInExpressions();
177    unwind_on_error = process_sp->GetUnwindOnErrorInExpressions();
178  } else {
179    ignore_breakpoints = true;
180    unwind_on_error = true;
181  }
182
183  show_summary = true;
184  try_all_threads = true;
185  timeout = 0;
186  debug = false;
187  language = eLanguageTypeUnknown;
188  m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
189  auto_apply_fixits = eLazyBoolCalculate;
190  top_level = false;
191  allow_jit = true;
192  suppress_persistent_result = eLazyBoolCalculate;
193}
194
195llvm::ArrayRef<OptionDefinition>
196CommandObjectExpression::CommandOptions::GetDefinitions() {
197  return llvm::ArrayRef(g_expression_options);
198}
199
200EvaluateExpressionOptions
201CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
202    const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
203  EvaluateExpressionOptions options;
204  options.SetCoerceToId(display_opts.use_objc);
205  options.SetUnwindOnError(unwind_on_error);
206  options.SetIgnoreBreakpoints(ignore_breakpoints);
207  options.SetKeepInMemory(true);
208  options.SetUseDynamic(display_opts.use_dynamic);
209  options.SetTryAllThreads(try_all_threads);
210  options.SetDebug(debug);
211  options.SetLanguage(language);
212  options.SetExecutionPolicy(
213      allow_jit ? EvaluateExpressionOptions::default_execution_policy
214                : lldb_private::eExecutionPolicyNever);
215
216  bool auto_apply_fixits;
217  if (this->auto_apply_fixits == eLazyBoolCalculate)
218    auto_apply_fixits = target.GetEnableAutoApplyFixIts();
219  else
220    auto_apply_fixits = this->auto_apply_fixits == eLazyBoolYes;
221
222  options.SetAutoApplyFixIts(auto_apply_fixits);
223  options.SetRetriesWithFixIts(target.GetNumberOfRetriesWithFixits());
224
225  if (top_level)
226    options.SetExecutionPolicy(eExecutionPolicyTopLevel);
227
228  // If there is any chance we are going to stop and want to see what went
229  // wrong with our expression, we should generate debug info
230  if (!ignore_breakpoints || !unwind_on_error)
231    options.SetGenerateDebugInfo(true);
232
233  if (timeout > 0)
234    options.SetTimeout(std::chrono::microseconds(timeout));
235  else
236    options.SetTimeout(std::nullopt);
237  return options;
238}
239
240bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
241    const OptionGroupValueObjectDisplay &display_opts) const {
242  // Explicitly disabling persistent results takes precedence over the
243  // m_verbosity/use_objc logic.
244  if (suppress_persistent_result != eLazyBoolCalculate)
245    return suppress_persistent_result == eLazyBoolYes;
246
247  return display_opts.use_objc &&
248         m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
249}
250
251CommandObjectExpression::CommandObjectExpression(
252    CommandInterpreter &interpreter)
253    : CommandObjectRaw(interpreter, "expression",
254                       "Evaluate an expression on the current "
255                       "thread.  Displays any returned value "
256                       "with LLDB's default formatting.",
257                       "",
258                       eCommandProcessMustBePaused | eCommandTryTargetAPILock),
259      IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
260      m_format_options(eFormatDefault),
261      m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
262                    true),
263      m_expr_line_count(0) {
264  SetHelpLong(
265      R"(
266Single and multi-line expressions:
267
268)"
269      "    The expression provided on the command line must be a complete expression \
270with no newlines.  To evaluate a multi-line expression, \
271hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
272Hit return on an empty line to end the multi-line expression."
273
274      R"(
275
276Timeouts:
277
278)"
279      "    If the expression can be evaluated statically (without running code) then it will be.  \
280Otherwise, by default the expression will run on the current thread with a short timeout: \
281currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted \
282and resumed with all threads running.  You can use the -a option to disable retrying on all \
283threads.  You can use the -t option to set a shorter timeout."
284      R"(
285
286User defined variables:
287
288)"
289      "    You can define your own variables for convenience or to be used in subsequent expressions.  \
290You define them the same way you would define variables in C.  If the first character of \
291your user defined variable is a $, then the variable's value will be available in future \
292expressions, otherwise it will just be available in the current expression."
293      R"(
294
295Continuing evaluation after a breakpoint:
296
297)"
298      "    If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
299you are done with your investigation, you can either remove the expression execution frames \
300from the stack with \"thread return -x\" or if you are still interested in the expression result \
301you can issue the \"continue\" command and the expression evaluation will complete and the \
302expression result will be available using the \"thread.completed-expression\" key in the thread \
303format."
304
305      R"(
306
307Examples:
308
309    expr my_struct->a = my_array[3]
310    expr -f bin -- (index * 8) + 5
311    expr unsigned int $foo = 5
312    expr char c[] = \"foo\"; c[0])");
313
314  CommandArgumentEntry arg;
315  CommandArgumentData expression_arg;
316
317  // Define the first (and only) variant of this arg.
318  expression_arg.arg_type = eArgTypeExpression;
319  expression_arg.arg_repetition = eArgRepeatPlain;
320
321  // There is only one variant this argument could be; put it into the argument
322  // entry.
323  arg.push_back(expression_arg);
324
325  // Push the data for the first argument into the m_arguments vector.
326  m_arguments.push_back(arg);
327
328  // Add the "--format" and "--gdb-format"
329  m_option_group.Append(&m_format_options,
330                        OptionGroupFormat::OPTION_GROUP_FORMAT |
331                            OptionGroupFormat::OPTION_GROUP_GDB_FMT,
332                        LLDB_OPT_SET_1);
333  m_option_group.Append(&m_command_options);
334  m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
335                        LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
336  m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
337  m_option_group.Finalize();
338}
339
340CommandObjectExpression::~CommandObjectExpression() = default;
341
342Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
343
344void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
345  EvaluateExpressionOptions options;
346  options.SetCoerceToId(m_varobj_options.use_objc);
347  options.SetLanguage(m_command_options.language);
348  options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
349  options.SetAutoApplyFixIts(false);
350  options.SetGenerateDebugInfo(false);
351
352  ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
353
354  // Get out before we start doing things that expect a valid frame pointer.
355  if (exe_ctx.GetFramePtr() == nullptr)
356    return;
357
358  Target *exe_target = exe_ctx.GetTargetPtr();
359  Target &target = exe_target ? *exe_target : GetDummyTarget();
360
361  unsigned cursor_pos = request.GetRawCursorPos();
362  // Get the full user input including the suffix. The suffix is necessary
363  // as OptionsWithRaw will use it to detect if the cursor is cursor is in the
364  // argument part of in the raw input part of the arguments. If we cut of
365  // of the suffix then "expr -arg[cursor] --" would interpret the "-arg" as
366  // the raw input (as the "--" is hidden in the suffix).
367  llvm::StringRef code = request.GetRawLineWithUnusedSuffix();
368
369  const std::size_t original_code_size = code.size();
370
371  // Remove the first token which is 'expr' or some alias/abbreviation of that.
372  code = llvm::getToken(code).second.ltrim();
373  OptionsWithRaw args(code);
374  code = args.GetRawPart();
375
376  // The position where the expression starts in the command line.
377  assert(original_code_size >= code.size());
378  std::size_t raw_start = original_code_size - code.size();
379
380  // Check if the cursor is actually in the expression string, and if not, we
381  // exit.
382  // FIXME: We should complete the options here.
383  if (cursor_pos < raw_start)
384    return;
385
386  // Make the cursor_pos again relative to the start of the code string.
387  assert(cursor_pos >= raw_start);
388  cursor_pos -= raw_start;
389
390  auto language = exe_ctx.GetFrameRef().GetLanguage();
391
392  Status error;
393  lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage(
394      code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
395      options, nullptr, error));
396  if (error.Fail())
397    return;
398
399  expr->Complete(exe_ctx, request, cursor_pos);
400}
401
402static lldb_private::Status
403CanBeUsedForElementCountPrinting(ValueObject &valobj) {
404  CompilerType type(valobj.GetCompilerType());
405  CompilerType pointee;
406  if (!type.IsPointerType(&pointee))
407    return Status("as it does not refer to a pointer");
408  if (pointee.IsVoidType())
409    return Status("as it refers to a pointer to void");
410  return Status();
411}
412
413bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
414                                                 Stream &output_stream,
415                                                 Stream &error_stream,
416                                                 CommandReturnObject &result) {
417  // Don't use m_exe_ctx as this might be called asynchronously after the
418  // command object DoExecute has finished when doing multi-line expression
419  // that use an input reader...
420  ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
421  Target *exe_target = exe_ctx.GetTargetPtr();
422  Target &target = exe_target ? *exe_target : GetDummyTarget();
423
424  lldb::ValueObjectSP result_valobj_sp;
425  StackFrame *frame = exe_ctx.GetFramePtr();
426
427  if (m_command_options.top_level && !m_command_options.allow_jit) {
428    result.AppendErrorWithFormat(
429        "Can't disable JIT compilation for top-level expressions.\n");
430    return false;
431  }
432
433  EvaluateExpressionOptions eval_options =
434      m_command_options.GetEvaluateExpressionOptions(target, m_varobj_options);
435  // This command manually removes the result variable, make sure expression
436  // evaluation doesn't do it first.
437  eval_options.SetSuppressPersistentResult(false);
438
439  ExpressionResults success = target.EvaluateExpression(
440      expr, frame, result_valobj_sp, eval_options, &m_fixed_expression);
441
442  // Only mention Fix-Its if the expression evaluator applied them.
443  // Compiler errors refer to the final expression after applying Fix-It(s).
444  if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
445    error_stream << "  Evaluated this expression after applying Fix-It(s):\n";
446    error_stream << "    " << m_fixed_expression << "\n";
447  }
448
449  if (result_valobj_sp) {
450    Format format = m_format_options.GetFormat();
451
452    if (result_valobj_sp->GetError().Success()) {
453      if (format != eFormatVoid) {
454        if (format != eFormatDefault)
455          result_valobj_sp->SetFormat(format);
456
457        if (m_varobj_options.elem_count > 0) {
458          Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
459          if (error.Fail()) {
460            result.AppendErrorWithFormat(
461                "expression cannot be used with --element-count %s\n",
462                error.AsCString(""));
463            return false;
464          }
465        }
466
467        bool suppress_result =
468            m_command_options.ShouldSuppressResult(m_varobj_options);
469
470        DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
471            m_command_options.m_verbosity, format));
472        options.SetHideRootName(suppress_result);
473        options.SetVariableFormatDisplayLanguage(
474            result_valobj_sp->GetPreferredDisplayLanguage());
475
476        result_valobj_sp->Dump(output_stream, options);
477
478        if (suppress_result)
479          if (auto result_var_sp =
480                  target.GetPersistentVariable(result_valobj_sp->GetName())) {
481            auto language = result_valobj_sp->GetPreferredDisplayLanguage();
482            if (auto *persistent_state =
483                    target.GetPersistentExpressionStateForLanguage(language))
484              persistent_state->RemovePersistentVariable(result_var_sp);
485          }
486        result.SetStatus(eReturnStatusSuccessFinishResult);
487      }
488    } else {
489      if (result_valobj_sp->GetError().GetError() ==
490          UserExpression::kNoResult) {
491        if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) {
492          error_stream.PutCString("(void)\n");
493        }
494
495        result.SetStatus(eReturnStatusSuccessFinishResult);
496      } else {
497        const char *error_cstr = result_valobj_sp->GetError().AsCString();
498        if (error_cstr && error_cstr[0]) {
499          const size_t error_cstr_len = strlen(error_cstr);
500          const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
501          if (strstr(error_cstr, "error:") != error_cstr)
502            error_stream.PutCString("error: ");
503          error_stream.Write(error_cstr, error_cstr_len);
504          if (!ends_with_newline)
505            error_stream.EOL();
506        } else {
507          error_stream.PutCString("error: unknown error\n");
508        }
509
510        result.SetStatus(eReturnStatusFailed);
511      }
512    }
513  } else {
514    error_stream.Printf("error: unknown error\n");
515  }
516
517  return (success != eExpressionSetupError &&
518          success != eExpressionParseError);
519}
520
521void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
522                                                     std::string &line) {
523  io_handler.SetIsDone(true);
524  StreamFileSP output_sp = io_handler.GetOutputStreamFileSP();
525  StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
526
527  CommandReturnObject return_obj(
528      GetCommandInterpreter().GetDebugger().GetUseColor());
529  EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj);
530  if (output_sp)
531    output_sp->Flush();
532  if (error_sp)
533    error_sp->Flush();
534}
535
536bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
537                                                       StringList &lines) {
538  // An empty lines is used to indicate the end of input
539  const size_t num_lines = lines.GetSize();
540  if (num_lines > 0 && lines[num_lines - 1].empty()) {
541    // Remove the last empty line from "lines" so it doesn't appear in our
542    // resulting input and return true to indicate we are done getting lines
543    lines.PopBack();
544    return true;
545  }
546  return false;
547}
548
549void CommandObjectExpression::GetMultilineExpression() {
550  m_expr_lines.clear();
551  m_expr_line_count = 0;
552
553  Debugger &debugger = GetCommandInterpreter().GetDebugger();
554  bool color_prompt = debugger.GetUseColor();
555  const bool multiple_lines = true; // Get multiple lines
556  IOHandlerSP io_handler_sp(
557      new IOHandlerEditline(debugger, IOHandler::Type::Expression,
558                            "lldb-expr", // Name of input reader for history
559                            llvm::StringRef(), // No prompt
560                            llvm::StringRef(), // Continuation prompt
561                            multiple_lines, color_prompt,
562                            1, // Show line numbers starting at 1
563                            *this));
564
565  StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP();
566  if (output_sp) {
567    output_sp->PutCString(
568        "Enter expressions, then terminate with an empty line to evaluate:\n");
569    output_sp->Flush();
570  }
571  debugger.RunIOHandlerAsync(io_handler_sp);
572}
573
574static EvaluateExpressionOptions
575GetExprOptions(ExecutionContext &ctx,
576               CommandObjectExpression::CommandOptions command_options) {
577  command_options.OptionParsingStarting(&ctx);
578
579  // Default certain settings for REPL regardless of the global settings.
580  command_options.unwind_on_error = false;
581  command_options.ignore_breakpoints = false;
582  command_options.debug = false;
583
584  EvaluateExpressionOptions expr_options;
585  expr_options.SetUnwindOnError(command_options.unwind_on_error);
586  expr_options.SetIgnoreBreakpoints(command_options.ignore_breakpoints);
587  expr_options.SetTryAllThreads(command_options.try_all_threads);
588
589  if (command_options.timeout > 0)
590    expr_options.SetTimeout(std::chrono::microseconds(command_options.timeout));
591  else
592    expr_options.SetTimeout(std::nullopt);
593
594  return expr_options;
595}
596
597void CommandObjectExpression::DoExecute(llvm::StringRef command,
598                                        CommandReturnObject &result) {
599  m_fixed_expression.clear();
600  auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
601  m_option_group.NotifyOptionParsingStarting(&exe_ctx);
602
603  if (command.empty()) {
604    GetMultilineExpression();
605    return;
606  }
607
608  OptionsWithRaw args(command);
609  llvm::StringRef expr = args.GetRawPart();
610
611  if (args.HasArgs()) {
612    if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
613      return;
614
615    if (m_repl_option.GetOptionValue().GetCurrentValue()) {
616      Target &target = GetSelectedOrDummyTarget();
617      // Drop into REPL
618      m_expr_lines.clear();
619      m_expr_line_count = 0;
620
621      Debugger &debugger = target.GetDebugger();
622
623      // Check if the LLDB command interpreter is sitting on top of a REPL
624      // that launched it...
625      if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
626                                          IOHandler::Type::REPL)) {
627        // the LLDB command interpreter is sitting on top of a REPL that
628        // launched it, so just say the command interpreter is done and
629        // fall back to the existing REPL
630        m_interpreter.GetIOHandler(false)->SetIsDone(true);
631      } else {
632        // We are launching the REPL on top of the current LLDB command
633        // interpreter, so just push one
634        bool initialize = false;
635        Status repl_error;
636        REPLSP repl_sp(target.GetREPL(repl_error, m_command_options.language,
637                                       nullptr, false));
638
639        if (!repl_sp) {
640          initialize = true;
641          repl_sp = target.GetREPL(repl_error, m_command_options.language,
642                                    nullptr, true);
643          if (!repl_error.Success()) {
644            result.SetError(repl_error);
645            return;
646          }
647        }
648
649        if (repl_sp) {
650          if (initialize) {
651            repl_sp->SetEvaluateOptions(
652                GetExprOptions(exe_ctx, m_command_options));
653            repl_sp->SetFormatOptions(m_format_options);
654            repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
655          }
656
657          IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
658          io_handler_sp->SetIsDone(false);
659          debugger.RunIOHandlerAsync(io_handler_sp);
660        } else {
661          repl_error.SetErrorStringWithFormat(
662              "Couldn't create a REPL for %s",
663              Language::GetNameForLanguageType(m_command_options.language));
664          result.SetError(repl_error);
665          return;
666        }
667      }
668    }
669    // No expression following options
670    else if (expr.empty()) {
671      GetMultilineExpression();
672      return;
673    }
674  }
675
676  Target &target = GetSelectedOrDummyTarget();
677  if (EvaluateExpression(expr, result.GetOutputStream(),
678                         result.GetErrorStream(), result)) {
679
680    if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
681      CommandHistory &history = m_interpreter.GetCommandHistory();
682      // FIXME: Can we figure out what the user actually typed (e.g. some alias
683      // for expr???)
684      // If we can it would be nice to show that.
685      std::string fixed_command("expression ");
686      if (args.HasArgs()) {
687        // Add in any options that might have been in the original command:
688        fixed_command.append(std::string(args.GetArgStringWithDelimiter()));
689        fixed_command.append(m_fixed_expression);
690      } else
691        fixed_command.append(m_fixed_expression);
692      history.AppendString(fixed_command);
693    }
694    return;
695  }
696  result.SetStatus(eReturnStatusFailed);
697}
698