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)
include_directories(.)
add_definitions("-std=c++1y")
add_definitions("-std=c++1y" -DPEGLIB_HAS_CONSTEXPR_SUPPORT)
add_executable(peglint lint/peglint.cc)
target_link_libraries(peglint pthread)
@ -20,5 +20,5 @@ target_link_libraries(calc2 pthread)
add_executable(calc3 example/calc3.cc)
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)

View File

@ -8,7 +8,11 @@ namespace culebra {
const auto grammar_ = R"(
PROGRAM <- _ STATEMENTS
STATEMENTS <- (EXPRESSION (';' _)?)*
STATEMENTS <- (STATEMENT (';' _)?)*
STATEMENT <- DEBUGGER / EXPRESSION
DEBUGGER <- 'debugger' _
EXPRESSION <- ASSIGNMENT / LOGICAL_OR
ASSIGNMENT <- MUTABLE PRIMARY (ARGUMENTS / INDEX / DOT)* '=' _ EXPRESSION
@ -336,7 +340,10 @@ inline std::ostream& operator<<(std::ostream& os, const Value& val)
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) {
if (this->outer) {
@ -387,10 +394,15 @@ struct Environment
std::shared_ptr<Environment> outer;
std::shared_ptr<Environment> parent;
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;
inline bool ObjectValue::has(const std::string& name) const {
if (properties->find(name) == properties->end()) {
const auto& props = const_cast<ObjectValue*>(this)->builtins();
@ -521,9 +533,20 @@ inline void setup_built_in_functions(Environment& env) {
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"" _;
if (debugger_) {
if (ast.original_tag == "STATEMENT"_) {
auto force_to_break = ast.tag == "DEBUGGER"_;
debugger_(ast, env, force_to_break);
}
}
switch (ast.tag) {
case "STATEMENTS"_: return eval_statements(ast, env);
case "WHILE"_: return eval_while(ast, env);
@ -547,6 +570,7 @@ struct Eval
case "BOOLEAN"_: return eval_bool(ast, env);
case "NUMBER"_: return eval_number(ast, env);
case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env);
case "DEBUGGER"_: return Value();
}
if (ast.is_token) {
@ -558,7 +582,7 @@ struct Eval
}
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) {
return eval(ast, env);
} else if (ast.nodes.empty()) {
@ -572,7 +596,7 @@ private:
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 (;;) {
auto cond = eval(*ast.nodes[0], env);
if (!cond.to_bool()) {
@ -583,7 +607,7 @@ private:
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;
for (auto i = 0u; i < nodes.size(); i += 2) {
@ -600,7 +624,7 @@ private:
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;
for (auto node: ast.nodes[0]->nodes) {
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& params = *f.params;
const auto& args = ast.nodes;
if (params.size() <= args.size()) {
auto callEnv = std::make_shared<Environment>();
auto callEnv = std::make_shared<Environment>(env);
callEnv->initialize("self", val, false);
for (auto iprm = 0u; iprm < params.size(); iprm++) {
auto param = params[iprm];
@ -642,7 +666,7 @@ private:
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();
auto idx = eval(ast, env).to_long();
if (0 <= idx && idx < static_cast<long>(arr.values->size())) {
@ -653,7 +677,7 @@ private:
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();
auto name = ast.token;
if (!obj.has(name)) {
@ -673,7 +697,7 @@ private:
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"" _;
Value val = eval(*ast.nodes[0], env);
@ -692,11 +716,11 @@ private:
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();
}
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.
Value val;
for (auto node: ast.nodes) {
@ -708,7 +732,7 @@ private:
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;
for (auto node: ast.nodes) {
val = eval(*node, env);
@ -719,7 +743,7 @@ private:
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.
auto lhs = eval(*ast.nodes[0], env);
@ -735,22 +759,22 @@ private:
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.
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.
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.
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();
for (auto i = 1u; i < ast.nodes.size(); i += 2) {
auto val = eval(*ast.nodes[i + 1], env).to_long();
@ -766,7 +790,7 @@ private:
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 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);
};
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;
for (auto i = 0u; i < ast.nodes.size(); i++) {
const auto& prop = *ast.nodes[i];
@ -842,7 +866,7 @@ private:
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;
for (auto i = 0u; i < ast.nodes.size(); i++) {
auto expr = ast.nodes[i];
@ -852,19 +876,19 @@ private:
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();
};
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");
};
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));
};
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;
for (auto node: ast.nodes) {
const auto& val = eval(*node, env);
@ -876,6 +900,8 @@ private:
}
return Value(std::move(s));
};
Debugger debugger_;
};
inline bool run(
@ -884,8 +910,9 @@ inline bool run(
const char* expr,
size_t len,
Value& val,
std::string& msg,
bool print_ast)
std::vector<std::string>& msgs,
std::shared_ptr<peglib::Ast>& ast,
Debugger debugger = nullptr)
{
try {
auto& parser = get_parser();
@ -893,21 +920,15 @@ inline bool run(
parser.log = [&](size_t ln, size_t col, const std::string& err_msg) {
std::stringstream ss;
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)) {
if (print_ast) {
ast->print();
}
val = Eval::eval(*ast, env);
if (parser.parse_n(expr, len, ast, path.c_str())) {
val = Eval(debugger).eval(*ast, env);
return true;
}
} catch (std::runtime_error& e) {
msg = e.what();
msgs.push_back(e.what());
}
return false;

View File

@ -24,6 +24,49 @@ bool read_file(const char* path, vector<char>& buff)
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)
{
for (;;) {
@ -35,15 +78,22 @@ int repl(shared_ptr<Environment> env, bool print_ast)
if (!line.empty()) {
Value val;
string msg;
if (run("(repl)", env, line.c_str(), line.size(), val, msg, print_ast)) {
vector<string> msgs;
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;
linenoise::AddHistory(line.c_str());
} else if (!msg.empty()) {
} else if (!msgs.empty()) {
for (const auto& msg: msgs) {
cout << msg << endl;;
}
}
}
}
return 0;
}
@ -52,6 +102,7 @@ int main(int argc, const char** argv)
{
auto print_ast = false;
auto shell = false;
auto debug = false;
vector<const char*> path_list;
int argi = 1;
@ -61,6 +112,8 @@ int main(int argc, const char** argv)
shell = true;
} else if (string("--ast") == arg) {
print_ast = true;
} else if (string("--debug") == arg) {
debug = true;
} else {
path_list.push_back(arg);
}
@ -82,10 +135,24 @@ int main(int argc, const char** argv)
}
Value val;
string msg;
if (!run(path, env, buff.data(), buff.size(), val, msg, print_ast)) {
vector<string> msgs;
std::shared_ptr<peglib::Ast> ast;
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;
} else if (print_ast) {
ast->print();
}
}

View File

@ -180,6 +180,7 @@ struct SemanticValue
struct SemanticValues : protected std::vector<SemanticValue>
{
const char* path;
const char* ss;
const char* s;
size_t n;
@ -407,6 +408,7 @@ inline bool fail(size_t len) {
*/
struct Context
{
const char* path;
const char* s;
size_t l;
@ -423,8 +425,9 @@ struct Context
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)
: s(s)
Context(const char* path, const char* s, size_t l, size_t def_count, bool enablePackratParsing)
: path(path)
, s(s)
, l(l)
, error_pos(nullptr)
, message_pos(nullptr)
@ -475,6 +478,7 @@ struct Context
if (!sv.empty()) {
sv.clear();
}
sv.path = path;
sv.ss = s;
sv.s = nullptr;
sv.n = 0;
@ -1085,32 +1089,32 @@ public:
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;
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);
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;
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);
return parse(s, n, dt);
return parse(s, n, dt, path);
}
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;
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()) {
val = sv[0].val.get<T>();
}
@ -1118,15 +1122,15 @@ public:
}
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);
return parse_and_get_value(s, n, val);
return parse_and_get_value(s, n, val, path);
}
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;
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()) {
val = sv[0].val.get<T>();
}
@ -1134,9 +1138,9 @@ public:
}
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);
return parse_and_get_value(s, n, dt, val);
return parse_and_get_value(s, n, dt, val, path);
}
Definition& operator=(Action a) {
@ -1173,11 +1177,11 @@ private:
Definition& operator=(const 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;
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);
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
{
Ast(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)
Ast(const char* path, size_t line, size_t column, const char* name, const std::vector<std::shared_ptr<Ast>>& nodes)
: path(path), line(line), column(column), name(name), original_name(name), is_token(false), nodes(nodes)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(str2tag(name)), original_tag(tag)
#endif
{}
Ast(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)
Ast(const char* path, size_t line, size_t column, const char* name, const std::string& token)
: path(path), line(line), column(column), name(name), original_name(name), is_token(true), token(token)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(str2tag(name)), original_tag(tag)
#endif
{}
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)
#ifdef PEGLIB_HAS_CONSTEXPR_SUPPORT
, tag(ast.tag), original_tag(str2tag(original_name))
@ -1979,6 +1983,7 @@ struct Ast
void print() const;
const std::string path;
const size_t line;
const size_t column;
const std::string name;
@ -2079,41 +2084,41 @@ public:
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) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, n);
auto r = rule.parse(s, n, path);
output_log(s, n, log, r);
return r.ret && r.len == n;
}
return false;
}
bool parse(const char* s) const {
bool parse(const char* s, const char* path = nullptr) const {
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) {
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);
return r.ret && r.len == n;
}
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);
return parse_n(s, n, dt);
return parse_n(s, n, dt, path);
}
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) {
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);
return r.ret && r.len == n;
}
@ -2121,16 +2126,16 @@ public:
}
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);
return parse_n(s, n, val);
return parse_n(s, n, val, path);
}
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) {
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);
return r.ret && r.len == n;
}
@ -2138,7 +2143,7 @@ public:
}
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);
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_) {
const auto& name = x.first;
auto& rule = x.second;
@ -2192,14 +2197,14 @@ public:
rule.action = [=](const SemanticValues& sv) {
if (is_token) {
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) {
auto ast = std::make_shared<Ast>(*sv[0].get<std::shared_ptr<Ast>>(), name.c_str());
return ast;
}
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>>());
};
}
}