summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2023-11-25 22:00:05 +0100
committerMikael Magnusson <mikma@users.sourceforge.net>2023-11-25 22:00:05 +0100
commita4a0755bafaa6dfeceb7badcd2e488f37047f407 (patch)
treef15416da05d3f1ec728bd4faaeac958679782397
parent63233e60fd9f93c8426ded7e5a81d2e7f35e84c9 (diff)
parent21faa54ec3251cb730a23a663ebf7775834ee7a8 (diff)
Merge commit '21faa54e' into wireguard-next-tmp7-1
-rw-r--r--filter/config.Y3
-rw-r--r--filter/decl.m48
-rw-r--r--filter/f-inst.c109
-rw-r--r--filter/f-inst.h2
-rw-r--r--filter/f-util.c34
-rw-r--r--filter/filter.c1
6 files changed, 85 insertions, 72 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 836695d6..389ca724 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -1158,8 +1158,7 @@ cmd:
{ new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
DO cmd {
cf_pop_block_scope(new_config);
- $$ = f_new_inst(FI_FOR_INIT, $6, $3);
- $$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
+ $$ = f_for_cycle($3, $6, $9);
}
| symbol_known '=' term ';' {
switch ($1->class) {
diff --git a/filter/decl.m4 b/filter/decl.m4
index 9ee3ae1a..a7710696 100644
--- a/filter/decl.m4
+++ b/filter/decl.m4
@@ -130,7 +130,7 @@ m4_ifelse($1,1,,[[FID_NEW_METHOD()m4_dnl
struct f_inst *arg$1 = args;
if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */
args = args->next;
- FID_METHOD_CALL() , arg$1]])
+FID_METHOD_CALL() , arg$1]])
FID_LINEARIZE_BODY()m4_dnl
pos = linearize(dest, whati->f$1, pos);
FID_INTERPRET_BODY()')
@@ -230,6 +230,12 @@ FID_NEW_ARGS()m4_dnl
, struct f_inst * f$1
FID_NEW_BODY()m4_dnl
whati->f$1 = f$1;
+m4_define([[INST_METHOD_NUM_ARGS]],m4_eval($1-1))m4_dnl
+FID_NEW_METHOD()m4_dnl
+ struct f_inst *arg$1 = args;
+ if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */
+ args = NULL; /* The rest is the line itself */
+FID_METHOD_CALL() , arg$1
FID_DUMP_BODY()m4_dnl
f_dump_line(item->fl$1, indent + 1);
FID_LINEARIZE_BODY()m4_dnl
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 1b89fdcb..f7361cc7 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -581,92 +581,63 @@
RESULT(T_LCLIST, ad, &null_adata);
}
- INST(FI_FOR_INIT, 1, 0) {
+ /* Common loop begin instruction, always created by f_for_cycle() */
+ INST(FI_FOR_LOOP_START, 0, 3) {
NEVER_CONSTANT;
- ARG_ANY(1);
SYMBOL;
- FID_NEW_BODY()
- ASSERT((sym->class & ~0xff) == SYM_VARIABLE);
+ /* Repeat the instruction which called us */
+ ASSERT_DIE(fstk->ecnt > 1);
+ prevline.pos--;
- /* Static type check */
- if (f1->type)
- {
- enum f_type t_var = (sym->class & 0xff);
- enum f_type t_arg = f_type_element_type(f1->type);
- if (!t_arg)
- cf_error("Value of expression in FOR must be iterable, got %s",
- f_type_name(f1->type));
- if (t_var != t_arg)
- cf_error("Loop variable '%s' in FOR must be %s, is %s",
- sym->name, f_type_name(t_arg), f_type_name(t_var));
- }
+ /* There should be exactly three items on the value stack to be taken care of */
+ fstk->vcnt += 3;
- FID_INTERPRET_BODY()
+ /* And these should also stay there after we finish for the caller instruction */
+ curline.ventry += 3;
- /* Dynamic type check */
- if ((sym->class & 0xff) != f_type_element_type(v1.type))
- runtime("Mismatched argument and variable type");
+ /* Assert the iterator variable positioning */
+ ASSERT_DIE(curline.vbase + sym->offset == fstk->vcnt - 1);
- /* Setup the index */
- v2 = (struct f_val) { .type = T_INT, .val.i = 0 };
-
- /* Keep v1 and v2 on the stack */
- fstk->vcnt += 2;
+ /* The result type declaration makes no sense here but is needed */
+ RESULT_TYPE(T_VOID);
}
- INST(FI_FOR_NEXT, 2, 0) {
+ /* Type-specific for_next iterators */
+ INST(FI_PATH_FOR_NEXT, 3, 0) {
NEVER_CONSTANT;
- SYMBOL;
-
- /* Type checks are done in FI_FOR_INIT */
-
- /* Loop variable */
- struct f_val *var = &fstk->vstk[curline.vbase + sym->offset];
- int step = 0;
-
- switch(v1.type)
- {
- case T_PATH:
- var->type = T_INT;
- step = as_path_walk(v1.val.ad, &v2.val.i, &var->val.i);
- break;
-
- case T_CLIST:
- var->type = T_PAIR;
- step = int_set_walk(v1.val.ad, &v2.val.i, &var->val.i);
- break;
+ ARG(1, T_PATH);
+ if (as_path_walk(v1.val.ad, &v2.val.i, &v3.val.i))
+ LINE(2,0);
- case T_ECLIST:
- var->type = T_EC;
- step = ec_set_walk(v1.val.ad, &v2.val.i, &var->val.ec);
- break;
+ METHOD_CONSTRUCTOR("!for_next");
+ }
- case T_LCLIST:
- var->type = T_LC;
- step = lc_set_walk(v1.val.ad, &v2.val.i, &var->val.lc);
- break;
+ INST(FI_CLIST_FOR_NEXT, 3, 0) {
+ NEVER_CONSTANT;
+ ARG(1, T_CLIST);
+ if (int_set_walk(v1.val.ad, &v2.val.i, &v3.val.i))
+ LINE(2,0);
- default:
- runtime( "Clist or lclist expected" );
- }
+ METHOD_CONSTRUCTOR("!for_next");
+ }
- if (step)
- {
- /* Keep v1 and v2 on the stack */
- fstk->vcnt += 2;
+ INST(FI_ECLIST_FOR_NEXT, 3, 0) {
+ NEVER_CONSTANT;
+ ARG(1, T_ECLIST);
+ if (ec_set_walk(v1.val.ad, &v2.val.i, &v3.val.ec))
+ LINE(2,0);
- /* Repeat this instruction */
- curline.pos--;
+ METHOD_CONSTRUCTOR("!for_next");
+ }
- /* Execute the loop body */
- LINE(1, 0);
+ INST(FI_LCLIST_FOR_NEXT, 3, 0) {
+ NEVER_CONSTANT;
+ ARG(1, T_LCLIST);
+ if (lc_set_walk(v1.val.ad, &v2.val.i, &v3.val.lc))
+ LINE(2,0);
- /* Space for loop variable, may be unused */
- fstk->vcnt += 1;
- }
- else
- var->type = T_VOID;
+ METHOD_CONSTRUCTOR("!for_next");
}
INST(FI_CONDITION, 1, 0) {
diff --git a/filter/f-inst.h b/filter/f-inst.h
index 0913ace6..55272737 100644
--- a/filter/f-inst.h
+++ b/filter/f-inst.h
@@ -96,6 +96,8 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
struct filter *f_new_where(struct f_inst *);
+struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block);
+
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
diff --git a/filter/f-util.c b/filter/f-util.c
index d814493e..ab5b9094 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -41,6 +41,40 @@ struct filter *f_new_where(struct f_inst *where)
return f;
}
+struct f_inst *
+f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
+{
+ ASSERT((var->class & ~0xff) == SYM_VARIABLE);
+ ASSERT(term->next == NULL);
+
+ /* Static type check */
+ if (term->type == T_VOID)
+ cf_error("Couldn't infer the type of FOR expression, please assign it to a variable.");
+
+ enum f_type el_type = f_type_element_type(term->type);
+ struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL;
+ struct symbol *ms = scope ? cf_find_symbol_scope(scope, "!for_next") : NULL;
+
+ if (!ms)
+ cf_error("Type %s is not iterable, can't be used in FOR", f_type_name(term->type));
+
+ if (var->class != (SYM_VARIABLE | el_type))
+ cf_error("Loop variable '%s' in FOR must be of type %s, got %s",
+ var->name, f_type_name(el_type), f_type_name(var->class & 0xff));
+
+ /* Push the iterator auxiliary value onto stack */
+ struct f_inst *iter = term->next = f_new_inst(FI_CONSTANT, (struct f_val) {});
+
+ /* Initialize the iterator variable */
+ iter->next = f_new_inst(FI_CONSTANT, (struct f_val) { .type = el_type });
+
+ /* Prepend the loop block with loop beginning instruction */
+ struct f_inst *loop_start = f_new_inst(FI_FOR_LOOP_START, var);
+ loop_start->next = block;
+
+ return ms->method->new_inst(term, loop_start);
+}
+
#define CA_KEY(n) n->name, n->fda.type
#define CA_NEXT(n) n->next
#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb))
diff --git a/filter/filter.c b/filter/filter.c
index b4516511..e2338be8 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -176,6 +176,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
fstk->estk[0].pos = 0;
#define curline fstk->estk[fstk->ecnt-1]
+#define prevline fstk->estk[fstk->ecnt-2]
#ifdef LOCAL_DEBUG
debug("Interpreting line.");