commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-3.0-6-gf2980e5


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-3.0-6-gf2980e5
Date: Wed, 23 Nov 2016 16:42:44 +0000 (UTC)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=f2980e5a1a7495e31f75b979b258bd0fffdb310e

The branch, master has been updated
       via  f2980e5a1a7495e31f75b979b258bd0fffdb310e (commit)
       via  4e162e9bb1a48269ce57a739a07d8c933a17bd57 (commit)
       via  15404d914aec7e80c884fc63dbfa5d3e347b32cb (commit)
      from  a04c6feb5007aeeb133b15558f13733743dee3e8 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f2980e5a1a7495e31f75b979b258bd0fffdb310e
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Nov 23 18:28:08 2016 +0200

    Redo sieve debugging support
    
    Instead of keeping individual debug flags for each Sieve machine,
    use global debugging mechanism, category "sieve".  The following
    levels are defined:
    
      trace1  -  print parse tree before optimization
      trace2  -  print parse tree after optimization
      trace3  -  print parser traces
      trace4  -  print tests and actions being executed
      trace8  -  print disassembled code, don't run
      trace9  -  print each Sieve instruction being executed
    
    * include/mailutils/sieve.h (mu_sieve_get_debug_level)
    (mu_sieve_set_debug_level): Remove.
    (mu_sieve_is_dry_run,mu_sieve_set_dry_run
    * lib/script.c (mu_script_debug_flags): Redo.
    * lib/sieve.c (sieve_init): Remove call to obsoleted
    mu_sieve_set_debug_level.
    
    * examples/numaddr.c: Use mu_sieve_trace
    * libmu_sieve/extensions/list.c: Likewise.
    * libmu_sieve/extensions/moderator.c: Likewise.
    * libmu_sieve/extensions/pipe.c: Likewise.
    * libmu_sieve/extensions/spamd.c: Likewise.
    * libmu_sieve/extensions/timestamp.c: Likewise.
    * libmu_sieve/extensions/vacation.c: Likewise.
    * libmu_sieve/tests.c: Likewise.
    
    * libmu_sieve/runtime.c (INSTR_DEBUG,INSTR_DISASS): Rewrite.
    (mu_sieve_get_debug_level): Remove.
    (mu_sieve_is_dry_run_: Rewrite.
    (mu_sieve_set_dry_run): New function.
    (mu_sieve_disass): Rewrite.
    * libmu_sieve/sieve-priv.h (mu_sieve_machine) <debug_level>: Remove.
    <dry_run>: New field.
    * libmu_sieve/sieve.y (mu_sieve_set_debug_level): Remove.
    * libmu_sieve/util.c (mu_sieve_trace): New function.
    * sieve/sieve.c: Rewrite support for --dry-run and --debug.
    
    * sieve/tests/ext.at: Use --libdir-prefix instead of -L

commit 4e162e9bb1a48269ce57a739a07d8c933a17bd57
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Nov 23 13:46:43 2016 +0200

    Further cleanup of sieve namespace
    
    Prefix internal function names with mu_i_

commit 15404d914aec7e80c884fc63dbfa5d3e347b32cb
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Nov 23 13:26:23 2016 +0200

    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.

-----------------------------------------------------------------------

Summary of changes:
 examples/numaddr.c                 |    5 +-
 include/mailutils/sieve.h          |   19 +-
 lib/script.c                       |   10 +-
 lib/sieve.c                        |    1 -
 libmailutils/diag/diag.c           |    9 +-
 libmu_auth/ldap.c                  |    2 -
 libmu_sieve/Makefile.am            |    1 +
 libmu_sieve/actions.c              |   10 +-
 libmu_sieve/comparator.c           |   68 ++-
 libmu_sieve/extensions/list.c      |    5 +-
 libmu_sieve/extensions/moderator.c |    7 +-
 libmu_sieve/extensions/pipe.c      |    5 +-
 libmu_sieve/extensions/spamd.c     |    7 +-
 libmu_sieve/extensions/timestamp.c |    5 +-
 libmu_sieve/extensions/vacation.c  |    5 +-
 libmu_sieve/load.c                 |    4 +-
 libmu_sieve/prog.c                 |  296 ++++------
 libmu_sieve/require.c              |   19 +-
 libmu_sieve/runtime.c              |   68 ++-
 libmu_sieve/sieve-priv.h           |  149 +++--
 libmu_sieve/sieve.l                |  238 ++++----
 libmu_sieve/sieve.y                | 1091 +++++++++++++++++++++++++++++-------
 libmu_sieve/tests.c                |   33 +-
 libmu_sieve/util.c                 |   45 +-
 sieve/sieve.c                      |   52 +-
 sieve/tests/ext.at                 |    2 +-
 sieve/tests/i-numeric.at           |    2 +-
 27 files changed, 1412 insertions(+), 746 deletions(-)

diff --git a/examples/numaddr.c b/examples/numaddr.c
index aa5990f..578bddc 100644
--- a/examples/numaddr.c
+++ b/examples/numaddr.c
@@ -84,10 +84,7 @@ numaddr_test (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   struct val_ctr vc;
   int rc;
   
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "NUMADDR");
-    }
+  mu_sieve_trace (mach, "NUMADDR");
 
   /* Retrieve required arguments: */
   /* First argument: list of header names */
diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h
index 9aab6c6..74fa7c5 100644
--- a/include/mailutils/sieve.h
+++ b/include/mailutils/sieve.h
@@ -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);
@@ -228,13 +231,15 @@ void *mu_sieve_get_data (mu_sieve_machine_t mach);
 void mu_sieve_set_data (mu_sieve_machine_t mach, void *);
 mu_message_t mu_sieve_get_message (mu_sieve_machine_t mach);
 size_t mu_sieve_get_message_num (mu_sieve_machine_t mach);
