make command argcount unlimited, remove maxargs checks from codegen

also adjust the bytecode appropriately, now you can call commands
with an unlimited number of args and aliases with max 32 args,
extra args will be ignored
master
Daniel Kolesa 2021-03-30 02:08:25 +02:00
parent c2bb8e4a3d
commit 3dc6ad866f
5 changed files with 51 additions and 91 deletions

View File

@ -163,9 +163,9 @@ enum {
BC_INST_ALIAS,
/* pop 2 values off the stack; top is value to set, below is alias name */
BC_INST_ALIAS_U,
/* call alias with index D[5..] and arg count D[0..5], pop the arguments
* off the stack (top being last); if unknown, raise error, store result
* in R according to M
/* call alias with index D and arg count following the instruction, pop
* the arguments off the stack (top being last); if unknown, raise error,
* store result in R according to M
*/
BC_INST_CALL,
/* given argument count D, pop the arguments off the stack (top being last)
@ -178,12 +178,12 @@ enum {
* last argument being topmost; result of the call goes in R according to M
*/
BC_INST_COM,
/* call builtin command with index D[5..] and number of arguments D[0..5]
* arguments are popped off the stack and passed as is
/* call builtin command with index D and arg count following the
* instruction, arguments are popped off the stack and passed as is
*/
BC_INST_COM_V,
/* call builtin command with index D[5..] and number of arguments D[0..5]
* arguments are popped off the stack and concatenated together
/* call builtin command with index D and arg count following the
* instruction, arguments are popped off the stack and concatenated
*/
BC_INST_COM_C,

View File

@ -308,7 +308,7 @@ lookupid:
}
goto done;
case ident_type::COMMAND: {
int comtype = BC_INST_COM, numargs = 0;
std::uint32_t comtype = BC_INST_COM, numargs = 0;
auto fmt = static_cast<command_impl *>(id)->get_args();
for (char c: fmt) {
switch (c) {
@ -375,9 +375,9 @@ lookupid:
goto done;
compilecomv:
gs.code.push_back(
comtype | ret_code(ltype) | (numargs << 8) |
(id->get_index() << 13)
comtype | ret_code(ltype) | (id->get_index() << 8)
);
gs.code.push_back(numargs);
gs.code.push_back(
BC_INST_RESULT_ARG | ret_code(ltype)
);
@ -802,7 +802,7 @@ static bool compilearg(
static void compile_cmd(
codegen_state &gs, command_impl *id, bool &more, int rettype
) {
int comtype = BC_INST_COM, numargs = 0, fakeargs = 0;
std::uint32_t comtype = BC_INST_COM, numargs = 0, fakeargs = 0;
bool rep = false;
auto fmt = id->get_args();
for (auto it = fmt.begin(); it != fmt.end(); ++it) {
@ -819,11 +819,7 @@ static void compile_cmd(
fakeargs++;
} else if ((it + 1) == fmt.end()) {
int numconc = 1;
while ((numargs + numconc) < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_STRING);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_STRING))) {
numconc++;
}
if (numconc > 1) {
@ -947,11 +943,7 @@ static void compile_cmd(
case 'C': /* concatenated string */
comtype = BC_INST_COM_C;
if (more) {
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_ANY);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_ANY))) {
numargs++;
}
}
@ -959,11 +951,7 @@ static void compile_cmd(
case 'V': /* varargs */
comtype = BC_INST_COM_V;
if (more) {
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_ANY);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_ANY))) {
numargs++;
}
}
@ -972,15 +960,10 @@ static void compile_cmd(
case '2':
case '3':
case '4':
if (more && (numargs < MAX_ARGUMENTS)) {
if (more) {
int numrep = *it - '0' + 1;
it -= numrep;
rep = true;
} else {
while (numargs > MAX_ARGUMENTS) {
gs.code.push_back(BC_INST_POP);
--numargs;
}
}
break;
}
@ -989,38 +972,29 @@ static void compile_cmd(
return;
compilecomv:
gs.code.push_back(
comtype | ret_code(rettype) | (numargs << 8) | (id->get_index() << 13)
comtype | ret_code(rettype) | (id->get_index() << 8)
);
gs.code.push_back(numargs);
}
static void compile_alias(codegen_state &gs, alias *id, bool &more) {
int numargs = 0;
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_ANY);
if (!more) {
break;
}
std::uint32_t numargs = 0;
while ((more = compilearg(gs, VAL_ANY))) {
++numargs;
}
gs.code.push_back(
BC_INST_CALL | (numargs << 8) | (id->get_index() << 13)
BC_INST_CALL | (id->get_index() << 8)
);
gs.code.push_back(numargs);
}
static void compile_local(codegen_state &gs, bool &more) {
int numargs = 0;
std::uint32_t numargs = 0;
if (more) {
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_IDENT);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_IDENT))) {
numargs++;
}
}
if (more) {
while ((more = compilearg(gs, VAL_POP)));
}
gs.code.push_back(BC_INST_LOCAL | (numargs << 8));
}
@ -1100,7 +1074,7 @@ static void compile_if(
static void compile_and_or(
codegen_state &gs, ident *id, bool &more, int rettype
) {
int numargs = 0;
std::uint32_t numargs = 0;
if (more) {
more = compilearg(gs, VAL_COND);
}
@ -1112,11 +1086,7 @@ static void compile_and_or(
} else {
numargs++;
int start = gs.code.size(), end = start;
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_COND);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_COND))) {
numargs++;
if ((gs.code[end] & ~BC_INST_RET_MASK) != (
BC_INST_BLOCK | (uint32_t(gs.code.size() - (end + 1)) << 8)
@ -1126,17 +1096,13 @@ static void compile_and_or(
end = gs.code.size();
}
if (more) {
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_COND);
if (!more) {
break;
}
while ((more = compilearg(gs, VAL_COND))) {
numargs++;
}
gs.code.push_back(
BC_INST_COM_V | ret_code(rettype) |
(numargs << 8) | (id->get_index() << 13)
BC_INST_COM_V | ret_code(rettype) | (id->get_index() << 8)
);
gs.code.push_back(numargs);
} else {
uint32_t op = (id->get_raw_type() == ID_AND)
? (BC_INST_JUMP_RESULT | BC_INST_FLAG_FALSE)
@ -1240,12 +1206,8 @@ static void compilestatements(codegen_state &gs, int rettype, int brak) {
}
if (idname.empty()) {
noid:
int numargs = 0;
while (numargs < MAX_ARGUMENTS) {
more = compilearg(gs, VAL_ANY);
if (!more) {
break;
}
std::uint32_t numargs = 0;
while ((more = compilearg(gs, VAL_ANY))) {
++numargs;
}
gs.code.push_back(BC_INST_CALL_U | (numargs << 8));
@ -1351,12 +1313,10 @@ noid:
if (!(more = compilearg(gs, VAL_STRING))) {
gs.code.push_back(BC_INST_PRINT | (id->get_index() << 8));
} else {
int numargs = 0;
std::uint32_t numargs = 0;
do {
++numargs;
} while (numargs < MAX_ARGUMENTS && (
more = compilearg(gs, VAL_ANY)
));
} while ((more = compilearg(gs, VAL_ANY)));
if (numargs > 1) {
gs.code.push_back(
BC_INST_CONC | BC_RET_STRING | (numargs << 8)

View File

@ -7,7 +7,7 @@
namespace cubescript {
static constexpr int MAX_ARGUMENTS = 32;
static constexpr std::size_t MAX_ARGUMENTS = 32;
using argset = std::bitset<MAX_ARGUMENTS>;
enum {

View File

@ -73,9 +73,9 @@ state::state(alloc_func func, void *data) {
p_tstate->istate = statep;
p_tstate->owner = true;
for (int i = 0; i < MAX_ARGUMENTS; ++i) {
char buf[32];
snprintf(buf, sizeof(buf), "arg%d", i + 1);
for (std::size_t i = 0; i < MAX_ARGUMENTS; ++i) {
char buf[16];
snprintf(buf, sizeof(buf), "arg%zu", i + 1);
new_ident(static_cast<char const *>(buf), IDENT_FLAG_ARG);
}
@ -419,15 +419,14 @@ LIBCUBESCRIPT_EXPORT command *state::new_command(
case 'e':
case 'r':
case '$':
if (nargs < MAX_ARGUMENTS) {
++nargs;
}
++nargs;
break;
case '1':
case '2':
case '3':
case '4':
if (nargs < (*fmt - '0')) {
case '4': {
int nrep = (*fmt - '0');
if (nargs < nrep) {
return nullptr;
}
if ((args.end() - fmt) != 2) {
@ -436,10 +435,9 @@ LIBCUBESCRIPT_EXPORT command *state::new_command(
if ((fmt[1] != 'C') && (fmt[1] != 'V')) {
return nullptr;
}
if (nargs < MAX_ARGUMENTS) {
fmt -= *fmt - '0' + 1;
}
nargs -= nrep;
break;
}
case 'C':
case 'V':
if ((fmt + 1) != args.end()) {

View File

@ -202,6 +202,8 @@ void exec_alias(
std::size_t callargs, std::size_t &nargs,
std::size_t offset, std::size_t skip, std::uint32_t op
) {
/* excess arguments get ignored (make error maybe?) */
callargs = std::min(callargs, MAX_ARGUMENTS);
integer_var *anargs = static_cast<integer_var *>(
ts.istate->identmap[ID_IDX_NUMARGS]
);
@ -1062,8 +1064,8 @@ std::uint32_t *vm_exec(
case BC_INST_CALL | BC_RET_FLOAT:
case BC_INST_CALL | BC_RET_INT: {
result.force_none();
ident *id = ts.istate->identmap[op >> 13];
std::size_t callargs = (op >> 8) & 0x1F;
ident *id = ts.istate->identmap[op >> 8];
std::size_t callargs = *code++;
std::size_t nnargs = args.size();
std::size_t offset = nnargs - callargs;
auto flags = id->get_flags();
@ -1232,9 +1234,9 @@ noid:
case BC_INST_COM_V | BC_RET_FLOAT:
case BC_INST_COM_V | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 13]
ts.istate->identmap[op >> 8]
);
std::size_t callargs = (op >> 8) & 0x1F;
std::size_t callargs = *code++;
std::size_t offset = args.size() - callargs;
result.force_none();
id->call(cs, std::span{&args[offset], callargs}, result);
@ -1247,10 +1249,10 @@ noid:
case BC_INST_COM_C | BC_RET_FLOAT:
case BC_INST_COM_C | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>(
ts.istate->identmap[op >> 13]
ts.istate->identmap[op >> 8]
);
std::size_t callargs = (op >> 8) & 0x1F,
offset = args.size() - callargs;
std::size_t callargs = *code++;
std::size_t offset = args.size() - callargs;
result.force_none();
{
any_value tv{cs};