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 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::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_environment_add::run( const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_ ) const { const std::string cmd = tokens_to_string(args_begin_, args_end_); _shell.store_in_buffer(cmd, displayer_); if (is_environment_setup_command(args_begin_, args_end_)) { displayer_.show_comment( data::text( "You don't need the environment add pragma to add this to the" " environment. The following command does this as well:" ) ); displayer_.show_cpp_code(cmd); } else { displayer_.show_comment( data::text( "Metashell (incorrectly) thinks that this command should execute a" " metaprogram and would not add it to the environment without using" " the \"environment add\" pragma. Please file a bug report containing" " this command (" + cmd + ") at" " https://github.com/sabel83/metashell/issues. Thank you." ) ); } }
data::type_or_error mdb_shell::run_metaprogram(const boost::optional<std::string>& expression, const boost::filesystem::path& output_path_, iface::displayer& displayer_) { const data::result res = _engine.eval( env, expression, output_path_, conf.use_precompiled_headers); if (!res.info.empty()) { displayer_.show_raw_text(res.info); } if (!res.successful) { return data::type_or_error::make_error(res.error); } else if (expression) { return data::type_or_error::make_type(data::type(res.output)); } else { return data::type_or_error::make_none(); } }
std::unique_ptr<iface::event_data_sequence> metaprogram_tracer_clang::eval( iface::environment& env_, const boost::filesystem::path&, const boost::optional<data::cpp_code>& expression_, data::metaprogram_mode mode_, iface::displayer& displayer_) { const auto out = eval_with_templight_dump_on_stdout( env_, expression_, boost::none, _clang_binary); const data::result& res = std::get<0>(out); const std::string& trace = std::get<1>(out); if (!res.info.empty()) { displayer_.show_raw_text(res.info); } if (trace.empty()) { throw exception(res.successful ? "Failed to get template trace" : res.error); } else { return filter_events( yaml_trace( trace, type_or_code_or_error_from_result(res, expression_), expression_ ? *expression_ : data::cpp_code("<environment>"), mode_), determine_from_line( env_.get(), expression_, data::stdin_name_in_clang())); } }
void mdb_shell::display_current_forwardtrace(boost::optional<int> max_depth, iface::displayer& displayer_) const { displayer_.show_call_graph(boost::make_iterator_range( forward_trace_iterator(*mp, max_depth), forward_trace_iterator())); }
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_); }
void mdb_shell::command_continue(const std::string& arg, iface::displayer& displayer_) { if (!require_evaluated_metaprogram(displayer_)) { return; } const auto continue_count = parse_defaultable_integer(arg, 1); if (!continue_count) { display_argument_parsing_failed(displayer_); return; } direction_t direction = *continue_count >= 0 ? direction_t::forward : direction_t::backwards; const breakpoint* breakpoint_ptr = nullptr; for (int i = 0; i < std::abs(*continue_count) && !mp->is_at_endpoint(direction); ++i) { breakpoint_ptr = continue_metaprogram(direction); } if (breakpoint_ptr) { displayer_.show_raw_text(breakpoint_ptr->to_string() + " reached"); } display_movement_info(*continue_count != 0, 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_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"); } }
void mdb_shell::display_frame(const data::frame& frame, iface::displayer& displayer_) const { displayer_.show_frame(frame); data::file_location source_location = frame.source_location(); if (source_location.name == _env_path) { // We don't want to show stuff from the internal header source_location = data::file_location(); } // TODO: we should somehow compensate the file_locations returned by // clang for the <stdin> file. This is hard because the file clang sees // is just two lines (an include for the PCH and the current line) // Until this is figured out, printing file sections for <stdin> is // turned off // displayer_.show_file_section(source_location, env.get()); displayer_.show_file_section(source_location, ""); }
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_which::run(const data::command::iterator& name_begin_, const data::command::iterator& name_end_, const data::command::iterator& args_begin_, const data::command::iterator& args_end_, iface::displayer& displayer_) const { using boost::filesystem::path; using boost::adaptors::transformed; using boost::adaptors::filtered; const parsed_arguments args = parse_arguments(data::tokens_to_string(name_begin_, name_end_).value(), args_begin_, args_end_); const auto include_path = _shell.engine().header_discoverer().include_path(args.header.type); const auto files = include_path | transformed(std::function<path(const path&)>( [&args](const path& path_) { return path_ / args.header.path; })) | filtered([](const path& path_) { return exists(path_); }); if (files.empty()) { throw exception("Include file " + data::tokens_to_string(args_begin_, args_end_).value() + " not found."); } else if (args.all) { displayer_.show_filename_list( std::vector<path>(files.begin(), files.end())); } else { displayer_.show_filename_list({files.front()}); } }
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_backtrace(iface::displayer& displayer_) const { displayer_.show_backtrace(mp->get_backtrace()); }
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 pragma_macros::run(iface::displayer& displayer_) const { displayer_.show_cpp_code(_shell.engine().macros(_shell.env())); }
void mdb_shell::display_argument_parsing_failed(iface::displayer& displayer_) const { displayer_.show_error("Argument parsing failed"); }
void mdb_shell::display_metaprogram_reached_the_beginning( iface::displayer& displayer_) const { displayer_.show_raw_text("Metaprogram reached the beginning"); }
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::display_metaprogram_finished(iface::displayer& displayer_) const { displayer_.show_raw_text("Metaprogram finished"); displayer_.show_type_or_error(mp->get_evaluation_result()); }