-int mu_sieve_get_debug_level (mu_sieve_machine_t mach);
+
+int mu_sieve_is_dry_run (mu_sieve_machine_t mach);
+int mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val);
+
 mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t mach);
 int mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *);
 char *mu_sieve_get_daemon_email (mu_sieve_machine_t mach);
 const char *mu_sieve_get_identifier (mu_sieve_machine_t mach);
 
-void mu_sieve_set_debug_level (mu_sieve_machine_t mach, int level);
 void mu_sieve_set_logger (mu_sieve_machine_t mach,
                          mu_sieve_action_log_t logger);
 void mu_sieve_set_mailer (mu_sieve_machine_t mach, mu_mailer_t mailer);
diff --git a/lib/script.c b/lib/script.c
index 5993897..2ac5378 100644
--- a/lib/script.c
+++ b/lib/script.c
@@ -39,6 +39,8 @@ struct mu_script_fun *script_tab[] = {
 int
 mu_script_debug_flags (const char *arg, char **endp)
 {
+  mu_debug_level_t lev;
+    
   for (; *arg; arg++)
     {
       switch (*arg)
@@ -48,11 +50,15 @@ mu_script_debug_flags (const char *arg, char **endp)
          break;
 
        case 't':
-         mu_script_debug_sieve |= MU_SIEVE_DEBUG_TRACE;
+         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_TRACE4));
          break;
          
        case 'i':
-         mu_script_debug_sieve |= MU_SIEVE_DEBUG_INSTR;
+         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_TRACE9));
          break;
          
        case 'l':
diff --git a/lib/sieve.c b/lib/sieve.c
index c5f7846..a7450c1 100644
--- a/lib/sieve.c
+++ b/lib/sieve.c
@@ -81,7 +81,6 @@ sieve_init (const char *prog, mu_script_descr_t *pdescr)
   rc = mu_sieve_machine_init (&mach);
   if (rc == 0)
     {
-      mu_sieve_set_debug_level (mach, mu_script_debug_sieve);
       if (mu_script_sieve_log)
        mu_sieve_set_logger (mach, _sieve_action_log);
       rc = mu_sieve_compile (mach, prog);
diff --git a/libmailutils/diag/diag.c b/libmailutils/diag/diag.c
index 3f10356..50b8aa9 100644
--- a/libmailutils/diag/diag.c
+++ b/libmailutils/diag/diag.c
@@ -61,10 +61,11 @@ mu_diag_at_locus (int level, struct mu_locus const *loc, 
const char *fmt, ...)
   va_list ap;
 
   va_start (ap, fmt);
-  mu_stream_printf (mu_strerr, "\033f<%d>%s\033l<%u>\033c<%u>",
-                   (unsigned) strlen (loc->mu_file), loc->mu_file,
-                   loc->mu_line,
-                   loc->mu_col);
+  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,
+                     loc->mu_col);
   mu_diag_voutput (level, fmt, ap);
   va_end (ap);
 }
diff --git a/libmu_auth/ldap.c b/libmu_auth/ldap.c
index 4798b56..37fb0c3 100644
--- a/libmu_auth/ldap.c
+++ b/libmu_auth/ldap.c
@@ -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);
diff --git a/libmu_sieve/Makefile.am b/libmu_sieve/Makefile.am
index d9025a9..63a21c7 100644
--- a/libmu_sieve/Makefile.am
+++ b/libmu_sieve/Makefile.am
@@ -17,6 +17,7 @@
 
 YLWRAP = $(SHELL) $(mu_aux_dir)/gylwrap
 AM_YFLAGS = -dtv
+#AM_LEXFLAGS=-dvp
 AM_CPPFLAGS =\
  @address@hidden
  -DMU_SIEVE_MODDIR=\"@address@hidden"
diff --git a/libmu_sieve/actions.c b/libmu_sieve/actions.c
index 335748a..84bd368 100644
--- a/libmu_sieve/actions.c
+++ b/libmu_sieve/actions.c
@@ -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, 
-                                  _("invalid permissions (near %s)"), p);
+             mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
+                               _("invalid permissions (near %s)"), p);
+             mu_i_sv_error (mach);
              err = 1;
            }
        }
@@ -561,7 +563,7 @@ static mu_sieve_tag_group_t fileinto_tag_groups[] = {
 };
   
 void
