Added print feature to debugger.

This commit is contained in:
yhirose 2015-07-29 17:58:20 -04:00
parent bca3785c89
commit e8ca00acb5
3 changed files with 126 additions and 55 deletions

View File

@ -341,8 +341,7 @@ inline std::ostream& operator<<(std::ostream& os, const Value& val)
struct Environment struct Environment
{ {
Environment(std::shared_ptr<Environment> parent = nullptr) Environment(std::shared_ptr<Environment> parent = nullptr)
: parent(parent) : level(parent ? parent->level + 1 : 0) {
, level(parent ? parent->level + 1 : 0) {
} }
void append_outer(std::shared_ptr<Environment> outer) { void append_outer(std::shared_ptr<Environment> outer) {
@ -354,15 +353,15 @@ struct Environment
} }
bool has(const std::string& s) const { bool has(const std::string& s) const {
if (dic_.find(s) != dic_.end()) { if (dictionary.find(s) != dictionary.end()) {
return true; return true;
} }
return outer && outer->has(s); return outer && outer->has(s);
} }
Value get(const std::string& s) const { Value get(const std::string& s) const {
if (dic_.find(s) != dic_.end()) { if (dictionary.find(s) != dictionary.end()) {
return dic_.at(s).val; return dictionary.at(s).val;
} }
if (outer) { if (outer) {
return outer->get(s); return outer->get(s);
@ -373,8 +372,8 @@ struct Environment
void assign(const std::string& s, const Value& val) { void assign(const std::string& s, const Value& val) {
assert(has(s)); assert(has(s));
if (dic_.find(s) != dic_.end()) { if (dictionary.find(s) != dictionary.end()) {
auto& sym = dic_[s]; auto& sym = dictionary[s];
if (!sym.mut) { if (!sym.mut) {
std::string msg = "immutable variable '" + s + "'..."; std::string msg = "immutable variable '" + s + "'...";
throw std::runtime_error(msg); throw std::runtime_error(msg);
@ -389,16 +388,12 @@ struct Environment
void initialize(const std::string& s, const Value& val, bool mut) { void initialize(const std::string& s, const Value& val, bool mut) {
//std::cout << "Env::initialize: " << s << std::endl; //std::cout << "Env::initialize: " << s << std::endl;
dic_[s] = Symbol{ val, mut }; dictionary[s] = Symbol{ val, mut };
} }
std::shared_ptr<Environment> outer; size_t level;
std::shared_ptr<Environment> outer;
std::shared_ptr<Environment> parent; std::map<std::string, Symbol> dictionary;
size_t level;
private:
std::map<std::string, Symbol> dic_;
}; };
typedef std::function<void (const peglib::Ast& ast, std::shared_ptr<Environment> env, bool force_to_break)> Debugger; typedef std::function<void (const peglib::Ast& ast, std::shared_ptr<Environment> env, bool force_to_break)> Debugger;
@ -810,7 +805,7 @@ private:
Value lval = eval(*ast.nodes[1], env); Value lval = eval(*ast.nodes[1], env);
auto end = ast.nodes.size() - 2; 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]; const auto& postfix = *ast.nodes[i];
switch (postfix.original_tag) { switch (postfix.original_tag) {

View File

@ -6,6 +6,7 @@
#include <vector> #include <vector>
using namespace culebra; using namespace culebra;
using namespace peglib;
using namespace std; using namespace std;
bool read_file(const char* path, vector<char>& buff) bool read_file(const char* path, vector<char>& buff)
@ -27,10 +28,14 @@ bool read_file(const char* path, vector<char>& buff)
struct CommandLineDebugger struct CommandLineDebugger
{ {
void operator()(const peglib::Ast& ast, shared_ptr<Environment> env, bool force_to_break) { void operator()(const Ast& ast, shared_ptr<Environment> env, bool force_to_break) {
if ((command == "n" && env->level <= level) || if (quit) {
(command == "s") || return;
(command == "o" && env->level < level)) { }
if ((command_ == "n" && env->level <= level_) ||
(command_ == "s") ||
(command_ == "o" && env->level < level_)) {
force_to_break = true; force_to_break = true;
} }
@ -38,30 +43,52 @@ struct CommandLineDebugger
show_lines(ast); show_lines(ast);
for (;;) { for (;;) {
command = linenoise::Readline("debug> "); cout << "debug> ";
string s;
std::getline(cin, s);
if (command == "bt") { istringstream is(s);
cout << "level: " << env->level << endl; is >> command_;
} else if (command == "c") { // continue
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; break;
} else if (command == "n") { // step over } else if (command_ == "n") {
break; break;
} else if (command == "s") { // step into } else if (command_ == "s") {
break; break;
} else if (command == "o") { // step out } else if (command_ == "o") {
break;
} else if (command_ == "q") {
quit = true;
break; 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; cout << "break in " << ast.path << ":" << ast.line << endl;
auto count = get_line_count(ast.path); auto count = get_line_count(ast.path);
auto digits = to_string(count).length();;
size_t start = max((int)ast.line - 1, 1); auto lines_ahead = (size_t)((display_lines_ - .5) / 2);
auto end = min(ast.line + 3, count); 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++) { for (auto l = start; l < end; l++) {
auto s = get_line(ast.path, l); auto s = get_line(ast.path, l);
if (l == ast.line) { if (l == ast.line) {
@ -69,19 +96,59 @@ struct CommandLineDebugger
} else { } else {
cout << " "; cout << " ";
} }
cout << setw(digits) << l << " " << s << endl; cout << setw(needed_digits) << l << " " << s << endl;
}
}
shared_ptr<Ast> 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<string>& 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<Environment> 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<Environment> env) {
auto node = find_function_node(ast);
set<string> 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) { 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) { 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 idx = line - 1;
auto first = idx > 0 ? positions[idx - 1] : 0; auto first = idx > 0 ? positions[idx - 1] : 0;
auto last = positions[idx]; auto last = positions[idx];
@ -106,12 +173,12 @@ struct CommandLineDebugger
} }
void prepare_cache(const string& path) { void prepare_cache(const string& path) {
auto it = sources.find(path); auto it = sources_.find(path);
if (it == sources.end()) { if (it == sources_.end()) {
vector<char> buff; vector<char> buff;
read_file(path.c_str(), buff); read_file(path.c_str(), buff);
auto& positions = sources[path]; auto& positions = sources_[path];
auto i = 0u; auto i = 0u;
for (; i < buff.size(); i++) { for (; i < buff.size(); i++) {
@ -123,9 +190,11 @@ struct CommandLineDebugger
} }
} }
string command; bool quit = false;
size_t level = 0; string command_;
map<string, vector<size_t>> sources; size_t level_ = 0;
size_t display_lines_ = 4;
map<string, vector<size_t>> sources_;
}; };
int repl(shared_ptr<Environment> env, bool print_ast) int repl(shared_ptr<Environment> env, bool print_ast)
@ -138,9 +207,9 @@ int repl(shared_ptr<Environment> env, bool print_ast)
} }
if (!line.empty()) { if (!line.empty()) {
Value val; Value val;
vector<string> msgs; vector<string> msgs;
shared_ptr<peglib::Ast> ast; shared_ptr<Ast> ast;
auto ret = run("(repl)", env, line.c_str(), line.size(), val, msgs, ast); auto ret = run("(repl)", env, line.c_str(), line.size(), val, msgs, ast);
if (ret) { if (ret) {
if (print_ast) { if (print_ast) {
@ -195,10 +264,10 @@ int main(int argc, const char** argv)
return -1; return -1;
} }
Value val; Value val;
vector<string> msgs; vector<string> msgs;
shared_ptr<peglib::Ast> ast; shared_ptr<Ast> ast;
Debugger dbg; Debugger dbg;
CommandLineDebugger debugger; CommandLineDebugger debugger;
if (debug) { if (debug) {

View File

@ -1991,6 +1991,7 @@ struct Ast
const bool is_token; const bool is_token;
const std::string token; const std::string token;
const std::vector<std::shared_ptr<Ast>> nodes; const std::vector<std::shared_ptr<Ast>> nodes;
std::shared_ptr<Ast> parent_node;
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT #ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
const unsigned int tag; const unsigned int tag;
const unsigned int original_tag; const unsigned int original_tag;
@ -2199,12 +2200,18 @@ public:
auto line = line_info(sv.ss, sv.s); auto line = line_info(sv.ss, sv.s);
return std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), std::string(sv.s, sv.n)); return std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), std::string(sv.s, sv.n));
} }
std::shared_ptr<Ast> ast;
if (opt && sv.size() == 1) { if (opt && sv.size() == 1) {
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str()); ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
return ast; } else {
auto line = line_info(sv.ss, sv.s);
ast = std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>());
} }
auto line = line_info(sv.ss, sv.s); for (auto node: ast->nodes) {
return std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>()); node->parent_node = ast;
}
return ast;
}; };
} }
} }