Added command-line debugger support.

This commit is contained in:
yhirose 2015-07-28 06:47:18 -04:00
parent 24b3da5d0f
commit 5d6755ff64
4 changed files with 192 additions and 99 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
include_directories(.) include_directories(.)
add_definitions("-std=c++1y") add_definitions("-std=c++1y" -DPEGLIB_HAS_CONSTEXPR_SUPPORT)
add_executable(peglint lint/peglint.cc) add_executable(peglint lint/peglint.cc)
target_link_libraries(peglint pthread) target_link_libraries(peglint pthread)
@ -20,5 +20,5 @@ target_link_libraries(calc2 pthread)
add_executable(calc3 example/calc3.cc) add_executable(calc3 example/calc3.cc)
target_link_libraries(calc3 pthread) target_link_libraries(calc3 pthread)
add_executable(culebra language/main.cc language/repl.cc language/interpreter.cc language/parser.cc) add_executable(culebra language/main.cc)
target_link_libraries(culebra pthread) target_link_libraries(culebra pthread)

View File

@ -8,7 +8,11 @@ namespace culebra {
const auto grammar_ = R"( const auto grammar_ = R"(
PROGRAM <- _ STATEMENTS PROGRAM <- _ STATEMENTS
STATEMENTS <- (EXPRESSION (';' _)?)* STATEMENTS <- (STATEMENT (';' _)?)*
STATEMENT <- DEBUGGER / EXPRESSION
DEBUGGER <- 'debugger' _
EXPRESSION <- ASSIGNMENT / LOGICAL_OR EXPRESSION <- ASSIGNMENT / LOGICAL_OR
ASSIGNMENT <- MUTABLE PRIMARY (ARGUMENTS / INDEX / DOT)* '=' _ EXPRESSION ASSIGNMENT <- MUTABLE PRIMARY (ARGUMENTS / INDEX / DOT)* '=' _ EXPRESSION
@ -336,7 +340,10 @@ inline std::ostream& operator<<(std::ostream& os, const Value& val)
struct Environment struct Environment
{ {
Environment() = default; Environment(std::shared_ptr<Environment> parent = nullptr)
: parent(parent)
, level(parent ? parent->level + 1 : 0) {
}
void append_outer(std::shared_ptr<Environment> outer) { void append_outer(std::shared_ptr<Environment> outer) {
if (this->outer) { if (this->outer) {
@ -385,12 +392,17 @@ struct Environment
dic_[s] = Symbol{ val, mut }; dic_[s] = Symbol{ val, mut };
} }
std::shared_ptr<Environment> outer; std::shared_ptr<Environment> outer;
std::shared_ptr<Environment> parent;
size_t level;
private: private:
std::map<std::string, Symbol> dic_; std::map<std::string, Symbol> dic_;
}; };
typedef std::function<void (const peglib::Ast& ast, std::shared_ptr<Environment> env, bool force_to_break)> Debugger;
inline bool ObjectValue::has(const std::string& name) const { inline bool ObjectValue::has(const std::string& name) const {
if (properties->find(name) == properties->end()) { if (properties->find(name) == properties->end()) {
const auto& props = const_cast<ObjectValue*>(this)->builtins(); const auto& props = const_cast<ObjectValue*>(this)->builtins();
@ -521,9 +533,20 @@ inline void setup_built_in_functions(Environment& env) {
struct Eval struct Eval
{ {
static Value eval(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Eval(Debugger debugger = nullptr)
: debugger_(debugger) {
}
Value eval(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
using peglib::operator"" _; using peglib::operator"" _;
if (debugger_) {
if (ast.original_tag == "STATEMENT"_) {
auto force_to_break = ast.tag == "DEBUGGER"_;
debugger_(ast, env, force_to_break);
}
}
switch (ast.tag) { switch (ast.tag) {
case "STATEMENTS"_: return eval_statements(ast, env); case "STATEMENTS"_: return eval_statements(ast, env);
case "WHILE"_: return eval_while(ast, env); case "WHILE"_: return eval_while(ast, env);
@ -547,6 +570,7 @@ struct Eval
case "BOOLEAN"_: return eval_bool(ast, env); case "BOOLEAN"_: return eval_bool(ast, env);
case "NUMBER"_: return eval_number(ast, env); case "NUMBER"_: return eval_number(ast, env);
case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env); case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env);
case "DEBUGGER"_: return Value();
} }
if (ast.is_token) { if (ast.is_token) {
@ -558,7 +582,7 @@ struct Eval
} }
private: private:
static Value eval_statements(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_statements(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
if (ast.is_token) { if (ast.is_token) {
return eval(ast, env); return eval(ast, env);
} else if (ast.nodes.empty()) { } else if (ast.nodes.empty()) {
@ -572,7 +596,7 @@ private:
return eval(**it, env); return eval(**it, env);
} }
static Value eval_while(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_while(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
for (;;) { for (;;) {
auto cond = eval(*ast.nodes[0], env); auto cond = eval(*ast.nodes[0], env);
if (!cond.to_bool()) { if (!cond.to_bool()) {
@ -583,7 +607,7 @@ private:
return Value(); return Value();
} }
static Value eval_if(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_if(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
const auto& nodes = ast.nodes; const auto& nodes = ast.nodes;
for (auto i = 0u; i < nodes.size(); i += 2) { for (auto i = 0u; i < nodes.size(); i += 2) {
@ -600,7 +624,7 @@ private:
return Value(); return Value();
} }
static Value eval_function(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_function(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
std::vector<FunctionValue::Parameter> params; std::vector<FunctionValue::Parameter> params;
for (auto node: ast.nodes[0]->nodes) { for (auto node: ast.nodes[0]->nodes) {
auto mut = node->nodes[0]->token == "mut"; auto mut = node->nodes[0]->token == "mut";
@ -619,13 +643,13 @@ private:
)); ));
}; };
static Value eval_function_call(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) { Value eval_function_call(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
const auto& f = val.to_function(); const auto& f = val.to_function();
const auto& params = *f.params; const auto& params = *f.params;
const auto& args = ast.nodes; const auto& args = ast.nodes;
if (params.size() <= args.size()) { if (params.size() <= args.size()) {
auto callEnv = std::make_shared<Environment>(); auto callEnv = std::make_shared<Environment>(env);
callEnv->initialize("self", val, false); callEnv->initialize("self", val, false);
for (auto iprm = 0u; iprm < params.size(); iprm++) { for (auto iprm = 0u; iprm < params.size(); iprm++) {
auto param = params[iprm]; auto param = params[iprm];
@ -642,7 +666,7 @@ private:
throw std::runtime_error(msg); throw std::runtime_error(msg);
} }
static Value eval_array_reference(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) { Value eval_array_reference(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
const auto& arr = val.to_array(); const auto& arr = val.to_array();
auto idx = eval(ast, env).to_long(); auto idx = eval(ast, env).to_long();
if (0 <= idx && idx < static_cast<long>(arr.values->size())) { if (0 <= idx && idx < static_cast<long>(arr.values->size())) {
@ -653,7 +677,7 @@ private:
return val; return val;
} }
static Value eval_property(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) { Value eval_property(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
const auto& obj = val.to_object(); const auto& obj = val.to_object();
auto name = ast.token; auto name = ast.token;
if (!obj.has(name)) { if (!obj.has(name)) {
@ -673,7 +697,7 @@ private:
return prop; return prop;
} }
static Value eval_call(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_call(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
using peglib::operator"" _; using peglib::operator"" _;
Value val = eval(*ast.nodes[0], env); Value val = eval(*ast.nodes[0], env);
@ -692,11 +716,11 @@ private:
return std::move(val); return std::move(val);
} }
static Value eval_block(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_block(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
return Value(); return Value();
} }
static Value eval_logical_or(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_logical_or(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
assert(ast.nodes.size() > 1); // if the size is 1, thes node will be hoisted. assert(ast.nodes.size() > 1); // if the size is 1, thes node will be hoisted.
Value val; Value val;
for (auto node: ast.nodes) { for (auto node: ast.nodes) {
@ -708,7 +732,7 @@ private:
return std::move(val); return std::move(val);
} }
static Value eval_logical_and(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_logical_and(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
Value val; Value val;
for (auto node: ast.nodes) { for (auto node: ast.nodes) {
val = eval(*node, env); val = eval(*node, env);
@ -719,7 +743,7 @@ private:
return std::move(val); return std::move(val);
} }
static Value eval_condition(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_condition(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
assert(ast.nodes.size() == 3); // if the size is 1, thes node will be hoisted. assert(ast.nodes.size() == 3); // if the size is 1, thes node will be hoisted.
auto lhs = eval(*ast.nodes[0], env); auto lhs = eval(*ast.nodes[0], env);
@ -735,22 +759,22 @@ private:
else { throw std::logic_error("invalid internal condition."); } else { throw std::logic_error("invalid internal condition."); }
} }
static Value eval_unary_plus(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_unary_plus(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted. assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
return eval(*ast.nodes[1], env); return eval(*ast.nodes[1], env);
} }
static Value eval_unary_minus(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_unary_minus(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted. assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
return Value(eval(*ast.nodes[1], env).to_long() * -1); return Value(eval(*ast.nodes[1], env).to_long() * -1);
} }
static Value eval_unary_not(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_unary_not(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted. assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
return Value(!eval(*ast.nodes[1], env).to_bool()); return Value(!eval(*ast.nodes[1], env).to_bool());
} }
static Value eval_bin_expression(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_bin_expression(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
auto ret = eval(*ast.nodes[0], env).to_long(); auto ret = eval(*ast.nodes[0], env).to_long();
for (auto i = 1u; i < ast.nodes.size(); i += 2) { for (auto i = 1u; i < ast.nodes.size(); i += 2) {
auto val = eval(*ast.nodes[i + 1], env).to_long(); auto val = eval(*ast.nodes[i + 1], env).to_long();
@ -766,7 +790,7 @@ private:
return Value(ret); return Value(ret);
} }
static Value eval_assignment(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_assignment(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
auto end = ast.nodes.size() - 1; auto end = ast.nodes.size() - 1;
auto mut = ast.nodes[0]->token == "mut"; auto mut = ast.nodes[0]->token == "mut";
@ -826,11 +850,11 @@ private:
} }
}; };
static Value eval_identifier(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_identifier(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
return env->get(ast.token); return env->get(ast.token);
}; };
static Value eval_object(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_object(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
ObjectValue obj; ObjectValue obj;
for (auto i = 0u; i < ast.nodes.size(); i++) { for (auto i = 0u; i < ast.nodes.size(); i++) {
const auto& prop = *ast.nodes[i]; const auto& prop = *ast.nodes[i];
@ -842,7 +866,7 @@ private:
return Value(std::move(obj)); return Value(std::move(obj));
} }
static Value eval_array(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_array(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
ArrayValue arr; ArrayValue arr;
for (auto i = 0u; i < ast.nodes.size(); i++) { for (auto i = 0u; i < ast.nodes.size(); i++) {
auto expr = ast.nodes[i]; auto expr = ast.nodes[i];
@ -852,19 +876,19 @@ private:
return Value(std::move(arr)); return Value(std::move(arr));
} }
static Value eval_undefined(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_undefined(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
return Value(); return Value();
}; };
static Value eval_bool(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_bool(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
return Value(ast.token == "true"); return Value(ast.token == "true");
}; };
static Value eval_number(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_number(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
return Value(stol(ast.token)); return Value(stol(ast.token));
}; };
static Value eval_interpolated_string(const peglib::Ast& ast, std::shared_ptr<Environment> env) { Value eval_interpolated_string(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
std::string s; std::string s;
for (auto node: ast.nodes) { for (auto node: ast.nodes) {
const auto& val = eval(*node, env); const auto& val = eval(*node, env);
@ -876,16 +900,19 @@ private:
} }
return Value(std::move(s)); return Value(std::move(s));
}; };
Debugger debugger_;
}; };
inline bool run( inline bool run(
const std::string& path, const std::string& path,
std::shared_ptr<Environment> env, std::shared_ptr<Environment> env,
const char* expr, const char* expr,
size_t len, size_t len,
Value& val, Value& val,
std::string& msg, std::vector<std::string>& msgs,
bool print_ast) std::shared_ptr<peglib::Ast>& ast,
Debugger debugger = nullptr)
{ {
try { try {
auto& parser = get_parser(); auto& parser = get_parser();
@ -893,21 +920,15 @@ inline bool run(
parser.log = [&](size_t ln, size_t col, const std::string& err_msg) { parser.log = [&](size_t ln, size_t col, const std::string& err_msg) {
std::stringstream ss; std::stringstream ss;
ss << path << ":" << ln << ":" << col << ": " << err_msg << std::endl; ss << path << ":" << ln << ":" << col << ": " << err_msg << std::endl;
msg = ss.str(); msgs.push_back(ss.str());
}; };
std::shared_ptr<peglib::Ast> ast; if (parser.parse_n(expr, len, ast, path.c_str())) {
val = Eval(debugger).eval(*ast, env);
if (parser.parse_n(expr, len, ast)) {
if (print_ast) {
ast->print();
}
val = Eval::eval(*ast, env);
return true; return true;
} }
} catch (std::runtime_error& e) { } catch (std::runtime_error& e) {
msg = e.what(); msgs.push_back(e.what());
} }
return false; return false;

View File

@ -24,6 +24,49 @@ bool read_file(const char* path, vector<char>& buff)
return true; return true;
} }
struct CommandLineDebugger
{
void operator()(const peglib::Ast& ast, std::shared_ptr<Environment> env, bool force_to_break) {
if (quit) {
force_to_break = false;
} if (line == "n" && env->level <= level) {
force_to_break = true;
} else if (line == "s") {
force_to_break = true;
} else if (line == "o" && env->level < level) {
force_to_break = true;
}
if (force_to_break) {
for (;;) {
line = linenoise::Readline("debug> ");
if (line == "bt") {
std::cout << "level: " << env->level << std::endl;
} else if (line == "l") { // show source file
std::cout << "line: " << ast.line << " in " << ast.path << std::endl;
} else if (line == "c") { // continue
break;
} else if (line == "n") { // step over
break;
} else if (line == "s") { // step into
break;
} else if (line == "o") { // step out
break;
} else if (line == "q") { // quit
quit = true;
break;
}
}
level = env->level;;
}
}
std::string line;
size_t level = 0;
bool quit = false;
};
int repl(shared_ptr<Environment> env, bool print_ast) int repl(shared_ptr<Environment> env, bool print_ast)
{ {
for (;;) { for (;;) {
@ -35,12 +78,19 @@ int repl(shared_ptr<Environment> env, bool print_ast)
if (!line.empty()) { if (!line.empty()) {
Value val; Value val;
string msg; vector<string> msgs;
if (run("(repl)", env, line.c_str(), line.size(), val, msg, print_ast)) { std::shared_ptr<peglib::Ast> ast;
auto ret = run("(repl)", env, line.c_str(), line.size(), val, msgs, ast);
if (ret) {
if (print_ast) {
ast->print();
}
cout << val << endl; cout << val << endl;
linenoise::AddHistory(line.c_str()); linenoise::AddHistory(line.c_str());
} else if (!msg.empty()) { } else if (!msgs.empty()) {
cout << msg << endl;; for (const auto& msg: msgs) {
cout << msg << endl;;
}
} }
} }
} }
@ -52,6 +102,7 @@ int main(int argc, const char** argv)
{ {
auto print_ast = false; auto print_ast = false;
auto shell = false; auto shell = false;
auto debug = false;
vector<const char*> path_list; vector<const char*> path_list;
int argi = 1; int argi = 1;
@ -61,6 +112,8 @@ int main(int argc, const char** argv)
shell = true; shell = true;
} else if (string("--ast") == arg) { } else if (string("--ast") == arg) {
print_ast = true; print_ast = true;
} else if (string("--debug") == arg) {
debug = true;
} else { } else {
path_list.push_back(arg); path_list.push_back(arg);
} }
@ -81,11 +134,25 @@ int main(int argc, const char** argv)
return -1; return -1;
} }
Value val; Value val;
string msg; vector<string> msgs;
if (!run(path, env, buff.data(), buff.size(), val, msg, print_ast)) { std::shared_ptr<peglib::Ast> ast;
cerr << msg << endl; Debugger dbg;
CommandLineDebugger debugger;
if (debug) {
dbg = debugger;
}
auto ret = run(path, env, buff.data(), buff.size(), val, msgs, ast, dbg);
if (!ret) {
for (const auto& msg: msgs) {
cerr << msg << endl;
}
return -1; return -1;
} else if (print_ast) {
ast->print();
} }
} }

View File

@ -180,6 +180,7 @@ struct SemanticValue
struct SemanticValues : protected std::vector<SemanticValue> struct SemanticValues : protected std::vector<SemanticValue>
{ {
const char* path;
const char* ss; const char* ss;
const char* s; const char* s;
size_t n; size_t n;
@ -407,6 +408,7 @@ inline bool fail(size_t len) {
*/ */
struct Context struct Context
{ {
const char* path;
const char* s; const char* s;
size_t l; size_t l;
@ -423,8 +425,9 @@ struct Context
std::map<std::pair<size_t, size_t>, std::tuple<size_t, any>> cache_result; std::map<std::pair<size_t, size_t>, std::tuple<size_t, any>> cache_result;
Context(const char* s, size_t l, size_t def_count, bool enablePackratParsing) Context(const char* path, const char* s, size_t l, size_t def_count, bool enablePackratParsing)
: s(s) : path(path)
, s(s)
, l(l) , l(l)
, error_pos(nullptr) , error_pos(nullptr)
, message_pos(nullptr) , message_pos(nullptr)
@ -475,6 +478,7 @@ struct Context
if (!sv.empty()) { if (!sv.empty()) {
sv.clear(); sv.clear();
} }
sv.path = path;
sv.ss = s; sv.ss = s;
sv.s = nullptr; sv.s = nullptr;
sv.n = 0; sv.n = 0;
@ -1085,32 +1089,32 @@ public:
return *this; return *this;
} }
Result parse(const char* s, size_t n) const { Result parse(const char* s, size_t n, const char* path = nullptr) const {
SemanticValues sv; SemanticValues sv;
any dt; any dt;
return parse_core(s, n, sv, dt); return parse_core(s, n, sv, dt, path);
} }
Result parse(const char* s) const { Result parse(const char* s, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse(s, n); return parse(s, n, path);
} }
Result parse(const char* s, size_t n, any& dt) const { Result parse(const char* s, size_t n, any& dt, const char* path = nullptr) const {
SemanticValues sv; SemanticValues sv;
return parse_core(s, n, sv, dt); return parse_core(s, n, sv, dt, path);
} }
Result parse(const char* s, any& dt) const { Result parse(const char* s, any& dt, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse(s, n, dt); return parse(s, n, dt, path);
} }
template <typename T> template <typename T>
Result parse_and_get_value(const char* s, size_t n, T& val) const { Result parse_and_get_value(const char* s, size_t n, T& val, const char* path = nullptr) const {
SemanticValues sv; SemanticValues sv;
any dt; any dt;
auto r = parse_core(s, n, sv, dt); auto r = parse_core(s, n, sv, dt, path);
if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) { if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) {
val = sv[0].val.get<T>(); val = sv[0].val.get<T>();
} }
@ -1118,15 +1122,15 @@ public:
} }
template <typename T> template <typename T>
Result parse_and_get_value(const char* s, T& val) const { Result parse_and_get_value(const char* s, T& val, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_and_get_value(s, n, val); return parse_and_get_value(s, n, val, path);
} }
template <typename T> template <typename T>
Result parse_and_get_value(const char* s, size_t n, any& dt, T& val) const { Result parse_and_get_value(const char* s, size_t n, any& dt, T& val, const char* path = nullptr) const {
SemanticValues sv; SemanticValues sv;
auto r = parse_core(s, n, sv, dt); auto r = parse_core(s, n, sv, dt, path);
if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) { if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) {
val = sv[0].val.get<T>(); val = sv[0].val.get<T>();
} }
@ -1134,9 +1138,9 @@ public:
} }
template <typename T> template <typename T>
Result parse_and_get_value(const char* s, any& dt, T& val) const { Result parse_and_get_value(const char* s, any& dt, T& val, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_and_get_value(s, n, dt, val); return parse_and_get_value(s, n, dt, val, path);
} }
Definition& operator=(Action a) { Definition& operator=(Action a) {
@ -1173,11 +1177,11 @@ private:
Definition& operator=(const Definition& rhs); Definition& operator=(const Definition& rhs);
Definition& operator=(Definition&& rhs); Definition& operator=(Definition&& rhs);
Result parse_core(const char* s, size_t n, SemanticValues& sv, any& dt) const { Result parse_core(const char* s, size_t n, SemanticValues& sv, any& dt, const char* path) const {
AssignIDToDefinition assignId; AssignIDToDefinition assignId;
holder_->accept(assignId); holder_->accept(assignId);
Context cxt(s, n, assignId.ids.size(), enablePackratParsing); Context cxt(path, s, n, assignId.ids.size(), enablePackratParsing);
auto len = holder_->parse(s, n, sv, cxt, dt); auto len = holder_->parse(s, n, sv, cxt, dt);
return Result{ success(len), len, cxt.error_pos, cxt.message_pos, cxt.message }; return Result{ success(len), len, cxt.error_pos, cxt.message_pos, cxt.message };
} }
@ -1953,22 +1957,22 @@ inline constexpr unsigned int operator "" _(const char* s, size_t) {
struct Ast struct Ast
{ {
Ast(size_t line, size_t column, const char* name, const std::vector<std::shared_ptr<Ast>>& nodes) Ast(const char* path, size_t line, size_t column, const char* name, const std::vector<std::shared_ptr<Ast>>& nodes)
: line(line), column(column), name(name), original_name(name), is_token(false), nodes(nodes) : path(path), line(line), column(column), name(name), original_name(name), is_token(false), nodes(nodes)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT #ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(str2tag(name)), original_tag(tag) , tag(str2tag(name)), original_tag(tag)
#endif #endif
{} {}
Ast(size_t line, size_t column, const char* name, const std::string& token) Ast(const char* path, size_t line, size_t column, const char* name, const std::string& token)
: line(line), column(column), name(name), original_name(name), is_token(true), token(token) : path(path), line(line), column(column), name(name), original_name(name), is_token(true), token(token)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT #ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(str2tag(name)), original_tag(tag) , tag(str2tag(name)), original_tag(tag)
#endif #endif
{} {}
Ast(const Ast& ast, const char* original_name) Ast(const Ast& ast, const char* original_name)
: line(ast.line), column(ast.column), name(ast.name), original_name(original_name) : path(ast.path), line(ast.line), column(ast.column), name(ast.name), original_name(original_name)
, is_token(ast.is_token), token(ast.token), nodes(ast.nodes) , is_token(ast.is_token), token(ast.token), nodes(ast.nodes)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT #ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(ast.tag), original_tag(str2tag(original_name)) , tag(ast.tag), original_tag(str2tag(original_name))
@ -1979,6 +1983,7 @@ struct Ast
void print() const; void print() const;
const std::string path;
const size_t line; const size_t line;
const size_t column; const size_t column;
const std::string name; const std::string name;
@ -2079,41 +2084,41 @@ public:
return load_grammar(s, n); return load_grammar(s, n);
} }
bool parse_n(const char* s, size_t n) const { bool parse_n(const char* s, size_t n, const char* path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, n); auto r = rule.parse(s, n, path);
output_log(s, n, log, r); output_log(s, n, log, r);
return r.ret && r.len == n; return r.ret && r.len == n;
} }
return false; return false;
} }
bool parse(const char* s) const { bool parse(const char* s, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_n(s, n); return parse_n(s, n, path);
} }
bool parse_n(const char* s, size_t n, any& dt) const { bool parse_n(const char* s, size_t n, any& dt, const char* path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, n, dt); auto r = rule.parse(s, n, dt, path);
output_log(s, n, log, r); output_log(s, n, log, r);
return r.ret && r.len == n; return r.ret && r.len == n;
} }
return false; return false;
} }
bool parse(const char* s, any& dt) const { bool parse(const char* s, any& dt, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_n(s, n, dt); return parse_n(s, n, dt, path);
} }
template <typename T> template <typename T>
bool parse_n(const char* s, size_t n, T& val) const { bool parse_n(const char* s, size_t n, T& val, const char* path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse_and_get_value(s, n, val); auto r = rule.parse_and_get_value(s, n, val, path);
output_log(s, n, log, r); output_log(s, n, log, r);
return r.ret && r.len == n; return r.ret && r.len == n;
} }
@ -2121,16 +2126,16 @@ public:
} }
template <typename T> template <typename T>
bool parse(const char* s, T& val) const { bool parse(const char* s, T& val, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_n(s, n, val); return parse_n(s, n, val, path);
} }
template <typename T> template <typename T>
bool parse_n(const char* s, size_t n, any& dt, T& val) const { bool parse_n(const char* s, size_t n, any& dt, T& val, const char* path = nullptr) const {
if (grammar_ != nullptr) { if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_]; const auto& rule = (*grammar_)[start_];
auto r = rule.parse_and_get_value(s, n, dt, val); auto r = rule.parse_and_get_value(s, n, dt, val, path);
output_log(s, n, log, r); output_log(s, n, log, r);
return r.ret && r.len == n; return r.ret && r.len == n;
} }
@ -2138,7 +2143,7 @@ public:
} }
template <typename T> template <typename T>
bool parse(const char* s, any& dt, T& val) const { bool parse(const char* s, any& dt, T& val, const char* path = nullptr) const {
auto n = strlen(s); auto n = strlen(s);
return parse_n(s, n, dt, val); return parse_n(s, n, dt, val);
} }
@ -2179,7 +2184,7 @@ public:
} }
} }
peg& enable_ast(bool optimize_nodes, const std::initializer_list<std::string>& filters) { peg& enable_ast(bool optimize_nodes, const std::initializer_list<std::string>& filters = {}) {
for (auto& x: *grammar_) { for (auto& x: *grammar_) {
const auto& name = x.first; const auto& name = x.first;
auto& rule = x.second; auto& rule = x.second;
@ -2192,14 +2197,14 @@ public:
rule.action = [=](const SemanticValues& sv) { rule.action = [=](const SemanticValues& sv) {
if (is_token) { if (is_token) {
auto line = line_info(sv.ss, sv.s); auto line = line_info(sv.ss, sv.s);
return std::make_shared<Ast>(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));
} }
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()); auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
return ast; return ast;
} }
auto line = line_info(sv.ss, sv.s); auto line = line_info(sv.ss, sv.s);
return std::make_shared<Ast>(line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>()); return std::make_shared<Ast>(sv.path, line.first, line.second, name.c_str(), sv.transform<std::shared_ptr<Ast>>());
}; };
} }
} }