Commit 15404d91 15404d914aec7e80c884fc63dbfa5d3e347b32cb by Sergey Poznyakoff

Rewrite sieve parser.

Three objectives:

1. Simplify code.
2. Produce optimized sieve code.
3. Improve error reporting.
4. Prepare for further extensions

* include/mailutils/sieve.h (mu_sieve_tag_checker_t): Change
signature (take mu_sieve_machine_t as the first arg).  All
uses changed.
(mu_sieve_require): Likewise.
(mu_sieve_yydebug): Remove global.

* libmu_sieve/sieve-priv.h (mu_locus_range): New struct.
(YYLTYPE): New define
(mu_sieve_state): New enum.
(mu_sieve_machine): New members: string_pool, state.
(mu_sieve_node_type): New enum.
(mu_sieve_node): New struct.
Remove unused prototypes.

* libmu_sieve/sieve.l: Keep track of code locations.  Use opool
for constructing string values.
* libmu_sieve/sieve.y: Rewrite.  First build the parse tree.  Then
optimize it.  Finally, generate code.
* libmu_sieve/tests.c (sieve_test_true,sieve_test_false): Remove.
True and false tests are always optimized away.
* libmu_sieve/util.c (mu_sv_compile_error): Remove.

* libmu_sieve/actions.c: Use mu_diag_at_locus to report errors
and mu_i_sv_error to mark sieve machine as being in error state.
* libmu_sieve/comparator.c: Likewise.
* libmu_sieve/prog.c (mu_sv_code): Replace with mu_i_sv_code.
(mu_sv_code_instr,mu_sv_code_handler)
(mu_sv_code_list,mu_sv_code_number)
(mu_sv_code_string,mu_sv_code_source)
(mu_sv_code_line,mu_sv_change_source)
(mu_sv_code_action,mu_sv_code_test)
(mu_sv_code_anyof,mu_sv_code_allof): Remove.
(mu_i_sv_locus,mu_i_sv_code_action)
(mu_i_sv_code_test): New function.
(mu_sv_code_command): Replace with a static function.
* libmu_sieve/require.c (mu_sieve_require): Take ptr to machine
as the first arg.
* libmu_sieve/runtime.c (mu_sieve_mailbox)
(mu_sieve_message): Refuse to run if the machine is in error state.

* sieve/sieve.c: Update.
* sieve/tests/i-numeric.at: Update expected error message.

