FOR var IN ... ; END support.

This commit is contained in:
Kelvin Sherlock 2016-06-16 00:04:29 -04:00
parent 701786277b
commit 92ddf18766
4 changed files with 76 additions and 7 deletions

View File

@ -487,7 +487,6 @@ int begin_command::execute(Environment &env, const fdmask &fds, bool throwup) {
int loop_command::execute(Environment &env, const fdmask &fds, bool throwup) {
// todo -- parse end for redirection.
std::string b = expand_vars(begin, env);
std::string e = expand_vars(end, env);
@ -515,7 +514,7 @@ int loop_command::execute(Environment &env, const fdmask &fds, bool throwup) {
if (status) return env.status(status);
int rv = 0;
for(;; env.echo("end") ) {
for(;;) {
if (control_c) throw execution_of_input_terminated();
@ -525,17 +524,64 @@ int loop_command::execute(Environment &env, const fdmask &fds, bool throwup) {
});
}
catch (break_command_t &ex) {
env.echo("end");
break;
}
catch (continue_command_t &ex) {
continue;
}
catch (continue_command_t &ex) {}
env.echo("end");
}
env.echo("end");
return env.status(rv);
}
int for_command::execute(Environment &env, const fdmask &fds, bool throwup) {
std::string b = expand_vars(begin, env);
std::string e = expand_vars(end, env);
env.set("command", "end");
// echo!
env.echo("%s ... %s",
b.c_str(),
e.c_str()
);
// check for extra tokens...
auto bt = tokenize(b, true);
if (bt.size() < 3 || strcasecmp(bt[2].string.c_str(), "in")) {
fprintf(stderr, "### For - Missing in keyword.\n");
fprintf(stderr, "Usage - For name in [word...]\n");
return env.status(-3);
}
fdmask newfds;
int status = check_ends(e, newfds);
newfds |= fds;
if (status) return env.status(status);
int rv = 0;
for (int i = 3; i < bt.size(); ++i ) {
if (control_c) throw execution_of_input_terminated();
env.set(bt[1].string, bt[i].string);
try {
env.loop_indent_and([&]{
rv = vector_command::execute(env, newfds);
});
}
catch (break_command_t &ex) {
env.echo("end");
break;
}
catch (continue_command_t &ex) {}
env.echo("end");
}
return env.status(rv);
}

View File

@ -158,6 +158,20 @@ struct loop_command : public vector_command {
virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override;
};
struct for_command : public vector_command {
template<class S1, class S2>
for_command(int t, command_ptr_vector &&v, S1 &&b, S2 &&e) :
vector_command(t, std::move(v)), begin(std::forward<S1>(b)), end(std::forward<S2>(e))
{}
std::string begin;
std::string end;
virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override;
};
typedef std::unique_ptr<struct if_else_clause> if_else_clause_ptr;
struct if_command : public command {

View File

@ -28,6 +28,7 @@ bool phase2_parser::continuation() const {
if (e.major == AMP_AMP) return true;
if (e.major == PIPE_PIPE) return true;
if (e.major == LOOP) return true;
if (e.major == FOR) return true;
}
return false;
}
@ -107,6 +108,7 @@ term(RV) ::= if_command(C). { RV = std::move(C); }
term(RV) ::= begin_command(C). { RV = std::move(C); }
term(RV) ::= paren_command(C). { RV = std::move(C); }
term(RV) ::= loop_command(C). { RV = std::move(C); }
term(RV) ::= for_command(C). { RV = std::move(C); }
/*
* fall back to an end error. w/o fallback, it will cause a parse conflict.
@ -146,6 +148,9 @@ loop_command(RV) ::= LOOP(T) sep compound_list(L) END(E). {
RV = std::make_unique<loop_command>(@T, std::move(L), std::move(T), std::move(E));
}
for_command(RV) ::= FOR(T) sep compound_list(L) END(E). {
RV = std::make_unique<for_command>(@T, std::move(L), std::move(T), std::move(E));
}
if_command(RV) ::= IF(I) sep compound_list(L) END(E). {

View File

@ -121,6 +121,7 @@
BEGIN = /begin/i;
EVALUATE = /evaluate/i;
LOOP = /loop/i;
FOR = /for/i;
BREAK = /break/i;
CONTINUE = /continue/i;
@ -147,6 +148,9 @@
LOOP %eof{ type = LOOP; return; };
LOOP ws => { type = LOOP; return; };
FOR %eof{ type = FOR; return; };
FOR ws => { type = FOR; return; };
BREAK %eof{ type = BREAK; return; };
BREAK ws => { type = BREAK; return; };