mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Filter: The for loop uses the method system for type dispatch
This commit is contained in:
parent
1d38726c64
commit
21faa54ec3
@ -1008,8 +1008,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) {
|
||||
|
@ -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
|
||||
|
109
filter/f-inst.c
109
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;
|
||||
ARG(1, T_PATH);
|
||||
if (as_path_walk(v1.val.ad, &v2.val.i, &v3.val.i))
|
||||
LINE(2,0);
|
||||
|
||||
/* Type checks are done in FI_FOR_INIT */
|
||||
METHOD_CONSTRUCTOR("!for_next");
|
||||
}
|
||||
|
||||
/* Loop variable */
|
||||
struct f_val *var = &fstk->vstk[curline.vbase + sym->offset];
|
||||
int step = 0;
|
||||
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);
|
||||
|
||||
switch(v1.type)
|
||||
{
|
||||
case T_PATH:
|
||||
var->type = T_INT;
|
||||
step = as_path_walk(v1.val.ad, &v2.val.i, &var->val.i);
|
||||
break;
|
||||
METHOD_CONSTRUCTOR("!for_next");
|
||||
}
|
||||
|
||||
case T_CLIST:
|
||||
var->type = T_PAIR;
|
||||
step = int_set_walk(v1.val.ad, &v2.val.i, &var->val.i);
|
||||
break;
|
||||
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);
|
||||
|
||||
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_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);
|
||||
|
||||
default:
|
||||
runtime( "Clist or lclist expected" );
|
||||
}
|
||||
|
||||
if (step)
|
||||
{
|
||||
/* Keep v1 and v2 on the stack */
|
||||
fstk->vcnt += 2;
|
||||
|
||||
/* Repeat this instruction */
|
||||
curline.pos--;
|
||||
|
||||
/* Execute the loop body */
|
||||
LINE(1, 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) {
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -174,6 +174,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.");
|
||||
|
Loading…
Reference in New Issue
Block a user