From e8ca00acb510ecf41dead48e40b25bef58afc06b Mon Sep 17 00:00:00 2001 From: yhirose Date: Wed, 29 Jul 2015 17:58:20 -0400 Subject: [PATCH] Added print feature to debugger. --- language/culebra.h | 27 ++++----- language/main.cc | 141 +++++++++++++++++++++++++++++++++------------ peglib.h | 15 +++-- 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/language/culebra.h b/language/culebra.h index d9196df..ce9c712 100644 --- a/language/culebra.h +++ b/language/culebra.h @@ -341,8 +341,7 @@ inline std::ostream& operator<<(std::ostream& os, const Value& val) struct Environment { Environment(std::shared_ptr parent = nullptr) - : parent(parent) - , level(parent ? parent->level + 1 : 0) { + : level(parent ? parent->level + 1 : 0) { } void append_outer(std::shared_ptr outer) { @@ -354,15 +353,15 @@ struct Environment } bool has(const std::string& s) const { - if (dic_.find(s) != dic_.end()) { + if (dictionary.find(s) != dictionary.end()) { return true; } return outer && outer->has(s); } Value get(const std::string& s) const { - if (dic_.find(s) != dic_.end()) { - return dic_.at(s).val; + if (dictionary.find(s) != dictionary.end()) { + return dictionary.at(s).val; } if (outer) { return outer->get(s); @@ -373,8 +372,8 @@ struct Environment void assign(const std::string& s, const Value& val) { assert(has(s)); - if (dic_.find(s) != dic_.end()) { - auto& sym = dic_[s]; + if (dictionary.find(s) != dictionary.end()) { + auto& sym = dictionary[s]; if (!sym.mut) { std::string msg = "immutable variable '" + s + "'..."; throw std::runtime_error(msg); @@ -389,16 +388,12 @@ struct Environment void initialize(const std::string& s, const Value& val, bool mut) { //std::cout << "Env::initialize: " << s << std::endl; - dic_[s] = Symbol{ val, mut }; + dictionary[s] = Symbol{ val, mut }; } - std::shared_ptr outer; - - std::shared_ptr parent; - size_t level; - -private: - std::map dic_; + size_t level; + std::shared_ptr outer; + std::map dictionary; }; typedef std::function env, bool force_to_break)> Debugger; @@ -810,7 +805,7 @@ private: Value lval = eval(*ast.nodes[1], env); auto end = ast.nodes.size() - 2; - for (auto i = 2; i < end; i++) { + for (auto i = 2u; i < end; i++) { const auto& postfix = *ast.nodes[i]; switch (postfix.original_tag) { diff --git a/language/main.cc b/language/main.cc index 544d035..51e4758 100644 --- a/language/main.cc +++ b/language/main.cc @@ -6,6 +6,7 @@ #include using namespace culebra; +using namespace peglib; using namespace std; bool read_file(const char* path, vector& buff) @@ -27,10 +28,14 @@ bool read_file(const char* path, vector& buff) struct CommandLineDebugger { - void operator()(const peglib::Ast& ast, shared_ptr env, bool force_to_break) { - if ((command == "n" && env->level <= level) || - (command == "s") || - (command == "o" && env->level < level)) { + void operator()(const Ast& ast, shared_ptr env, bool force_to_break) { + if (quit) { + return; + } + + if ((command_ == "n" && env->level <= level_) || + (command_ == "s") || + (command_ == "o" && env->level < level_)) { force_to_break = true; } @@ -38,30 +43,52 @@ struct CommandLineDebugger show_lines(ast); for (;;) { - command = linenoise::Readline("debug> "); - - if (command == "bt") { - cout << "level: " << env->level << endl; - } else if (command == "c") { // continue + cout << "debug> "; + string s; + std::getline(cin, s); + + istringstream is(s); + is >> command_; + + if (command_ == "h") { + cout << "(c)ontinue, (n)ext, (s)tep in, step (o)out, (p)ring, (l)ist, (q)uit" << endl; + } else if (command_ == "l") { + is >> display_lines_; + show_lines(ast); + } else if (command_ == "p") { + string symbol; + is >> symbol; + print(ast, env, symbol); + } else if (command_ == "c") { break; - } else if (command == "n") { // step over + } else if (command_ == "n") { break; - } else if (command == "s") { // step into + } else if (command_ == "s") { break; - } else if (command == "o") { // step out + } else if (command_ == "o") { + break; + } else if (command_ == "q") { + quit = true; break; } } - level = env->level;; + level_ = env->level;; } } - void show_lines(const peglib::Ast& ast) { + void show_lines(const Ast& ast) { + prepare_cache(ast.path); + cout << "break in " << ast.path << ":" << ast.line << endl; + auto count = get_line_count(ast.path); - auto digits = to_string(count).length();; - size_t start = max((int)ast.line - 1, 1); - auto end = min(ast.line + 3, count); + + auto lines_ahead = (size_t)((display_lines_ - .5) / 2); + auto start = (size_t)max((int)ast.line - (int)lines_ahead, 1); + auto end = min(start + display_lines_, count); + + auto needed_digits = to_string(count).length(); + for (auto l = start; l < end; l++) { auto s = get_line(ast.path, l); if (l == ast.line) { @@ -69,19 +96,59 @@ struct CommandLineDebugger } else { cout << " "; } - cout << setw(digits) << l << " " << s << endl; + cout << setw(needed_digits) << l << " " << s << endl; + } + } + + shared_ptr find_function_node(const Ast& ast) { + auto node = ast.parent_node; + while (node->parent_node && node->tag != "FUNCTION"_) { + node = node->parent_node; + } + return node; + } + + void enum_identifiers(const Ast& ast, set& references) { + for (auto node: ast.nodes) { + switch (node->tag) { + case "IDENTIFIER"_: + references.insert(node->token); + break; + case "FUNCTION"_: + break; + default: + enum_identifiers(*node, references); + break; + } + } + } + + void print(const Ast& ast, shared_ptr env, const string& symbol) { + if (symbol.empty()) { + print_all(ast, env); + } else if (env->has(symbol)) { + cout << symbol << ": " << env->get(symbol).str() << endl; + } else { + cout << "'" << symbol << "'" << "is not undefined." << endl; + } + } + + void print_all(const Ast& ast, shared_ptr env) { + auto node = find_function_node(ast); + set references; + enum_identifiers(*node, references); + for (const auto& symbol: references) { + const auto& val = env->get(symbol); + cout << symbol << ": " << val.str() << endl; } } size_t get_line_count(const string& path) { - prepare_cache(path); - return sources[path].size(); + return sources_[path].size(); } string get_line(const string& path, size_t line) { - prepare_cache(path); - - const auto& positions = sources[path]; + const auto& positions = sources_[path]; auto idx = line - 1; auto first = idx > 0 ? positions[idx - 1] : 0; auto last = positions[idx]; @@ -106,12 +173,12 @@ struct CommandLineDebugger } void prepare_cache(const string& path) { - auto it = sources.find(path); - if (it == sources.end()) { + auto it = sources_.find(path); + if (it == sources_.end()) { vector buff; read_file(path.c_str(), buff); - auto& positions = sources[path]; + auto& positions = sources_[path]; auto i = 0u; for (; i < buff.size(); i++) { @@ -123,9 +190,11 @@ struct CommandLineDebugger } } - string command; - size_t level = 0; - map> sources; + bool quit = false; + string command_; + size_t level_ = 0; + size_t display_lines_ = 4; + map> sources_; }; int repl(shared_ptr env, bool print_ast) @@ -138,9 +207,9 @@ int repl(shared_ptr env, bool print_ast) } if (!line.empty()) { - Value val; - vector msgs; - shared_ptr ast; + Value val; + vector msgs; + shared_ptr ast; auto ret = run("(repl)", env, line.c_str(), line.size(), val, msgs, ast); if (ret) { if (print_ast) { @@ -195,10 +264,10 @@ int main(int argc, const char** argv) return -1; } - Value val; - vector msgs; - shared_ptr ast; - Debugger dbg; + Value val; + vector msgs; + shared_ptr ast; + Debugger dbg; CommandLineDebugger debugger; if (debug) { diff --git a/peglib.h b/peglib.h index 4addbbb..67b4b40 100644 --- a/peglib.h +++ b/peglib.h @@ -1991,6 +1991,7 @@ struct Ast const bool is_token; const std::string token; const std::vector> nodes; + std::shared_ptr parent_node; #ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT const unsigned int tag; const unsigned int original_tag; @@ -2199,12 +2200,18 @@ public: auto line = line_info(sv.ss, sv.s); return std::make_shared(sv.path, line.first, line.second, name.c_str(), std::string(sv.s, sv.n)); } + + std::shared_ptr ast; if (opt && sv.size() == 1) { - auto ast = std::make_shared(*sv[0].get>(), name.c_str()); - return ast; + ast = std::make_shared(*sv[0].get>(), name.c_str()); + } else { + auto line = line_info(sv.ss, sv.s); + ast = std::make_shared(sv.path, line.first, line.second, name.c_str(), sv.transform>()); + } + for (auto node: ast->nodes) { + node->parent_node = ast; } - auto line = line_info(sv.ss, sv.s); - return std::make_shared(sv.path, line.first, line.second, name.c_str(), sv.transform>()); + return ast; }; } }