implement delayed heredocument parsing
This commit is contained in:
parent
3e21098d95
commit
15ac04f505
6 changed files with 292 additions and 281 deletions
|
|
@ -6,6 +6,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#define SPACES " \t"
|
#define SPACES " \t"
|
||||||
#define SEPARATORS " \t\n"
|
#define SEPARATORS " \t\n"
|
||||||
|
|
@ -33,9 +34,13 @@
|
||||||
|
|
||||||
// structs
|
// structs
|
||||||
|
|
||||||
void parse_error(std::string const& message, parse_context& ctx);
|
struct list_parse_options {
|
||||||
|
char end_char=0;
|
||||||
|
bool word_mode=false;
|
||||||
|
std::vector<std::string> end_words={};
|
||||||
|
const char* expecting=NULL;
|
||||||
|
};
|
||||||
|
|
||||||
void parse_error(std::string const& message, parse_context& ctx, uint64_t i);
|
|
||||||
// globals
|
// globals
|
||||||
|
|
||||||
extern const std::vector<std::string> posix_cmdvar;
|
extern const std::vector<std::string> posix_cmdvar;
|
||||||
|
|
@ -48,12 +53,17 @@ std::pair<shmain*, parse_context> parse_text(std::string const& in, std::string
|
||||||
inline std::pair<shmain*, parse_context> parse(std::string const& file) { return parse_text(import_file(file), file); }
|
inline std::pair<shmain*, parse_context> parse(std::string const& file) { return parse_text(import_file(file), file); }
|
||||||
|
|
||||||
// tools
|
// tools
|
||||||
|
|
||||||
parse_context make_context(std::string const& in, std::string const& filename="", bool bash=false);
|
parse_context make_context(std::string const& in, std::string const& filename="", bool bash=false);
|
||||||
parse_context make_context(parse_context ctx, std::string const& in="", std::string const& filename="", bool bash=false);
|
parse_context make_context(parse_context ctx, std::string const& in="", std::string const& filename="", bool bash=false);
|
||||||
parse_context make_context(parse_context ctx, uint64_t i);
|
parse_context make_context(parse_context ctx, uint64_t i);
|
||||||
parse_context operator+(parse_context ctx, int64_t a);
|
parse_context operator+(parse_context ctx, int64_t a);
|
||||||
parse_context operator-(parse_context ctx, int64_t a);
|
parse_context operator-(parse_context ctx, int64_t a);
|
||||||
|
|
||||||
|
// error handlers
|
||||||
|
void parse_error(std::string const& message, parse_context& ctx);
|
||||||
|
void parse_error(std::string const& message, parse_context& ctx, uint64_t i);
|
||||||
|
|
||||||
// ** unit parsers ** //
|
// ** unit parsers ** //
|
||||||
|
|
||||||
/* util parsers */
|
/* util parsers */
|
||||||
|
|
@ -76,9 +86,10 @@ inline uint32_t skip_unread(parse_context const& ct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// list
|
// list
|
||||||
std::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL);
|
// std::pair<list*, parse_context> parse_list_until(parse_context ct, char end_c, const char* expecting=NULL);
|
||||||
std::pair<list*, parse_context> parse_list_until(parse_context ct, std::string const& end_word);
|
// std::pair<list*, parse_context> parse_list_until(parse_context ct, std::string const& end_word);
|
||||||
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
// std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, std::vector<std::string> const& end_words, const char* expecting=NULL);
|
||||||
|
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ct, list_parse_options opts={});
|
||||||
// name
|
// name
|
||||||
std::pair<variable*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
|
std::pair<variable*, parse_context> parse_var(parse_context ct, bool specialvars=true, bool array=false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,21 @@ subarg: can be one of
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// pre-definitions
|
||||||
|
|
||||||
|
#define AND_OP false
|
||||||
|
#define OR_OP true
|
||||||
|
|
||||||
|
class condlist;
|
||||||
|
class block;
|
||||||
|
class pipeline;
|
||||||
|
class arg;
|
||||||
|
class subarg;
|
||||||
|
class cmd;
|
||||||
|
class redirect;
|
||||||
|
|
||||||
|
// structs
|
||||||
|
|
||||||
struct parse_context {
|
struct parse_context {
|
||||||
const char* data=NULL;
|
const char* data=NULL;
|
||||||
uint64_t size=0;
|
uint64_t size=0;
|
||||||
|
|
@ -73,9 +88,16 @@ struct parse_context {
|
||||||
const char* here_doc="";
|
const char* here_doc="";
|
||||||
const char operator[](uint64_t a) { return data[a]; }
|
const char operator[](uint64_t a) { return data[a]; }
|
||||||
bool has_errored=false;
|
bool has_errored=false;
|
||||||
|
redirect* here_document=nullptr;
|
||||||
|
char* here_delimitor=NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct generate_context {
|
||||||
|
arg* here_document=nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// exceptions
|
// exceptions
|
||||||
|
|
||||||
class format_error : public std::exception
|
class format_error : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -97,20 +119,8 @@ private:
|
||||||
std::string sdat;
|
std::string sdat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// objects
|
// objects
|
||||||
|
|
||||||
|
|
||||||
#define AND_OP false
|
|
||||||
#define OR_OP true
|
|
||||||
|
|
||||||
class condlist;
|
|
||||||
class block;
|
|
||||||
class pipeline;
|
|
||||||
class arg;
|
|
||||||
class subarg;
|
|
||||||
class cmd;
|
|
||||||
|
|
||||||
// type pack of condlist
|
// type pack of condlist
|
||||||
typedef std::vector<arg*> arglist_t;
|
typedef std::vector<arg*> arglist_t;
|
||||||
|
|
||||||
|
|
@ -229,15 +239,17 @@ public:
|
||||||
class redirect : public _obj
|
class redirect : public _obj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; }
|
redirect(std::string strop="") { type=_obj::_redirect; op=strop; target=nullptr; here_document=nullptr; }
|
||||||
redirect(arg* in) { type=_obj::_redirect; target=in; }
|
redirect(arg* in) { type=_obj::_redirect; target=in; here_document=nullptr; }
|
||||||
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; }
|
redirect(std::string strop, arg* in) { type=_obj::_redirect; op=strop; target=in; here_document=nullptr; }
|
||||||
|
redirect(std::string strop, arg* in, arg* doc) { type=_obj::_redirect; op=strop; target=in; here_document=doc; }
|
||||||
~redirect() { if(target != nullptr) delete target; }
|
~redirect() { if(target != nullptr) delete target; }
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind);
|
||||||
|
|
||||||
std::string op;
|
std::string op;
|
||||||
arg* target;
|
arg* target;
|
||||||
|
arg* here_document;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Meta block
|
// Meta block
|
||||||
|
|
@ -252,9 +264,9 @@ public:
|
||||||
// subshell: return the containing cmd, if it is a single command
|
// subshell: return the containing cmd, if it is a single command
|
||||||
cmd* single_cmd();
|
cmd* single_cmd();
|
||||||
|
|
||||||
std::string generate_redirs(int ind, std::string const& _str);
|
std::string generate_redirs(int ind, std::string const& _str, generate_context* ctx);
|
||||||
|
|
||||||
virtual std::string generate(int ind)=0;
|
virtual std::string generate(int ind, generate_context* ctx)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// PL
|
// PL
|
||||||
|
|
@ -269,7 +281,8 @@ public:
|
||||||
|
|
||||||
bool negated; // negated return value (! at start)
|
bool negated; // negated return value (! at start)
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); };
|
||||||
};
|
};
|
||||||
|
|
||||||
// CL
|
// CL
|
||||||
|
|
@ -370,7 +383,8 @@ public:
|
||||||
|
|
||||||
arglist* args;
|
arglist* args;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class shmain : public block
|
class shmain : public block
|
||||||
|
|
@ -388,7 +402,8 @@ public:
|
||||||
list* lst;
|
list* lst;
|
||||||
|
|
||||||
std::string generate(bool print_shebang=true, int ind=0);
|
std::string generate(bool print_shebang=true, int ind=0);
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class subshell : public block
|
class subshell : public block
|
||||||
|
|
@ -404,7 +419,8 @@ public:
|
||||||
|
|
||||||
list* lst;
|
list* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class brace : public block
|
class brace : public block
|
||||||
|
|
@ -419,7 +435,8 @@ public:
|
||||||
|
|
||||||
list* lst;
|
list* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class function : public block
|
class function : public block
|
||||||
|
|
@ -433,7 +450,8 @@ public:
|
||||||
std::string name;
|
std::string name;
|
||||||
list* lst;
|
list* lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class case_block : public block
|
class case_block : public block
|
||||||
|
|
@ -453,7 +471,8 @@ public:
|
||||||
arg* carg;
|
arg* carg;
|
||||||
std::vector< std::pair<std::vector<arg*>, list*> > cases;
|
std::vector< std::pair<std::vector<arg*>, list*> > cases;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class if_block : public block
|
class if_block : public block
|
||||||
|
|
@ -473,7 +492,8 @@ public:
|
||||||
|
|
||||||
list* else_lst;
|
list* else_lst;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class for_block : public block
|
class for_block : public block
|
||||||
|
|
@ -491,7 +511,8 @@ public:
|
||||||
arglist* iter;
|
arglist* iter;
|
||||||
list* ops;
|
list* ops;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class while_block : public block
|
class while_block : public block
|
||||||
|
|
@ -508,7 +529,8 @@ public:
|
||||||
list* cond;
|
list* cond;
|
||||||
list* ops;
|
list* ops;
|
||||||
|
|
||||||
std::string generate(int ind);
|
std::string generate(int ind, generate_context* ctx);
|
||||||
|
std::string generate(int ind) { return this->generate(ind, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subarg subtypes //
|
// Subarg subtypes //
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ void parse_exec(FILE* fd, parse_context ctx)
|
||||||
ctx=pp.second;
|
ctx=pp.second;
|
||||||
if(ctx.has_errored)
|
if(ctx.has_errored)
|
||||||
{
|
{
|
||||||
parse_list_until(ctx, 0);
|
parse_list_until(ctx);
|
||||||
throw std::runtime_error("Aborting due to previous errors");
|
throw std::runtime_error("Aborting due to previous errors");
|
||||||
}
|
}
|
||||||
t_lst->add(pp.first);
|
t_lst->add(pp.first);
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ std::string arglist::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pipeline::generate(int ind)
|
std::string pipeline::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -53,11 +53,11 @@ std::string pipeline::generate(int ind)
|
||||||
|
|
||||||
if(negated)
|
if(negated)
|
||||||
ret += "! ";
|
ret += "! ";
|
||||||
ret += cmds[0]->generate(ind);
|
ret += cmds[0]->generate(ind, ctx);
|
||||||
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
||||||
{
|
{
|
||||||
ret += opt_minify ? "|" : " | " ;
|
ret += opt_minify ? "|" : " | " ;
|
||||||
ret += cmds[i]->generate(ind);
|
ret += cmds[i]->generate(ind, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -68,18 +68,27 @@ std::string condlist::generate(int ind)
|
||||||
std::string ret;
|
std::string ret;
|
||||||
if(pls.size() <= 0)
|
if(pls.size() <= 0)
|
||||||
return "";
|
return "";
|
||||||
ret += pls[0]->generate(ind);
|
generate_context ctx;
|
||||||
|
ret += pls[0]->generate(ind, &ctx);
|
||||||
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
||||||
{
|
{
|
||||||
if(or_ops[i])
|
if(or_ops[i])
|
||||||
ret += opt_minify ? "||" : " || ";
|
ret += opt_minify ? "||" : " || ";
|
||||||
else
|
else
|
||||||
ret += opt_minify ? "&&" : " && ";
|
ret += opt_minify ? "&&" : " && ";
|
||||||
ret += pls[i+1]->generate(ind);
|
ret += pls[i+1]->generate(ind, &ctx);
|
||||||
}
|
}
|
||||||
if(ret=="")
|
if(ret=="")
|
||||||
return "";
|
return "";
|
||||||
if(parallel)
|
if(ctx.here_document != nullptr)
|
||||||
|
{
|
||||||
|
if(parallel)
|
||||||
|
ret += '&';
|
||||||
|
ret += '\n';
|
||||||
|
ret += ctx.here_document->generate(0);
|
||||||
|
ret += '\n';
|
||||||
|
}
|
||||||
|
else if(parallel)
|
||||||
{
|
{
|
||||||
ret += opt_minify ? "&" : " &\n";
|
ret += opt_minify ? "&" : " &\n";
|
||||||
}
|
}
|
||||||
|
|
@ -123,12 +132,18 @@ std::string redirect::generate(int ind)
|
||||||
|
|
||||||
// BLOCK
|
// BLOCK
|
||||||
|
|
||||||
std::string block::generate_redirs(int ind, std::string const& _str)
|
std::string block::generate_redirs(int ind, std::string const& _str, generate_context* ctx=nullptr)
|
||||||
{
|
{
|
||||||
std::string ret=" ";
|
std::string ret=" ";
|
||||||
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
bool previous_isnt_num = _str.size()>0 && !is_num(_str[_str.size()-1]);
|
||||||
for(auto it: redirs)
|
for(auto it: redirs)
|
||||||
{
|
{
|
||||||
|
if(ctx != nullptr && it->here_document != nullptr)
|
||||||
|
{
|
||||||
|
if(ctx->here_document != nullptr)
|
||||||
|
throw std::runtime_error("Unsupported generation of concurrent here documents");
|
||||||
|
ctx->here_document = it->here_document;
|
||||||
|
}
|
||||||
std::string _r = it->generate(0);
|
std::string _r = it->generate(0);
|
||||||
if(opt_minify && _r.size() > 0 && !is_num(_r[0]) && previous_isnt_num)
|
if(opt_minify && _r.size() > 0 && !is_num(_r[0]) && previous_isnt_num)
|
||||||
ret.pop_back(); // remove one space if possible
|
ret.pop_back(); // remove one space if possible
|
||||||
|
|
@ -139,7 +154,7 @@ std::string block::generate_redirs(int ind, std::string const& _str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string if_block::generate(int ind)
|
std::string if_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -169,11 +184,11 @@ std::string if_block::generate(int ind)
|
||||||
|
|
||||||
ret += indented("fi", ind);
|
ret += indented("fi", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string for_block::generate(int ind)
|
std::string for_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -187,11 +202,11 @@ std::string for_block::generate(int ind)
|
||||||
|
|
||||||
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string while_block::generate(int ind)
|
std::string while_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -207,11 +222,11 @@ std::string while_block::generate(int ind)
|
||||||
|
|
||||||
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
if(opt_minify && ret.size()>1 && !is_alpha(ret[ret.size()-2]))
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string subshell::generate(int ind)
|
std::string subshell::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// open subshell
|
// open subshell
|
||||||
|
|
@ -224,11 +239,11 @@ std::string subshell::generate(int ind)
|
||||||
// close subshell
|
// close subshell
|
||||||
ret += indented(")", ind);
|
ret += indented(")", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string shmain::generate(int ind)
|
std::string shmain::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
return this->generate(false, ind);
|
return this->generate(false, ind);
|
||||||
}
|
}
|
||||||
|
|
@ -241,11 +256,10 @@ std::string shmain::generate(bool print_shebang, int ind)
|
||||||
if( opt_minify && ret[ret.size()-1] == '\n')
|
if( opt_minify && ret[ret.size()-1] == '\n')
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string brace::generate(int ind)
|
std::string brace::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
|
|
@ -253,11 +267,11 @@ std::string brace::generate(int ind)
|
||||||
ret += lst->generate(ind+1);
|
ret += lst->generate(ind+1);
|
||||||
ret += indented("}", ind);
|
ret += indented("}", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string function::generate(int ind)
|
std::string function::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// function definition
|
// function definition
|
||||||
|
|
@ -268,11 +282,11 @@ std::string function::generate(int ind)
|
||||||
ret += lst->generate(ind+1);
|
ret += lst->generate(ind+1);
|
||||||
ret += indented("}", ind);
|
ret += indented("}", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string case_block::generate(int ind)
|
std::string case_block::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret += "case " + carg->generate(ind) + " in\n";
|
ret += "case " + carg->generate(ind) + " in\n";
|
||||||
|
|
@ -307,14 +321,15 @@ std::string case_block::generate(int ind)
|
||||||
ind--;
|
ind--;
|
||||||
ret += indented("esac", ind);
|
ret += indented("esac", ind);
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmd::generate(int ind)
|
std::string cmd::generate(int ind, generate_context* ctx)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// var assigns
|
|
||||||
|
// is a varassign cmd
|
||||||
if(is_cmdvar)
|
if(is_cmdvar)
|
||||||
{
|
{
|
||||||
ret += args->generate(ind) + ' ';
|
ret += args->generate(ind) + ' ';
|
||||||
|
|
@ -330,6 +345,7 @@ std::string cmd::generate(int ind)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pre-cmd var assigns
|
||||||
for(auto it: var_assigns)
|
for(auto it: var_assigns)
|
||||||
{
|
{
|
||||||
if(it.first != nullptr)
|
if(it.first != nullptr)
|
||||||
|
|
@ -339,6 +355,7 @@ std::string cmd::generate(int ind)
|
||||||
ret += ' ';
|
ret += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cmd itself
|
||||||
if(args!=nullptr && args->size()>0)
|
if(args!=nullptr && args->size()>0)
|
||||||
{
|
{
|
||||||
// command
|
// command
|
||||||
|
|
@ -353,7 +370,7 @@ std::string cmd::generate(int ind)
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += generate_redirs(ind, ret);
|
ret += generate_redirs(ind, ret, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
402
src/parse.cpp
402
src/parse.cpp
|
|
@ -25,7 +25,6 @@ const std::vector<std::string> out_reserved_words = { "then", "else", "fi", "esa
|
||||||
|
|
||||||
// stuff
|
// stuff
|
||||||
|
|
||||||
|
|
||||||
std::string unexpected_token(char c)
|
std::string unexpected_token(char c)
|
||||||
{
|
{
|
||||||
std::string print;
|
std::string print;
|
||||||
|
|
@ -442,9 +441,9 @@ parse_context do_one_subarg_step(arg* ret, parse_context ctx, uint32_t& j, bool
|
||||||
// get subshell
|
// get subshell
|
||||||
parse_context newct = ctx;
|
parse_context newct = ctx;
|
||||||
ctx.size=k;
|
ctx.size=k;
|
||||||
auto r=parse_list_until(newct, 0);
|
auto r=parse_list_until(newct);
|
||||||
ret->add(new subshell_subarg(new subshell(r.first), is_quoted));
|
ret->add(new subshell_subarg(new subshell(std::get<0>(r)), is_quoted));
|
||||||
ctx = r.second;
|
ctx = std::get<1>(r);
|
||||||
ctx.i++;
|
ctx.i++;
|
||||||
j = ctx.i;
|
j = ctx.i;
|
||||||
}
|
}
|
||||||
|
|
@ -617,6 +616,35 @@ std::pair<arg*, parse_context> parse_arg(parse_context ctx, const char* end, con
|
||||||
return std::make_pair(ret, ctx);
|
return std::make_pair(ret, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_context parse_heredocument(parse_context ctx)
|
||||||
|
{
|
||||||
|
if(ctx.here_document == nullptr)
|
||||||
|
return ctx;
|
||||||
|
|
||||||
|
uint32_t j=ctx.i;
|
||||||
|
char* tc=NULL;
|
||||||
|
std::string delimitor=ctx.here_delimitor;
|
||||||
|
tc = (char*) strstr(ctx.data+ctx.i, std::string("\n"+delimitor+"\n").c_str()); // find delimitor
|
||||||
|
if(tc!=NULL) // delimitor was found
|
||||||
|
{
|
||||||
|
ctx.i = (tc-ctx.data)+delimitor.size()+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.i = ctx.size;
|
||||||
|
}
|
||||||
|
// std::string tmpparse=std::string(ctx.data+j, ctx.i-j);
|
||||||
|
auto pval = parse_arg({ .data=ctx.data, .size=ctx.i, .i=j, .bash=ctx.bash} , NULL);
|
||||||
|
ctx.here_document->here_document = pval.first;
|
||||||
|
|
||||||
|
//
|
||||||
|
ctx.here_document=nullptr;
|
||||||
|
free(ctx.here_delimitor);
|
||||||
|
ctx.here_delimitor=NULL;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
|
std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
|
||||||
{
|
{
|
||||||
bool is_redirect=false;
|
bool is_redirect=false;
|
||||||
|
|
@ -717,14 +745,20 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
|
||||||
ctx.i = skip_chars(ctx, SPACES);
|
ctx.i = skip_chars(ctx, SPACES);
|
||||||
if(ret->op == "<<")
|
if(ret->op == "<<")
|
||||||
{
|
{
|
||||||
|
if(ctx.here_document != nullptr)
|
||||||
|
{
|
||||||
|
parse_error("unsupported multiple here documents at the same time", ctx);
|
||||||
|
return std::make_pair(ret, ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx.here_document=ret;
|
||||||
|
|
||||||
auto pa = parse_arg(ctx);
|
auto pa = parse_arg(ctx);
|
||||||
std::string delimitor = pa.first->string();
|
std::string delimitor = pa.first->string();
|
||||||
delete pa.first;
|
|
||||||
pa.first = nullptr;
|
|
||||||
|
|
||||||
if(delimitor == "")
|
if(delimitor == "")
|
||||||
{
|
{
|
||||||
parse_error("Non-static or empty text input delimitor", ctx);
|
parse_error("non-static or empty here document delimitor", ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(delimitor.find('"') != std::string::npos || delimitor.find('\'') != std::string::npos || delimitor.find('\\') != std::string::npos)
|
if(delimitor.find('"') != std::string::npos || delimitor.find('\'') != std::string::npos || delimitor.find('\\') != std::string::npos)
|
||||||
|
|
@ -732,34 +766,11 @@ std::pair<redirect*, parse_context> parse_redirect(parse_context ctx)
|
||||||
delimitor = ztd::sh("echo "+delimitor); // shell resolve the delimitor
|
delimitor = ztd::sh("echo "+delimitor); // shell resolve the delimitor
|
||||||
delimitor.pop_back(); // remove \n
|
delimitor.pop_back(); // remove \n
|
||||||
}
|
}
|
||||||
|
ret->target = pa.first;
|
||||||
ctx = pa.second;
|
ctx = pa.second;
|
||||||
ctx.i = skip_chars(ctx, SPACES); // skip spaces
|
// copy delimitor
|
||||||
|
ctx.here_delimitor = (char*) malloc(delimitor.length()+1);
|
||||||
if(ctx[ctx.i] == '#') // skip comment
|
strcpy(ctx.here_delimitor, delimitor.c_str());
|
||||||
ctx.i = skip_until(ctx, "\n"); //skip to endline
|
|
||||||
if(ctx[ctx.i] != '\n') // has another arg
|
|
||||||
{
|
|
||||||
parse_error("Additionnal argument after text input delimitor", ctx);
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.i++;
|
|
||||||
uint32_t j=ctx.i;
|
|
||||||
char* tc=NULL;
|
|
||||||
tc = (char*) strstr(ctx.data+ctx.i, std::string("\n"+delimitor+"\n").c_str()); // find delimitor
|
|
||||||
if(tc!=NULL) // delimitor was found
|
|
||||||
{
|
|
||||||
ctx.i = (tc-ctx.data)+delimitor.size()+1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx.i = ctx.size;
|
|
||||||
}
|
|
||||||
std::string tmpparse=std::string(ctx.data+j, ctx.i-j);
|
|
||||||
auto pval = parse_arg({ .data=tmpparse.c_str(), .size=tmpparse.size(), .i=0, .bash=ctx.bash}, NULL);
|
|
||||||
ret->target = pval.first;
|
|
||||||
ret->target->insert(0, delimitor+"\n");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1017,67 +1028,7 @@ std::pair<condlist*, parse_context> parse_condlist(parse_context ctx)
|
||||||
return std::make_pair(ret, ctx);
|
return std::make_pair(ret, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<list*, parse_context> parse_list_until(parse_context ctx, char end_c, const char* expecting)
|
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx, list_parse_options opts)
|
||||||
{
|
|
||||||
list* ret = new list;
|
|
||||||
ctx.i=skip_unread(ctx);
|
|
||||||
|
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
const char* old_expect=ctx.expecting;
|
|
||||||
if(ctx.expecting!=NULL)
|
|
||||||
ctx.expecting = expecting;
|
|
||||||
|
|
||||||
while(ctx[ctx.i] != end_c)
|
|
||||||
{
|
|
||||||
auto pp=parse_condlist(ctx);
|
|
||||||
ret->add(pp.first);
|
|
||||||
ctx=pp.second;
|
|
||||||
|
|
||||||
if(ctx.i < ctx.size)
|
|
||||||
{
|
|
||||||
if(ctx[ctx.i] == end_c) // end char, stop here
|
|
||||||
break;
|
|
||||||
else if(ctx[ctx.i] == '#')
|
|
||||||
; // skip here
|
|
||||||
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
|
||||||
ctx.i++; // skip on next char
|
|
||||||
else if(is_in(ctx[ctx.i], CONTROL_END))
|
|
||||||
{
|
|
||||||
parse_error( unexpected_token(ctx[ctx.i]), ctx);
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.i = skip_unread(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ctx.i>=ctx.size)
|
|
||||||
{
|
|
||||||
if(end_c != 0)
|
|
||||||
{
|
|
||||||
parse_error(strf("Expecting '%s'", expecting), ctx);
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.expecting = old_expect;
|
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
}
|
|
||||||
catch(format_error& e)
|
|
||||||
{
|
|
||||||
delete ret;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<list*, parse_context> parse_list_until(parse_context ctx, std::string const& end_word)
|
|
||||||
{
|
{
|
||||||
list* ret = new list;
|
list* ret = new list;
|
||||||
ctx.i=skip_unread(ctx);
|
ctx.i=skip_unread(ctx);
|
||||||
|
|
@ -1088,114 +1039,114 @@ std::pair<list*, parse_context> parse_list_until(parse_context ctx, std::string
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
char& end_c = opts.end_char;
|
||||||
|
std::vector<std::string>& end_words = opts.end_words;
|
||||||
|
|
||||||
const char* old_expect=ctx.expecting;
|
const char* old_expect=ctx.expecting;
|
||||||
|
|
||||||
ctx.expecting=end_word.c_str();
|
if(opts.expecting!=NULL)
|
||||||
|
ctx.expecting=opts.expecting;
|
||||||
while(true)
|
else if(opts.word_mode)
|
||||||
{
|
|
||||||
// check word
|
|
||||||
auto wp=get_word(ctx, ARG_END);
|
|
||||||
if(wp.first == end_word)
|
|
||||||
{
|
|
||||||
ctx.i=wp.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// do a parse
|
|
||||||
auto pp=parse_condlist(ctx);
|
|
||||||
ret->add(pp.first);
|
|
||||||
ctx=pp.second;
|
|
||||||
if(ctx.i<ctx.size)
|
|
||||||
{
|
|
||||||
if(ctx[ctx.i] == '#')
|
|
||||||
; // skip here
|
|
||||||
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
|
||||||
ctx.i++;
|
|
||||||
else if(is_in(ctx[ctx.i], CONTROL_END))
|
|
||||||
{
|
|
||||||
parse_error(unexpected_token(ctx[ctx.i]), ctx);
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.i = skip_unread(ctx);
|
|
||||||
}
|
|
||||||
// word wasn't found
|
|
||||||
if(ctx.i>=ctx.size)
|
|
||||||
{
|
|
||||||
parse_error(strf("Expecting '%s'", ctx.expecting), ctx);
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.expecting=old_expect;
|
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
}
|
|
||||||
catch(format_error& e)
|
|
||||||
{
|
|
||||||
delete ret;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return std::make_pair(ret, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::tuple<list*, parse_context, std::string> parse_list_until(parse_context ctx, std::vector<std::string> const& end_words, const char* expecting)
|
|
||||||
{
|
|
||||||
list* ret = new list;
|
|
||||||
ctx.i=skip_unread(ctx);
|
|
||||||
std::string found_end_word;
|
|
||||||
|
|
||||||
#ifndef NO_PARSE_CATCH
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
const char* old_expect=ctx.expecting;
|
|
||||||
|
|
||||||
if(expecting!=NULL)
|
|
||||||
ctx.expecting=expecting;
|
|
||||||
else
|
|
||||||
ctx.expecting=end_words[0].c_str();
|
ctx.expecting=end_words[0].c_str();
|
||||||
|
else
|
||||||
|
ctx.expecting=std::string(&end_c, 1).c_str();
|
||||||
|
|
||||||
bool stop=false;
|
bool stop=false;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
// check words
|
if(opts.word_mode)
|
||||||
auto wp=get_word(ctx, ARG_END);
|
|
||||||
for(auto it: end_words)
|
|
||||||
{
|
{
|
||||||
if(it == ";" && ctx[ctx.i] == ';')
|
// check words
|
||||||
|
auto wp=get_word(ctx, ARG_END);
|
||||||
|
for(auto it: end_words)
|
||||||
{
|
{
|
||||||
found_end_word=";";
|
if(it == ";" && ctx[ctx.i] == ';')
|
||||||
ctx.i++;
|
{
|
||||||
stop=true;
|
found_end_word=";";
|
||||||
break;
|
ctx.i++;
|
||||||
|
stop=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(wp.first == it)
|
||||||
|
{
|
||||||
|
found_end_word=it;
|
||||||
|
ctx.i=wp.second;
|
||||||
|
stop=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(wp.first == it)
|
if(stop)
|
||||||
{
|
|
||||||
found_end_word=it;
|
|
||||||
ctx.i=wp.second;
|
|
||||||
stop=true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(stop)
|
else if(ctx[ctx.i] == end_c)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// do a parse
|
// do a parse
|
||||||
auto pp=parse_condlist(ctx);
|
auto pp=parse_condlist(ctx);
|
||||||
ret->add(pp.first);
|
ret->add(pp.first);
|
||||||
ctx=pp.second;
|
ctx=pp.second;
|
||||||
if(ctx[ctx.i] == '#')
|
|
||||||
|
if(!opts.word_mode && ctx[ctx.i] == end_c)
|
||||||
|
break; // reached end char: stop here
|
||||||
|
else if(ctx[ctx.i] == '\n')
|
||||||
|
{
|
||||||
|
if(ctx.here_document != nullptr)
|
||||||
|
ctx = parse_heredocument(ctx+1);
|
||||||
|
// do here document parse
|
||||||
|
}
|
||||||
|
else if(ctx[ctx.i] == '#')
|
||||||
; // skip here
|
; // skip here
|
||||||
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
else if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||||
ctx.i++; // skip on next
|
; // skip on next
|
||||||
|
else if(is_in(ctx[ctx.i], CONTROL_END))
|
||||||
|
{
|
||||||
|
// control end: unexpected
|
||||||
|
parse_error( unexpected_token(ctx[ctx.i]), ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.here_document != nullptr)
|
||||||
|
{
|
||||||
|
uint8_t do_twice=2;
|
||||||
|
// case of : cat << EOF ;
|
||||||
|
while(do_twice>0)
|
||||||
|
{
|
||||||
|
if(ctx[ctx.i] == '\n')
|
||||||
|
{
|
||||||
|
ctx = parse_heredocument(ctx+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(ctx[ctx.i] == '#')
|
||||||
|
{
|
||||||
|
ctx.i = skip_until(ctx, "\n"); //skip to endline
|
||||||
|
ctx = parse_heredocument(ctx+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
skip_chars(ctx, SPACES);
|
||||||
|
do_twice--;
|
||||||
|
}
|
||||||
|
// case of : cat << EOF ; ;
|
||||||
|
if(do_twice==0 && is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||||
|
parse_error( unexpected_token(ctx[ctx.i]), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_in(ctx[ctx.i], COMMAND_SEPARATOR))
|
||||||
|
ctx.i++;
|
||||||
|
|
||||||
ctx.i = skip_unread(ctx);
|
ctx.i = skip_unread(ctx);
|
||||||
|
|
||||||
// word wasn't found
|
// word wasn't found
|
||||||
if(ctx.i>=ctx.size)
|
if(ctx.i>=ctx.size)
|
||||||
{
|
{
|
||||||
parse_error(strf("Expecting '%s'", ctx.expecting), ctx);
|
if(opts.word_mode || opts.end_char != 0)
|
||||||
return std::make_tuple(ret, ctx, "");
|
{
|
||||||
|
parse_error(strf("Expecting '%s'", ctx.expecting), ctx);
|
||||||
|
return std::make_tuple(ret, ctx, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.expecting=old_expect;
|
ctx.expecting=old_expect;
|
||||||
|
|
@ -1224,9 +1175,9 @@ std::pair<subshell*, parse_context> parse_subshell(parse_context ctx)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
auto pp=parse_list_until(ctx, ')', ")");
|
auto pp=parse_list_until(ctx, {.end_char=')', .expecting=")"} );
|
||||||
ret->lst=pp.first;
|
ret->lst=std::get<0>(pp);
|
||||||
ctx=pp.second;
|
ctx=std::get<1>(pp);
|
||||||
if(ret->lst->size()<=0)
|
if(ret->lst->size()<=0)
|
||||||
{
|
{
|
||||||
parse_error("Subshell is empty", ctx, start-1);
|
parse_error("Subshell is empty", ctx, start-1);
|
||||||
|
|
@ -1258,9 +1209,9 @@ std::pair<brace*, parse_context> parse_brace(parse_context ctx)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
auto pp=parse_list_until(ctx, '}', "}");
|
auto pp=parse_list_until(ctx, {.end_char='}', .expecting="}"});
|
||||||
ret->lst=pp.first;
|
ret->lst=std::get<0>(pp);
|
||||||
ctx=pp.second;
|
ctx=std::get<1>(pp);
|
||||||
if(ret->lst->size()<=0)
|
if(ret->lst->size()<=0)
|
||||||
{
|
{
|
||||||
parse_error("Brace block is empty", ctx, start-1);
|
parse_error("Brace block is empty", ctx, start-1);
|
||||||
|
|
@ -1299,16 +1250,16 @@ std::pair<function*, parse_context> parse_function(parse_context ctx, const char
|
||||||
}
|
}
|
||||||
ctx.i++;
|
ctx.i++;
|
||||||
|
|
||||||
auto pp=parse_list_until(ctx, '}', "}");
|
auto pp=parse_list_until(ctx, {.end_char='}', .expecting="}"} );
|
||||||
if(pp.first->size()<=0)
|
ret->lst=std::get<0>(pp);
|
||||||
|
if(ret->lst->size()<=0)
|
||||||
{
|
{
|
||||||
parse_error("Function is empty", ctx);
|
parse_error("Function is empty", ctx);
|
||||||
ctx.i=pp.second.i+1;
|
ctx.i=std::get<1>(pp).i+1;
|
||||||
return std::make_pair(ret, ctx);
|
return std::make_pair(ret, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret->lst=pp.first;
|
ctx=std::get<1>(pp);
|
||||||
ctx=pp.second;
|
|
||||||
ctx.i++;
|
ctx.i++;
|
||||||
#ifndef NO_PARSE_CATCH
|
#ifndef NO_PARSE_CATCH
|
||||||
}
|
}
|
||||||
|
|
@ -1549,7 +1500,7 @@ std::pair<case_block*, parse_context> parse_case(parse_context ctx)
|
||||||
ctx.i++;
|
ctx.i++;
|
||||||
|
|
||||||
// until ;;
|
// until ;;
|
||||||
auto tp = parse_list_until(ctx, {";", "esac"}, ";;");
|
auto tp = parse_list_until(ctx, { .word_mode=true, .end_words={";", "esac"}, .expecting=";;" });
|
||||||
cc->second = std::get<0>(tp);
|
cc->second = std::get<0>(tp);
|
||||||
ctx = std::get<1>(tp);
|
ctx = std::get<1>(tp);
|
||||||
std::string word = std::get<2>(tp);
|
std::string word = std::get<2>(tp);
|
||||||
|
|
@ -1600,20 +1551,21 @@ std::pair<if_block*, parse_context> parse_if(parse_context ctx)
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
std::string word;
|
std::string word;
|
||||||
|
parse_context oldctx = ctx;
|
||||||
|
|
||||||
ret->blocks.push_back(std::make_pair(nullptr, nullptr));
|
ret->blocks.push_back(std::make_pair(nullptr, nullptr));
|
||||||
auto ll = ret->blocks.end()-1;
|
auto ll = ret->blocks.end()-1;
|
||||||
|
|
||||||
auto pp=parse_list_until(ctx, "then");
|
auto pp=parse_list_until(ctx, {.word_mode=true, .end_words={"then"}});
|
||||||
ll->first = pp.first;
|
ll->first = std::get<0>(pp);
|
||||||
|
ctx = std::get<1>(pp);
|
||||||
if(ll->first->size()<=0)
|
if(ll->first->size()<=0)
|
||||||
{
|
{
|
||||||
parse_error("Condition is empty", ctx);
|
parse_error("Condition is empty", oldctx);
|
||||||
pp.second.has_errored=true;
|
ctx.has_errored=true;
|
||||||
}
|
}
|
||||||
ctx = pp.second;
|
|
||||||
|
|
||||||
auto tp=parse_list_until(ctx, {"fi", "elif", "else"});
|
auto tp=parse_list_until(ctx, {.word_mode=true, .end_words={"fi", "elif", "else"}} );
|
||||||
ll->second = std::get<0>(tp);
|
ll->second = std::get<0>(tp);
|
||||||
parse_context newctx = std::get<1>(tp);
|
parse_context newctx = std::get<1>(tp);
|
||||||
word = std::get<2>(tp);
|
word = std::get<2>(tp);
|
||||||
|
|
@ -1628,14 +1580,17 @@ std::pair<if_block*, parse_context> parse_if(parse_context ctx)
|
||||||
break;
|
break;
|
||||||
if(word == "else")
|
if(word == "else")
|
||||||
{
|
{
|
||||||
auto pp=parse_list_until(ctx, "fi");
|
auto pp=parse_list_until(ctx, {.word_mode=true, .end_words={"fi"}});
|
||||||
if(pp.first->size()<=0)
|
ret->else_lst=std::get<0>(pp);
|
||||||
|
if(ret->else_lst->size()<=0)
|
||||||
{
|
{
|
||||||
parse_error("else block is empty", ctx);
|
parse_error("else block is empty", ctx);
|
||||||
pp.second.has_errored=true;
|
ctx=std::get<1>(pp);
|
||||||
|
ctx.has_errored=true;
|
||||||
}
|
}
|
||||||
ret->else_lst=pp.first;
|
else
|
||||||
ctx=pp.second;
|
ctx=std::get<1>(pp);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1714,9 +1669,9 @@ std::pair<for_block*, parse_context> parse_for(parse_context ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ops
|
// ops
|
||||||
auto lp = parse_list_until(ctx, "done");
|
auto lp = parse_list_until(ctx, {.word_mode=true, .end_words={"done"}} );
|
||||||
ret->ops=lp.first;
|
ret->ops=std::get<0>(lp);
|
||||||
ctx=lp.second;
|
ctx=std::get<1>(lp);
|
||||||
#ifndef NO_PARSE_CATCH
|
#ifndef NO_PARSE_CATCH
|
||||||
}
|
}
|
||||||
catch(format_error& e)
|
catch(format_error& e)
|
||||||
|
|
@ -1739,24 +1694,28 @@ std::pair<while_block*, parse_context> parse_while(parse_context ctx)
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
// cond
|
// cond
|
||||||
auto pp=parse_list_until(ctx, "do");
|
parse_context oldctx = ctx;
|
||||||
if(pp.first->size() <= 0)
|
auto pp=parse_list_until(ctx, {.word_mode=true, .end_words={"do"}});
|
||||||
|
|
||||||
|
ret->cond = std::get<0>(pp);
|
||||||
|
ctx = std::get<1>(pp);
|
||||||
|
|
||||||
|
if(ret->cond->size() <= 0)
|
||||||
{
|
{
|
||||||
parse_error("condition is empty", ctx);
|
parse_error("condition is empty", oldctx);
|
||||||
pp.second.has_errored=true;
|
ctx.has_errored=true;
|
||||||
}
|
}
|
||||||
ret->cond = pp.first;
|
|
||||||
ctx = pp.second;
|
|
||||||
|
|
||||||
// ops
|
// ops
|
||||||
auto lp = parse_list_until(ctx, "done");
|
oldctx = ctx;
|
||||||
if(lp.first->size() <= 0)
|
auto lp = parse_list_until(ctx, {.word_mode=true, .end_words={"done"}} );
|
||||||
|
ret->ops=std::get<0>(lp);
|
||||||
|
ctx = std::get<1>(lp);
|
||||||
|
if(ret->ops->size() <= 0)
|
||||||
{
|
{
|
||||||
parse_error("while is empty", ctx);
|
parse_error("while is empty", oldctx);
|
||||||
lp.second.has_errored=true;
|
ctx.has_errored=true;
|
||||||
}
|
}
|
||||||
ret->ops=lp.first;
|
|
||||||
ctx = lp.second;
|
|
||||||
#ifndef NO_PARSE_CATCH
|
#ifndef NO_PARSE_CATCH
|
||||||
}
|
}
|
||||||
catch(format_error& e)
|
catch(format_error& e)
|
||||||
|
|
@ -1936,13 +1895,14 @@ std::pair<shmain*, parse_context> parse_text(parse_context ctx)
|
||||||
if(!ctx.bash)
|
if(!ctx.bash)
|
||||||
ctx.bash = (binshebang == "bash" || binshebang == "lxsh");
|
ctx.bash = (binshebang == "bash" || binshebang == "lxsh");
|
||||||
// parse all commands
|
// parse all commands
|
||||||
auto pp=parse_list_until(ctx, 0);
|
auto pp=parse_list_until(ctx);
|
||||||
ret->lst=pp.first;
|
ret->lst=std::get<0>(pp);
|
||||||
|
ctx = std::get<1>(pp);
|
||||||
|
|
||||||
if(pp.second.has_errored)
|
if(ctx.has_errored)
|
||||||
throw std::runtime_error("Aborted due to previous errors");
|
throw std::runtime_error("Aborted due to previous errors");
|
||||||
|
|
||||||
return std::make_pair(ret, pp.second);
|
return std::make_pair(ret, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<shmain*, parse_context> parse_text(std::string const& in, std::string const& filename)
|
std::pair<shmain*, parse_context> parse_text(std::string const& in, std::string const& filename)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ condlist* make_condlist(std::string const& in)
|
||||||
|
|
||||||
list* make_list(std::string const& in)
|
list* make_list(std::string const& in)
|
||||||
{
|
{
|
||||||
return parse_list_until(make_context(in), 0).first;
|
auto t = parse_list_until(make_context(in));
|
||||||
|
return std::get<0>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
block* make_block(std::string const& in)
|
block* make_block(std::string const& in)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue