return me_finished (me);
else
{
- me->state = me->param->positional ? ME_ARG : ME_KEYWORD;
+ me->state = (!me->param->positional ? ME_KEYWORD
+ : me->param->arg_type == ARG_ENCLOSE ? ME_ENCLOSE
+ : ME_ARG);
return 0;
}
}
static int
me_add_arg (struct macro_expander *me, const struct macro_token *mt)
{
+ const struct macro_param *p = me->param;
+
const struct token *token = &mt->token;
- if (token->type == T_ENDCMD || token->type == T_STOP)
+ if ((token->type == T_ENDCMD || token->type == T_STOP)
+ && p->arg_type != ARG_CMDEND)
{
msg (SE, _("Unexpected end of command reading argument %s "
"to macro %s."), me->param->name, me->macro->name);
me->n_tokens++;
- const struct macro_param *p = me->param;
struct macro_tokens **argp = &me->args[p - me->macro->params];
if (!*argp)
*argp = xzalloc (sizeof **argp);
static const struct macro_param *
macro_find_parameter_by_name (const struct macro *m, struct substring name)
{
+ if (ss_first (name) == '!')
+ ss_advance (&name, 1);
+
for (size_t i = 0; i < m->n_params; i++)
{
const struct macro_param *p = &m->params[i];
- struct substring p_name = ss_cstr (p->name);
+ struct substring p_name = ss_cstr (p->name + 1);
if (!utf8_strncasecmp (p_name.string, p_name.length,
name.string, name.length))
return p;
return 1;
else
{
- me->state = macro->params[0].positional ? ME_ARG : ME_KEYWORD;
+ me->state = (!macro->params[0].positional ? ME_KEYWORD
+ : macro->params[0].arg_type == ARG_ENCLOSE ? ME_ENCLOSE
+ : ME_ARG);
me->args = xcalloc (macro->n_params, sizeof *me->args);
me->param = macro->params;
return 0;
else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
input_consumed))
{
- struct string s;
- bool all_strings = true;
+ struct string s = DS_EMPTY_INITIALIZER;
for (size_t i = 0; i < args.n; i++)
{
if (args.mts[i].token.type == T_STRING)
ds_put_substring (&s, args.mts[i].token.string);
else
- {
- all_strings = false;
- ds_put_substring (&s, args.mts[i].representation);
- }
+ ds_put_substring (&s, args.mts[i].representation);
}
- if (all_strings)
- {
- *output = (struct macro_token) {
- .token = { .type = T_STRING, .string = s.ss },
- };
- output->representation = ss_cstr (token_to_string (&output->token));
- }
- else
- {
- *output = (struct macro_token) {
- .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss },
- };
- ss_alloc_substring (&output->representation, s.ss);
- }
+ *output = (struct macro_token) {
+ .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss },
+ };
+ ss_alloc_substring (&output->representation, s.ss);
}
else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
input_consumed))
else
macro_token_copy (output, &args.mts[0]);
}
+ else if (ctx->n_input > 0
+ && ctx->input[0].token.type == T_MACRO_ID
+ && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null")))
+ {
+ *input_consumed = 1;
+ *output = (struct macro_token) {
+ .token = { .type = T_MACRO_ID /* XXX*/ },
+ };
+ ss_alloc_substring (&output->token.string, ss_cstr (""));
+ return true;
+ }
else
return false;
const struct macro_expander *me, bool *expand,
struct macro_tokens *exp)
{
+ /* Macro expansion:
+
+ - Macro names in macro bodies are not expanded by default. !EVAL()
+ expands them.
+
+ - Macro names in arguments to macro invocations (outside of macro bodies)
+ are expanded by default, unless !NOEXPAND. */
if (nesting_countdown <= 0)
{
printf ("maximum nesting level exceeded\n");