mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-23 04:15: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
|
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;
|
|
||||||
|
|
||||||
std::shared_ptr<Environment> parent;
|
|
||||||
size_t level;
|
size_t level;
|
||||||
|
std::shared_ptr<Environment> outer;
|
||||||
private:
|
std::map<std::string, Symbol> dictionary;
|
||||||
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) {
|
||||||
|
129
language/main.cc
129
language/main.cc
@ -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)
|
||||||
@ -140,7 +209,7 @@ 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) {
|
||||||
@ -197,7 +266,7 @@ int main(int argc, const char** argv)
|
|||||||
|
|
||||||
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;
|
||||||
|
15
peglib.h
15
peglib.h
@ -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);
|
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>>());
|
ast = 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