void pragma_environment_save::run(const data::command::iterator&, const data::command::iterator&, const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_) const { if (_config.saving_enabled) { const std::string fn = boost::algorithm::trim_copy(tokens_to_string(args_begin_, args_end_)); if (fn.empty()) { displayer_.show_error( "Filename to save the environment into is missing."); } else { std::ofstream f(fn.c_str()); f << _env.get_all() << std::endl; if (f.fail() || f.bad()) { displayer_.show_error("Failed to save the environment into file " + fn); } } } else { displayer_.show_error( "Saving is disabled by the --disable_saving command line argument."); } }
void mdb_shell::line_available(const std::string& line_arg, iface::displayer& displayer_, iface::history& history_) { try { using boost::algorithm::all; using boost::is_space; std::string line = line_arg; if (line != prev_line && !line.empty()) { history_.add(line); } if (line.empty()) { if (!last_command_repeatable) { return; } line = prev_line; } else { prev_line = line; } if (all(line, is_space())) { return; } auto command_arg_pair = command_handler.get_command_for_line(line); if (!command_arg_pair) { displayer_.show_error("Command parsing failed\n"); last_command_repeatable = false; return; } mdb_command cmd; std::string args; std::tie(cmd, args) = *command_arg_pair; last_command_repeatable = cmd.is_repeatable(); cmd.get_func()(*this, args, displayer_); } catch (const std::exception& ex) { displayer_.show_error(std::string("Error: ") + ex.what() + "\n"); } catch (...) { displayer_.show_error("Unknown error\n"); } }
void pragma_switch::run(const data::command::iterator&, const data::command::iterator&, const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_) const { auto i = args_begin_; if (i != args_end_) { const std::string v = i->value().value(); if (valid_argument(v)) { ++i; if (i == args_end_) { _update(element_of(true_values, v)); } else { displayer_.show_error("Invalid arguments after " + v + ": " + tokens_to_string(i, args_end_).value()); } } else { displayer_.show_error("Invalid argument " + v + ". Valid values are: " + valid_arguments()); } } displayer_.show_comment( data::text(_name + " is " + (_query() ? "on" : "off"))); }
void mdb_shell::command_frame(const std::string& arg, iface::displayer& displayer_) { if (!require_running_or_errored_metaprogram(displayer_)) { return; } const auto frame_index = parse_mandatory_integer(arg); if (!frame_index) { display_argument_parsing_failed(displayer_); return; } auto backtrace = mp->get_backtrace(); if (frame_index < 0 || *frame_index >= static_cast<int>(backtrace.size())) { displayer_.show_error("Frame index out of range"); return; } display_frame(backtrace[*frame_index], displayer_); }
bool mdb_shell::run_metaprogram_with_templight( const boost::optional<std::string>& expression, metaprogram::mode_t mode, iface::displayer& displayer_) { const boost::filesystem::path output_path = _mdb_temp_dir / "templight.pb"; data::type_or_error evaluation_result = run_metaprogram(expression, output_path, displayer_); // Opening in binary mode, because some platforms interpret some characters // specially in text mode, which caused parsing to fail. std::ifstream protobuf_stream(output_path.string() + ".trace.pbf", std::ios_base::in | std::ios_base::binary); if (!protobuf_stream) { if (evaluation_result.is_error()) { displayer_.show_error(evaluation_result.get_error()); } else { // Shouldn't happen displayer_.show_error("Unexpected type type_or_error result"); } mp = boost::none; return false; } mp = metaprogram::create_from_protobuf_stream( protobuf_stream, mode, expression ? *expression : "<environment>", data::file_location{}, // TODO something sensible here? evaluation_result); assert(mp); if (mp->is_empty() && evaluation_result.is_error()) { // Most errors will cause templight to generate an empty trace // We're only intrested in non-empty traces displayer_.show_error(evaluation_result.get_error()); mp = boost::none; return false; } return true; }
void mdb_shell::command_help(const std::string& arg, iface::displayer& displayer_) { if (arg.empty()) { displayer_.show_raw_text("List of available commands:"); displayer_.show_raw_text(""); for (const mdb_command& cmd : command_handler.get_commands()) { displayer_.show_raw_text(cmd.get_keys().front() + " -- " + cmd.get_short_description()); } displayer_.show_raw_text(""); displayer_.show_raw_text( "Type \"help\" followed by a command name for more information."); displayer_.show_raw_text( "Command name abbreviations are allowed if unambiguous."); displayer_.show_raw_text( "A blank line as an input will repeat the last command," " if it makes sense."); return; } auto command_arg_pair = command_handler.get_command_for_line(arg); if (!command_arg_pair) { displayer_.show_error("Command not found\n"); return; } using boost::algorithm::join; mdb_command cmd; std::string command_args; std::tie(cmd, command_args) = *command_arg_pair; if (!command_args.empty()) { displayer_.show_error("Only one argument expected\n"); return; } displayer_.show_raw_text(join(cmd.get_keys(), "|") + " " + cmd.get_usage()); displayer_.show_raw_text(cmd.get_full_description()); }
void mdb_shell::command_rbreak(const std::string& arg, iface::displayer& displayer_) { if (arg.empty()) { displayer_.show_error("Argument expected"); return; } if (!require_evaluated_metaprogram(displayer_)) { return; } try { breakpoint bp{next_breakpoint_id, boost::regex(arg)}; ++next_breakpoint_id; unsigned match_count = 0; for (metaprogram::vertex_descriptor vertex : mp->get_vertices()) { if (bp.match(mp->get_vertex_property(vertex).type)) { match_count += mp->get_traversal_count(vertex); } } if (match_count == 0) { displayer_.show_raw_text("Breakpoint \"" + arg + "\" will never stop the execution"); } else { displayer_.show_raw_text( "Breakpoint \"" + arg + "\" will stop the execution on " + std::to_string(match_count) + (match_count > 1 ? " locations" : " location")); breakpoints.push_back(bp); } } catch (const boost::regex_error&) { displayer_.show_error("\"" + arg + "\" is not a valid regex"); } }
bool mdb_shell::require_evaluated_metaprogram(iface::displayer& displayer_) const { if (!mp) { displayer_.show_error("Metaprogram not evaluated yet"); return false; } return true; }
bool mdb_shell::require_empty_args(const std::string& args, iface::displayer& displayer_) const { if (!args.empty()) { displayer_.show_error("This command doesn't accept arguments"); return false; } return true; }
void pragma_config_load::run(const data::command::iterator&, const data::command::iterator&, const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_) const { const data::shell_config_name name = data::shell_config_name( tokens_to_string(args_begin_, args_end_).value()); const auto& configs = _shell.get_config().shell_configs(); const auto cfg = std::find_if( configs.begin(), configs.end(), [&name](const data::shell_config& cfg_) { return cfg_.name == name; }); if (cfg == configs.end()) { throw exception("Config " + name + " not found."); } else { const auto old_config = _shell.get_config().active_shell_config().name; _shell.get_config().activate(name); try { _shell.rebuild_environment(); displayer_.show_comment(data::text("Switched to config " + name)); } catch (const std::exception& e) { displayer_.show_error("Error loading config " + name + ": " + e.what()); restore_config(old_config, _shell); } catch (...) { displayer_.show_error("Error loading config " + name + ": unknown exception"); restore_config(old_config, _shell); } } }
void mdb_shell::command_break(const std::string& arg, iface::displayer& displayer_) { // TODO there will other more kinds of arguments here but needs a proper but // it needs a proper command parser if (arg != "list") { displayer_.show_error("Call break like this: \"break list\""); return; } if (breakpoints.empty()) { displayer_.show_raw_text("No breakpoints currently set"); return; } for (const breakpoint& bp : breakpoints) { displayer_.show_raw_text(bp.to_string()); } }
void pragma_help::run(const data::command::iterator&, const data::command::iterator&, const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_) const { using boost::algorithm::join; if (args_begin_ == args_end_) { display_all(displayer_, _pragma_handlers); } else { std::vector<std::string> args; for (auto i = args_begin_; i != args_end_; ++i) { switch (i->category()) { case data::token_category::whitespace: case data::token_category::comment: // skip token break; default: args.push_back(i->value().value()); } } data::text help_text; bool was_pragma = false; for (const auto& h : _pragma_handlers) { if (prefix_of(args.begin(), args.end(), h.first.begin(), h.first.end())) { if (was_pragma) { help_text.paragraphs.push_back(data::paragraph("")); } else { was_pragma = true; } const std::string p_args = h.second.arguments(); help_text.paragraphs.push_back( data::paragraph("#msh " + join(h.first, " ") + (p_args.empty() ? std::string() : " " + p_args))); help_text.paragraphs.push_back( data::paragraph(h.second.description(), " ")); } } if (was_pragma) { displayer_.show_comment(help_text); } else { displayer_.show_error("Pragma " + join(args, " ") + " not found."); } } }
void mdb_shell::command_evaluate(const std::string& arg_copy, iface::displayer& displayer_) { // Easier not to use spirit here (or probably not...) // TODO OK. after -profile, this parsing really needs some refactoring std::string arg = arg_copy; const std::string full_flag = "-full"; const std::string profile_flag = "-profile"; bool has_full = false; bool has_profile = false; // Intentionally left really ugly for more motivation to refactor while (true) { if (boost::starts_with(arg, full_flag) && (arg.size() == full_flag.size() || std::isspace(arg[full_flag.size()]))) { has_full = true; arg = boost::trim_left_copy(arg.substr(full_flag.size())); } else if (boost::starts_with(arg, profile_flag) && (arg.size() == profile_flag.size() || std::isspace(arg[profile_flag.size()]))) { has_profile = true; arg = boost::trim_left_copy(arg.substr(profile_flag.size())); } else { break; } } if (has_full && has_profile) { displayer_.show_error( "-full and -profile flags cannot be used together."); return; } boost::optional<std::string> expression = arg; if (expression->empty()) { if (!mp) { displayer_.show_error("Nothing has been evaluated yet."); return; } expression = last_evaluated_expression; } else if (*expression == "-") { expression = boost::none; } next_breakpoint_id = 1; breakpoints.clear(); metaprogram::mode_t mode = [&] { if (has_full) { return metaprogram::mode_t::full; } if (has_profile) { return metaprogram::mode_t::profile; } return metaprogram::mode_t::normal; }(); last_evaluated_expression = expression; if (!run_metaprogram_with_templight(expression, mode, displayer_)) { return; } displayer_.show_raw_text("Metaprogram started"); filter_metaprogram(bool(expression)); }
void mdb_shell::display_argument_parsing_failed(iface::displayer& displayer_) const { displayer_.show_error("Argument parsing failed"); }