use an ellipsis for variadics instead of V

master
Daniel Kolesa 2021-04-29 19:56:48 +02:00
parent e14d5c4aa3
commit 5d4bcaf797
10 changed files with 78 additions and 80 deletions

View File

@ -316,13 +316,13 @@ struct LIBCUBESCRIPT_EXPORT state {
* check the type explicitly for whether it was actually provided.
*
* Commands also support variadics. Variadic commands have their type
* list suffixed with `V`.
* list suffixed with `...`.
*
* If `V` is used alone, the inputs are any arbitrary values. However,
* If `...` is used alone, the inputs are any arbitrary values. However,
* they can also be used with repetition. Repetition works for example
* like `if2V`. The `2` is the number of types to repeat; it must be at
* like `if2...`. The `2` is the number of types to repeat; it must be at
* most the number of simple types preceeding it. It must be followed by
* `V`. This specific example means that the variadic arguments are a
* `...`. This specific example means that the variadic arguments are a
* sequence of integer, float, integer, float, integer, float and so on.
*
* The resulting command stores the number of arguments it takes. The

View File

@ -543,7 +543,7 @@ lookup_id:
gs.gen_val_integer(-1);
++numargs;
break;
case 'V':
case '.':
comtype = BC_INST_COM_V;
break;
case '1':
@ -991,7 +991,8 @@ bool parser_state::parse_call_command(
gs.gen_val_integer(numargs - fakeargs);
++numargs;
break;
case 'V': /* varargs */
case '.': /* varargs */
it += 2; /* third will be skipped by the loop */
comtype = BC_INST_COM_V;
if (more) {
for (;;) {
@ -1271,7 +1272,8 @@ static bool parse_assign_var(
ps.gs.gen_val_integer(nargs);
++nargs;
break;
case 'V':
case '.':
it += 2; /* third will be skipped by the loop */
comtype = BC_INST_COM_V;
if (more && !got) {
more = ps.parse_arg(VAL_ANY);

View File

@ -199,7 +199,7 @@ state::state(alloc_func func, void *data) {
});
static_cast<command_impl *>(p)->p_type = ID_NOT;
p = &new_command("&&", "c1V", [](auto &cs, auto args, auto &res) {
p = &new_command("&&", "c1...", [](auto &cs, auto args, auto &res) {
if (args.empty()) {
res.set_integer(1);
} else {
@ -218,7 +218,7 @@ state::state(alloc_func func, void *data) {
});
static_cast<command_impl *>(p)->p_type = ID_AND;
p = &new_command("||", "c1V", [](auto &cs, auto args, auto &res) {
p = &new_command("||", "c1...", [](auto &cs, auto args, auto &res) {
if (args.empty()) {
res.set_integer(0);
} else {
@ -616,12 +616,12 @@ LIBCUBESCRIPT_EXPORT command &state::new_command(
*this, "not enough arguments to repeat"
};
}
if ((args.end() - fmt) != 2) {
if ((args.end() - fmt) != 4) {
throw error{
*this, "malformed argument list"
};
}
if (fmt[1] != 'V') {
if (fmt[1] != '.') {
throw error{
*this, "repetition without variadic arguments"
};
@ -629,12 +629,16 @@ LIBCUBESCRIPT_EXPORT command &state::new_command(
nargs -= nrep;
break;
}
case 'V':
if ((fmt + 1) != args.end()) {
case '.':
if (
((fmt + 3) != args.end()) ||
std::memcmp(&fmt[0], "...", 3)
) {
throw error{
*this, "unterminated variadic argument list"
};
}
fmt += 2;
break;
default:
throw error{

View File

@ -112,7 +112,7 @@ void exec_command(
i += 1;
args[i].set_integer(integer_type(lookup ? -1 : i - fakeargs));
break;
case 'V':
case '.':
i = std::max(i + 1, numargs);
static_cast<command_impl *>(id)->call(
ts, span_type<any_value>{args, std::size_t(i)}, res

View File

@ -106,7 +106,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
}
});
new_cmd_quiet(gcs, "cond", "bb2V", [](auto &cs, auto args, auto &res) {
new_cmd_quiet(gcs, "cond", "bb2...", [](auto &cs, auto args, auto &res) {
for (size_t i = 0; i < args.size(); i += 2) {
if ((i + 1) < args.size()) {
if (cs.run(args[i].get_code()).get_bool()) {
@ -120,7 +120,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
}
});
new_cmd_quiet(gcs, "case", "iab2V", [](auto &cs, auto args, auto &res) {
new_cmd_quiet(gcs, "case", "iab2...", [](auto &cs, auto args, auto &res) {
integer_type val = args[0].get_integer();
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (
@ -133,7 +133,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
}
});
new_cmd_quiet(gcs, "casef", "fab2V", [](auto &cs, auto args, auto &res) {
new_cmd_quiet(gcs, "casef", "fab2...", [](auto &cs, auto args, auto &res) {
float_type val = args[0].get_float();
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (
@ -146,7 +146,7 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
}
});
new_cmd_quiet(gcs, "cases", "sab2V", [](auto &cs, auto args, auto &res) {
new_cmd_quiet(gcs, "cases", "sab2...", [](auto &cs, auto args, auto &res) {
string_ref val = args[0].get_string(cs);
for (size_t i = 1; (i + 1) < args.size(); i += 2) {
if (

View File

@ -147,7 +147,7 @@ LIBCUBESCRIPT_EXPORT void std_init_list(state &gcs) {
);
});
new_cmd_quiet(gcs, "at", "si1V", [](auto &cs, auto args, auto &res) {
new_cmd_quiet(gcs, "at", "si1...", [](auto &cs, auto args, auto &res) {
if (args.empty()) {
return;
}

View File

@ -116,28 +116,28 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
res.set_float(std::exp(args[0].get_float()));
});
new_cmd_quiet(cs, "min", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "min", "i1...", [](auto &, auto args, auto &res) {
integer_type v = (!args.empty() ? args[0].get_integer() : 0);
for (size_t i = 1; i < args.size(); ++i) {
v = std::min(v, args[i].get_integer());
}
res.set_integer(v);
});
new_cmd_quiet(cs, "max", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "max", "i1...", [](auto &, auto args, auto &res) {
integer_type v = (!args.empty() ? args[0].get_integer() : 0);
for (size_t i = 1; i < args.size(); ++i) {
v = std::max(v, args[i].get_integer());
}
res.set_integer(v);
});
new_cmd_quiet(cs, "minf", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "minf", "f1...", [](auto &, auto args, auto &res) {
float_type v = (!args.empty() ? args[0].get_float() : 0);
for (size_t i = 1; i < args.size(); ++i) {
v = std::min(v, args[i].get_float());
}
res.set_float(v);
});
new_cmd_quiet(cs, "maxf", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "maxf", "f1...", [](auto &, auto args, auto &res) {
float_type v = (!args.empty() ? args[0].get_float() : 0);
for (size_t i = 1; i < args.size(); ++i) {
v = std::max(v, args[i].get_float());
@ -171,43 +171,43 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
res.set_float(r);
});
new_cmd_quiet(cs, "+", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "+", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(args, res, 0, std::plus<integer_type>(), math_noop<integer_type>());
});
new_cmd_quiet(cs, "*", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "*", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 1, std::multiplies<integer_type>(), math_noop<integer_type>()
);
});
new_cmd_quiet(cs, "-", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "-", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, std::minus<integer_type>(), std::negate<integer_type>()
);
});
new_cmd_quiet(cs, "^", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "^", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, std::bit_xor<integer_type>(), [](integer_type val) { return ~val; }
);
});
new_cmd_quiet(cs, "~", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "~", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, std::bit_xor<integer_type>(), [](integer_type val) { return ~val; }
);
});
new_cmd_quiet(cs, "&", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "&", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, std::bit_and<integer_type>(), math_noop<integer_type>()
);
});
new_cmd_quiet(cs, "|", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "|", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, std::bit_or<integer_type>(), math_noop<integer_type>()
);
});
/* special combined cases */
new_cmd_quiet(cs, "^~", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "^~", "i1...", [](auto &, auto args, auto &res) {
integer_type val;
if (args.size() >= 2) {
val = args[0].get_integer() ^ ~args[1].get_integer();
@ -219,7 +219,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}
res.set_integer(val);
});
new_cmd_quiet(cs, "&~", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "&~", "i1...", [](auto &, auto args, auto &res) {
integer_type val;
if (args.size() >= 2) {
val = args[0].get_integer() & ~args[1].get_integer();
@ -231,7 +231,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}
res.set_integer(val);
});
new_cmd_quiet(cs, "|~", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "|~", "i1...", [](auto &, auto args, auto &res) {
integer_type val;
if (args.size() >= 2) {
val = args[0].get_integer() | ~args[1].get_integer();
@ -244,7 +244,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
res.set_integer(val);
});
new_cmd_quiet(cs, "<<", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "<<", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
return (val2 < integer_type(sizeof(integer_type) * CHAR_BIT))
@ -253,7 +253,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}, math_noop<integer_type>()
);
});
new_cmd_quiet(cs, ">>", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, ">>", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
return val1 >> std::clamp(
@ -263,23 +263,23 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
);
});
new_cmd_quiet(cs, "+f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "+f", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 0, std::plus<float_type>(), math_noop<float_type>()
);
});
new_cmd_quiet(cs, "*f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "*f", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 1, std::multiplies<float_type>(), math_noop<float_type>()
);
});
new_cmd_quiet(cs, "-f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "-f", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 0, std::minus<float_type>(), std::negate<float_type>()
);
});
new_cmd_quiet(cs, "div", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "div", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
if (val2) {
@ -289,7 +289,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}, math_noop<integer_type>()
);
});
new_cmd_quiet(cs, "mod", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "mod", "i1...", [](auto &, auto args, auto &res) {
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
if (val2) {
@ -299,7 +299,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}, math_noop<integer_type>()
);
});
new_cmd_quiet(cs, "divf", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "divf", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
if (val2) {
@ -309,7 +309,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
}, math_noop<float_type>()
);
});
new_cmd_quiet(cs, "modf", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "modf", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
if (val2) {
@ -320,7 +320,7 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
);
});
new_cmd_quiet(cs, "pow", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "pow", "f1...", [](auto &, auto args, auto &res) {
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
return float_type(pow(val1, val2));
@ -328,41 +328,41 @@ LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
);
});
new_cmd_quiet(cs, "=", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "=", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::equal_to<integer_type>());
});
new_cmd_quiet(cs, "!=", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "!=", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::not_equal_to<integer_type>());
});
new_cmd_quiet(cs, "<", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "<", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::less<integer_type>());
});
new_cmd_quiet(cs, ">", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, ">", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::greater<integer_type>());
});
new_cmd_quiet(cs, "<=", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "<=", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::less_equal<integer_type>());
});
new_cmd_quiet(cs, ">=", "i1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, ">=", "i1...", [](auto &, auto args, auto &res) {
cmp_op<integer_type>(args, res, std::greater_equal<integer_type>());
});
new_cmd_quiet(cs, "=f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "=f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::equal_to<float_type>());
});
new_cmd_quiet(cs, "!=f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "!=f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::not_equal_to<float_type>());
});
new_cmd_quiet(cs, "<f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "<f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::less<float_type>());
});
new_cmd_quiet(cs, ">f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, ">f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::greater<float_type>());
});
new_cmd_quiet(cs, "<=f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, "<=f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::less_equal<float_type>());
});
new_cmd_quiet(cs, ">=f", "f1V", [](auto &, auto args, auto &res) {
new_cmd_quiet(cs, ">=f", "f1...", [](auto &, auto args, auto &res) {
cmp_op<float_type>(args, res, std::greater_equal<float_type>());
});
}

View File

@ -91,15 +91,15 @@ LIBCUBESCRIPT_EXPORT void std_init_string(state &cs) {
res.set_string(s.str(), ccs);
});
new_cmd_quiet(cs, "concat", "V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "concat", "...", [](auto &ccs, auto args, auto &res) {
res.set_string(concat_values(ccs, args, " "));
});
new_cmd_quiet(cs, "concatword", "V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "concatword", "...", [](auto &ccs, auto args, auto &res) {
res.set_string(concat_values(ccs, args));
});
new_cmd_quiet(cs, "format", "V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "format", "...", [](auto &ccs, auto args, auto &res) {
if (args.empty()) {
return;
}
@ -166,25 +166,25 @@ LIBCUBESCRIPT_EXPORT void std_init_string(state &cs) {
}, ccs);
});
new_cmd_quiet(cs, "strcmp", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "strcmp", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::equal_to<std::string_view>());
});
new_cmd_quiet(cs, "=s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "=s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::equal_to<std::string_view>());
});
new_cmd_quiet(cs, "!=s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "!=s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::not_equal_to<std::string_view>());
});
new_cmd_quiet(cs, "<s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "<s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::less<std::string_view>());
});
new_cmd_quiet(cs, ">s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, ">s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::greater<std::string_view>());
});
new_cmd_quiet(cs, "<=s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, "<=s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::less_equal<std::string_view>());
});
new_cmd_quiet(cs, ">=s", "s1V", [](auto &ccs, auto args, auto &res) {
new_cmd_quiet(cs, ">=s", "s1...", [](auto &ccs, auto args, auto &res) {
str_cmp_by(ccs, args, res, std::greater_equal<std::string_view>());
});

View File

@ -50,7 +50,7 @@ int main(int argc, char **argv) {
cs::state gcs;
cs::std_init_all(gcs);
gcs.new_command("echo", "V", [](auto &s, auto args, auto &) {
gcs.new_command("echo", "...", [](auto &s, auto args, auto &) {
std::printf("%s\n", cs::concat_values(s, args, " ").data());
});

View File

@ -75,20 +75,18 @@ inline std::string_view get_arg_type(char arg) {
}
inline void fill_cmd_args(std::string &writer, std::string_view args) {
char variadic = '\0';
bool variadic = false;
int nrep = 0;
if (!args.empty() && ((args.back() == 'V') || (args.back() == 'C'))) {
variadic = args.back();
args.remove_suffix(1);
if ((args.size() >= 3) && (args.substr(args.size() - 3) == "...")) {
variadic = true;
args.remove_suffix(3);
if (!args.empty() && isdigit(args.back())) {
nrep = args.back() - '0';
args.remove_suffix(1);
}
}
if (args.empty()) {
if (variadic == 'C') {
writer += "concat(...)";
} else if (variadic == 'V') {
if (variadic) {
writer += "...";
}
return;
@ -107,9 +105,6 @@ inline void fill_cmd_args(std::string &writer, std::string_view args) {
if (norep > 0) {
writer += ", ";
}
if (variadic == 'C') {
writer += "concat(";
}
if (!args.empty()) {
if (args.size() > 1) {
writer += '{';
@ -125,9 +120,6 @@ inline void fill_cmd_args(std::string &writer, std::string_view args) {
}
}
writer += "...";
if (variadic == 'C') {
writer += ")";
}
}
}
@ -371,7 +363,7 @@ int main(int argc, char **argv) {
}
});
gcs.new_command("echo", "V", [](auto &css, auto args, auto &) {
gcs.new_command("echo", "...", [](auto &css, auto args, auto &) {
std::printf("%s\n", cs::concat_values(css, args, " ").data());
});