#include "libpspp/message.h"
#include "libpspp/str.h"
#include "libpspp/string-array.h"
-#include "libpspp/string-map.h"
+#include "libpspp/stringi-map.h"
#include "libpspp/stringi-set.h"
#include "gl/c-ctype.h"
hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
}
\f
-/* Macro expander. */
+/* Macro call parsing.. */
enum mc_state
{
enum mc_state state;
size_t n_tokens;
const struct macro_param *param; /* Parameter currently being parsed. */
-
- enum segmenter_mode segmenter_mode;
};
/* Completes macro expansion by initializing arguments that weren't supplied to
NOT_REACHED ();
}
}
+\f
+/* Macro expansion. */
+
+struct macro_expander
+ {
+ const struct macro_set *macros;
+ const struct macro *macro;
+ struct macro_tokens **args;
+ enum segmenter_mode segmenter_mode;
+ struct stringi_map *vars;
+ bool *expand;
+ bool *break_;
+ int nesting_countdown;
+ };
/* Each argument to a macro function is one of:
{
const struct macro_token *input;
size_t n_input;
- int nesting_countdown;
- const struct macro_set *macros;
- const struct macro_call *mc;
+ const struct macro_expander *me;
const struct macro_expansion_stack *stack;
- struct string_map *vars;
- bool *expand;
};
static void
-macro_expand (const struct macro_tokens *, int nesting_countdown,
- const struct macro_set *,
- const struct macro_call *, struct string_map *vars,
- const struct macro_expansion_stack *stack,
- bool *expand, bool *break_,
- struct macro_tokens *exp);
+macro_expand (const struct macro_tokens *, const struct macro_expander *,
+ const struct macro_expansion_stack *,
+ struct macro_tokens *);
static bool
expand_macro_function (struct parse_macro_function_ctx *ctx,
{
const struct macro_token *tokens = ctx->input;
const struct token *token = &tokens[i].token;
- if (token->type == T_MACRO_ID)
+ if (token->type == T_MACRO_ID && ctx->me->macro)
{
const struct macro_param *param = macro_find_parameter_by_name (
- ctx->mc->macro, token->string);
+ ctx->me->macro, token->string);
if (param)
{
- size_t param_idx = param - ctx->mc->macro->params;
- const struct macro_tokens *marg = ctx->mc->args[param_idx];
+ size_t param_idx = param - ctx->me->macro->params;
+ const struct macro_tokens *marg = ctx->me->args[param_idx];
for (size_t i = 0; i < marg->n; i++)
{
if (i)
if (is_bang_star (ctx->input, ctx->n_input, i))
{
- for (size_t i = 0; i < ctx->mc->macro->n_params; i++)
+ for (size_t i = 0; i < ctx->me->macro->n_params; i++)
{
- if (!ctx->mc->macro->params[i].positional)
+ if (!ctx->me->macro->params[i].positional)
break;
- const struct macro_tokens *marg = ctx->mc->args[i];
+ const struct macro_tokens *marg = ctx->me->args[i];
for (size_t j = 0; j < marg->n; j++)
{
if (i || j)
return 2;
}
- if (ctx->vars)
+ const char *value = stringi_map_find__ (ctx->me->vars,
+ token->string.string,
+ token->string.length);
+ if (value)
{
- const char *value = string_map_find__ (ctx->vars,
- token->string.string,
- token->string.length);
- if (value)
- {
- ds_put_cstr (farg, value);
- return 1;
- }
+ ds_put_cstr (farg, value);
+ return 1;
}
struct parse_macro_function_ctx subctx = {
.input = &ctx->input[i],
.n_input = ctx->n_input - i,
- .nesting_countdown = ctx->nesting_countdown,
- .macros = ctx->macros,
- .mc = ctx->mc,
+ .me = ctx->me,
.stack = ctx->stack,
- .vars = ctx->vars,
- .expand = ctx->expand,
};
size_t subinput_consumed;
if (expand_macro_function (&subctx, farg, &subinput_consumed))
input_consumed))
{
for (size_t i = 0; i < args.n; i++)
- if (!unquote_string (args.strings[i], ctx->mc->segmenter_mode, output))
+ if (!unquote_string (args.strings[i], ctx->me->segmenter_mode, output))
ds_put_cstr (output, args.strings[i]);
}
else if (parse_macro_function (ctx, &args, ss_cstr ("!HEAD"), 1, 1,
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->mc->segmenter_mode, &tmp);
+ ctx->me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->mc->segmenter_mode,
+ macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
ctx->stack);
if (mts.n > 0)
ds_put_substring (output, mts.mts[0].representation);
else if (parse_macro_function (ctx, &args, ss_cstr ("!QUOTE"), 1, 1,
input_consumed))
{
- if (unquote_string (args.strings[0], ctx->mc->segmenter_mode, NULL))
+ if (unquote_string (args.strings[0], ctx->me->segmenter_mode, NULL))
ds_put_cstr (output, args.strings[0]);
else
{
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->mc->segmenter_mode, &tmp);
+ ctx->me->segmenter_mode, &tmp);
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->mc->segmenter_mode,
+ macro_tokens_from_string__ (&mts, ss_cstr (s), ctx->me->segmenter_mode,
ctx->stack);
if (mts.n > 1)
{
else if (parse_macro_function (ctx, &args, ss_cstr ("!UNQUOTE"), 1, 1,
input_consumed))
{
- if (!unquote_string (args.strings[0], ctx->mc->segmenter_mode, output))
+ if (!unquote_string (args.strings[0], ctx->me->segmenter_mode, output))
ds_put_cstr (output, args.strings[0]);
}
else if (parse_macro_function (ctx, &args, ss_cstr ("!UPCASE"), 1, 1,
{
struct string tmp;
const char *s = unquote_string_in_place (args.strings[0],
- ctx->mc->segmenter_mode, &tmp);
+ ctx->me->segmenter_mode, &tmp);
char *upper = utf8_to_upper (s);
ds_put_cstr (output, upper);
free (upper);
{
struct macro_tokens mts = { .n = 0 };
macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
- ctx->mc->segmenter_mode, ctx->stack);
+ ctx->me->segmenter_mode, ctx->stack);
struct macro_tokens exp = { .n = 0 };
- macro_expand (&mts, ctx->nesting_countdown - 1,
- ctx->macros, ctx->mc, ctx->vars,
+ struct macro_expander subme = *ctx->me;
+ subme.break_ = NULL;
+ macro_expand (&mts, &subme,
&(struct macro_expansion_stack) {
.name = "!EVAL",
.next = ctx->stack,
- }, ctx->expand, NULL, &exp);
+ }, &exp);
macro_tokens_to_representation (&exp, output, NULL, NULL);
macro_tokens_uninit (&exp);
macro_tokens_uninit (&mts);
return true;
}
-struct expr_context
- {
- int nesting_countdown;
- const struct macro_set *macros;
- const struct macro_call *mc;
- const struct macro_expansion_stack *stack;
- struct string_map *vars;
- bool *expand;
- };
-
-static char *macro_evaluate_or (const struct expr_context *ctx,
+static char *macro_evaluate_or (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end);
static char *
-macro_evaluate_literal (const struct expr_context *ctx,
+macro_evaluate_literal (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
if (p->token.type == T_LPAREN)
{
p++;
- char *value = macro_evaluate_or (ctx, &p, end);
+ char *value = macro_evaluate_or (me, stack, &p, end);
if (!value)
return NULL;
if (p >= end || p->token.type != T_RPAREN)
{
free (value);
- macro_error (ctx->stack, p < end ? p : NULL,
+ macro_error (stack, p < end ? p : NULL,
_("Expecting ')' in macro expression."));
return NULL;
}
}
else if (p->token.type == T_RPAREN)
{
- macro_error (ctx->stack, p, _("Expecting literal or function invocation "
- "in macro expression."));
+ macro_error (stack, p, _("Expecting literal or function invocation "
+ "in macro expression."));
return NULL;
}
struct parse_macro_function_ctx fctx = {
.input = p,
.n_input = end - p,
- .nesting_countdown = ctx->nesting_countdown,
- .macros = ctx->macros,
- .mc = ctx->mc,
- .stack = ctx->stack,
- .vars = ctx->vars,
- .expand = ctx->expand,
+ .me = me,
+ .stack = stack,
};
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
struct string unquoted = DS_EMPTY_INITIALIZER;
- if (unquote_string (ds_cstr (&function_output), ctx->mc->segmenter_mode,
+ if (unquote_string (ds_cstr (&function_output), me->segmenter_mode,
&unquoted))
{
ds_swap (&function_output, &unquoted);
}
static char *
-macro_evaluate_relational (const struct expr_context *ctx,
+macro_evaluate_relational (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_literal (ctx, &p, end);
+ char *lhs = macro_evaluate_literal (me, stack, &p, end);
if (!lhs)
return NULL;
}
p++;
- char *rhs = macro_evaluate_literal (ctx, &p, end);
+ char *rhs = macro_evaluate_literal (me, stack, &p, end);
if (!rhs)
{
free (lhs);
}
struct string lhs_tmp, rhs_tmp;
- int cmp = strcmp (unquote_string_in_place (lhs, ctx->mc->segmenter_mode,
+ int cmp = strcmp (unquote_string_in_place (lhs, me->segmenter_mode,
&lhs_tmp),
- unquote_string_in_place (rhs, ctx->mc->segmenter_mode,
+ unquote_string_in_place (rhs, me->segmenter_mode,
&rhs_tmp));
ds_destroy (&lhs_tmp);
ds_destroy (&rhs_tmp);
}
static char *
-macro_evaluate_not (const struct expr_context *ctx,
+macro_evaluate_not (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
negations++;
}
- char *operand = macro_evaluate_relational (ctx, &p, end);
+ char *operand = macro_evaluate_relational (me, stack, &p, end);
if (!operand || !negations)
{
*tokens = p;
}
static char *
-macro_evaluate_and (const struct expr_context *ctx,
+macro_evaluate_and (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_not (ctx, &p, end);
+ char *lhs = macro_evaluate_not (me, stack, &p, end);
if (!lhs)
return NULL;
|| ss_equals (p->representation, ss_cstr ("&"))))
{
p++;
- char *rhs = macro_evaluate_not (ctx, &p, end);
+ char *rhs = macro_evaluate_not (me, stack, &p, end);
if (!rhs)
{
free (lhs);
}
static char *
-macro_evaluate_or (const struct expr_context *ctx,
+macro_evaluate_or (const struct macro_expander *me,
+ const struct macro_expansion_stack *stack,
const struct macro_token **tokens,
const struct macro_token *end)
{
const struct macro_token *p = *tokens;
- char *lhs = macro_evaluate_and (ctx, &p, end);
+ char *lhs = macro_evaluate_and (me, stack, &p, end);
if (!lhs)
return NULL;
|| ss_equals (p->representation, ss_cstr ("|"))))
{
p++;
- char *rhs = macro_evaluate_and (ctx, &p, end);
+ char *rhs = macro_evaluate_and (me, stack, &p, end);
if (!rhs)
{
free (lhs);
static char *
macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
- int nesting_countdown,
- const struct macro_set *macros,
- const struct macro_call *mc,
- const struct macro_expansion_stack *stack,
- struct string_map *vars, bool *expand)
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack)
{
- const struct expr_context ctx = {
- .nesting_countdown = nesting_countdown,
- .macros = macros,
- .mc = mc,
- .stack = stack,
- .vars = vars,
- .expand = expand,
- };
- return macro_evaluate_or (&ctx, tokens, *tokens + n_tokens);
+ return macro_evaluate_or (me, stack, tokens, *tokens + n_tokens);
}
static bool
macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
- int nesting_countdown,
- const struct macro_set *macros,
- const struct macro_call *mc,
+ const struct macro_expander *me,
const struct macro_expansion_stack *stack,
- struct string_map *vars,
- bool *expand, double *number)
+ double *number)
{
- char *s = macro_evaluate_expression (tokens, n_tokens, nesting_countdown,
- macros, mc, stack, vars, expand);
+ char *s = macro_evaluate_expression (tokens, n_tokens, me, stack);
if (!s)
return false;
struct macro_tokens mts = { .n = 0 };
- macro_tokens_from_string__ (&mts, ss_cstr (s), mc->segmenter_mode, stack);
+ macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, stack);
if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
{
macro_error (stack, mts.n > 0 ? &mts.mts[0] : NULL,
static size_t
macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_call *mc,
+ const struct macro_expander *me,
const struct macro_expansion_stack *stack,
- struct string_map *vars,
- bool *expand, bool *break_, struct macro_tokens *exp)
+ struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
return 0;
p++;
- char *result = macro_evaluate_expression (&p, end - p,
- nesting_countdown,
- macros, mc,
- stack, vars, expand);
+ char *result = macro_evaluate_expression (&p, end - p, me, stack);
if (!result)
return 0;
bool b = strcmp (result, "0");
.mts = CONST_CAST (struct macro_token *, start),
.n = n,
};
- macro_expand (&mts, nesting_countdown, macros, mc, vars,
- &(struct macro_expansion_stack) {
+ macro_expand (&mts, me, &(struct macro_expansion_stack) {
.name = "!IF",
.next = stack,
},
- expand, break_, exp);
+ exp);
}
return (end_if + 1) - tokens;
}
static size_t
macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_call *mc,
- const struct macro_expansion_stack *stack,
- struct string_map *vars, bool *expand)
+ const struct macro_expander *me,
+ const struct macro_expansion_stack *stack)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
}
const struct substring var_name = p->token.string;
if (is_macro_keyword (var_name)
- || macro_find_parameter_by_name (mc->macro, var_name))
+ || (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
{
macro_error (stack, p < end ? p : NULL,
_("Cannot use argument name or macro keyword "
}
p++;
- char *value = macro_evaluate_expression (&p, end - p, nesting_countdown,
- macros, mc, stack, vars, expand);
+ char *value = macro_evaluate_expression (&p, end - p, me, stack);
if (!value)
return 0;
- string_map_replace_nocopy (vars, ss_xstrdup (var_name), value);
+ stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name), value);
return p - tokens;
}
static size_t
macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
- int nesting_countdown, const struct macro_set *macros,
- const struct macro_call *mc,
+ const struct macro_expander *me,
const struct macro_expansion_stack *stack,
- struct string_map *vars,
- bool *expand, struct macro_tokens *exp)
+ struct macro_tokens *exp)
{
const struct macro_token *p = tokens;
const struct macro_token *end = tokens + n_tokens;
}
const struct substring var_name = p->token.string;
if (is_macro_keyword (var_name)
- || macro_find_parameter_by_name (mc->macro, var_name))
+ || (me->macro && macro_find_parameter_by_name (me->macro, var_name)))
{
macro_error (stack, p, _("Cannot use argument name or macro "
"keyword as !DO variable."));
&& ss_equals_case (p->token.string, ss_cstr ("!IN")))
{
p++;
- char *list = macro_evaluate_expression (&p, end - p, nesting_countdown,
- macros, mc, &next_stack, vars,
- expand);
+ char *list = macro_evaluate_expression (&p, end - p, me, &next_stack);
if (!list)
return 0;
struct macro_tokens items = { .n = 0 };
- macro_tokens_from_string__ (&items, ss_cstr (list), mc->segmenter_mode,
+ macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode,
stack);
free (list);
.mts = CONST_CAST (struct macro_token *, p),
.n = do_end - p
};
- for (size_t i = 0; i < items.n; i++)
+
+ bool break_ = false;
+ struct macro_expander subme = *me;
+ subme.break_ = &break_;
+
+ for (size_t i = 0; i < items.n && !break_; i++)
{
if (i >= miterate)
{
miterate);
break;
}
- string_map_replace_nocopy (vars, ss_xstrdup (var_name),
- ss_xstrdup (items.mts[i].representation));
+ stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
+ ss_xstrdup (items.mts[i].representation));
- bool break_ = false;
- macro_expand (&inner, nesting_countdown, macros,
- mc, vars, &next_stack, expand, &break_, exp);
- if (break_)
- break;
+ macro_expand (&inner, &subme, &next_stack, exp);
}
return do_end - tokens + 1;
}
{
p++;
double first;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown,
- macros, mc, &next_stack,
- vars, expand, &first))
+ if (!macro_evaluate_number (&p, end - p, me, &next_stack, &first))
return 0;
if (p >= end || p->token.type != T_MACRO_ID
p++;
double last;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown,
- macros, mc, &next_stack,
- vars, expand, &last))
+ if (!macro_evaluate_number (&p, end - p, me, &next_stack, &last))
return 0;
double by = 1.0;
&& ss_equals_case (p->token.string, ss_cstr ("!BY")))
{
p++;
- if (!macro_evaluate_number (&p, end - p, nesting_countdown,
- macros, mc, &next_stack,
- vars, expand, &by))
+ if (!macro_evaluate_number (&p, end - p, me, &next_stack, &by))
return 0;
if (by == 0.0)
.n = do_end - p
};
+ bool break_ = false;
+ struct macro_expander subme = *me;
+ subme.break_ = &break_;
+
if ((by > 0 && first <= last) || (by < 0 && first >= last))
{
int i = 0;
for (double index = first;
- by > 0 ? (index <= last) : (index >= last);
+ by > 0 ? (index <= last) : (index >= last) && !break_;
index += by)
{
if (i++ > miterate)
char index_s[DBL_BUFSIZE_BOUND];
c_dtoastr (index_s, sizeof index_s, 0, 0, index);
- string_map_replace_nocopy (vars, ss_xstrdup (var_name),
- xstrdup (index_s));
-
- bool break_ = false;
- macro_expand (&inner, nesting_countdown,
- macros, mc, vars, &next_stack, expand, &break_,
- exp);
- if (break_)
- break;
+ stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
+ xstrdup (index_s));
+
+ macro_expand (&inner, &subme, &next_stack, exp);
}
}
}
static void
-macro_expand (const struct macro_tokens *mts, int nesting_countdown,
- const struct macro_set *macros,
- const struct macro_call *mc, struct string_map *vars,
+macro_expand (const struct macro_tokens *mts,
+ const struct macro_expander *me,
const struct macro_expansion_stack *stack,
- bool *expand, bool *break_, struct macro_tokens *exp)
+ struct macro_tokens *exp)
{
- if (nesting_countdown <= 0)
+ if (me->nesting_countdown <= 0)
{
macro_error (stack, NULL, _("Maximum nesting level %d exceeded. "
"(Use SET MNEST to change the limit.)"),
return;
}
- struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
- if (!vars)
- vars = &own_vars;
-
- for (size_t i = 0; i < mts->n && (!break_ || !*break_); i++)
+ for (size_t i = 0; i < mts->n && (!me->break_ || !*me->break_); i++)
{
const struct macro_token *mt = &mts->mts[i];
const struct token *token = &mt->token;
- if (token->type == T_MACRO_ID && mc)
+ if (token->type == T_MACRO_ID && me->macro)
{
const struct macro_param *param = macro_find_parameter_by_name (
- mc->macro, token->string);
+ me->macro, token->string);
if (param)
{
- const struct macro_tokens *arg = mc->args[param - mc->macro->params];
- if (*expand && param->expand_arg)
- macro_expand (arg, nesting_countdown,
- macros, NULL, NULL,
- &(struct macro_expansion_stack) {
- .name = param->name,
- .next = stack,
- }, expand, break_, exp);
+ const struct macro_tokens *arg
+ = me->args[param - me->macro->params];
+ if (*me->expand && param->expand_arg)
+ {
+ struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expander subme = {
+ .macros = me->macros,
+ .macro = NULL,
+ .args = NULL,
+ .segmenter_mode = me->segmenter_mode,
+ .expand = me->expand,
+ .break_ = NULL,
+ .vars = &vars,
+ .nesting_countdown = me->nesting_countdown,
+ };
+ macro_expand (arg, &subme, &(struct macro_expansion_stack) {
+ .name = param->name,
+ .next = stack,
+ }, exp);
+ stringi_map_destroy (&vars);
+ }
else
for (size_t i = 0; i < arg->n; i++)
macro_tokens_add (exp, &arg->mts[i]);
if (is_bang_star (mts->mts, mts->n, i))
{
- for (size_t j = 0; j < mc->macro->n_params; j++)
+ for (size_t j = 0; j < me->macro->n_params; j++)
{
- const struct macro_param *param = &mc->macro->params[j];
+ const struct macro_param *param = &me->macro->params[j];
if (!param->positional)
break;
- const struct macro_tokens *arg = mc->args[j];
- if (*expand && param->expand_arg)
- macro_expand (arg, nesting_countdown,
- macros, NULL, NULL,
- &(struct macro_expansion_stack) {
- .name = "!*",
- .next = stack,
- }, expand, break_, exp);
+ const struct macro_tokens *arg = me->args[j];
+ if (*me->expand && param->expand_arg)
+ {
+ struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expander subme = {
+ .macros = me->macros,
+ .macro = NULL,
+ .args = NULL,
+ .segmenter_mode = me->segmenter_mode,
+ .expand = me->expand,
+ .break_ = NULL,
+ .vars = &vars,
+ .nesting_countdown = me->nesting_countdown,
+ };
+ macro_expand (arg, &subme,
+ &(struct macro_expansion_stack) {
+ .name = "!*",
+ .next = stack,
+ }, exp);
+ stringi_map_destroy (&vars);
+ }
else
for (size_t k = 0; k < arg->n; k++)
macro_tokens_add (exp, &arg->mts[k]);
continue;
}
- size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
- nesting_countdown,
- macros, mc, stack,
- vars, expand, break_, exp);
+ size_t n = macro_expand_if (&mts->mts[i], mts->n - i, me, stack,
+ exp);
if (n > 0)
{
i += n - 1;
}
}
- if (token->type == T_MACRO_ID && vars)
+ if (token->type == T_MACRO_ID)
{
- const char *value = string_map_find__ (vars, token->string.string,
- token->string.length);
+ const char *value = stringi_map_find__ (me->vars,
+ token->string.string,
+ token->string.length);
if (value)
{
macro_tokens_from_string__ (exp, ss_cstr (value),
- mc->segmenter_mode, stack);
+ me->segmenter_mode, stack);
continue;
}
}
- if (*expand)
+ if (*me->expand)
{
- struct macro_call *subme;
- int retval = macro_call_create (macros, token, &subme);
+ struct macro_call *submc;
+ int retval = macro_call_create (me->macros, token, &submc);
for (size_t j = 1; !retval; j++)
{
- const struct macro_token endcmd = { .token = { .type = T_ENDCMD } };
+ const struct macro_token endcmd
+ = { .token = { .type = T_ENDCMD } };
retval = macro_call_add (
- subme, i + j < mts->n ? &mts->mts[i + j] : &endcmd);
+ submc, i + j < mts->n ? &mts->mts[i + j] : &endcmd);
}
if (retval > 0)
{
i += retval - 1;
- macro_expand (&subme->macro->body, nesting_countdown - 1,
- macros, subme, NULL,
+ struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expander subme = {
+ .macros = submc->macros,
+ .macro = submc->macro,
+ .args = submc->args,
+ .segmenter_mode = me->segmenter_mode,
+ .expand = me->expand,
+ .break_ = NULL,
+ .vars = &vars,
+ .nesting_countdown = me->nesting_countdown - 1,
+ };
+ macro_expand (&submc->macro->body, &subme,
&(struct macro_expansion_stack) {
- .name = subme->macro->name,
- .file_name = subme->macro->file_name,
- .first_line = subme->macro->first_line,
- .last_line = subme->macro->last_line,
+ .name = submc->macro->name,
+ .file_name = submc->macro->file_name,
+ .first_line = submc->macro->first_line,
+ .last_line = submc->macro->last_line,
.next = stack,
- }, expand, break_, exp);
- macro_call_destroy (subme);
+ }, exp);
+ macro_call_destroy (submc);
+ stringi_map_destroy (&vars);
continue;
}
- macro_call_destroy (subme);
+ macro_call_destroy (submc);
}
if (token->type != T_MACRO_ID)
if (ss_equals_case (token->string, ss_cstr ("!break")))
{
- if (!break_)
+ if (!me->break_)
macro_error (stack, mt, _("!BREAK outside !DO."));
else
{
- *break_ = true;
+ *me->break_ = true;
break;
}
}
struct parse_macro_function_ctx ctx = {
.input = &mts->mts[i],
.n_input = mts->n - i,
- .nesting_countdown = nesting_countdown,
- .macros = macros,
- .mc = mc,
+ .me = me,
.stack = stack,
- .vars = vars,
- .expand = expand,
};
struct string function_output = DS_EMPTY_INITIALIZER;
size_t function_consumed;
i += function_consumed - 1;
macro_tokens_from_string__ (exp, function_output.ss,
- mc->segmenter_mode, stack);
+ me->segmenter_mode, stack);
ds_destroy (&function_output);
continue;
}
- size_t n = macro_parse_let (&mts->mts[i], mts->n - i,
- nesting_countdown,
- macros, mc, stack, vars, expand);
+ size_t n = macro_parse_let (&mts->mts[i], mts->n - i, me, stack);
if (n > 0)
{
i += n - 1;
continue;
}
- n = macro_expand_do (&mts->mts[i], mts->n - i,
- nesting_countdown, macros, mc, stack,
- vars, expand, exp);
+ n = macro_expand_do (&mts->mts[i], mts->n - i, me, stack, exp);
if (n > 0)
{
i += n - 1;
}
if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
- *expand = true;
+ *me->expand = true;
else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
- *expand = false;
+ *me->expand = false;
else
macro_tokens_add (exp, mt);
}
- if (vars == &own_vars)
- string_map_destroy (&own_vars);
}
void
struct macro_tokens *exp)
{
assert (mc->state == MC_FINISHED);
- mc->segmenter_mode = segmenter_mode;
bool expand = true;
+ struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
+ struct macro_expander me = {
+ .macros = mc->macros,
+ .macro = mc->macro,
+ .args = mc->args,
+ .segmenter_mode = segmenter_mode,
+ .expand = &expand,
+ .break_ = NULL,
+ .vars = &vars,
+ .nesting_countdown = settings_get_mnest (),
+ };
+
struct macro_expansion_stack stack = {
.name = mc->macro->name,
.file_name = mc->macro->file_name,
.first_line = mc->macro->first_line,
.last_line = mc->macro->last_line,
};
- macro_expand (&mc->macro->body, settings_get_mnest (),
- mc->macros, mc, NULL, &stack, &expand, NULL, exp);
+ macro_expand (&mc->macro->body, &me, &stack, exp);
+
+ stringi_map_destroy (&vars);
}