mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added command-line debugger support.
This commit is contained in:
parent
24b3da5d0f
commit
5d6755ff64
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
peglib.h
91
peglib.h
@ -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>>());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user