* libmailutils/diag/diag.c (mu_diag_at_locus): Don't pass locus
if mu_file is NULL.
* libmu_auth/ldap.c (_mu_entry_to_auth_data): Remove leftover
mu_error.
1 parent a04c6feb
......@@ -47,7 +47,8 @@ typedef int (*mu_sieve_comparator_t) (const char *, const char *);
typedef int (*mu_sieve_retrieve_t) (void *item, void *data, int idx,
char **pval);
typedef void (*mu_sieve_destructor_t) (void *data);
typedef int (*mu_sieve_tag_checker_t) (const char *name,
typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach,
const char *name,
mu_list_t tags, mu_list_t args);
typedef enum
......@@ -121,7 +122,6 @@ typedef struct
#define MU_SIEVE_DEBUG_DISAS 0x0004
#define MU_SIEVE_DRY_RUN 0x0008
extern int mu_sieve_yydebug;
extern mu_debug_handle_t mu_sieve_debug_handle;
extern mu_list_t mu_sieve_include_path;
extern mu_list_t mu_sieve_library_path;
......@@ -190,13 +190,16 @@ int mu_sieve_str_to_relcmp (const char *str, mu_sieve_relcmp_t * test,
mu_sieve_relcmp_t mu_sieve_get_relcmp (mu_sieve_machine_t mach,
mu_list_t tags);
void mu_sieve_require (mu_list_t slist);
void mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist);
int mu_sieve_tag_lookup (mu_list_t taglist, char *name,
mu_sieve_value_t ** arg);
int mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
int mu_sieve_match_part_checker (const char *name, mu_list_t tags,
int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags,
mu_list_t args);
int mu_sieve_match_part_checker (const char *name, mu_list_t tags,
int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags,
mu_list_t args);
/* Operations in value lists */
mu_sieve_value_t *mu_sieve_value_get (mu_list_t vlist, size_t index);
......
......@@ -61,6 +61,7 @@ mu_diag_at_locus (int level, struct mu_locus const *loc, const char *fmt, ...)
va_list ap;
va_start (ap, fmt);
if (loc && loc->mu_file)
mu_stream_printf (mu_strerr, "\033f<%d>%s\033l<%u>\033c<%u>",
(unsigned) strlen (loc->mu_file), loc->mu_file,
loc->mu_line,
......
......@@ -538,8 +538,6 @@ _mu_entry_to_auth_data (LDAP *ld, LDAPMessage *msg,
rc = ldap_get_dn_ber (ld, msg, &ber, &bv);
ufn = ldap_dn2ufn (bv.bv_val);
/* FIXME: Use debug or diag functions */
mu_error ("INFO: %s", ufn);
ldap_memfree (ufn);
mu_assoc_get_iterator (ldap_param.field_map, &itr);
......
......@@ -17,6 +17,7 @@
YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap
AM_YFLAGS = -dtv
#AM_LEXFLAGS=-dvp
AM_CPPFLAGS =\
@MU_LIB_COMMON_INCLUDES@\
-DMU_SIEVE_MODDIR=\"@MU_SIEVE_MODDIR@\"
......
......@@ -522,7 +522,8 @@ mu_sieve_data_type fileinto_args[] = {
};
static int
perms_tag_checker (const char *name, mu_list_t tags, mu_list_t args)
perms_tag_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags, mu_list_t args)
{
mu_iterator_t itr;
int err = 0;
......@@ -540,8 +541,9 @@ perms_tag_checker (const char *name, mu_list_t tags, mu_list_t args)
{
if (mu_parse_stream_perm_string (&flag, t->arg->v.string, &p))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("invalid permissions (near %s)"), p);
mu_i_sv_error (mach);
err = 1;
}
}
......
......@@ -139,7 +139,9 @@ mu_sieve_get_comparator (mu_sieve_machine_t mach, mu_list_t tags)
/* Compile time support */
struct regex_data {
struct regex_data
{
mu_sieve_machine_t mach;
int flags;
mu_list_t list;
};
......@@ -158,7 +160,7 @@ _regex_compile (void *item, void *data)
{
struct regex_data *rd = data;
int rc;
regex_t *preg = mu_sieve_malloc (mu_sieve_machine, sizeof (*preg));
regex_t *preg = mu_sieve_malloc (rd->mach, sizeof (*preg));
rc = regcomp (preg, (char*)item, rd->flags);
if (rc)
......@@ -168,11 +170,13 @@ _regex_compile (void *item, void *data)
if (errbuf)
{
regerror (rc, preg, errbuf, size);
mu_sv_compile_error (&mu_sieve_locus, _("regex error: %s"), errbuf);
mu_diag_at_locus (MU_LOG_ERROR, &rd->mach->locus,
_("regex error: %s"), errbuf);
free (errbuf);
}
else
mu_sv_compile_error (&mu_sieve_locus, _("regex error"));
mu_diag_at_locus (MU_LOG_ERROR, &rd->mach->locus, _("regex error"));
mu_i_sv_error (rd->mach);
return rc;
}
......@@ -203,7 +207,8 @@ comp_false (const char *pattern, const char *text)
}
int
mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
mu_sieve_match_part_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags, mu_list_t args)
{
mu_iterator_t itr;
mu_sieve_runtime_tag_t *match = NULL;
......@@ -233,9 +238,10 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
{
if (match)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("match type specified twice in call to `%s'"),
name);
mu_i_sv_error (mach);
err = 1;
}
else
......@@ -269,13 +275,14 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
if (comp && strcmp (comp->arg->v.string, "i;ascii-numeric"))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
/* TRANSLATORS: Do not translate ':count'.
It is the name of a Sieve tag */
_("comparator %s is incompatible with "
":count in call to `%s'"),
comp->arg->v.string,
name);
mu_i_sv_error (mach);
return 1;
}
......@@ -288,16 +295,18 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
mu_list_count (val->v.list, &count);
if (count > 1)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("second argument must be a list of one element"));
mu_i_sv_error (mach);
return 1;
}
mu_list_get (val->v.list, 0, (void **) &str);
count = strtoul (str, &str, 10);
if (*str)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("second argument cannot be converted to number"));
mu_i_sv_error (mach);
return 1;
}
}
......@@ -306,9 +315,10 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
if (mu_sieve_str_to_relcmp (str, NULL, NULL))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("invalid relational match `%s' in call to `%s'"),
str, name);
mu_i_sv_error (mach);
return 1;
}
}
......@@ -316,18 +326,18 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
if (!compfun)
{
compname = comp ? comp->arg->v.string : "i;ascii-casemap";
compfun = mu_sieve_comparator_lookup (mu_sieve_machine, compname,
matchtype);
compfun = mu_sieve_comparator_lookup (mach, compname, matchtype);
if (!compfun)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("comparator `%s' is incompatible with match type `%s' in call to `%s'"),
compname, match ? match->tag : "is", name);
mu_i_sv_error (mach);
return 1;
}
}
tmp = mu_sieve_malloc (mu_sieve_machine, sizeof (*tmp));
tmp = mu_sieve_malloc (mach, sizeof (*tmp));
tmp->tag = TAG_COMPFUN;
tmp->arg = mu_sieve_value_create (SVT_POINTER, compfun);
mu_list_append (tags, tmp);
......@@ -343,6 +353,7 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
if (mu_list_get (args, 1, (void**)&val))
return 0;
rd.mach = mach;
rd.flags = REG_EXTENDED;
if (strcmp (compname, "i;ascii-casemap") == 0)
rd.flags |= REG_ICASE;
......@@ -351,8 +362,7 @@ mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args)
rc = mu_sieve_vlist_do (val, _regex_compile, &rd);
mu_sieve_machine_add_destructor (mu_sieve_machine, _free_reglist,
rd.list);
mu_sieve_machine_add_destructor (rd.mach, _free_reglist, rd.list);
if (rc)
return rc;
......
......@@ -25,70 +25,53 @@
#include <sieve-priv.h>
int
mu_sv_code (sieve_op_t *op)
mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op)
{
if (mu_sieve_machine->pc >= mu_sieve_machine->progsize)
if (mach->pc >= mach->progsize)
{
size_t newsize = mu_sieve_machine->progsize + SIEVE_CODE_INCR;
sieve_op_t *newprog = mu_sieve_mrealloc (mu_sieve_machine,
mu_sieve_machine->prog,
newsize *
sizeof mu_sieve_machine->prog[0]);
size_t newsize = mach->progsize + SIEVE_CODE_INCR;
sieve_op_t *newprog =
mu_sieve_mrealloc (mach, mach->prog, newsize * sizeof mach->prog[0]);
if (!newprog)
{
mu_sv_compile_error (&mu_sieve_locus, _("not enough memory"));
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, _("not enough memory"));
mu_i_sv_error (mach);
return 1;
}
mu_sieve_machine->prog = newprog;
mu_sieve_machine->progsize = newsize;
mach->prog = newprog;
mach->progsize = newsize;
}
mu_sieve_machine->prog[mu_sieve_machine->pc++] = *op;
mach->prog[mach->pc++] = op;
return 0;
}
int
mu_sv_code_instr (sieve_instr_t instr)
{
sieve_op_t op;
op.instr = instr;
return mu_sv_code (&op);
}
int
mu_sv_code_handler (mu_sieve_handler_t handler)
{
sieve_op_t op;
op.handler = handler;
return mu_sv_code (&op);
}
int
mu_sv_code_list (mu_list_t list)
{
sieve_op_t op;
op.list = list;
return mu_sv_code (&op);
}
int
mu_sv_code_number (long num)
static int
file_eq (char const *a, char const *b)
{
sieve_op_t op;
op.number = num;
return mu_sv_code (&op);
if (a)
return b ? (strcmp (a, b) == 0) : 1;
return b ? -1 : 0;
}
/* FIXME: 1. Only beg is stored
2. mu_col is not used
*/
int
mu_sv_code_string (const char *string)
mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr)
{
sieve_op_t op;
if (!file_eq (mach->locus.mu_file, lr->beg.mu_file))
{
mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_source);
mu_i_sv_code (mach, (sieve_op_t) lr->beg.mu_file);
}
if (mach->locus.mu_line != lr->beg.mu_line)
{
mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_line);
mu_i_sv_code (mach, (sieve_op_t) lr->beg.mu_line);
}
op.string = string;
return mu_sv_code (&op);
mach->locus = lr->beg;
return 0;
}
mu_sieve_tag_def_t *
......@@ -119,7 +102,9 @@ _compare_ptr (void *item, void *data)
return item == data;
}
struct check_arg {
struct check_arg
{
struct mu_sieve_machine *mach;
const char *name;
mu_list_t args;
mu_list_t tags;
......@@ -129,11 +114,13 @@ static int
_run_checker (void *item, void *data)
{
struct check_arg *arg = data;
return (*(mu_sieve_tag_checker_t)item) (arg->name, arg->tags, arg->args);
return (*(mu_sieve_tag_checker_t)item) (arg->mach, arg->name,
arg->tags, arg->args);
}
int
mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
static int
sv_code_command (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
{
mu_iterator_t itr;
mu_list_t arg_list = NULL;
......@@ -144,7 +131,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
int rc, err = 0;
static mu_sieve_data_type empty[] = { SVT_VOID };
if (mu_sv_code_handler (reg->handler))
if (mu_i_sv_code (mach, (sieve_op_t) reg->handler))
return 1;
exp_arg = reg->req_args ? reg->req_args : empty;
......@@ -155,13 +142,15 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
if (rc)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create iterator: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
return 1;
}
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
mu_sieve_value_t *val;
mu_sieve_runtime_tag_t tagrec, *tagptr;
......@@ -171,21 +160,24 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
if (val->type == SVT_TAG)
{
mu_sieve_tag_checker_t cf;
mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string, &cf);
mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string,
&cf);
if (!tag)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("invalid tag name `%s' for `%s'"),
val->v.string, reg->name);
mu_i_sv_error (mach);
err = 1;
break;
}
if (!tag_list && (rc = mu_list_create (&tag_list)))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create tag list: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -196,24 +188,25 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
mu_iterator_next (itr);
if (mu_iterator_is_done (itr))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("required argument for tag %s is missing"),
tag->name);
mu_i_sv_error (mach);
err = 1;
break;
}
mu_iterator_current (itr, (void **)&tagrec.arg);
if (tagrec.arg->type != tag->argtype)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("type mismatch in argument to "
"tag `%s'"),
tag->name);
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("expected %s but passed %s"),
mu_sieve_type_str (tag->argtype),
mu_sieve_type_str
(tagrec.arg->type));
mu_sieve_type_str (tagrec.arg->type));
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -221,7 +214,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
else
tagrec.arg = NULL;
tagptr = mu_sieve_malloc (mu_sieve_machine, sizeof (*tagptr));
tagptr = mu_sieve_malloc (mach, sizeof (*tagptr));
*tagptr = tagrec;
mu_list_append (tag_list, tagptr);
......@@ -229,9 +222,10 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
{
if (!chk_list && (rc = mu_list_create (&chk_list)))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create check list: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -250,9 +244,10 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
}
else
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("too many arguments in call to `%s'"),
reg->name);
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -266,19 +261,20 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
mu_list_create (&list);
mu_list_append (list, val->v.string);
mu_sieve_mfree (mu_sieve_machine, val);
mu_sieve_mfree (mach, val);
val = mu_sieve_value_create (SVT_STRING_LIST, list);
}
else
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("type mismatch in argument %lu to `%s'"),
(unsigned long) (exp_arg - reg->req_args + 1),
reg->name);
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("expected %s but passed %s"),
mu_sieve_type_str (*exp_arg),
mu_sieve_type_str (val->type));
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -286,9 +282,10 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
if (!arg_list && (rc = mu_list_create (&arg_list)))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create arg list: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
err = 1;
break;
}
......@@ -304,9 +301,10 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
{
if (!opt_args && *exp_arg != SVT_VOID)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("too few arguments in call to `%s'"),
reg->name);
mu_i_sv_error (mach);
err = 1;
}
......@@ -314,6 +312,7 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
{
struct check_arg chk_arg;
chk_arg.mach = mach;
chk_arg.name = reg->name;
chk_arg.tags = tag_list;
chk_arg.args = arg_list;
......@@ -322,9 +321,9 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
}
if (!err)
err = mu_sv_code_list (arg_list)
|| mu_sv_code_list (tag_list)
|| mu_sv_code_string (reg->name);
err = mu_i_sv_code (mach, (sieve_op_t) arg_list)
|| mu_i_sv_code (mach, (sieve_op_t) tag_list)
|| mu_i_sv_code (mach, (sieve_op_t) (char*) reg->name);
if (err)
{
......@@ -337,95 +336,18 @@ mu_sv_code_command (mu_sieve_register_t *reg, mu_list_t arglist)
}
int
mu_sv_code_source (const char *name)
mu_i_sv_code_action (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
{
char *s;
if (mu_list_locate (mu_sieve_machine->source_list,
(void*) name, (void **) &s))
{
s = mu_sieve_mstrdup (mu_sieve_machine, name);
mu_list_append (mu_sieve_machine->source_list, s);
}
return mu_sv_code_instr (_mu_sv_instr_source)
|| mu_sv_code_string (s);
return mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_action)
|| sv_code_command (mach, reg, arglist);
}
int
mu_sv_code_line (size_t line)
mu_i_sv_code_test (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
{
sieve_op_t op;
op.line = line;
return mu_sv_code_instr (_mu_sv_instr_line)
|| mu_sv_code (&op);
}
static int sieve_source_changed;
void
mu_sv_change_source ()
{
sieve_source_changed = 1;
}
static int
sieve_check_source_changed ()
{
if (sieve_source_changed)
{
sieve_source_changed = 0;
return mu_sv_code_source (mu_sieve_locus.mu_file);
}
return 0;
}
int
mu_sv_code_action (mu_sieve_register_t *reg, mu_list_t arglist)
{
return sieve_check_source_changed ()
|| mu_sv_code_line (mu_sieve_locus.mu_line)
|| mu_sv_code_instr (_mu_sv_instr_action)
|| mu_sv_code_command (reg, arglist);
}
int
mu_sv_code_test (mu_sieve_register_t *reg, mu_list_t arglist)
{
return sieve_check_source_changed ()
|| mu_sv_code_line (mu_sieve_locus.mu_line)
|| mu_sv_code_instr (_mu_sv_instr_test)
|| mu_sv_code_command (reg, arglist);
}
void
mu_sv_code_anyof (size_t start)
{
size_t end = mu_sieve_machine->pc;
while (mu_sieve_machine->prog[start+1].pc != 0)
{
size_t next = mu_sieve_machine->prog[start+1].pc;
mu_sieve_machine->prog[start].instr = _mu_sv_instr_brnz;
mu_sieve_machine->prog[start+1].pc = end - start - 2;
start = next;
}
mu_sieve_machine->prog[start].instr = _mu_sv_instr_nop;
mu_sieve_machine->prog[start+1].instr = _mu_sv_instr_nop;
}
void
mu_sv_code_allof (size_t start)
{
size_t end = mu_sieve_machine->pc;
while (mu_sieve_machine->prog[start+1].pc != 0)
{
size_t next = mu_sieve_machine->prog[start+1].pc;
mu_sieve_machine->prog[start+1].pc = end - start - 2;
start = next;
}
mu_sieve_machine->prog[start].instr = _mu_sv_instr_nop;
mu_sieve_machine->prog[start+1].instr = _mu_sv_instr_nop;
return mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_test)
|| sv_code_command (mach, reg, arglist);
}
......
......@@ -27,7 +27,7 @@
#include <sieve-priv.h>
void
mu_sieve_require (mu_list_t slist)
mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist)
{
int status;
mu_iterator_t itr;
......@@ -35,9 +35,10 @@ mu_sieve_require (mu_list_t slist)
status = mu_list_get_iterator (slist, &itr);
if (status)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create iterator: %s"),
mu_strerror (status));
mu_i_sv_error (mach);
return;
}
......@@ -73,12 +74,12 @@ mu_sieve_require (mu_list_t slist)
text = _("required action");
}
if (reqfn (mu_sieve_machine, name))
if (reqfn (mach, name))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("source for the %s %s is not available"),
text,
name);
text, name);
mu_i_sv_error (mach);
}
}
mu_iterator_destroy (&itr);
......
......@@ -339,6 +339,10 @@ mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox)
if (!mach || !mbox)
return EINVAL;
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_running;
mu_observer_create (&observer, mach);
mu_observer_set_action (observer, _sieve_action, mach);
mu_mailbox_get_observable (mbox, &observable);
......@@ -353,6 +357,7 @@ mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox)
mu_observable_detach (observable, observer);
mu_observer_destroy (&observer, mach);
mach->state = mu_sieve_state_compiled;
mach->mailbox = NULL;
return rc;
......@@ -366,10 +371,15 @@ mu_sieve_message (mu_sieve_machine_t mach, mu_message_t msg)
if (!mach || !msg)
return EINVAL;
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_running;
mach->msgno = 1;
mach->msg = msg;
mach->mailbox = NULL;
rc = sieve_run (mach);
mach->state = mu_sieve_state_compiled;
mach->msg = NULL;
return rc;
......
......@@ -31,11 +31,28 @@ typedef union
mu_sieve_value_t *val;
mu_list_t list;
long number;
const char *string;
size_t pc;
size_t line;
int inum;
char *string;
} sieve_op_t;
struct mu_locus_range
{
struct mu_locus beg;
struct mu_locus end;
};
#define YYLTYPE struct mu_locus_range
enum mu_sieve_state
{
mu_sieve_state_init,
mu_sieve_state_error,
mu_sieve_state_compiled,
mu_sieve_state_running
};
struct mu_sieve_machine
{
/* Static data */
......@@ -45,6 +62,7 @@ struct mu_sieve_machine
mu_list_t destr_list; /* List of destructor functions */
/* Symbol space: */
mu_opool_t string_pool; /* String constants */
mu_list_t test_list; /* Tests */
mu_list_t action_list; /* Actions */
mu_list_t comp_list; /* Comparators */
......@@ -54,6 +72,7 @@ struct mu_sieve_machine
sieve_op_t *prog; /* Compiled program */
/* Runtime data */
enum mu_sieve_state state;
size_t pc; /* Current program counter */
long reg; /* Numeric register */
mu_list_t stack; /* Runtime stack */
......@@ -77,42 +96,67 @@ struct mu_sieve_machine
void *data;
};
extern struct mu_locus mu_sieve_locus;
enum mu_sieve_node_type
{
mu_sieve_node_noop,
mu_sieve_node_false,
mu_sieve_node_true,
mu_sieve_node_test,
mu_sieve_node_action,
mu_sieve_node_cond,
mu_sieve_node_anyof,
mu_sieve_node_allof,
mu_sieve_node_not,
};
struct mu_sieve_node
{
struct mu_sieve_node *prev, *next;
enum mu_sieve_node_type type;
struct mu_locus_range locus;
union
{
mu_sieve_value_t *value;
mu_list_t list;
struct mu_sieve_node *node;
struct
{
struct mu_sieve_node *expr;
struct mu_sieve_node *iftrue;
struct mu_sieve_node *iffalse;
} cond;
struct
{
mu_sieve_register_t *reg;
mu_list_t arg;
} command;
} v;
};
int mu_sieve_yyerror (const char *s);
int mu_sieve_yylex (void);
int mu_i_sv_lex_begin (const char *name);
int mu_i_sv_lex_begin_string (const char *buf, int bufsize,
const char *fname, int line);
void mu_i_sv_lex_finish (struct mu_sieve_machine *mach);
extern mu_sieve_machine_t mu_sieve_machine;
extern int mu_sieve_error_count;
#define TAG_COMPFUN "__compfun__"
#define TAG_RELFUN "__relfun__"
void mu_sv_compile_error (struct mu_locus *locus,
const char *fmt, ...) MU_PRINTFLIKE(2,3);
void mu_sv_print_value_list (mu_list_t list, mu_stream_t str);
void mu_sv_print_tag_list (mu_list_t list, mu_stream_t str);
int mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op);
int mu_sv_lex_begin (const char *name);
int mu_sv_lex_begin_string (const char *buf, int bufsize,
const char *fname, int line);
void mu_sv_lex_finish (void);
int mu_sieve_yyerror (const char *s);
int mu_sieve_yylex ();
void mu_sv_register_standard_actions (mu_sieve_machine_t mach);
void mu_sv_register_standard_tests (mu_sieve_machine_t mach);
void mu_sv_register_standard_comparators (mu_sieve_machine_t mach);
void mu_i_sv_compile_error (struct mu_sieve_machine *mach,
const char *fmt, ...) MU_PRINTFLIKE(2,3);
int mu_sv_code (sieve_op_t *op);
int mu_sv_code_instr (sieve_instr_t instr);
int mu_sv_code_handler (mu_sieve_handler_t handler);
int mu_sv_code_list (mu_list_t list);
int mu_sv_code_number (long num);
int mu_sv_code_test (mu_sieve_register_t *reg, mu_list_t arglist);
int mu_sv_code_action (mu_sieve_register_t *reg, mu_list_t arglist);
void mu_sv_code_anyof (size_t start);
void mu_sv_code_allof (size_t start);
int mu_sv_code_source (const char *name);
int mu_sv_code_line (size_t line);
void mu_sv_change_source (void);
int mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr);
int mu_i_sv_code_action (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist);
int mu_i_sv_code_test (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist);
/* Opcodes */
void _mu_sv_instr_action (mu_sieve_machine_t mach);
void _mu_sv_instr_test (mu_sieve_machine_t mach);
void _mu_sv_instr_push (mu_sieve_machine_t mach);
......@@ -127,3 +171,12 @@ void _mu_sv_instr_line (mu_sieve_machine_t mach);
int mu_sv_load_add_dir (mu_sieve_machine_t mach, const char *name);
void mu_sv_register_standard_actions (mu_sieve_machine_t mach);
void mu_sv_register_standard_tests (mu_sieve_machine_t mach);
void mu_sv_register_standard_comparators (mu_sieve_machine_t mach);
void mu_sv_print_value_list (mu_list_t list, mu_stream_t str);
void mu_sv_print_tag_list (mu_list_t list, mu_stream_t str);
void mu_i_sv_error (mu_sieve_machine_t mach);
......
......@@ -35,10 +35,6 @@
#include <sieve-priv.h>
#include <sieve-gram.h>
struct mu_locus mu_sieve_locus;
ino_t sieve_source_inode;
static mu_list_t string_list;
static char *multiline_delimiter;
static int strip_tabs;
......@@ -57,6 +53,11 @@ static void sieve_searchpath (void);
static char *str_unescape (char *text, size_t len);
static int isemptystr (char *text);
static ino_t sieve_source_inode;
struct mu_locus mu_sieve_locus;
static int newline;
static mu_list_t file_names;
static mu_stream_t input_stream;
static int
......@@ -89,6 +90,61 @@ fillbuf (char *buf, size_t max_size)
yy_switch_to_buffer (s); \
} while (0)
static int
file_name_cmp (const void *a, const void *b)
{
return strcmp (a, b);
}
static void
init_locus (char const *name, ino_t ino)
{
mu_sieve_locus.mu_file = NULL;
if (name)
{
if (!file_names)
{
mu_list_create (&file_names);
mu_list_set_comparator (file_names, file_name_cmp);
mu_list_set_destroy_item (file_names, mu_list_free_item);
}
else
{
mu_list_locate (file_names, (void*) name,
(void**) &mu_sieve_locus.mu_file);
}
if (!mu_sieve_locus.mu_file)
{
mu_sieve_locus.mu_file = strdup (name);//FIXME: Error checking
mu_list_append (file_names, mu_sieve_locus.mu_file);
}
}
mu_sieve_locus.mu_line = 1;
mu_sieve_locus.mu_col = 0;
newline = 0;
sieve_source_inode = ino;
}
static void
advance_locus (void)
{
if (newline)
{
mu_sieve_locus.mu_line++;
mu_sieve_locus.mu_col = 0;
yylloc.beg = yylloc.end = mu_sieve_locus;
}
else
{
mu_sieve_locus.mu_col += yyleng;
yylloc.beg = yylloc.end = mu_sieve_locus;
yylloc.beg.mu_col -= yyleng;
}
newline = yytext[yyleng-1] == '\n';
}
#define YY_USER_ACTION advance_locus ();
struct buffer_ctx
{
struct buffer_ctx *prev;
......@@ -125,8 +181,9 @@ push_source (const char *name)
if (stat (name, &st))
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus,
_("cannot stat `%s': %s"), name, strerror (errno));
mu_i_sv_error (mu_sieve_machine);
return 1;
}
......@@ -139,28 +196,36 @@ push_source (const char *name)
{
yyerror (_("recursive inclusion"));
if (ctx->prev)
mu_sv_compile_error (&ctx->prev->locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &ctx->prev->locus,
_("`%s' already included here"),
name);
mu_i_sv_error (mu_sieve_machine);
}
else
mu_sv_compile_error (&mu_sieve_locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus,
_("`%s' already included at top level"),
name);
mu_i_sv_error (mu_sieve_machine);
}
return 1;
}
rc = mu_file_stream_create (&stream, name, MU_STREAM_READ);
if (rc)
{
mu_sv_compile_error (&mu_sieve_locus,
mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus,
_("cannot open file `%s': %s"),
name, mu_strerror (rc));
mu_i_sv_error (mu_sieve_machine);
return 1;
}
/* Push current context */
if (mu_sieve_locus.mu_file)
{
advance_locus ();
ctx = mu_sieve_alloc (sizeof (*ctx));
ctx->locus = mu_sieve_locus;
ctx->i_node = sieve_source_inode;
......@@ -173,12 +238,7 @@ push_source (const char *name)
}
input_stream = stream;
mu_sieve_locus.mu_file = strdup (name);
mu_sieve_locus.mu_line = 1;
mu_sieve_locus.mu_col = 0; /* FIXME: not used */
sieve_source_inode = st.st_ino;
mu_sv_change_source ();
init_locus (name, st.st_ino);
return 0;
}
......@@ -190,26 +250,21 @@ pop_source ()
mu_stream_destroy (&input_stream);
if (mu_sieve_locus.mu_file)
free (mu_sieve_locus.mu_file);
if (!context_stack)
{
input_stream = NULL;
mu_sieve_locus.mu_file = NULL;
init_locus (NULL, 0);
return 1;
}
/* Restore previous context */
input_stream = context_stack->input;
mu_sieve_locus = context_stack->locus;
mu_sieve_locus.mu_line++; /* #include rule did not increment it */
sieve_source_inode = context_stack->i_node;
RESTORE_BUFFER_STATE (context_stack->state);
ctx = context_stack->prev;
free (context_stack);
context_stack = ctx;
mu_sv_change_source ();
return 0;
}
%}
......@@ -225,16 +280,16 @@ SIZESUF [kKmMgG]
%%
/* C-style comments */
"/*" BEGIN(COMMENT);
"/*" { BEGIN(COMMENT); }
<COMMENT>[^*\n]* /* eat anything that's not a '*' */
<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
<COMMENT>\n ++mu_sieve_locus.mu_line;
<COMMENT>"*"+"/" BEGIN(INITIAL);
<COMMENT>\n ;
<COMMENT>"*"+"/" { BEGIN (INITIAL); }
/* Preprocessor directives (an extension) */
#[ \t]*include.*\n { sieve_include (); }
#[ \t]*searchpath.*\n { sieve_searchpath (); }
/* End-of-line comments */
#.*\n { mu_sieve_locus.mu_line++; }
#.*\n ;
#.* /* end-of-file comment */;
/* Reserved words */
require return REQUIRE;
......@@ -244,6 +299,8 @@ else return ELSE;
anyof return ANYOF;
allof return ALLOF;
not return NOT;
false return FALSE;
true return TRUE;
/* Identifiers */
{IDENT} { ident (yytext); return IDENT; }
:{IDENT} { ident (yytext + 1); return TAG; }
......@@ -264,24 +321,18 @@ not return NOT;
return STRING; }
/* Multiline strings */
text:-?[ \t]*#.*\n { BEGIN(ML);
multiline_begin ();
mu_sieve_locus.mu_line++; }
multiline_begin (); }
text:-?[ \t]*\n { BEGIN(ML);
multiline_begin ();
mu_sieve_locus.mu_line++; }
text:-?\\?{IDENT}[ \t]*#.*\n { BEGIN(ML); multiline_begin ();
mu_sieve_locus.mu_line++; }
text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); multiline_begin ();
mu_sieve_locus.mu_line++; }
multiline_begin (); }
text:-?\\?{IDENT}[ \t]*#.*\n { BEGIN(ML);
multiline_begin (); }
text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML);
multiline_begin (); }
<ML>#[ \t]*include.*\n { if (multiline_delimiter[0] == '\\')
{
mu_sieve_locus.mu_line++;
multiline_add (NULL);
}
else
sieve_include (); }
<ML>.*\n { char *p = multiline_strip_tabs (yytext);
mu_sieve_locus.mu_line++;
if (strncmp (p, multiline_delimiter, strlen (multiline_delimiter))
== 0
......@@ -296,7 +347,7 @@ text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); multiline_begin ();
multiline_add (NULL); }
{WS} ;
/* Other tokens */
\n { mu_sieve_locus.mu_line++; }
\n ;
. return yytext[0];
%%
......@@ -400,7 +451,7 @@ sieve_include ()
}
static void
sieve_searchpath ()
sieve_searchpath (void)
{
char *p, *endp = yytext + yyleng, *name;
......@@ -416,13 +467,13 @@ sieve_searchpath ()
}
int
mu_sv_lex_begin (const char *name)
mu_i_sv_lex_begin (const char *name)
{
return push_source (name);
}
int
mu_sv_lex_begin_string (const char *buf, int bufsize,
mu_i_sv_lex_begin_string (const char *buf, int bufsize,
const char *fname, int line)
{
int rc;
......@@ -439,19 +490,18 @@ mu_sv_lex_begin_string (const char *buf, int bufsize,
return 1;
}
mu_sieve_locus.mu_file = strdup (fname);
mu_sieve_locus.mu_line = line;
sieve_source_inode = 0;
init_locus (fname, 0);
mu_sv_change_source ();
return 0;
}
void
mu_sv_lex_finish ()
mu_i_sv_lex_finish (struct mu_sieve_machine *mach)
{
while (pop_source () == 0)
;
mach->source_list = file_names;
file_names = NULL;
}
static int
......@@ -507,19 +557,7 @@ multiline_strip_tabs (char *text)
static void
line_add (char *text, size_t len)
{
char *s;
if (len == 0)
len = strlen (text);
s = malloc (len + 1);
if (!s)
{
yyerror (_("not enough memory"));
exit (1);
}
memcpy (s, text, len);
s[len] = 0;
mu_list_append (string_list, s);
mu_opool_append (mu_sieve_machine->string_pool, text, len);
}
static void
......@@ -527,27 +565,17 @@ multiline_add (char *s)
{
if (!s)
s = multiline_strip_tabs (yytext);
line_add (s, 0);
mu_opool_appendz (mu_sieve_machine->string_pool, s);
}
static void
line_begin ()
line_begin (void)
{
int status;
if (string_list)
mu_sieve_slist_destroy (&string_list);
status = mu_list_create (&string_list);
if (status)
{
mu_sv_compile_error (&mu_sieve_locus,
"mu_list_create: %s", mu_strerror (status));
exit (1);
}
/* nothing */
}
static void
multiline_begin ()
multiline_begin (void)
{
char *p = yytext + 5; /* past the text: keyword */
......@@ -587,42 +615,14 @@ multiline_begin ()
}
static void
line_finish ()
line_finish (void)
{
mu_iterator_t itr;
int length = 0;
char *p;
if (!string_list || mu_list_get_iterator (string_list, &itr))
return;
/* Count number of characters in the multiline */
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
char *s;
mu_iterator_current (itr, (void **)&s);
length += strlen (s);
}
/* Copy the contents */
yylval.string = mu_sieve_malloc (mu_sieve_machine, length + 1);
p = yylval.string;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
char *s;
mu_iterator_current (itr, (void **)&s);
strcpy (p, s);
p += strlen (s);
free (s);
}
*p = 0;
mu_iterator_destroy (&itr);
mu_list_destroy (&string_list);
mu_opool_append_char (mu_sieve_machine->string_pool, 0);
yylval.string = mu_opool_finish (mu_sieve_machine->string_pool, NULL);
}
static void
multiline_finish ()
multiline_finish (void)
{
line_finish ();
}
......
......@@ -24,220 +24,256 @@
#include <stdlib.h>
#include <assert.h>
#include <sieve-priv.h>
#include <mailutils/stdstream.h>
mu_sieve_machine_t mu_sieve_machine;
int mu_sieve_error_count;
static void branch_fixup (size_t start, size_t end);
static struct mu_sieve_node *sieve_tree;
static struct mu_sieve_node *node_alloc (enum mu_sieve_node_type,
struct mu_locus_range *);
static void cond_join (struct mu_sieve_node *node);
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
{ \
if (N) \
{ \
(Current).beg = YYRHSLOC(Rhs, 1).beg; \
(Current).end = YYRHSLOC(Rhs, N).end; \
} \
else \
{ \
(Current).beg = YYRHSLOC(Rhs, 0).end; \
(Current).end = (Current).beg; \
} \
} while (0)
#define LOCUS_EQ(a,b) \
((((a)->mu_file == (b)->mu_file) \
|| ((a)->mu_file && (b)->mu_file \
&& strcmp((a)->mu_file, (b)->mu_file) == 0)) \
&& (a)->mu_line == (b)->mu_line)
#define YY_LOCATION_PRINT(File, Loc) \
do \
{ \
if (LOCUS_EQ(&(Loc).beg, &(Loc).end)) \
fprintf(File, "%s:%u.%u-%u.%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col, \
(Loc).end.mu_line, (Loc).end.mu_col); \
else \
fprintf(File, "%s:%u.%u-%s:%u.%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col, \
(Loc).end.mu_file, \
(Loc).end.mu_line, (Loc).end.mu_col); \
} \
while (0)
%}
%error-verbose
%locations
%union {
char *string;
size_t number;
sieve_instr_t instr;
mu_sieve_value_t *value;
mu_list_t list;
size_t pc;
struct {
size_t start;
size_t end;
} pclist;
struct {
struct
{
char *ident;
mu_list_t args;
} command;
struct {
size_t begin;
size_t cond;
size_t branch;
} branch;
struct node_list
{
struct mu_sieve_node *head, *tail;
} node_list;
struct mu_sieve_node *node;
}
%token <string> IDENT TAG
%token <number> NUMBER
%token <string> STRING MULTILINE
%token REQUIRE IF ELSIF ELSE ANYOF ALLOF NOT
%token REQUIRE IF ELSIF ELSE ANYOF ALLOF NOT FALSE TRUE
%type <value> arg
%type <list> slist stringlist stringorlist arglist maybe_arglist
%type <command> command
%type <pclist> testlist
%type <pc> action test statement list elsif else cond begin if block
%type <branch> elsif_branch maybe_elsif else_part
%type <node> action test statement block cond
%type <node> else_part
%type <node_list> list testlist elsif_branch maybe_elsif
%%
input : /* empty */
{
sieve_tree = NULL;
}
| list
{ /* to placate bison */ }
{
sieve_tree = $1.head;
}
;
list : statement
{
$$.head = $$.tail = $1;
}
| list statement
{
if ($2)
{
$2->prev = $1.tail;
if ($1.tail)
$1.tail->next = $2;
else
$1.head = $2;
$1.tail = $2;
}
$$ = $1;
}
;
statement : REQUIRE stringorlist ';'
{
mu_sieve_require ($2);
mu_sieve_require (mu_sieve_machine, $2);
/* All the items in $2 are registered in memory_pool,
so we don't free them */
mu_list_destroy (&$2);
$$ = mu_sieve_machine->pc;
$$ = NULL;
}
| action ';'
/* 1 2 3 4 */
| if cond block else_part
| IF cond block else_part
{
mu_sieve_machine->prog[$2].pc = $4.begin - $2 - 1;
if ($4.branch)
branch_fixup ($4.branch, mu_sieve_machine->pc);
}
;
if : IF
{
$$ = mu_sieve_machine->pc;
$$ = node_alloc (mu_sieve_node_cond, &@1);
$$->v.cond.expr = $2;
$$->v.cond.iftrue = $3;
$$->v.cond.iffalse = $4;
}
;
else_part : maybe_elsif
{
if ($1.begin)
mu_sieve_machine->prog[$1.cond].pc =
mu_sieve_machine->pc - $1.cond - 1;
else
{
$$.begin = mu_sieve_machine->pc;
$$.branch = 0;
cond_join ($1.head);
$$ = $1.head;
}
}
| maybe_elsif else block
| maybe_elsif ELSE block
{
if ($1.begin)
$3->prev = $1.tail;
if ($1.head)
{
mu_sieve_machine->prog[$1.cond].pc = $3 - $1.cond - 1;
mu_sieve_machine->prog[$2].pc = $1.branch;
$$.begin = $1.begin;
$$.branch = $2;
$1.tail->next = $3;
$1.tail = $3;
cond_join ($1.head);
$$ = $1.head;
}
else
{
$$.begin = $3;
$$.branch = $2;
}
$$ = $3;
}
;
maybe_elsif : /* empty */
{
$$.begin = 0;
$$.head = $$.tail = NULL;
}
| elsif_branch
;
elsif_branch : elsif begin cond block
{
$$.begin = $2;
$$.branch = $1;
$$.cond = $3;
}
| elsif_branch elsif begin cond block
{
mu_sieve_machine->prog[$1.cond].pc = $3 - $1.cond - 1;
mu_sieve_machine->prog[$2].pc = $1.branch;
$$.begin = $1.begin;
$$.branch = $2;
$$.cond = $4;
}
;
elsif : ELSIF
elsif_branch : ELSIF cond block
{
mu_sv_code_instr (_mu_sv_instr_branch);
$$ = mu_sieve_machine->pc;
mu_sv_code_number (0);
struct mu_sieve_node *node =
node_alloc (mu_sieve_node_cond, &@1);
node->v.cond.expr = $2;
node->v.cond.iftrue = $3;
node->v.cond.iffalse = NULL;
$$.head = $$.tail = node;
}
;
else : ELSE
| elsif_branch ELSIF cond block
{
mu_sv_code_instr (_mu_sv_instr_branch);
$$ = mu_sieve_machine->pc;
mu_sv_code_number (0);
struct mu_sieve_node *node =
node_alloc (mu_sieve_node_cond, &@2);
node->v.cond.expr = $3;
node->v.cond.iftrue = $4;
node->v.cond.iffalse = NULL;
node->prev = $1.tail;
$1.tail->next = node;
$1.tail = node;
$$ = $1;
}
;
block : '{' list '}'
{
$$ = $2;
$$ = $2.head;
}
;
testlist : cond_expr
{
$$.start = $$.end = mu_sieve_machine->pc;
if (mu_sv_code_instr (_mu_sv_instr_brz)
|| mu_sv_code_number (0))
YYERROR;
}
| testlist ',' cond_expr
testlist : cond
{
mu_sieve_machine->prog[$1.end+1].pc = mu_sieve_machine->pc;
$1.end = mu_sieve_machine->pc;
if (mu_sv_code_instr (_mu_sv_instr_brz)
|| mu_sv_code_number (0))
YYERROR;
$$ = $1;
$$.head = $$.tail = $1;
}
;
cond : cond_expr
| testlist ',' cond
{
mu_sv_code_instr (_mu_sv_instr_brz);
$$ = mu_sieve_machine->pc;
mu_sv_code_number (0);
$3->prev = $1.tail;
$1.tail->next = $3;
$1.tail = $3;
}
;
cond_expr : test
{ /* to placate bison */ }
cond : test
| ANYOF '(' testlist ')'
{
mu_sv_code_anyof ($3.start);
$$ = node_alloc (mu_sieve_node_anyof, &@1);
$$->v.node = $3.head;
}
| ALLOF '(' testlist ')'
{
mu_sv_code_allof ($3.start);
$$ = node_alloc (mu_sieve_node_allof, &@1);
$$->v.node = $3.head;
}
| NOT cond_expr
| NOT cond
{
if (mu_sv_code_instr (_mu_sv_instr_not))
YYERROR;
}
;
begin : /* empty */
{
$$ = mu_sieve_machine->pc;
$$ = node_alloc (mu_sieve_node_not, &@1);
$$->v.node = $2;
}
;
test : command
{
mu_sieve_register_t *reg =
mu_sieve_test_lookup (mu_sieve_machine, $1.ident);
$$ = mu_sieve_machine->pc;
mu_sieve_register_t *reg;
mu_sieve_machine->locus = @1.beg;
reg = mu_sieve_test_lookup (mu_sieve_machine, $1.ident);
if (!reg)
mu_sv_compile_error (&mu_sieve_locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
_("unknown test: %s"),
$1.ident);
mu_i_sv_error (mu_sieve_machine);
}
else if (!reg->required)
mu_sv_compile_error (&mu_sieve_locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
_("test `%s' has not been required"),
$1.ident);
else if (mu_sv_code_test (reg, $1.args))
YYERROR;
mu_i_sv_error (mu_sieve_machine);
}
$$ = node_alloc (mu_sieve_node_test, &@1);
$$->v.command.reg = reg;
$$->v.command.arg = $1.args;
}
| TRUE
{
$$ = node_alloc (mu_sieve_node_true, &@1);
}
| FALSE
{
$$ = node_alloc (mu_sieve_node_false, &@1);
}
;
......@@ -250,20 +286,29 @@ command : IDENT maybe_arglist
action : command
{
mu_sieve_register_t *reg =
mu_sieve_action_lookup (mu_sieve_machine, $1.ident);
mu_sieve_register_t *reg;
mu_sieve_machine->locus = @1.beg;
reg = mu_sieve_action_lookup (mu_sieve_machine, $1.ident);
$$ = mu_sieve_machine->pc;
if (!reg)
mu_sv_compile_error (&mu_sieve_locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
_("unknown action: %s"),
$1.ident);
mu_i_sv_error (mu_sieve_machine);
}
else if (!reg->required)
mu_sv_compile_error (&mu_sieve_locus,
{
mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
_("action `%s' has not been required"),
$1.ident);
else if (mu_sv_code_action (reg, $1.args))
YYERROR;
mu_i_sv_error (mu_sieve_machine);
}
$$ = node_alloc(mu_sieve_node_action, &@1);
$$->v.command.reg = reg;
$$->v.command.arg = $1.args;
}
;
......@@ -339,10 +384,604 @@ slist : STRING
int
yyerror (const char *s)
{
mu_sv_compile_error (&mu_sieve_locus, "%s", s);
extern struct mu_locus mu_sieve_locus;
mu_sieve_machine->locus = mu_sieve_locus;
mu_diag_at_locus (MU_LOG_ERROR, &mu_sieve_locus, "%s", s);
mu_i_sv_error (mu_sieve_machine);
return 0;
}
static void
cond_join (struct mu_sieve_node *node)
{
while (node)
{
struct mu_sieve_node *next = node->next;
node->prev = node->next = NULL;
node->v.cond.iffalse = next;
node = next;
}
}
static struct mu_sieve_node *
node_alloc (enum mu_sieve_node_type type, struct mu_locus_range *lr)
{
struct mu_sieve_node *node = malloc (sizeof (*node));
if (node)
{
node->prev = node->next = NULL;
node->type = type;
node->locus = *lr;
}
return node;
}
static void node_optimize (struct mu_sieve_node *node);
static void node_free (struct mu_sieve_node *node);
static void node_replace (struct mu_sieve_node *node,
struct mu_sieve_node *repl);
static int node_code (struct mu_sieve_machine *mach,
struct mu_sieve_node *node);
static void node_dump (mu_stream_t str, struct mu_sieve_node *node,
unsigned level);
static void tree_free (struct mu_sieve_node **tree);
static void tree_optimize (struct mu_sieve_node *tree);
static int tree_code (struct mu_sieve_machine *mach,
struct mu_sieve_node *tree);
static void tree_dump (mu_stream_t str, struct mu_sieve_node *tree, unsigned level);
static void
indent (mu_stream_t str, unsigned level)
{
#define tab " "
#define tablen (sizeof (tab) - 1)
while (level--)
mu_stream_write (str, tab, tablen, NULL);
}
/* mu_sieve_node_noop */
static void
dump_node_noop (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "NOOP\n");
}
/* mu_sieve_node_false */
static void
dump_node_false (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "FALSE\n");
}
/* mu_sieve_node_true */
static void
dump_node_true (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "TRUE\n");
}
/* mu_sieve_node_test & mu_sieve_node_action */
static void
free_node_command (struct mu_sieve_node *node)
{
mu_list_destroy (&node->v.command.arg);
}
static int
code_node_test (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
return mu_i_sv_code_test (mach, node->v.command.reg, node->v.command.arg);
}
static int
code_node_action (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
return mu_i_sv_code_action (mach, node->v.command.reg, node->v.command.arg);
}
struct string_dumper_data
{
int init;
mu_stream_t stream;
};
static int
string_dumper (void *item, void *data)
{
struct string_dumper_data *dp = data;
if (dp->init == 0)
dp->init = 1;
else
mu_stream_printf (dp->stream, ", ");
mu_stream_printf (dp->stream, "\"%s\"", (char*)item);
return 0;
}
static int
dump_val (void *item, void *data)
{
mu_sieve_value_t *val = item;
mu_stream_t str = data;
mu_stream_printf (str, " ");
switch (val->type)
{
case SVT_VOID:
mu_stream_printf (str, "(void)");
break;
case SVT_NUMBER:
mu_stream_printf (str, "%zu", val->v.number);
break;
case SVT_STRING:
mu_stream_printf (str, "\"%s\"", val->v.string);
break;
case SVT_STRING_LIST:
{
struct string_dumper_data d;
d.init = 0;
d.stream = str;
mu_stream_printf (str, "[");
mu_list_foreach (val->v.list, string_dumper, &d);
mu_stream_printf (str, "]");
}
break;
case SVT_TAG:
mu_stream_printf (str, ":%s", val->v.string);
break;
case SVT_IDENT:
mu_stream_printf (str, "%s", val->v.string);
break;
case SVT_VALUE_LIST:
mu_stream_printf (str, "[");
mu_list_foreach (val->v.list, dump_val, str);
mu_stream_printf (str, "]");
break;
case SVT_POINTER:
mu_stream_printf (str, "%p", val->v.ptr);
break;
default:
abort ();
}
return 0;
}
static void
dump_node_command (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "COMMAND %s", node->v.command.reg->name);
mu_list_foreach (node->v.command.arg, dump_val, str);
mu_stream_printf (str, "\n");
}
/* mu_sieve_node_cond */
static void
free_node_cond (struct mu_sieve_node *node)
{
tree_free (&node->v.cond.expr);
tree_free (&node->v.cond.iftrue);
tree_free (&node->v.cond.iffalse);
}
static void
optimize_node_cond (struct mu_sieve_node *node)
{
tree_optimize (node->v.cond.expr);
switch (node->v.cond.expr->type)
{
case mu_sieve_node_true:
tree_optimize (node->v.cond.iftrue);
node_replace (node, node->v.cond.iftrue);
break;
case mu_sieve_node_false:
tree_optimize (node->v.cond.iffalse);
node_replace (node, node->v.cond.iffalse);
break;
default:
tree_optimize (node->v.cond.iftrue);
tree_optimize (node->v.cond.iffalse);
}
}
static int
code_node_cond (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
size_t br1;
tree_code (mach, node->v.cond.expr);
mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_brz);
br1 = mach->pc;
mu_i_sv_code (mach, (sieve_op_t) 0);
tree_code (mach, node->v.cond.iftrue);
if (node->v.cond.iffalse)
{
size_t br2;
mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_branch);
br2 = mach->pc;
mu_i_sv_code (mach, (sieve_op_t) 0);
mach->prog[br1].pc = mach->pc - br1 - 1;
tree_code (mach, node->v.cond.iffalse);
mach->prog[br2].pc = mach->pc - br2 - 1;
}
else
mach->prog[br1].pc = mach->pc - br1 - 1;
return 0;
}
static void
dump_node_cond (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "COND\n");
++level;
indent (str, level);
mu_stream_printf (str, "EXPR:\n");
tree_dump (str, node->v.cond.expr, level + 1);
indent (str, level);
mu_stream_printf (str, "IFTRUE:\n");
tree_dump (str, node->v.cond.iftrue, level + 1);
indent (str, level);
mu_stream_printf (str, "IFFALSE:\n");
tree_dump (str, node->v.cond.iffalse, level + 1);
}
/* mu_sieve_node_anyof & mu_sieve_node_allof */
static void
free_node_x_of (struct mu_sieve_node *node)
{
tree_free (&node->v.node);
}
static void
optimize_x_of (struct mu_sieve_node *node, enum mu_sieve_node_type solve)
{
struct mu_sieve_node *cur;
tree_optimize (node->v.node);
cur = node->v.node;
while (cur)
{
struct mu_sieve_node *next = cur->next;
switch (cur->type)
{
case mu_sieve_node_false:
case mu_sieve_node_true:
if (cur->type == solve)
{
tree_free (&node->v.node);
node->type = solve;
return;
}
else
{
if (cur->prev)
cur->prev->next = next;
else
node->v.node = next;
if (next)
next->prev = cur->prev;
node_free (cur);
}
break;
default:
break;
}
cur = next;
}
if (!node->v.node)
node->type = solve == mu_sieve_node_false ? mu_sieve_node_true : mu_sieve_node_false;
}
static int
code_node_x_of (struct mu_sieve_machine *mach, struct mu_sieve_node *node,
sieve_op_t op)
{
struct mu_sieve_node *cur = node->v.node;
size_t pc = 0;
size_t end;
while (cur)
{
node_code (mach, cur);
if (cur->next)
{
mu_i_sv_code (mach, op);
mu_i_sv_code (mach, (sieve_op_t) pc);
pc = mach->pc - 1;
}
cur = cur->next;
}
/* Fix-up locations */
end = mach->pc;
while (pc != 0)
{
size_t prev = mach->prog[pc].pc;
mach->prog[pc].pc = end - pc - 1;
pc = prev;
}
return 0;
}
static void
dump_node_x_of (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "%s:\n",
node->type == mu_sieve_node_allof ? "ALLOF" : "ANYOF");
++level;
node = node->v.node;
while (node)
{
node_dump (str, node, level + 1);
node = node->next;
if (node)
{
indent (str, level);
mu_stream_printf (str, "%s:\n",
node->type == mu_sieve_node_allof ? "AND" : "OR");
}
}
}
/* mu_sieve_node_anyof */
static void
optimize_node_anyof (struct mu_sieve_node *node)
{
optimize_x_of (node, mu_sieve_node_true);
}
static int
code_node_anyof (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
return code_node_x_of (mach, node, (sieve_op_t) _mu_sv_instr_brnz);
}
/* mu_sieve_node_allof */
static void
optimize_node_allof (struct mu_sieve_node *node)
{
return optimize_x_of (node, mu_sieve_node_false);
}
static int
code_node_allof (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
return code_node_x_of (mach, node, (sieve_op_t) _mu_sv_instr_brz);
}
/* mu_sieve_node_not */
static void
free_node_not (struct mu_sieve_node *node)
{
tree_free (&node->v.node);
}
static void
optimize_node_not (struct mu_sieve_node *node)
{
tree_optimize (node->v.node);
switch (node->v.node->type)
{
case mu_sieve_node_false:
tree_free (&node->v.node);
node->type = mu_sieve_node_true;
break;
case mu_sieve_node_true:
tree_free (&node->v.node);
node->type = mu_sieve_node_false;
break;
default:
break;
}
}
static int
code_node_not (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
node_code (mach, node->v.node);
return mu_i_sv_code (mach, (sieve_op_t) _mu_sv_instr_not);
}
static void
dump_node_not (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
indent (str, level);
mu_stream_printf (str, "NOT\n");
node_dump (str, node->v.node, level + 1);
}
struct node_descr
{
int (*code_fn) (struct mu_sieve_machine *mach, struct mu_sieve_node *node);
void (*optimize_fn) (struct mu_sieve_node *node);
void (*free_fn) (struct mu_sieve_node *node);
void (*dump_fn) (mu_stream_t str, struct mu_sieve_node *node, unsigned level);
};
static struct node_descr node_descr[] = {
[mu_sieve_node_noop] = { NULL, NULL, NULL, dump_node_noop },
[mu_sieve_node_false] = { NULL, NULL, NULL, dump_node_false },
[mu_sieve_node_true] = { NULL, NULL, NULL, dump_node_true },
[mu_sieve_node_test] = { code_node_test, NULL,
free_node_command, dump_node_command },
[mu_sieve_node_action] = { code_node_action, NULL,
free_node_command, dump_node_command },
[mu_sieve_node_cond] = { code_node_cond, optimize_node_cond,
free_node_cond, dump_node_cond },
[mu_sieve_node_anyof] = { code_node_anyof, optimize_node_anyof,
free_node_x_of, dump_node_x_of },
[mu_sieve_node_allof] = { code_node_allof, optimize_node_allof,
free_node_x_of, dump_node_x_of },
[mu_sieve_node_not] = { code_node_not, optimize_node_not,
free_node_not, dump_node_not },
};
static void
node_optimize (struct mu_sieve_node *node)
{
if ((int)node->type >= MU_ARRAY_SIZE (node_descr))
abort ();
if (node_descr[node->type].optimize_fn)
node_descr[node->type].optimize_fn (node);
}
static void
node_free (struct mu_sieve_node *node)
{
if ((int)node->type >= MU_ARRAY_SIZE (node_descr))
abort ();
if (node_descr[node->type].free_fn)
node_descr[node->type].free_fn (node);
free (node);
}
static void
node_replace (struct mu_sieve_node *node, struct mu_sieve_node *repl)
{
struct mu_sieve_node copy;
if ((int)node->type >= MU_ARRAY_SIZE (node_descr))
abort ();
copy = *node;
if (repl)
{
node->type = repl->type;
node->v = repl->v;
switch (copy.type)
{
case mu_sieve_node_cond:
if (repl == copy.v.cond.expr)
copy.v.cond.expr = NULL;
else if (repl == copy.v.cond.iftrue)
copy.v.cond.iftrue = NULL;
else if (repl == copy.v.cond.iffalse)
copy.v.cond.iffalse = NULL;
break;
case mu_sieve_node_not:
if (repl == copy.v.node)
copy.v.node = NULL;
break;
default:
break;
}
}
else
node->type = mu_sieve_node_noop;
if (node_descr[node->type].free_fn)
node_descr[node->type].free_fn (&copy);
}
static int
node_code (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
if ((int)node->type >= MU_ARRAY_SIZE (node_descr))
abort ();
if (!node_descr[node->type].code_fn)
return 0;
if (mu_i_sv_locus (mach, &node->locus))
return 1;
return node_descr[node->type].code_fn (mach, node);
}
static void
node_dump (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
{
if ((int)node->type >= MU_ARRAY_SIZE (node_descr)
|| !node_descr[node->type].dump_fn)
abort ();
node_descr[node->type].dump_fn (str, node, level);
}
static void
tree_free (struct mu_sieve_node **tree)
{
struct mu_sieve_node *cur = *tree;
while (cur)
{
struct mu_sieve_node *next = cur->next;
node_free (cur);
cur = next;
}
}
static void
tree_optimize (struct mu_sieve_node *tree)
{
while (tree)
{
node_optimize (tree);
tree = tree->next;
}
}
static int
tree_code (struct mu_sieve_machine *mach, struct mu_sieve_node *tree)
{
while (tree)
{
if (node_code (mach, tree))
return 1;
tree = tree->next;
}
return 0;
}
static void
tree_dump (mu_stream_t str, struct mu_sieve_node *tree, unsigned level)
{
while (tree)
{
node_dump (str, tree, level);
tree = tree->next;
}
}
void
mu_i_sv_error (mu_sieve_machine_t mach)
{
mach->state = mu_sieve_state_error;
}
int
mu_sieve_machine_init_ex (mu_sieve_machine_t *pmach,
void *data, mu_stream_t errstream)
......@@ -362,6 +1001,16 @@ mu_sieve_machine_init_ex (mu_sieve_machine_t *pmach,
return rc;
}
rc = mu_opool_create (&mach->string_pool, MU_OPOOL_DEFAULT);
if (rc)
{
mu_list_destroy (&mach->memory_pool);
free (mach);
return rc;
}
mach->source_list = NULL;
mach->data = data;
mach->errstream = errstream;
mu_stream_ref (errstream);
......@@ -417,6 +1066,7 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
mach->progsize = in->progsize;
mach->prog = in->prog;
mach->state = in->state;
mach->pc = 0;
mach->reg = 0;
mach->stack = NULL;
......@@ -571,97 +1221,140 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
mu_list_destroy (&mach->test_list);
mu_list_destroy (&mach->comp_list);
mu_list_destroy (&mach->source_list);
mu_opool_destroy (&mach->string_pool);
mu_sieve_slist_destroy (&mach->memory_pool);
free (mach);
*pmach = NULL;
}
static int
string_comp (const void *item, const void *value)
{
return strcmp (item, value);
}
void
mu_sieve_machine_begin (mu_sieve_machine_t mach, const char *file)
static void
sieve_machine_begin (mu_sieve_machine_t mach, const char *file)
{
mu_sieve_machine = mach;
mu_sieve_error_count = 0;
mu_sv_code_instr (NULL);
mu_list_create (&mach->source_list);
mu_list_set_comparator (mach->source_list, string_comp);
mu_sv_register_standard_actions (mach);
mu_sv_register_standard_tests (mach);
mu_sv_register_standard_comparators (mach);
mu_sieve_machine = mach;
}
void
mu_sieve_machine_finish (mu_sieve_machine_t mach)
static void
sieve_machine_finish (void)
{
mu_sv_code_instr (NULL);
//nothing
}
int
mu_sieve_compile (mu_sieve_machine_t mach, const char *name)
with_machine (mu_sieve_machine_t mach, char const *name,
int (*thunk) (void *), void *data)
{
int rc = 0;
mu_stream_t save_errstr = mu_strerr;
mu_sieve_machine_begin (mach, name);
mu_stream_ref (save_errstr);
mu_strerr = mach->errstream;
mu_stream_ref (mu_strerr);
if (mu_sv_lex_begin (name) == 0)
{
if (yyparse () || mu_sieve_error_count)
rc = MU_ERR_PARSE;
mu_sv_lex_finish ();
}
else
rc = MU_ERR_FAILURE;
sieve_machine_begin (mach, name);
rc = thunk (data);
sieve_machine_finish ();
mu_stream_unref (save_errstr);
mu_strerr = save_errstr;
mu_stream_unref (mu_strerr);
mu_sieve_machine_finish (mach);
return rc;
}
int
mu_sieve_compile_buffer (mu_sieve_machine_t mach,
const char *buf, int bufsize,
const char *fname, int line)
static int
sieve_parse (void)
{
int rc;
mu_sieve_machine_begin (mach, fname);
sieve_tree = NULL;
yydebug = mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE3);
if (mu_sv_lex_begin_string (buf, bufsize, fname, line) == 0)
{
rc = yyparse ();
if (mu_sieve_error_count)
rc = 1;
mu_sv_lex_finish ();
mu_i_sv_lex_finish (mu_sieve_machine);
if (rc)
mu_i_sv_error (mu_sieve_machine);
if (mu_sieve_machine->state == mu_sieve_state_init)
{
if (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE1))
{
mu_error (_("Unoptimized parse tree"));
tree_dump (mu_strerr, sieve_tree, 0);
}
tree_optimize (sieve_tree);
if (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE2))
{
mu_error (_("Optimized parse tree"));
tree_dump (mu_strerr, sieve_tree, 0);
}
mu_i_sv_code (mu_sieve_machine, (sieve_op_t) 0);
rc = tree_code (mu_sieve_machine, sieve_tree);
if (rc)
mu_i_sv_error (mu_sieve_machine);
mu_i_sv_code (mu_sieve_machine, (sieve_op_t) 0);
}
if (rc == 0)
{
if (mu_sieve_machine->state == mu_sieve_state_error)
rc = MU_ERR_PARSE;
else
rc = 1;
mu_sieve_machine->state = mu_sieve_state_compiled;
}
mu_sieve_machine_finish (mach);
tree_free (&sieve_tree);
return rc;
}
static void
_branch_fixup (size_t start, size_t end)
static int
sieve_compile_file (void *name)
{
size_t prev = mu_sieve_machine->prog[start].pc;
if (!prev)
return;
branch_fixup (prev, end);
mu_sieve_machine->prog[prev].pc = end - prev - 1;
if (mu_i_sv_lex_begin (name) == 0)
return sieve_parse ();
return MU_ERR_FAILURE;
}
static void
branch_fixup (size_t start, size_t end)
int
mu_sieve_compile (mu_sieve_machine_t mach, const char *name)
{
_branch_fixup (start, end);
mu_sieve_machine->prog[start].pc = end - start - 1;
return with_machine (mach, name, sieve_compile_file, (void *) name);
}
struct strbuf
{
const char *ptr;
size_t size;
const char *file;
int line;
};
static int
sieve_compile_strbuf (void *name)
{
struct strbuf *buf = name;
if (mu_i_sv_lex_begin_string (buf->ptr, buf->size, buf->file, buf->line) == 0)
return sieve_parse ();
return MU_ERR_FAILURE;
}
//FIXME: The API is clumsy
int
mu_sieve_compile_buffer (mu_sieve_machine_t mach,
const char *str, int strsize,
const char *fname, int line)
{
struct strbuf buf;
buf.ptr = str;
buf.size = strsize;
buf.file = fname;
buf.line = line;
return with_machine (mach, fname, sieve_compile_strbuf, &buf);
}
......
......@@ -320,22 +320,6 @@ sieve_test_size (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
}
int
sieve_test_true (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "TRUE");
return 1;
}
int
sieve_test_false (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
mu_sieve_debug (mach, "FALSE");
return 0;
}
int
_test_exists (void *item, void *data)
{
mu_header_t hdr = data;
......@@ -446,8 +430,7 @@ mu_sieve_tag_group_t header_tag_groups[] = {
void
mu_sv_register_standard_tests (mu_sieve_machine_t mach)
{
mu_sieve_register_test (mach, "false", sieve_test_false, NULL, NULL, 1);
mu_sieve_register_test (mach, "true", sieve_test_true, NULL, NULL, 1);
/* true and false are built-ins */
mu_sieve_register_test (mach, "address", sieve_test_address,
address_req_args, address_tag_groups, 1);
mu_sieve_register_test (mach, "size", sieve_test_size,
......
......@@ -171,7 +171,7 @@ mu_sieve_value_create (mu_sieve_data_type type, void *data)
break;
default:
mu_sv_compile_error (&mu_sieve_locus, _("invalid data type"));
mu_error ("%s", _("invalid data type"));
abort ();
}
return val;
......@@ -186,24 +186,6 @@ mu_sieve_value_get (mu_list_t vlist, size_t index)
}
void
mu_sv_compile_error (struct mu_locus *ploc, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
mu_sieve_error_count++;
mu_stream_ioctl (mu_sieve_machine->errstream,
MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
ploc);
mu_stream_printf (mu_sieve_machine->errstream,
"\033s<%d>\033O<%d>",
MU_LOG_ERROR, MU_LOGMODE_LOCUS);
mu_stream_vprintf (mu_sieve_machine->errstream, fmt, ap);
mu_stream_write (mu_sieve_machine->errstream, "\n", 1, NULL);
va_end (ap);
}
void
mu_sieve_error (mu_sieve_machine_t mach, const char *fmt, ...)
{
va_list ap;
......
......@@ -83,7 +83,9 @@ set_debug_level (const char *arg)
break;
case 'g':
mu_sieve_yydebug = 1;
mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
mu_debug_set_category_level (mu_sieve_debug_handle,
lev | MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE1));
break;
case 't':
......
......@@ -38,7 +38,7 @@ if header :comparator "i;ascii-numeric" :contains "X-Number" "15"
discard;
}
],[78],[],
[sieve: prog:5: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header'
[sieve: prog:4:1: comparator `i;ascii-numeric' is incompatible with match type `contains' in call to `header'
])
AT_CLEANUP
......