From fc9d471b36b91429e5d86aa794716683a5281449 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 16 Jun 2023 17:35:37 +0200 Subject: Filter: Methods rework Methods can now be called as x.m(y), as long as x can have its type inferred in config time. If used as a command, it modifies the object, if used as a value, it keeps the original object intact. Also functions add(x,y), delete(x,y), filter(x,y) and prepend(x,y) now spit a warning and are considered deprecated. It's also possible to call a method on a constant, see filter/test.conf for examples like bgp_path = +empty+.prepend(1). Inside instruction definitions (filter/f-inst.c), a METHOD_CONSTRUCTOR() call is added, which registers the instruction as a method for the type of its first argument. Each type has its own method symbol table and filter parser switches between them based on the inferred type of the object calling the method. Also FI_CLIST_(ADD|DELETE|FILTER) instructions have been split to allow for this method dispatch. With type inference, it's now possible. --- conf/cf-lex.l | 23 ++++++++++++++--------- conf/conf.h | 13 +++++++------ conf/confbase.Y | 2 +- conf/gen_keywords.m4 | 7 +++---- 4 files changed, 25 insertions(+), 20 deletions(-) (limited to 'conf') diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9e52417a..c4760e40 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -54,7 +54,6 @@ struct keyword { byte *name; int value; - enum keyword_scope scope; }; #include "conf/keywords.h" @@ -80,7 +79,8 @@ static uint cf_hash(const byte *c); HASH_DEFINE_REHASH_FN(SYM, struct symbol) struct sym_scope *global_root_scope; -static pool *global_root_scope_pool; +pool *global_root_scope_pool; +linpool *global_root_scope_linpool; linpool *cfg_mem; @@ -557,7 +557,7 @@ check_eof(void) static inline void cf_swap_soft_scope(struct config *conf); -static struct symbol * +struct symbol * cf_new_symbol(struct sym_scope *scope, pool *p, struct linpool *lp, const byte *c) { if (scope->readonly) @@ -686,6 +686,8 @@ cf_lex_symbol(const char *data) cf_lval.i = -val; return ENUM; } + case SYM_METHOD: + return sym->method->arg_num ? CF_SYM_METHOD_ARGS : CF_SYM_METHOD_BARE; case SYM_VOID: return CF_SYM_UNDEFINED; default: @@ -693,6 +695,8 @@ cf_lex_symbol(const char *data) } } +void f_type_methods_register(void); + /** * cf_lex_init - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration @@ -707,18 +711,19 @@ cf_lex_init(int is_cli, struct config *c) if (!global_root_scope_pool) { global_root_scope_pool = rp_new(&root_pool, "Keywords pool"); - linpool *kwlp = lp_new(global_root_scope_pool); - global_root_scope = lp_allocz(kwlp, sizeof(*global_root_scope) * CFK__MAX); + global_root_scope_linpool = lp_new(global_root_scope_pool); + global_root_scope = lp_allocz(global_root_scope_linpool, sizeof(*global_root_scope)); for (const struct keyword *k = keyword_list; k->name; k++) { - struct symbol *sym = cf_new_symbol(&global_root_scope[k->scope], global_root_scope_pool, kwlp, k->name); + struct symbol *sym = cf_new_symbol(global_root_scope, global_root_scope_pool, global_root_scope_linpool, k->name); sym->class = SYM_KEYWORD; sym->keyword = k; } - for (int s = 0; s < CFK__MAX; s++) - global_root_scope[s].readonly = 1; + global_root_scope->readonly = 1; + + f_type_methods_register(); } ifs_head = ifs = push_ifs(NULL); @@ -742,7 +747,7 @@ cf_lex_init(int is_cli, struct config *c) if (is_cli) c->current_scope->next = config->root_scope; else - c->current_scope->next = &global_root_scope[CFK_KEYWORDS]; + c->current_scope->next = global_root_scope; } /** diff --git a/conf/conf.h b/conf/conf.h index b7c97ce5..1413cb58 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -126,6 +126,7 @@ struct symbol { struct f_val *val; /* For SYM_CONSTANT */ uint offset; /* For SYM_VARIABLE */ const struct keyword *keyword; /* For SYM_KEYWORD */ + const struct f_method *method; /* For SYM_METHOD */ }; char name[0]; @@ -144,13 +145,9 @@ struct sym_scope { byte readonly:1; /* Do not add new symbols */ }; -enum keyword_scope { - CFK_KEYWORDS, - CFK_METHODS, - CFK__MAX -}; - extern struct sym_scope *global_root_scope; +extern pool *global_root_scope_pool; +extern linpool *global_root_scope_linpool; struct bytestring { size_t length; @@ -168,6 +165,7 @@ struct bytestring { #define SYM_TABLE 5 #define SYM_ATTRIBUTE 6 #define SYM_KEYWORD 7 +#define SYM_METHOD 8 #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ #define SYM_VARIABLE_RANGE SYM_VARIABLE ... (SYM_VARIABLE | 0xff) @@ -215,6 +213,9 @@ struct symbol *cf_localize_symbol(struct config *conf, struct symbol *sym); static inline int cf_symbol_is_local(struct config *conf, struct symbol *sym) { return (sym->scope == conf->current_scope) && !conf->current_scope->soft_scopes; } +/* internal */ +struct symbol *cf_new_symbol(struct sym_scope *scope, pool *p, struct linpool *lp, const byte *c); + /** * cf_define_symbol - define meaning of a symbol * @sym: symbol to be defined diff --git a/conf/confbase.Y b/conf/confbase.Y index e10666f8..c62731b5 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -104,7 +104,7 @@ CF_DECLS %token IP4 %token IP6 %token VPN_RD -%token CF_SYM_KNOWN CF_SYM_UNDEFINED +%token CF_SYM_KNOWN CF_SYM_UNDEFINED CF_SYM_METHOD_BARE CF_SYM_METHOD_ARGS %token TEXT %token BYTETEXT %type ipa_scope diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 06a38ffd..4e8651f6 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -23,11 +23,10 @@ m4_define(CF_DECLS, `m4_divert(-1)') m4_define(CF_DEFINES, `m4_divert(-1)') # Keywords are translated to C initializers -m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, CF_keywd_target }, +m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1 }, m4_divert(-1)') -m4_define(CF_keywd, `m4_ifdef([[CF_tok_]]CF_keywd_target[[_$1]],,[[m4_define([[CF_tok_]]CF_keywd_target[[_$1]],1)CF_handle_kw($1)]])') -m4_define(CF_KEYWORDS, `m4_define([[CF_keywd_target]],CFK_KEYWORDS)CF_iterate([[CF_keywd]], [[$@]])DNL') -m4_define(CF_METHODS, `m4_define([[CF_keywd_target]],CFK_METHODS)CF_iterate([[CF_keywd]], [[$@]])DNL') +m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])') +m4_define(CF_KEYWORDS, `CF_iterate([[CF_keywd]], [[$@]])DNL') m4_define(CF_KEYWORDS_EXCLUSIVE, `CF_KEYWORDS($@)') # CLI commands generate keywords as well -- cgit v1.2.3