-mu_sv_register_standard_actions (mu_sieve_machine_t mach)
+mu_i_sv_register_standard_actions (mu_sieve_machine_t mach)
 {
   mu_sieve_register_action (mach, "stop", sieve_action_stop, NULL, NULL, 1);
   mu_sieve_register_action (mach, "keep", sieve_action_keep, NULL, NULL, 1);
diff --git a/libmu_sieve/comparator.c b/libmu_sieve/comparator.c
index 184936d..d7be199 100644
--- a/libmu_sieve/comparator.c
+++ b/libmu_sieve/comparator.c
@@ -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, 
-                            _("match type specified twice in call to `%s'"),
-                                  name);
+             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, 
-                                  /* 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_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, 
-                              _("invalid relational match `%s' in call to 
`%s'"),
-                              str, name);
+         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, 
-                          _("comparator `%s' is incompatible with match type 
`%s' in call to `%s'"),
-                              compname, match ? match->tag : "is", name);
+         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;
@@ -492,7 +502,7 @@ i_ascii_numeric_eq (const char *pattern, const char *text)
 }
 
 void
-mu_sv_register_standard_comparators (mu_sieve_machine_t mach)
+mu_i_sv_register_standard_comparators (mu_sieve_machine_t mach)
 {
   mu_sieve_register_comparator (mach,
                             "i;octet",
diff --git a/libmu_sieve/extensions/list.c b/libmu_sieve/extensions/list.c
index caef14f..46b7a25 100644
--- a/libmu_sieve/extensions/list.c
+++ b/libmu_sieve/extensions/list.c
@@ -152,10 +152,7 @@ list_test (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   struct header_closure clos;
   int result;
 
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "LIST");
-    }
+  mu_sieve_trace (mach, "LIST");
   
   memset (&clos, 0, sizeof clos);
   if (mu_sieve_tag_lookup (tags, "delim", &arg))
diff --git a/libmu_sieve/extensions/moderator.c 
b/libmu_sieve/extensions/moderator.c
index d889725..00b1de4 100644
--- a/libmu_sieve/extensions/moderator.c
+++ b/libmu_sieve/extensions/moderator.c
@@ -273,11 +273,8 @@ moderator_action (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   int discard = 0;
   int ismime;
   
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "moderator_test %lu",
-                     (unsigned long) mu_sieve_get_message_num (mach));
-    }
+  mu_sieve_trace (mach, "moderator_test %lu",
+                 (unsigned long) mu_sieve_get_message_num (mach));
 
   msg = mu_sieve_get_message (mach);
   mu_message_is_multipart (msg, &ismime);
diff --git a/libmu_sieve/extensions/pipe.c b/libmu_sieve/extensions/pipe.c
index cb2e78a..783950b 100644
--- a/libmu_sieve/extensions/pipe.c
+++ b/libmu_sieve/extensions/pipe.c
@@ -105,10 +105,7 @@ sieve_pipe (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags, int test)
     }
   cmd = val->v.string;
 
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, test ? "PIPE (test)" : "PIPE (action)");
-    }
+  mu_sieve_trace (mach, test ? "PIPE (test)" : "PIPE (action)");
 
   if (mu_sieve_is_dry_run (mach))
     return 0;
diff --git a/libmu_sieve/extensions/spamd.c b/libmu_sieve/extensions/spamd.c
index 6689328..1fd8837 100644
--- a/libmu_sieve/extensions/spamd.c
+++ b/libmu_sieve/extensions/spamd.c
@@ -368,11 +368,8 @@ spamd_test (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   mu_header_t hdr;
   mu_debug_handle_t lev = 0;
   
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "spamd_test %lu",
-                     (unsigned long) mu_sieve_get_message_num (mach));
-    }
+  mu_sieve_trace (mach, "spamd_test %lu",
+                 (unsigned long) mu_sieve_get_message_num (mach));
   
   if (mu_sieve_is_dry_run (mach))
     return 0;
diff --git a/libmu_sieve/extensions/timestamp.c 
b/libmu_sieve/extensions/timestamp.c
index 7fdcf14..67fceb0 100644
--- a/libmu_sieve/extensions/timestamp.c
+++ b/libmu_sieve/extensions/timestamp.c
@@ -57,10 +57,7 @@ timestamp_test (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   time_t tlimit, tval;
   int rc;
   
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "TIMESTAMP");
-    }
+  mu_sieve_trace (mach, "TIMESTAMP");
 
   /* Retrieve required arguments: */
   /* First argument: header name */
diff --git a/libmu_sieve/extensions/vacation.c 
b/libmu_sieve/extensions/vacation.c
index d6b6a2e..863fe15 100644
--- a/libmu_sieve/extensions/vacation.c
+++ b/libmu_sieve/extensions/vacation.c
@@ -136,10 +136,7 @@ build_mime (mu_sieve_machine_t mach, mu_list_t tags, 
mu_mime_t *pmime,
 static int
 diag (mu_sieve_machine_t mach)
 {
-  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
-    {
-      mu_sieve_debug (mach, "VACATION");
-    }
+  mu_sieve_trace (mach, "VACATION");
 
   mu_sieve_log_action (mach, "VACATION", NULL);
   return mu_sieve_is_dry_run (mach);
diff --git a/libmu_sieve/load.c b/libmu_sieve/load.c
index 341aa9f..c164c27 100644
--- a/libmu_sieve/load.c
+++ b/libmu_sieve/load.c
@@ -136,7 +136,7 @@ _add_load_dir (void *item, void *unused)
 }
 
 int
-mu_sv_load_add_dir (mu_sieve_machine_t mach, const char *name)
+mu_i_sv_load_add_dir (mu_sieve_machine_t mach, const char *name)
 {
   if (sieve_init_load_path ())
     return 1;
@@ -155,7 +155,7 @@ mu_sieve_load_ext (mu_sieve_machine_t mach, const char 
*name)
 }
 
 int
-mu_sv_load_add_dir (mu_sieve_machine_t mach, const char *name)
+mu_i_sv_load_add_dir (mu_sieve_machine_t mach, const char *name)
 {
   return 1;
 }
diff --git a/libmu_sieve/prog.c b/libmu_sieve/prog.c
index 5b0140e..50af4c9 100644
--- a/libmu_sieve/prog.c
+++ b/libmu_sieve/prog.c
@@ -25,72 +25,55 @@
 #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 ? 0 : 1;
 }
-
+      
+/* 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_i_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_i_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 *
 find_tag (mu_sieve_tag_group_t *taglist, char *tagname,
          mu_sieve_tag_checker_t *checker)
@@ -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, 
-                               _("cannot create iterator: %s"),
-                              mu_strerror (rc));
+         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, 
-                                      _("invalid tag name `%s' for `%s'"),
-                                      val->v.string, reg->name);
+                 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, 
-                                       _("cannot create tag list: %s"),
-                                      mu_strerror (rc));
+                 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);
+                                       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, 
-                                          _("type mismatch in argument to "
-                                            "tag `%s'"),
-                                          tag->name);
-                     mu_sv_compile_error (&mu_sieve_locus, 
-                                          _("expected %s but passed %s"),
-                                          mu_sieve_type_str (tag->argtype),
-                                          mu_sieve_type_str
-                                                        (tagrec.arg->type));
+                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                                            _("type mismatch in argument to "
+                                              "tag `%s'"),
+                                            tag->name);
+                     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_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, 
-                                        _("cannot create check list: %s"),
-                                          mu_strerror (rc));
+                     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, 
-                                     _("too many arguments in call to `%s'"),
-                                          reg->name);
+                     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, 
-                                          _("expected %s but passed %s"),
-                                          mu_sieve_type_str (*exp_arg),
-                                          mu_sieve_type_str (val->type));
+                                            reg->name);
+                     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, 
-                                       _("cannot create arg list: %s"),
-                                      mu_strerror (rc));
+                 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,16 +301,18 @@ 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, 
-                               _("too few arguments in call to `%s'"),
-                              reg->name);
+         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;
        }
 
       if (chk_list)
        {
          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)
-{
-  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);
-}
-
-int
-mu_sv_code_line (size_t line)
+mu_i_sv_code_action (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);
+  return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_action)
+         || sv_code_command (mach, 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)
+mu_i_sv_code_test (struct mu_sieve_machine *mach,
+                  mu_sieve_register_t *reg, mu_list_t arglist)
 {
-  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;
+  return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_test)
+         || sv_code_command (mach, reg, arglist);
 }
 
-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;
-}
-               
diff --git a/libmu_sieve/require.c b/libmu_sieve/require.c
index de6ac00..18c348e 100644
--- a/libmu_sieve/require.c
+++ b/libmu_sieve/require.c
@@ -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,
-                          _("cannot create iterator: %s"),
-                          mu_strerror (status));
+      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,
-                              _("source for the %s %s is not available"),
-                              text,
-                              name);
+         mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
+                           _("source for the %s %s is not available"),
+                           text, name);
+         mu_i_sv_error (mach);
        }
     }
   mu_iterator_destroy (&itr);
diff --git a/libmu_sieve/runtime.c b/libmu_sieve/runtime.c
index 60bdecc..2778739 100644
--- a/libmu_sieve/runtime.c
+++ b/libmu_sieve/runtime.c
@@ -28,18 +28,19 @@
 #define SIEVE_ADJUST(m,n) (m)->pc+=(n)
 
 #define INSTR_DEBUG(m) \
-  ((m)->debug_level & (MU_SIEVE_DEBUG_INSTR|MU_SIEVE_DEBUG_DISAS))
-#define INSTR_DISASS(m) ((m)->debug_level & MU_SIEVE_DEBUG_DISAS)
+  (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9)) 
+#define INSTR_DISASS(m) \
+  (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE8)) 
 
 void
-_mu_sv_instr_nop (mu_sieve_machine_t mach)
+_mu_i_sv_instr_nop (mu_sieve_machine_t mach)
 {
   if (INSTR_DEBUG (mach))
     mu_sieve_debug (mach, "%4lu: NOP", (unsigned long) (mach->pc - 1));
 }
 
 void
-_mu_sv_instr_source (mu_sieve_machine_t mach)
+_mu_i_sv_instr_source (mu_sieve_machine_t mach)
 {
   mach->locus.mu_file = (char*) SIEVE_ARG (mach, 0, string);
   mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
@@ -53,7 +54,7 @@ _mu_sv_instr_source (mu_sieve_machine_t mach)
 }
                 
 void
-_mu_sv_instr_line (mu_sieve_machine_t mach)
+_mu_i_sv_instr_line (mu_sieve_machine_t mach)
 {
   mach->locus.mu_line = SIEVE_ARG (mach, 0, line);
   mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
@@ -80,9 +81,9 @@ instr_run (mu_sieve_machine_t mach)
     {
       mu_stream_printf (mach->errstream,
                        "\033s<%d>Arguments: ", MU_LOG_DEBUG);
-      mu_sv_print_value_list (arg_list, mach->errstream);
+      mu_i_sv_print_value_list (arg_list, mach->errstream);
       mu_stream_printf (mach->errstream, "\n\033s<%d>Tags: ", MU_LOG_DEBUG);
-      mu_sv_print_tag_list (tag_list, mach->errstream);
+      mu_i_sv_print_tag_list (tag_list, mach->errstream);
       mu_stream_printf (mach->errstream, "\n");
     }
 
@@ -92,7 +93,7 @@ instr_run (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_action (mu_sieve_machine_t mach)
+_mu_i_sv_instr_action (mu_sieve_machine_t mach)
 {
   mach->identifier = SIEVE_ARG (mach, 3, string);
   if (INSTR_DEBUG (mach))
@@ -105,7 +106,7 @@ _mu_sv_instr_action (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_test (mu_sieve_machine_t mach)
+_mu_i_sv_instr_test (mu_sieve_machine_t mach)
 {
   mach->identifier = SIEVE_ARG (mach, 3, string);
   if (INSTR_DEBUG (mach))
@@ -117,7 +118,7 @@ _mu_sv_instr_test (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_push (mu_sieve_machine_t mach)
+_mu_i_sv_instr_push (mu_sieve_machine_t mach)
 {
   if (INSTR_DEBUG (mach))
     {
@@ -135,7 +136,7 @@ _mu_sv_instr_push (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_pop (mu_sieve_machine_t mach)
+_mu_i_sv_instr_pop (mu_sieve_machine_t mach)
 {
   if (INSTR_DEBUG (mach))
     {
@@ -153,7 +154,7 @@ _mu_sv_instr_pop (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_not (mu_sieve_machine_t mach)
+_mu_i_sv_instr_not (mu_sieve_machine_t mach)
 {
   if (INSTR_DEBUG (mach))
     {
@@ -165,7 +166,7 @@ _mu_sv_instr_not (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_branch (mu_sieve_machine_t mach)
+_mu_i_sv_instr_branch (mu_sieve_machine_t mach)
 {
   long num = SIEVE_ARG (mach, 0, number);
 
@@ -183,7 +184,7 @@ _mu_sv_instr_branch (mu_sieve_machine_t mach)
 }
 
 void
-_mu_sv_instr_brz (mu_sieve_machine_t mach)
+_mu_i_sv_instr_brz (mu_sieve_machine_t mach)
 {
   long num = SIEVE_ARG (mach, 0, number);
   SIEVE_ADJUST (mach, 1);
@@ -202,7 +203,7 @@ _mu_sv_instr_brz (mu_sieve_machine_t mach)
 }
   
 void
-_mu_sv_instr_brnz (mu_sieve_machine_t mach)
+_mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
 {
   long num = SIEVE_ARG (mach, 0, number);
   SIEVE_ADJUST (mach, 1);
@@ -263,12 +264,6 @@ mu_sieve_get_message_num (mu_sieve_machine_t mach)
   return mach->msgno;
 }
 
-int
-mu_sieve_get_debug_level (mu_sieve_machine_t mach)
-{
-  return mach->debug_level;
-}
-
 const char *
 mu_sieve_get_identifier (mu_sieve_machine_t mach)
 {
@@ -278,7 +273,15 @@ mu_sieve_get_identifier (mu_sieve_machine_t mach)
 int
 mu_sieve_is_dry_run (mu_sieve_machine_t mach)
 {
-  return mach->debug_level & MU_SIEVE_DRY_RUN;
+  return mach->dry_run;
+}
+
+int
+mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val)
+{
+  if (mach->state != mu_sieve_state_compiled)
+    return EINVAL; //FIXME: another error code
+  return mach->dry_run = val;
 }
 
 int
@@ -304,12 +307,15 @@ sieve_run (mu_sieve_machine_t mach)
 int
 mu_sieve_disass (mu_sieve_machine_t mach)
 {
-  int level = mach->debug_level;
+  mu_debug_level_t lev;
   int rc;
-
-  mach->debug_level = MU_SIEVE_DEBUG_INSTR | MU_SIEVE_DEBUG_DISAS;
+  
+  mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
+  mu_debug_set_category_level (mu_sieve_debug_handle,
+                              MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE8)
+                              | MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9));
   rc = sieve_run (mach);
-  mach->debug_level = level;
+  mu_debug_set_category_level (mu_sieve_debug_handle, lev);
   return rc;
 }
   
@@ -339,6 +345,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 +363,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 +377,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;
diff --git a/libmu_sieve/sieve-priv.h b/libmu_sieve/sieve-priv.h
index 894e19d..1ff62d9 100644
--- a/libmu_sieve/sieve-priv.h
+++ b/libmu_sieve/sieve-priv.h
@@ -31,20 +31,38 @@ 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 */
-  struct mu_locus locus;    /* Approximate location in the code */
+  struct mu_locus locus;     /* Approximate location in the code */
 
   mu_list_t memory_pool;     /* Pool of allocated memory objects */
   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,11 +72,12 @@ 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 */
 
