Commit 4f24c098 4f24c098704dd28622d1d653945388a4abbfb434 by Sergey Poznyakoff

Try to display exact error locations in Sieve diagnostics

* include/mailutils/sieve.h (mu_sieve_value_t)<locus>: New field.
* libmu_sieve/util.c (mu_sieve_value_create): Take a pointer to
mu_locus_range.  Use it to initialize the locus field.
* libmu_sieve/sieve-gram.y: Pass loci in calls to mu_sieve_value_create.
* libmu_sieve/actions.c: Use the most specific locus when displaying
the message.
* libmu_sieve/comparator.c: Likewise.
* libmu_sieve/prog.c: Likewise.
* libmu_sieve/variables.c: Likewise.
* sieve/tests/i-numeric.at: Update the expected error location.
1 parent fa5d4812
...@@ -88,6 +88,7 @@ typedef struct ...@@ -88,6 +88,7 @@ typedef struct
88 { 88 {
89 mu_sieve_data_type type; 89 mu_sieve_data_type type;
90 char *tag; 90 char *tag;
91 struct mu_locus_range locus;
91 union mu_sieve_value_storage v; 92 union mu_sieve_value_storage v;
92 } mu_sieve_value_t; 93 } mu_sieve_value_t;
93 94
...@@ -163,7 +164,9 @@ void mu_sieve_reclaim_default (void *p); ...@@ -163,7 +164,9 @@ void mu_sieve_reclaim_default (void *p);
163 void mu_sieve_reclaim_value (void *p); 164 void mu_sieve_reclaim_value (void *p);
164 165
165 size_t mu_sieve_value_create (mu_sieve_machine_t mach, 166 size_t mu_sieve_value_create (mu_sieve_machine_t mach,
166 mu_sieve_data_type type, void *data); 167 mu_sieve_data_type type,
168 struct mu_locus_range const *locus,
169 void *data);
167 170
168 /* Symbol space functions */ 171 /* Symbol space functions */
169 mu_sieve_registry_t *mu_sieve_registry_add (mu_sieve_machine_t mach, 172 mu_sieve_registry_t *mu_sieve_registry_add (mu_sieve_machine_t mach,
......
...@@ -528,7 +528,7 @@ perms_tag_checker (mu_sieve_machine_t mach) ...@@ -528,7 +528,7 @@ perms_tag_checker (mu_sieve_machine_t mach)
528 { 528 {
529 if (mu_parse_stream_perm_string (&flag, t->v.string, &p)) 529 if (mu_parse_stream_perm_string (&flag, t->v.string, &p))
530 { 530 {
531 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 531 mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus,
532 _("invalid permissions (near %s)"), p); 532 _("invalid permissions (near %s)"), p);
533 mu_i_sv_error (mach); 533 mu_i_sv_error (mach);
534 err = 1; 534 err = 1;
......
...@@ -174,7 +174,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -174,7 +174,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
174 { 174 {
175 if (match) 175 if (match)
176 { 176 {
177 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 177 mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus,
178 _("match type specified twice in call to `%s'"), 178 _("match type specified twice in call to `%s'"),
179 mach->identifier); 179 mach->identifier);
180 mu_i_sv_error (mach); 180 mu_i_sv_error (mach);
...@@ -209,7 +209,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -209,7 +209,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
209 209
210 if (compname && strcmp (compname, "i;ascii-numeric")) 210 if (compname && strcmp (compname, "i;ascii-numeric"))
211 { 211 {
212 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 212 mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus,
213 /* TRANSLATORS: Do not translate ':count'. 213 /* TRANSLATORS: Do not translate ':count'.
214 It is the name of a Sieve tag */ 214 It is the name of a Sieve tag */
215 _("comparator %s is incompatible with " 215 _("comparator %s is incompatible with "
...@@ -235,7 +235,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -235,7 +235,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
235 break; 235 break;
236 /* fall through */ 236 /* fall through */
237 default: 237 default:
238 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 238 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
239 _(":count requires second argument to be a list of one element")); 239 _(":count requires second argument to be a list of one element"));
240 mu_i_sv_error (mach); 240 mu_i_sv_error (mach);
241 return 1; 241 return 1;
...@@ -246,7 +246,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -246,7 +246,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
246 char *p = mu_str_skip_class (argstr->orig, MU_CTYPE_DIGIT); 246 char *p = mu_str_skip_class (argstr->orig, MU_CTYPE_DIGIT);
247 if (*p) 247 if (*p)
248 { 248 {
249 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 249 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
250 _("second argument cannot be converted to number")); 250 _("second argument cannot be converted to number"));
251 mu_i_sv_error (mach); 251 mu_i_sv_error (mach);
252 return 1; 252 return 1;
...@@ -258,7 +258,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -258,7 +258,7 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
258 258
259 if (mu_sieve_str_to_relcmp (str, NULL, NULL)) 259 if (mu_sieve_str_to_relcmp (str, NULL, NULL))
260 { 260 {
261 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 261 mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus,
262 _("invalid relational match `%s' in call to `%s'"), 262 _("invalid relational match `%s' in call to `%s'"),
263 str, mach->identifier); 263 str, mach->identifier);
264 mu_i_sv_error (mach); 264 mu_i_sv_error (mach);
...@@ -278,10 +278,16 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach) ...@@ -278,10 +278,16 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
278 compfun = mu_sieve_comparator_lookup (mach, compname, matchtype); 278 compfun = mu_sieve_comparator_lookup (mach, compname, matchtype);
279 if (!compfun) 279 if (!compfun)
280 { 280 {
281 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 281 if (match)
282 mu_diag_at_locus_range (MU_LOG_ERROR, &match->locus,
283 _("comparator `%s' is incompatible with match type `%s' in call to `%s'"),
284 compname, match->tag,
285 mach->identifier);
286 else
287 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus,
282 _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), 288 _("comparator `%s' is incompatible with match type `%s' in call to `%s'"),
283 compname, match ? match->tag : "is", 289 compname, "is",
284 mach->identifier); 290 mach->identifier);
285 mu_i_sv_error (mach); 291 mu_i_sv_error (mach);
286 return 1; 292 return 1;
287 } 293 }
......
...@@ -171,7 +171,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, ...@@ -171,7 +171,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
171 171
172 if (!tag) 172 if (!tag)
173 { 173 {
174 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 174 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
175 _("invalid tag name `%s' for `%s'"), 175 _("invalid tag name `%s' for `%s'"),
176 val->v.string, reg->name); 176 val->v.string, reg->name);
177 mu_i_sv_error (mach); 177 mu_i_sv_error (mach);
...@@ -191,6 +191,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, ...@@ -191,6 +191,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
191 { 191 {
192 if (i + 1 == node->v.command.argcount) 192 if (i + 1 == node->v.command.argcount)
193 { 193 {
194 /* FIXME: more exact locus */
194 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 195 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus,
195 _("required argument for tag %s is missing"), 196 _("required argument for tag %s is missing"),
196 tag->name); 197 tag->name);
...@@ -208,11 +209,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, ...@@ -208,11 +209,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
208 209
209 if (val->type != tag->argtype) 210 if (val->type != tag->argtype)
210 { 211 {
211 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 212 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
212 _("type mismatch in argument to " 213 _("type mismatch in argument to "
213 "tag `%s'"), 214 "tag `%s'"),
214 tag->name); 215 tag->name);
215 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 216 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
216 _("expected %s but passed %s"), 217 _("expected %s but passed %s"),
217 mu_sieve_type_str (tag->argtype), 218 mu_sieve_type_str (tag->argtype),
218 mu_sieve_type_str (val->type)); 219 mu_sieve_type_str (val->type));
...@@ -274,11 +275,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, ...@@ -274,11 +275,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
274 /* compatible types */; 275 /* compatible types */;
275 else 276 else
276 { 277 {
277 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 278 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
278 _("type mismatch in argument %lu to `%s'"), 279 _("type mismatch in argument %lu to `%s'"),
279 (unsigned long) (exp_arg - reg->v.command.req_args + 1), 280 (unsigned long) (exp_arg - reg->v.command.req_args + 1),
280 reg->name); 281 reg->name);
281 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 282 mu_diag_at_locus_range (MU_LOG_ERROR, &val->locus,
282 _("expected %s but passed %s"), 283 _("expected %s but passed %s"),
283 mu_sieve_type_str (*exp_arg), 284 mu_sieve_type_str (*exp_arg),
284 mu_sieve_type_str (val->type)); 285 mu_sieve_type_str (val->type));
...@@ -294,8 +295,8 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach, ...@@ -294,8 +295,8 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
294 if (!err && !opt_args && *exp_arg != SVT_VOID) 295 if (!err && !opt_args && *exp_arg != SVT_VOID)
295 { 296 {
296 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 297 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus,
297 _("too few arguments in call to `%s'"), 298 _("too few arguments in call to `%s'"),
298 reg->name); 299 reg->name);
299 mu_i_sv_error (mach); 300 mu_i_sv_error (mach);
300 err = 1; 301 err = 1;
301 } 302 }
......
...@@ -305,23 +305,27 @@ arglist : arg ...@@ -305,23 +305,27 @@ arglist : arg
305 arg : stringlist 305 arg : stringlist
306 { 306 {
307 $$ = mu_sieve_value_create (mu_sieve_machine, 307 $$ = mu_sieve_value_create (mu_sieve_machine,
308 SVT_STRING_LIST, &$1); 308 SVT_STRING_LIST, &@1, &$1);
309 } 309 }
310 | STRING 310 | STRING
311 { 311 {
312 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1); 312 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING,
313 &@1, $1);
313 } 314 }
314 | MULTILINE 315 | MULTILINE
315 { 316 {
316 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING, $1); 317 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_STRING,
318 &@1, $1);
317 } 319 }
318 | NUMBER 320 | NUMBER
319 { 321 {
320 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_NUMBER, &$1); 322 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_NUMBER,
323 &@1, &$1);
321 } 324 }
322 | TAG 325 | TAG
323 { 326 {
324 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_TAG, $1); 327 $$ = mu_sieve_value_create (mu_sieve_machine, SVT_TAG,
328 &@1, $1);
325 } 329 }
326 ; 330 ;
327 331
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
28 28
29 size_t 29 size_t
30 mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type, 30 mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type,
31 struct mu_locus_range const *locus,
31 void *data) 32 void *data)
32 { 33 {
33 size_t idx; 34 size_t idx;
...@@ -43,6 +44,18 @@ mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type, ...@@ -43,6 +44,18 @@ mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type,
43 memset (val, 0, sizeof *val); 44 memset (val, 0, sizeof *val);
44 45
45 val->type = type; 46 val->type = type;
47
48 /* Copy locus. */
49 val->locus.beg.mu_file =
50 mu_i_sv_id_str (mach, mu_i_sv_id_num (mach, locus->beg.mu_file));
51 val->locus.beg.mu_line = locus->beg.mu_line;
52 val->locus.beg.mu_col = locus->beg.mu_col;
53 val->locus.end.mu_file =
54 mu_i_sv_id_str (mach, mu_i_sv_id_num (mach, locus->end.mu_file));
55 val->locus.end.mu_line = locus->end.mu_line;
56 val->locus.end.mu_col = locus->end.mu_col;
57
58 mu_locus_range_copy (&val->locus, locus);
46 switch (type) 59 switch (type)
47 { 60 {
48 case SVT_NUMBER: 61 case SVT_NUMBER:
......
...@@ -226,9 +226,12 @@ set_tag_checker (mu_sieve_machine_t mach) ...@@ -226,9 +226,12 @@ set_tag_checker (mu_sieve_machine_t mach)
226 *mu_sieve_get_tag_n (mach, j + 1) = *t; 226 *mu_sieve_get_tag_n (mach, j + 1) = *t;
227 else if (prec == tmp_prec) 227 else if (prec == tmp_prec)
228 { 228 {
229 mu_diag_at_locus_range (MU_LOG_ERROR, &mach->locus, 229 mu_diag_at_locus_range (MU_LOG_ERROR, &t->locus,
230 _("%s and %s can't be used together"), 230 _("%s and %s can't be used together"),
231 tmp.tag, t->tag); 231 tmp.tag, t->tag);
232 mu_diag_at_locus_range (MU_LOG_ERROR, &tmp.locus,
233 _("%s encountered here"),
234 tmp.tag);
232 mu_i_sv_error (mach); 235 mu_i_sv_error (mach);
233 return 1; 236 return 1;
234 } 237 }
......
...@@ -38,7 +38,7 @@ if header :comparator "i;ascii-numeric" :contains "X-Number" "15" ...@@ -38,7 +38,7 @@ if header :comparator "i;ascii-numeric" :contains "X-Number" "15"
38 discard; 38 discard;
39 } 39 }
40 ],[78],[], 40 ],[78],[],
41 [sieve: prog:4.4-65: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header' 41 [sieve: prog:4.41-49: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header'
42 ]) 42 ])
43 AT_CLEANUP 43 AT_CLEANUP
44 44
......