mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added print feature to debugger.
This commit is contained in:
parent
bca3785c89
commit
e8ca00acb5
@ -341,8 +341,7 @@ inline std::ostream& operator<<(std::ostream& os, const Value& val)
|
||||
struct Environment
|
||||
{
|
||||
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) {
|
||||
@ -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<Environment> outer;
|
||||
|
||||
std::shared_ptr<Environment> parent;
|
||||
size_t level;
|
||||
|
||||
private:
|
||||
std::map<std::string, Symbol> dic_;
|
||||
size_t level;
|
||||
std::shared_ptr<Environment> outer;
|
||||
std::map<std::string, Symbol> dictionary;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
|
139
language/main.cc
139
language/main.cc
@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
using namespace culebra;
|
||||
using namespace peglib;
|
||||
using namespace std;
|
||||
|
||||
bool read_file(const char* path, vector<char>& buff)
|
||||
@ -27,10 +28,14 @@ bool read_file(const char* path, vector<char>& buff)
|
||||
|
||||
struct CommandLineDebugger
|
||||
{
|
||||
void operator()(const peglib::Ast& ast, shared_ptr<Environment> 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<Environment> 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> ");
|
||||
cout << "debug> ";
|
||||
string s;
|
||||
std::getline(cin, s);
|
||||
|
||||
if (command == "bt") {
|
||||
cout << "level: " << env->level << endl;
|
||||
} else if (command == "c") { // continue
|
||||
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<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) {
|
||||
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<char> 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<string, vector<size_t>> sources;
|
||||
bool quit = false;
|
||||
string command_;
|
||||
size_t level_ = 0;
|
||||
size_t display_lines_ = 4;
|
||||
map<string, vector<size_t>> sources_;
|
||||
};
|
||||
|
||||
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()) {
|
||||
Value val;
|
||||
vector<string> msgs;
|
||||
shared_ptr<peglib::Ast> ast;
|
||||
Value val;
|
||||
vector<string> msgs;
|
||||
shared_ptr<Ast> 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<string> msgs;
|
||||
shared_ptr<peglib::Ast> ast;
|
||||
Debugger dbg;
|
||||
Value val;
|
||||
vector<string> msgs;
|
||||
shared_ptr<Ast> ast;
|
||||
Debugger dbg;
|
||||
|
||||
CommandLineDebugger debugger;
|
||||
if (debug) {
|
||||
|
15
peglib.h
15
peglib.h
@ -1991,6 +1991,7 @@ struct Ast
|
||||
const bool is_token;
|
||||
const std::string token;
|
||||
const std::vector<std::shared_ptr<Ast>> nodes;
|
||||
std::shared_ptr<Ast> 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<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) {
|
||||
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
|
||||
return ast;
|
||||
ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
|
||||
} 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);
|
||||
return std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>());
|
||||
for (auto node: ast->nodes) {
|
||||
node->parent_node = ast;
|
||||
}
|
||||
return ast;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user