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

View File

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

View File

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

View File

@ -73,9 +73,9 @@ state::state(alloc_func func, void *data) {
p_tstate->istate = statep; p_tstate->istate = statep;
p_tstate->owner = true; p_tstate->owner = true;
for (int i = 0; i < MAX_ARGUMENTS; ++i) { for (std::size_t i = 0; i < MAX_ARGUMENTS; ++i) {
char buf[32]; char buf[16];
snprintf(buf, sizeof(buf), "arg%d", i + 1); snprintf(buf, sizeof(buf), "arg%zu", i + 1);
new_ident(static_cast<char const *>(buf), IDENT_FLAG_ARG); new_ident(static_cast<char const *>(buf), IDENT_FLAG_ARG);
} }
@ -419,15 +419,14 @@ LIBCUBESCRIPT_EXPORT command *state::new_command(
case 'e': case 'e':
case 'r': case 'r':
case '$': case '$':
if (nargs < MAX_ARGUMENTS) { ++nargs;
++nargs;
}
break; break;
case '1': case '1':
case '2': case '2':
case '3': case '3':
case '4': case '4': {
if (nargs < (*fmt - '0')) { int nrep = (*fmt - '0');
if (nargs < nrep) {
return nullptr; return nullptr;
} }
if ((args.end() - fmt) != 2) { if ((args.end() - fmt) != 2) {
@ -436,10 +435,9 @@ LIBCUBESCRIPT_EXPORT command *state::new_command(
if ((fmt[1] != 'C') && (fmt[1] != 'V')) { if ((fmt[1] != 'C') && (fmt[1] != 'V')) {
return nullptr; return nullptr;
} }
if (nargs < MAX_ARGUMENTS) { nargs -= nrep;
fmt -= *fmt - '0' + 1;
}
break; break;
}
case 'C': case 'C':
case 'V': case 'V':
if ((fmt + 1) != args.end()) { 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 callargs, std::size_t &nargs,
std::size_t offset, std::size_t skip, std::uint32_t op 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 *>( integer_var *anargs = static_cast<integer_var *>(
ts.istate->identmap[ID_IDX_NUMARGS] 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_FLOAT:
case BC_INST_CALL | BC_RET_INT: { case BC_INST_CALL | BC_RET_INT: {
result.force_none(); result.force_none();
ident *id = ts.istate->identmap[op >> 13]; ident *id = ts.istate->identmap[op >> 8];
std::size_t callargs = (op >> 8) & 0x1F; std::size_t callargs = *code++;
std::size_t nnargs = args.size(); std::size_t nnargs = args.size();
std::size_t offset = nnargs - callargs; std::size_t offset = nnargs - callargs;
auto flags = id->get_flags(); 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_FLOAT:
case BC_INST_COM_V | BC_RET_INT: { case BC_INST_COM_V | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>( 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; std::size_t offset = args.size() - callargs;
result.force_none(); result.force_none();
id->call(cs, std::span{&args[offset], callargs}, result); 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_FLOAT:
case BC_INST_COM_C | BC_RET_INT: { case BC_INST_COM_C | BC_RET_INT: {
command_impl *id = static_cast<command_impl *>( 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++;
offset = args.size() - callargs; std::size_t offset = args.size() - callargs;
result.force_none(); result.force_none();
{ {
any_value tv{cs}; any_value tv{cs};