-  int debug_level;           /* Debugging level */
+  int dry_run;               /* Dry-run mode */
   jmp_buf errbuf;            /* Target location for non-local exits */
   const char *identifier;    /* Name of action or test being executed */
   
@@ -76,54 +95,88 @@ struct mu_sieve_machine
   char *daemon_email;
   void *data;
 };
+
+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);
 
-extern struct mu_locus mu_sieve_locus;
+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);
+
+void mu_i_sv_compile_error (struct mu_sieve_machine *mach,
+                           const char *fmt, ...) MU_PRINTFLIKE(2,3);
+
+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_i_sv_instr_action (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_test (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_push (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_pop (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_not (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_branch (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_brz (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_brnz (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_nop (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_source (mu_sieve_machine_t mach);
+void _mu_i_sv_instr_line (mu_sieve_machine_t mach);
+
+int mu_i_sv_load_add_dir (mu_sieve_machine_t mach, const char *name);
+
+void mu_i_sv_register_standard_actions (mu_sieve_machine_t mach);
+void mu_i_sv_register_standard_tests (mu_sieve_machine_t mach);
+void mu_i_sv_register_standard_comparators (mu_sieve_machine_t mach);
+
+void mu_i_sv_print_value_list (mu_list_t list, mu_stream_t str);
+void mu_i_sv_print_tag_list (mu_list_t list, mu_stream_t str);
+
+void mu_i_sv_error (mu_sieve_machine_t mach);
 
-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);
-
-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);
-
-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);
-void _mu_sv_instr_pop (mu_sieve_machine_t mach);
-void _mu_sv_instr_not (mu_sieve_machine_t mach);
-void _mu_sv_instr_branch (mu_sieve_machine_t mach);
-void _mu_sv_instr_brz (mu_sieve_machine_t mach);
-void _mu_sv_instr_brnz (mu_sieve_machine_t mach);
-void _mu_sv_instr_nop (mu_sieve_machine_t mach);
-void _mu_sv_instr_source (mu_sieve_machine_t mach);
-void _mu_sv_instr_line (mu_sieve_machine_t mach);
-
-int mu_sv_load_add_dir (mu_sieve_machine_t mach, const char *name);
-  
diff --git a/libmu_sieve/sieve.l b/libmu_sieve/sieve.l
index 7b478ee..1bbb2a0 100644
--- a/libmu_sieve/sieve.l
+++ b/libmu_sieve/sieve.l
@@ -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,
-                           _("cannot stat `%s': %s"), name, strerror (errno));
+      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,
-                             _("`%s' already included here"),
-                             name);
+       {
+         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, 
-                             _("`%s' already included at top level"),
-                            name);
+       {
+         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, 
-                           _("cannot open file `%s': %s"),
-                          name, mu_strerror (rc));
+      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;
@@ -172,14 +237,9 @@ push_source (const char *name)
       SET_BUFFER_STATE (ctx->state);
     }
   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 (); } 
+#[ \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; }
@@ -254,34 +311,28 @@ not     return NOT;
          /* Quoted strings */
 \"[^\\"\n]*\"                 { return string (); }
 \"[^\\"\n]*\\.    { BEGIN(STR);
-                   line_begin ();
-                  line_add (str_unescape (yytext + 1, yyleng - 1), 0); }
+                    line_begin ();
+                   line_add (str_unescape (yytext + 1, yyleng - 1), 0); }
 <STR>[^\\"\n]*\\. { line_add (str_unescape (yytext, yyleng), 0); }
 <STR>[^\\"\n]*\" { BEGIN(INITIAL);
-                   if (yyleng > 1) 
+                  if (yyleng > 1) 
                      line_add (yytext, yyleng - 1); 
                    line_finish ();
                   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);
-                             }
+                              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;
   
@@ -410,20 +461,20 @@ sieve_searchpath ()
   name = get_file_name (p, endp, NULL);
   if (name)
     {
-      mu_sv_load_add_dir (mu_sieve_machine, name);
+      mu_i_sv_load_add_dir (mu_sieve_machine, name);
       free (name);
     }
 }
 
 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,
-                       const char *fname, int line)
+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 ();
 }
diff --git a/libmu_sieve/sieve.y b/libmu_sieve/sieve.y
index ce6fa4d..86fb962 100644
--- a/libmu_sieve/sieve.y
+++ b/libmu_sieve/sieve.y
@@ -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);
+                $$ = node_alloc (mu_sieve_node_cond, &@1);
+                $$->v.cond.expr = $2;
+                $$->v.cond.iftrue = $3;
+                $$->v.cond.iffalse = $4;
               }                 
              ;
 
-if           : IF
-               {
-                $$ = mu_sieve_machine->pc;
-              }
-             ;
-
 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
+elsif_branch : ELSIF cond block
                {
-                $$.begin = $2; 
-                $$.branch = $1;
-                $$.cond = $3;
+                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;
               }
-             | elsif_branch elsif begin cond block
+             | elsif_branch ELSIF 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
-               {
-                mu_sv_code_instr (_mu_sv_instr_branch);
-                $$ = mu_sieve_machine->pc;
-                mu_sv_code_number (0);
-              }
-             ;
-
-else         : ELSE
-               {
-                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;
+                $$ = node_alloc (mu_sieve_node_not, &@1);
+                $$->v.node = $2;
               }
              ;
 
-begin        : /* empty */
-               {
-                $$ = mu_sieve_machine->pc;
-              }
-             ; 
-
 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,
-                                       _("unknown test: %s"),
-                                       $1.ident);
+                  {
+                    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,
-                                       _("test `%s' has not been required"),
-                                       $1.ident);
-                else if (mu_sv_code_test (reg, $1.args))
-                  YYERROR;
+                  {
+                    mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
+                                      _("test `%s' has not been required"),
+                                      $1.ident);
+                    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,
-                                       _("unknown action: %s"),
-                                       $1.ident);
+                  {
+                    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,
-                                       _("action `%s' has not been required"),
-                                       $1.ident);
-                else if (mu_sv_code_action (reg, $1.args))
-                  YYERROR;
+                  {
+                    mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
+                                      _("action `%s' has not been required"),
+                                      $1.ident);
+                    mu_i_sv_error (mu_sieve_machine);
+                  }
+                
+                $$ = node_alloc(mu_sieve_node_action, &@1);
+                $$->v.command.reg = reg;
+                $$->v.command.arg = $1.args;
               }
              ;
 
@@ -287,7 +332,7 @@ arglist      : arg
              ;
 
 arg          : stringlist
-               {
+               {                
                 $$ = mu_sieve_value_create (SVT_STRING_LIST, $1);
               }
              | STRING
@@ -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_i_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_i_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_i_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_i_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_i_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);
@@ -388,7 +1037,7 @@ mu_sieve_machine_inherit (mu_sieve_machine_t const parent,
     return rc;
 
   child->logger = parent->logger;
-  child->debug_level = parent->debug_level;
+  child->dry_run = parent->dry_run;
   *pmach = child;
   return 0;
 }
@@ -417,11 +1066,12 @@ 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;
 
-  mach->debug_level = in->debug_level;
+  mach->dry_run = in->dry_run;
   
   mach->errstream = in->errstream;
   mu_stream_ref (mach->errstream);
@@ -450,12 +1100,6 @@ mu_sieve_set_diag_stream (mu_sieve_machine_t mach, 
mu_stream_t str)
 }
 
 void
-mu_sieve_set_debug_level (mu_sieve_machine_t mach, int level)
-{
-  mach->debug_level = level;
-}
-
-void
 mu_sieve_set_logger (mu_sieve_machine_t mach, mu_sieve_action_log_t logger)
 {
   mach->logger = logger;
@@ -571,97 +1215,146 @@ 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_i_sv_register_standard_actions (mach);
+  mu_i_sv_register_standard_tests (mach);
+  mu_i_sv_register_standard_comparators (mach);
   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);
 }
 
-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);
+
+  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);
 
-  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;
-  
-  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);
 
-  if (mu_sv_lex_begin_string (buf, bufsize, fname, line) == 0)
+  sieve_tree = NULL;
+  yydebug = mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE3);
+
+  rc = yyparse ();
+  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)
     {
-      rc = yyparse ();
-      if (mu_sieve_error_count)
-       rc = 1;
-      mu_sv_lex_finish ();
+      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);
+
+      /* Clear location, so that mu_i_sv_locus will do its job. */
+      mu_sieve_machine->locus.mu_file = NULL;
+      mu_sieve_machine->locus.mu_line = 0;
+      mu_sieve_machine->locus.mu_col = 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);
     }
-  else
-    rc = 1;
   
-  mu_sieve_machine_finish (mach);
+  if (rc == 0)
+    {
+      if (mu_sieve_machine->state == mu_sieve_state_error)
+       rc = MU_ERR_PARSE;
+      else
+       mu_sieve_machine->state = mu_sieve_state_compiled;
+    }
+
+  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)
+{
+  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)
 {
-  _branch_fixup (start, end);
-  mu_sieve_machine->prog[start].pc = end - start - 1;
+  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);
 }
 
 
 
+
diff --git a/libmu_sieve/tests.c b/libmu_sieve/tests.c
index f0f989e..5d3efee 100644
--- a/libmu_sieve/tests.c
+++ b/libmu_sieve/tests.c
@@ -119,8 +119,7 @@ sieve_test_address (mu_sieve_machine_t mach, mu_list_t 
args, mu_list_t tags)
   int rc;
   size_t count;
   
-  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
-    mu_sieve_debug (mach, "ADDRESS");
+  mu_sieve_trace (mach, "ADDRESS");
 
   h = mu_sieve_value_get (args, 0);
   if (!h)
@@ -183,8 +182,7 @@ sieve_test_header (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   size_t count, mcount = 0;
   struct header_closure clos;
   
-  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
-    mu_sieve_debug (mach, "HEADER");
+  mu_sieve_trace (mach, "HEADER");
 
   h = mu_sieve_value_get (args, 0);
   if (!h)
@@ -267,8 +265,7 @@ sieve_test_envelope (mu_sieve_machine_t mach, mu_list_t 
args, mu_list_t tags)
   int rc;
   size_t count;
   
-  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
-    mu_sieve_debug (mach, "ENVELOPE");
+  mu_sieve_trace (mach, "ENVELOPE");
 
   h = mu_sieve_value_get (args, 0);
   if (!h)
@@ -320,22 +317,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;
@@ -350,8 +331,7 @@ sieve_test_exists (mu_sieve_machine_t mach, mu_list_t args, 
mu_list_t tags)
   mu_header_t header = NULL;
   mu_sieve_value_t *val;   
 
-  if (mach->debug_level & MU_SIEVE_DEBUG_TRACE)
-    mu_sieve_debug (mach, "EXISTS");
+  mu_sieve_trace (mach, "EXISTS");
 
   mu_message_get_header (mu_sieve_get_message (mach), &header);
   val = mu_sieve_value_get (args, 0);
@@ -444,10 +424,9 @@ mu_sieve_tag_group_t header_tag_groups[] = {
 };
 
 void
-mu_sv_register_standard_tests (mu_sieve_machine_t mach)
+mu_i_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,
diff --git a/libmu_sieve/util.c b/libmu_sieve/util.c
index fa6c623..d0538b8 100644
--- a/libmu_sieve/util.c
+++ b/libmu_sieve/util.c
@@ -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;
@@ -248,6 +230,27 @@ mu_sieve_debug (mu_sieve_machine_t mach, const char *fmt, 
...)
 }
 
 void
+mu_sieve_trace (mu_sieve_machine_t mach, const char *fmt, ...)
+{
+  va_list ap;
+
+  if (!mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE4))
+    return;
+  
+  va_start (ap, fmt);
+  mu_stream_printf (mach->errstream, "\033s<%d>", MU_LOG_DEBUG);
+  if (mach->locus.mu_file)
+    mu_stream_printf (mach->errstream, "\033O<%d>\033f<%u>%s\033l<%u>",
+                     MU_LOGMODE_LOCUS,
+                     (unsigned) strlen (mach->locus.mu_file),
+                     mach->locus.mu_file,
+                     mach->locus.mu_line);
+  mu_stream_vprintf (mach->errstream, fmt, ap);
+  mu_stream_write (mach->errstream, "\n", 1, NULL);
+  va_end (ap);
+}
+
+void
 mu_sieve_log_action (mu_sieve_machine_t mach, const char *action,
                     const char *fmt, ...)
 {
@@ -357,7 +360,7 @@ sieve_print_value (mu_sieve_value_t *val, mu_stream_t str)
 } 
 
 void
-mu_sv_print_value_list (mu_list_t list, mu_stream_t str)
+mu_i_sv_print_value_list (mu_list_t list, mu_stream_t str)
 {
   mu_sieve_value_t val;
   
@@ -384,7 +387,7 @@ tag_printer (void *item, void *data)
 }
 
 void
-mu_sv_print_tag_list (mu_list_t list, mu_stream_t str)
+mu_i_sv_print_tag_list (mu_list_t list, mu_stream_t str)
 {
   mu_list_foreach (list, tag_printer, str);
 }
diff --git a/sieve/sieve.c b/sieve/sieve.c
index 2b7fb9e..0f7789a 100644
--- a/sieve/sieve.c
+++ b/sieve/sieve.c
@@ -55,43 +55,46 @@ int sieve_debug;
 int verbose;
 char *script;
 int expression_option;
+int dry_run;
 
 static int sieve_print_locus = 1; /* Should the log messages include the
                                     locus */
 
 static void
-set_debug_level (const char *arg)
+modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr)
 {
   mu_debug_level_t lev;
   
+  mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
+  mu_debug_set_category_level (mu_sieve_debug_handle, (lev & ~clr) | set);
+}
+
+static void
+set_debug_level (const char *arg)
+{
   for (; *arg; arg++)
     {
       switch (*arg)
        {
        case 'T':
-         mu_debug_get_category_level (mu_sieve_debug_handle, &lev);
-         mu_debug_set_category_level (mu_sieve_debug_handle, 
-                                      lev |
-                                   (MU_DEBUG_LEVEL_UPTO(MU_DEBUG_TRACE9) &
-                                    ~MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR)));
+         modify_debug_flags (MU_DEBUG_LEVEL_UPTO(MU_DEBUG_TRACE9),
+                             MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR));
          break;
 
        case 'P':
-         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_PROT));
+         modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_PROT), 0);
          break;
 
        case 'g':
-         mu_sieve_yydebug = 1;
+         modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE1), 0);
          break;
 
        case 't':
-         sieve_debug |= MU_SIEVE_DEBUG_TRACE;
+         modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE4), 0);
          break;
          
        case 'i':
-         sieve_debug |= MU_SIEVE_DEBUG_INSTR;
+         modify_debug_flags (MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9), 0);
          break;
          
        default:
@@ -101,13 +104,6 @@ set_debug_level (const char *arg)
 }
 
 static void
-cli_dry_run (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
-{
-  sieve_debug |= MU_SIEVE_DRY_RUN;
-  verbose = 1;
-}
-
-static void
 cli_compile_and_dump (struct mu_parseopt *po, struct mu_option *opt,
                      char const *arg)
 {
@@ -136,10 +132,10 @@ cli_no_program_name (struct mu_parseopt *po, struct 
mu_option *opt,
 }
 
 static struct mu_option sieve_options[] = {
-  { "no-actions", 'n', NULL, MU_OPTION_DEFAULT,
+  { "dry-run", 'n', NULL, MU_OPTION_DEFAULT,
     N_("do not execute any actions, just print what would be done"),
-    mu_c_string, NULL, cli_dry_run },
-  { "dry-run", 0, NULL, MU_OPTION_ALIAS },
+    mu_c_bool, &dry_run },
+  { "no-actions", 0, NULL, MU_OPTION_ALIAS },
   { "keep-going", 'k', NULL, MU_OPTION_DEFAULT,
     N_("keep on going if execution fails on a message"),
     mu_c_bool, &keep_going },
@@ -157,7 +153,7 @@ static struct mu_option sieve_options[] = {
     mu_c_string, &mu_ticket_file },
   { "debug", 'd', N_("FLAGS"), MU_OPTION_ARG_OPTIONAL,
     N_("debug flags (defaults to \"" D_DEFAULT "\")"),
-    mu_c_string, NULL, cli_debug },
+    mu_c_string, NULL, cli_debug, D_DEFAULT },
   { "verbose", 'v', NULL, MU_OPTION_DEFAULT,
     N_("log all actions"), 
     mu_c_bool, &verbose },
@@ -332,7 +328,7 @@ sieve_mailbox (mu_sieve_machine_t mach)
     }
 
   /* Open the mailbox read-only if we aren't going to modify it. */
-  if (sieve_debug & MU_SIEVE_DRY_RUN)
+  if (mu_sieve_is_dry_run (mach))
     rc = mu_mailbox_open (mbox, MU_STREAM_READ);
   else
     rc = mu_mailbox_open (mbox, MU_STREAM_RDWR);
@@ -358,7 +354,7 @@ sieve_mailbox (mu_sieve_machine_t mach)
   rc = mu_sieve_mailbox (mach, mbox);
   
  cleanup:
-  if (mbox && !(sieve_debug & MU_SIEVE_DRY_RUN))
+  if (mbox && !dry_run)
     {
       int e;
       
@@ -403,7 +399,9 @@ main (int argc, char *argv[])
   mu_register_all_formats ();
 
   mu_cli (argc, argv, &cli, sieve_capa, NULL, &argc, &argv);
-
+  if (dry_run)
+    verbose++;
+  
   if (argc == 0)
     {
       mu_error (_("script must be specified"));
@@ -446,7 +444,7 @@ main (int argc, char *argv[])
       return EX_OK;
     }
 
-  mu_sieve_set_debug_level (mach, sieve_debug);
+  mu_sieve_set_dry_run (mach, dry_run);
 
   if (mbox_url && strcmp (mbox_url, "-") == 0)
     rc = sieve_message (mach);
diff --git a/sieve/tests/ext.at b/sieve/tests/ext.at
index 633b30e..4bfec67 100644
--- a/sieve/tests/ext.at
+++ b/sieve/tests/ext.at
@@ -32,7 +32,7 @@ if numaddr [[ "to", "cc" ]] :over 5
 MUT_MBCOPY($abs_top_srcdir/testsuite/spool/bigto.mbox)
 
 sieve MUT_SIEVE_CMDLINE dnl
- --clearpath -L "${abs_top_builddir}/examples" -f ./bigto.mbox prog
+ --clearpath --libdir-prefix= "${abs_top_builddir}/examples" -f ./bigto.mbox 
prog
 ],
 [0],
 [],
diff --git a/sieve/tests/i-numeric.at b/sieve/tests/i-numeric.at
index fe30de8..c6e494f 100644
--- a/sieve/tests/i-numeric.at
+++ b/sieve/tests/i-numeric.at
@@ -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
 


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]