From 87512e97516160ec980e9d0621522ada405438fe Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 5 Nov 2019 15:13:57 +0100 Subject: [PATCH] Filter: Improve typecheck error messages --- filter/data.c | 43 +++++++++++++++++++++++++++++++++++++++++++ filter/data.h | 2 ++ filter/decl.m4 | 29 ++++++++++++++++++++++------- filter/f-inst.h | 4 +++- filter/filter.c | 2 +- 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/filter/data.c b/filter/data.c index db55070f..62edd9e0 100644 --- a/filter/data.c +++ b/filter/data.c @@ -25,6 +25,49 @@ #include "filter/f-inst.h" #include "filter/data.h" +static const char * const f_type_str[] = { + [T_VOID] = "void", + + [T_INT] = "int", + [T_BOOL] = "bool", + [T_PAIR] = "pair", + [T_QUAD] = "quad", + + [T_ENUM_RTS] = "enum rts", + [T_ENUM_BGP_ORIGIN] = "enum bgp_origin", + [T_ENUM_SCOPE] = "enum scope", + [T_ENUM_RTC] = "enum rtc", + [T_ENUM_RTD] = "enum rtd", + [T_ENUM_ROA] = "enum roa", + [T_ENUM_NETTYPE] = "enum nettype", + [T_ENUM_RA_PREFERENCE] = "enum ra_preference", + [T_ENUM_AF] = "enum af", + + [T_IP] = "ip", + [T_NET] = "prefix", + [T_STRING] = "string", + [T_PATH_MASK] = "bgpmask", + [T_PATH] = "bgppath", + [T_CLIST] = "clist", + [T_EC] = "ec", + [T_ECLIST] = "eclist", + [T_LC] = "lc", + [T_LCLIST] = "lclist", + [T_RD] = "rd", +}; + +const char * +f_type_name(enum f_type t) +{ + if (t < ARRAY_SIZE(f_type_str)) + return f_type_str[t] ?: "?"; + + if ((t == T_SET) || (t == T_PREFIX_SET)) + return "set"; + + return "?"; +} + const struct f_val f_const_empty_path = { .type = T_PATH, .val.ad = &null_adata, diff --git a/filter/data.h b/filter/data.h index db6b6e12..578ff98f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -167,6 +167,8 @@ void trie_format(const struct f_trie *t, buffer *buf); #define F_CMP_ERROR 999 +const char *f_type_name(enum f_type t); + int val_same(const struct f_val *v1, const struct f_val *v2); int val_compare(const struct f_val *v1, const struct f_val *v2); void val_format(const struct f_val *v, buffer *buf); diff --git a/filter/decl.m4 b/filter/decl.m4 index 5618dafa..a78450a3 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -104,7 +104,7 @@ FID_STRUCT_IN()m4_dnl struct f_inst * f$1; FID_NEW_ARGS()m4_dnl , struct f_inst * f$1 -FID_NEW_BODY +FID_NEW_BODY()m4_dnl whati->f$1 = f$1; for (const struct f_inst *child = f$1; child; child = child->next) { what->size += child->size; @@ -164,10 +164,19 @@ m4_define(ARG, `ARG_ANY($1) ARG_TYPE($1,$2)') m4_define(ARG_TYPE, ` FID_NEW_BODY()m4_dnl if (f$1->type && (f$1->type != ($2)) && !f_const_promotion(f$1, ($2))) - cf_error("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), f$1->type); + cf_error("Argument $1 of %s must be of type %s, got type %s", + f_instruction_name(what->fi_code), f_type_name($2), f_type_name(f$1->type)); FID_INTERPRET_EXEC()m4_dnl if (v$1.type != ($2)) - runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl + runtime("Argument $1 of %s must be of type %s, got type %s", + f_instruction_name(what->fi_code), f_type_name($2), f_type_name(v$1.type)); +FID_INTERPRET_BODY()') + +m4_define(ARG_SAME_TYPE, ` +FID_NEW_BODY()m4_dnl +if (f$1->type && f$2->type && (f$1->type != f$2->type) && + !f_const_promotion(f$2, f$1->type) && !f_const_promotion(f$1, f$2->type)) + cf_error("Arguments $1 and $2 of %s must be of the same type", f_instruction_name(what->fi_code)); FID_INTERPRET_BODY()') # Executing another filter line. This replaces the recursion @@ -217,10 +226,16 @@ m4_define(ERROR, `m4_errprint(m4___file__:m4___line__: $* )m4_m4exit(1)') +# This macro specifies result type and makes there are no conflicting definitions m4_define(RESULT_TYPE, `m4_ifdef([[INST_RESULT_TYPE]], [[m4_ifelse(INST_RESULT_TYPE,$1,,[[ERROR([[Multiple type definitons]])]])]], - [[m4_define(INST_RESULT_TYPE,$1) FID_NEW_BODY() what->type = $1;FID_INTERPRET_BODY()]])') + [[m4_define(INST_RESULT_TYPE,$1) RESULT_TYPE_($1)]])') + +m4_define(RESULT_TYPE_, ` +FID_NEW_BODY()m4_dnl +what->type = $1; +FID_INTERPRET_BODY()') # Some common filter instruction members m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)') @@ -420,7 +435,7 @@ FID_WR_PUT(5) }; const char * -f_instruction_name(enum f_instruction_code fi) +f_instruction_name_(enum f_instruction_code fi) { if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0]))) return f_instruction_name_str[fi]; @@ -494,7 +509,7 @@ void f_dump_line(const struct f_line *dest, uint indent) debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len); for (uint i=0; ilen; i++) { const struct f_line_item *item = &dest->items[i]; - debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); + debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name_(item->fi_code), item->lineno); switch (item->fi_code) { FID_WR_PUT(7) default: bug("Unknown instruction %x in f_dump_line", item->fi_code); @@ -529,7 +544,7 @@ f_linearize_concat(const struct f_inst * const inst[], uint count) for (uint i=0; ilen = linearize(out, inst[i], out->len); -#if DEBUGGING +#ifdef LOCAL_DEBUG f_dump_line(out, 0); #endif return out; diff --git a/filter/f-inst.h b/filter/f-inst.h index 33fcf4a9..8be8443b 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -29,7 +29,9 @@ enum f_instruction_flags { #define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__) /* Convert the instruction back to the enum name */ -const char *f_instruction_name(enum f_instruction_code fi); +const char *f_instruction_name_(enum f_instruction_code fi); +static inline const char *f_instruction_name(enum f_instruction_code fi) +{ return f_instruction_name_(fi) + 3; } /* Filter structures for execution */ /* Line of instructions to be unconditionally executed one after another */ diff --git a/filter/filter.c b/filter/filter.c index 60e351f9..ad9588b2 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -174,7 +174,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) #define curline fstk->estk[fstk->ecnt-1] -#if DEBUGGING +#ifdef LOCAL_DEBUG debug("Interpreting line."); f_dump_line(line, 1); #endif