clean up command call parsing
parent
0ee0ebfb42
commit
7229672f56
327
src/cs_parser.cc
327
src/cs_parser.cc
|
@ -943,26 +943,96 @@ bool parser_state::parse_arg(int ltype, charbuf *word) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_cmd_arg(parser_state &ps, char s, bool more, bool rep) {
|
||||||
|
switch (s) {
|
||||||
|
case 's': /* string */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_STRING);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_string();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'i': /* integer */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_INT);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_integer();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'b': /* integer, INT_MIN default */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_INT);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_integer(std::numeric_limits<integer_type>::min());
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'f': /* float */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_FLOAT);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_float();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'F': /* float, prev-argument default */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_FLOAT);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_dup(VAL_FLOAT);
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 't': /* any arg */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_ANY);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_null();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'E': /* condition */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_COND);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_null();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'e': /* code */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_CODE);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_block();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
case 'r': /* ident */
|
||||||
|
if (more) {
|
||||||
|
more = ps.parse_arg(VAL_IDENT);
|
||||||
|
}
|
||||||
|
if (!more && !rep) {
|
||||||
|
ps.gs.gen_val_ident();
|
||||||
|
}
|
||||||
|
return more;
|
||||||
|
default:
|
||||||
|
return more;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool parser_state::parse_call_command(
|
bool parser_state::parse_call_command(
|
||||||
command_impl *id, ident &self, int rettype, std::uint32_t limit
|
command_impl *id, ident &self, int rettype
|
||||||
) {
|
) {
|
||||||
std::uint32_t comtype = BC_INST_COM, numargs = 0, numcargs = 0, fakeargs = 0;
|
std::uint32_t comtype = BC_INST_COM, numargs = 0, fakeargs = 0;
|
||||||
bool rep = false;
|
|
||||||
auto fmt = id->get_args();
|
auto fmt = id->get_args();
|
||||||
bool more = true;
|
bool more = true, rep = false;
|
||||||
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
|
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
|
||||||
switch (*it) {
|
switch (*it) {
|
||||||
case 's': /* string */
|
case 's': /* string */
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
more = parse_cmd_arg(*this, 's', more, rep);
|
||||||
more = parse_arg(VAL_STRING);
|
if (more && ((it + 1) == fmt.end())) {
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_string();
|
|
||||||
fakeargs++;
|
|
||||||
} else if ((it + 1) == fmt.end()) {
|
|
||||||
int numconc = 1;
|
int numconc = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
more = parse_arg(VAL_STRING);
|
more = parse_arg(VAL_STRING);
|
||||||
|
@ -974,166 +1044,54 @@ bool parser_state::parse_call_command(
|
||||||
if (numconc > 1) {
|
if (numconc > 1) {
|
||||||
gs.gen_concat(numconc, true, VAL_STRING);
|
gs.gen_concat(numconc, true, VAL_STRING);
|
||||||
}
|
}
|
||||||
}
|
} else if (!more) {
|
||||||
numargs++;
|
if (!rep) {
|
||||||
numcargs++;
|
++fakeargs;
|
||||||
break;
|
} else {
|
||||||
case 'i': /* integer */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_INT);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gs.gen_val_integer();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
}
|
||||||
numargs++;
|
++numargs;
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'b': /* integer, INT_MIN default */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_INT);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_integer(std::numeric_limits<integer_type>::min());
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'f': /* float */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_FLOAT);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_float();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'F': /* float, prev-argument default */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_FLOAT);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_dup(VAL_FLOAT);
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 't': /* any arg */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_ANY);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_null();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'E': /* condition */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_COND);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_null();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'e': /* code */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_CODE);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_block();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
|
||||||
case 'r': /* ident */
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
more = parse_arg(VAL_IDENT);
|
|
||||||
}
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
if (rep) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gs.gen_val_ident();
|
|
||||||
fakeargs++;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
break;
|
break;
|
||||||
case '$': /* self */
|
case '$': /* self */
|
||||||
gs.gen_val_ident(self);
|
gs.gen_val_ident(self);
|
||||||
numargs++;
|
++numargs;
|
||||||
break;
|
break;
|
||||||
case 'N': /* number of arguments */
|
case 'N': /* number of arguments */
|
||||||
gs.gen_val_integer(numargs - fakeargs);
|
gs.gen_val_integer(numargs - fakeargs);
|
||||||
numargs++;
|
++numargs;
|
||||||
break;
|
break;
|
||||||
case 'C': /* concatenated string */
|
case 'C': /* concatenated string */
|
||||||
comtype = BC_INST_COM_C;
|
case 'V': /* varargs */
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
comtype = (*it == 'C') ? BC_INST_COM_C : BC_INST_COM_V;
|
||||||
|
if (more) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
more = parse_arg(VAL_ANY);
|
more = parse_arg(VAL_ANY);
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
if (!more) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
numargs++;
|
++numargs;
|
||||||
numcargs++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'V': /* varargs */
|
case '1': case '2': case '3': case '4': /* vararg repetition */
|
||||||
comtype = BC_INST_COM_V;
|
if (more) {
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
for(;;) {
|
|
||||||
more = parse_arg(VAL_ANY);
|
|
||||||
if (!more || (limit && (numcargs >= limit))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
numargs++;
|
|
||||||
numcargs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '1': /* vararg repetition */
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
if (more && (!limit || (numcargs < limit))) {
|
|
||||||
int numrep = *it - '0' + 1;
|
int numrep = *it - '0' + 1;
|
||||||
it -= numrep;
|
it -= numrep;
|
||||||
rep = true;
|
rep = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
more = parse_cmd_arg(*this, *it, more, rep);
|
||||||
|
if (!more) {
|
||||||
|
if (!rep) {
|
||||||
|
++fakeargs;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++numargs;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gs.gen_command_call(*id, comtype, rettype, numargs);
|
gs.gen_command_call(*id, comtype, rettype, numargs);
|
||||||
|
@ -1367,6 +1325,58 @@ static bool parse_no_id(parser_state &ps, int term) {
|
||||||
return finish_statement(ps, false, term);
|
return finish_statement(ps, false, term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_assign_var(
|
||||||
|
parser_state &ps, command_impl *id, ident &var, int ltype
|
||||||
|
) {
|
||||||
|
auto fmt = id->get_args();
|
||||||
|
std::uint32_t comtype = BC_INST_COM;
|
||||||
|
std::uint32_t nargs = 0;
|
||||||
|
bool more = true, got = false, rep = false;
|
||||||
|
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
|
||||||
|
switch (*it) {
|
||||||
|
case '$':
|
||||||
|
ps.gs.gen_val_ident(var);
|
||||||
|
++nargs;
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
ps.gs.gen_val_integer(nargs);
|
||||||
|
++nargs;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
case 'V':
|
||||||
|
comtype = (*it == 'C') ? BC_INST_COM_C : BC_INST_COM_V;
|
||||||
|
if (more && !got) {
|
||||||
|
more = ps.parse_arg(VAL_ANY);
|
||||||
|
if (more) {
|
||||||
|
got = true;
|
||||||
|
++nargs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '1': case '2': case '3': case '4':
|
||||||
|
if (more && !got) {
|
||||||
|
int numrep = *it - '0' + 1;
|
||||||
|
it -= numrep;
|
||||||
|
rep = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
auto gotarg = parse_cmd_arg(ps, *it, got ? false : more, rep);
|
||||||
|
if (!got) {
|
||||||
|
more = gotarg;
|
||||||
|
}
|
||||||
|
if (gotarg) {
|
||||||
|
++nargs;
|
||||||
|
got = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ps.gs.gen_command_call(*id, comtype, ltype, nargs);
|
||||||
|
return more;
|
||||||
|
}
|
||||||
|
|
||||||
bool parser_state::parse_assign(
|
bool parser_state::parse_assign(
|
||||||
charbuf &idname, int ltype, int term, bool &noass
|
charbuf &idname, int ltype, int term, bool &noass
|
||||||
) {
|
) {
|
||||||
|
@ -1409,25 +1419,22 @@ bool parser_state::parse_assign(
|
||||||
}
|
}
|
||||||
case ident_type::IVAR: {
|
case ident_type::IVAR: {
|
||||||
auto *hid = ts.istate->cmd_ivar;
|
auto *hid = ts.istate->cmd_ivar;
|
||||||
bool more = parse_call_command(
|
bool more = parse_assign_var(
|
||||||
static_cast<command_impl *>(hid),
|
*this, static_cast<command_impl *>(hid), id, ltype
|
||||||
id, ltype, 1
|
|
||||||
);
|
);
|
||||||
return finish_statement(*this, more, term);
|
return finish_statement(*this, more, term);
|
||||||
}
|
}
|
||||||
case ident_type::FVAR: {
|
case ident_type::FVAR: {
|
||||||
auto *hid = ts.istate->cmd_fvar;
|
auto *hid = ts.istate->cmd_fvar;
|
||||||
bool more = parse_call_command(
|
bool more = parse_assign_var(
|
||||||
static_cast<command_impl *>(hid),
|
*this, static_cast<command_impl *>(hid), id, ltype
|
||||||
id, ltype, 1
|
|
||||||
);
|
);
|
||||||
return finish_statement(*this, more, term);
|
return finish_statement(*this, more, term);
|
||||||
}
|
}
|
||||||
case ident_type::SVAR: {
|
case ident_type::SVAR: {
|
||||||
auto *hid = ts.istate->cmd_svar;
|
auto *hid = ts.istate->cmd_svar;
|
||||||
bool more = parse_call_command(
|
bool more = parse_assign_var(
|
||||||
static_cast<command_impl *>(hid),
|
*this, static_cast<command_impl *>(hid), id, ltype
|
||||||
id, ltype, 1
|
|
||||||
);
|
);
|
||||||
return finish_statement(*this, more, term);
|
return finish_statement(*this, more, term);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,7 @@ struct parser_state {
|
||||||
void parse_blockarg(int ltype);
|
void parse_blockarg(int ltype);
|
||||||
bool parse_arg(int ltype, charbuf *word = nullptr);
|
bool parse_arg(int ltype, charbuf *word = nullptr);
|
||||||
|
|
||||||
bool parse_call_command(
|
bool parse_call_command(command_impl *id, ident &self, int rettype);
|
||||||
command_impl *id, ident &self, int rettype, std::uint32_t limit = 0
|
|
||||||
);
|
|
||||||
bool parse_call_alias(alias &id);
|
bool parse_call_alias(alias &id);
|
||||||
bool parse_call_id(ident &id, int ltype);
|
bool parse_call_id(ident &id, int ltype);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue