Patch 7.3.1153
Problem:    New regexp engine: Some look-behind matches are very expensive.
Solution:   Pospone invisible matches further, until a match is almost found.
Files:      src/regexp_nfa.c


*** ../vim-7.3.1152/src/regexp_nfa.c    2013-06-08 23:30:00.000000000 +0200
--- src/regexp_nfa.c    2013-06-09 16:11:41.000000000 +0200
***************
*** 3354,3369 ****
  typedef struct nfa_pim_S nfa_pim_T;
  struct nfa_pim_S
  {
!     nfa_state_T       *state;
!     int               result;         /* NFA_PIM_TODO, NFA_PIM_[NO]MATCH */
!     nfa_pim_T *pim;           /* another PIM at the same position */
      regsubs_T subs;           /* submatch info, only party used */
  };
  
  /* Values for done in nfa_pim_T. */
! #define NFA_PIM_TODO    0
! #define NFA_PIM_MATCH   1
! #define NFA_PIM_NOMATCH -1
  
  
  /* nfa_thread_T contains execution information of a NFA state */
--- 3354,3374 ----
  typedef struct nfa_pim_S nfa_pim_T;
  struct nfa_pim_S
  {
!     int               result;         /* NFA_PIM_*, see below */
!     nfa_state_T       *state;         /* the invisible match start state */
      regsubs_T subs;           /* submatch info, only party used */
+     union
+     {
+       lpos_T  pos;
+       char_u  *ptr;
+     } end;                    /* where the match must end */
  };
  
  /* Values for done in nfa_pim_T. */
! #define NFA_PIM_UNUSED   0    /* pim not used */
! #define NFA_PIM_TODO     1    /* pim not done yet */
! #define NFA_PIM_MATCH    2    /* pim executed, matches */
! #define NFA_PIM_NOMATCH  3    /* pim executed, no match */
  
  
  /* nfa_thread_T contains execution information of a NFA state */
***************
*** 3371,3377 ****
  {
      nfa_state_T       *state;
      int               count;
!     nfa_pim_T *pim;           /* if not NULL: postponed invisible match */
      regsubs_T subs;           /* submatch info, only party used */
  } nfa_thread_T;
  
--- 3376,3383 ----
  {
      nfa_state_T       *state;
      int               count;
!     nfa_pim_T pim;            /* if pim.result != NFA_PIM_UNUSED: postponed
!                                * invisible match */
      regsubs_T subs;           /* submatch info, only party used */
  } nfa_thread_T;
  
***************
*** 3424,3434 ****
--- 3430,3457 ----
                    e == NULL ? "NULL" : e);
        }
  }
+ 
+     static char *
+ pim_info(nfa_pim_T *pim)
+ {
+     static char buf[30];
+ 
+     if (pim == NULL || pim->result == NFA_PIM_UNUSED)
+       buf[0] = NUL;
+     else
+     {
+       sprintf(buf, " PIM col %d", REG_MULTI ? (int)pim->end.pos.col
+               : (int)(pim->end.ptr - reginput));
+     }
+     return buf;
+ }
+ 
  #endif
  
  /* Used during execution: whether a match has been found. */
  static int nfa_match;
  
+ static void copy_pim __ARGS((nfa_pim_T *to, nfa_pim_T *from));
  static void clear_sub __ARGS((regsub_T *sub));
  static void copy_sub __ARGS((regsub_T *to, regsub_T *from));
  static void copy_sub_off __ARGS((regsub_T *to, regsub_T *from));
***************
*** 3436,3444 ****
  static int has_state_with_pos __ARGS((nfa_list_T *l, nfa_state_T *state, 
regsubs_T *subs));
  static int match_follows __ARGS((nfa_state_T *startstate, int depth));
  static int state_in_list __ARGS((nfa_list_T *l, nfa_state_T *state, regsubs_T 
*subs));
! static void addstate __ARGS((nfa_list_T *l, nfa_state_T *state, regsubs_T 
*subs, int off));
  static void addstate_here __ARGS((nfa_list_T *l, nfa_state_T *state, 
regsubs_T *subs, nfa_pim_T *pim, int *ip));
  
      static void
  clear_sub(sub)
      regsub_T *sub;
--- 3459,3485 ----
  static int has_state_with_pos __ARGS((nfa_list_T *l, nfa_state_T *state, 
regsubs_T *subs));
  static int match_follows __ARGS((nfa_state_T *startstate, int depth));
  static int state_in_list __ARGS((nfa_list_T *l, nfa_state_T *state, regsubs_T 
*subs));
! static void addstate __ARGS((nfa_list_T *l, nfa_state_T *state, regsubs_T 
*subs, nfa_pim_T *pim, int off));
  static void addstate_here __ARGS((nfa_list_T *l, nfa_state_T *state, 
regsubs_T *subs, nfa_pim_T *pim, int *ip));
  
+ /*
+  * Copy postponed invisible match info from "from" to "to".
+  */
+     static void
+ copy_pim(to, from)
+     nfa_pim_T *to;
+     nfa_pim_T *from;
+ {
+     to->result = from->result;
+     to->state = from->state;
+     copy_sub(&to->subs.norm, &from->subs.norm);
+ #ifdef FEAT_SYN_HL
+     if (nfa_has_zsubexpr)
+       copy_sub(&to->subs.synt, &from->subs.synt);
+ #endif
+     to->end = from->end;
+ }
+ 
      static void
  clear_sub(sub)
      regsub_T *sub;
***************
*** 3583,3589 ****
  
  #ifdef ENABLE_LOG
      static void
! report_state(char *action, regsub_T *sub, nfa_state_T *state, int lid)
  {
      int col;
  
--- 3624,3634 ----
  
  #ifdef ENABLE_LOG
      static void
! report_state(char *action,
!            regsub_T *sub,
!            nfa_state_T *state,
!            int lid,
!            nfa_pim_T *pim)
  {
      int col;
  
***************
*** 3594,3601 ****
      else
        col = (int)(sub->list.line[0].start - regline);
      nfa_set_code(state->c);
!     fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col %d)\n",
!           action, abs(state->id), lid, state->c, code, col);
  }
  #endif
  
--- 3639,3647 ----
      else
        col = (int)(sub->list.line[0].start - regline);
      nfa_set_code(state->c);
!     fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col 
%d)%s\n",
!           action, abs(state->id), lid, state->c, code, col,
!           pim_info(pim));
  }
  #endif
  
***************
*** 3646,3651 ****
--- 3692,3701 ----
        switch (state->c)
        {
            case NFA_MATCH:
+           case NFA_MCLOSE:
+           case NFA_END_INVISIBLE:
+           case NFA_END_INVISIBLE_NEG:
+           case NFA_END_PATTERN:
                return TRUE;
  
            case NFA_SPLIT:
***************
*** 3727,3736 ****
  }
  
      static void
! addstate(l, state, subs, off)
      nfa_list_T                *l;     /* runtime state list */
      nfa_state_T               *state; /* state to update */
      regsubs_T         *subs;  /* pointers to subexpressions */
      int                       off;    /* byte offset, when -1 go to next line 
*/
  {
      int                       subidx;
--- 3777,3787 ----
  }
  
      static void
! addstate(l, state, subs, pim, off)
      nfa_list_T                *l;     /* runtime state list */
      nfa_state_T               *state; /* state to update */
      regsubs_T         *subs;  /* pointers to subexpressions */
+     nfa_pim_T         *pim;   /* postponed look-behind match */
      int                       off;    /* byte offset, when -1 go to next line 
*/
  {
      int                       subidx;
***************
*** 3856,3876 ****
            state->lastlist[nfa_ll_index] = l->id;
            thread = &l->t[l->n++];
            thread->state = state;
!           thread->pim = NULL;
            copy_sub(&thread->subs.norm, &subs->norm);
  #ifdef FEAT_SYN_HL
            if (nfa_has_zsubexpr)
                copy_sub(&thread->subs.synt, &subs->synt);
  #endif
  #ifdef ENABLE_LOG
!           report_state("Adding", &thread->subs.norm, state, l->id);
            did_print = TRUE;
  #endif
      }
  
  #ifdef ENABLE_LOG
      if (!did_print)
!       report_state("Processing", &subs->norm, state, l->id);
  #endif
      switch (state->c)
      {
--- 3907,3930 ----
            state->lastlist[nfa_ll_index] = l->id;
            thread = &l->t[l->n++];
            thread->state = state;
!           if (pim == NULL)
!               thread->pim.result = NFA_PIM_UNUSED;
!           else
!               copy_pim(&thread->pim, pim);
            copy_sub(&thread->subs.norm, &subs->norm);
  #ifdef FEAT_SYN_HL
            if (nfa_has_zsubexpr)
                copy_sub(&thread->subs.synt, &subs->synt);
  #endif
  #ifdef ENABLE_LOG
!           report_state("Adding", &thread->subs.norm, state, l->id, pim);
            did_print = TRUE;
  #endif
      }
  
  #ifdef ENABLE_LOG
      if (!did_print)
!       report_state("Processing", &subs->norm, state, l->id, pim);
  #endif
      switch (state->c)
      {
***************
*** 3880,3893 ****
  
        case NFA_SPLIT:
            /* order matters here */
!           addstate(l, state->out, subs, off);
!           addstate(l, state->out1, subs, off);
            break;
  
        case NFA_SKIP_CHAR:
        case NFA_NOPEN:
        case NFA_NCLOSE:
!           addstate(l, state->out, subs, off);
            break;
  
        case NFA_MOPEN:
--- 3934,3947 ----
  
        case NFA_SPLIT:
            /* order matters here */
!           addstate(l, state->out, subs, pim, off);
!           addstate(l, state->out1, subs, pim, off);
            break;
  
        case NFA_SKIP_CHAR:
        case NFA_NOPEN:
        case NFA_NCLOSE:
!           addstate(l, state->out, subs, pim, off);
            break;
  
        case NFA_MOPEN:
***************
*** 3983,3989 ****
                sub->list.line[subidx].start = reginput + off;
            }
  
!           addstate(l, state->out, subs, off);
  
            if (save_in_use == -1)
            {
--- 4037,4043 ----
                sub->list.line[subidx].start = reginput + off;
            }
  
!           addstate(l, state->out, subs, pim, off);
  
            if (save_in_use == -1)
            {
***************
*** 4001,4007 ****
            {
                /* Do not overwrite the position set by \ze. If no \ze
                 * encountered end will be set in nfa_regtry(). */
!               addstate(l, state->out, subs, off);
                break;
            }
        case NFA_MCLOSE1:
--- 4055,4061 ----
            {
                /* Do not overwrite the position set by \ze. If no \ze
                 * encountered end will be set in nfa_regtry(). */
!               addstate(l, state->out, subs, pim, off);
                break;
            }
        case NFA_MCLOSE1:
***************
*** 4070,4076 ****
                sub->list.line[subidx].end = reginput + off;
            }
  
!           addstate(l, state->out, subs, off);
  
            if (REG_MULTI)
                sub->list.multi[subidx].end = save_lpos;
--- 4124,4130 ----
                sub->list.line[subidx].end = reginput + off;
            }
  
!           addstate(l, state->out, subs, pim, off);
  
            if (REG_MULTI)
                sub->list.multi[subidx].end = save_lpos;
***************
*** 4098,4112 ****
      int tlen = l->n;
      int count;
      int listidx = *ip;
-     int i;
  
      /* first add the state(s) at the end, so that we know how many there are 
*/
!     addstate(l, state, subs, 0);
! 
!     /* fill in the "pim" field in the new states */
!     if (pim != NULL)
!       for (i = tlen; i < l->n; ++i)
!           l->t[i].pim = pim;
  
      /* when "*ip" was at the end of the list, nothing to do */
      if (listidx + 1 == tlen)
--- 4152,4160 ----
      int tlen = l->n;
      int count;
      int listidx = *ip;
  
      /* first add the state(s) at the end, so that we know how many there are 
*/
!     addstate(l, state, subs, pim, 0);
  
      /* when "*ip" was at the end of the list, nothing to do */
      if (listidx + 1 == tlen)
***************
*** 4355,4369 ****
      return val == pos;
  }
  
! static int recursive_regmatch __ARGS((nfa_state_T *state, nfa_regprog_T 
*prog, regsubs_T *submatch, regsubs_T *m, int **listids));
  static int nfa_regmatch __ARGS((nfa_regprog_T *prog, nfa_state_T *start, 
regsubs_T *submatch, regsubs_T *m));
  
  /*
   * Recursively call nfa_regmatch()
   */
      static int
! recursive_regmatch(state, prog, submatch, m, listids)
      nfa_state_T           *state;
      nfa_regprog_T   *prog;
      regsubs_T     *submatch;
      regsubs_T     *m;
--- 4403,4420 ----
      return val == pos;
  }
  
! static int recursive_regmatch __ARGS((nfa_state_T *state, nfa_pim_T *pim, 
nfa_regprog_T *prog, regsubs_T *submatch, regsubs_T *m, int **listids));
  static int nfa_regmatch __ARGS((nfa_regprog_T *prog, nfa_state_T *start, 
regsubs_T *submatch, regsubs_T *m));
  
  /*
   * Recursively call nfa_regmatch()
+  * "pim" is NULL or contains info about a Postponed Invisible Match (start
+  * position).
   */
      static int
! recursive_regmatch(state, pim, prog, submatch, m, listids)
      nfa_state_T           *state;
+     nfa_pim_T     *pim;
      nfa_regprog_T   *prog;
      regsubs_T     *submatch;
      regsubs_T     *m;
***************
*** 4380,4397 ****
      int               result;
      int               need_restore = FALSE;
  
      if (state->c == NFA_START_INVISIBLE_BEFORE
          || state->c == NFA_START_INVISIBLE_BEFORE_NEG)
      {
!       /* The recursive match must end at the current position. */
        endposp = &endpos;
        if (REG_MULTI)
        {
!           endpos.se_u.pos.col = (int)(reginput - regline);
!           endpos.se_u.pos.lnum = reglnum;
        }
        else
!           endpos.se_u.ptr = reginput;
  
        /* Go back the specified number of bytes, or as far as the
         * start of the previous line, to try matching "\@<=" or
--- 4431,4468 ----
      int               result;
      int               need_restore = FALSE;
  
+     if (pim != NULL)
+     {
+       /* start at the position where the postponed match was */
+       if (REG_MULTI)
+           reginput = regline + pim->end.pos.col;
+       else
+           reginput = pim->end.ptr;
+     }
+ 
      if (state->c == NFA_START_INVISIBLE_BEFORE
          || state->c == NFA_START_INVISIBLE_BEFORE_NEG)
      {
!       /* The recursive match must end at the current position. When "pim" is
!        * not NULL it specifies the current position. */
        endposp = &endpos;
        if (REG_MULTI)
        {
!           if (pim == NULL)
!           {
!               endpos.se_u.pos.col = (int)(reginput - regline);
!               endpos.se_u.pos.lnum = reglnum;
!           }
!           else
!               endpos.se_u.pos = pim->end.pos;
        }
        else
!       {
!           if (pim == NULL)
!               endpos.se_u.ptr = reginput;
!           else
!               endpos.se_u.ptr = pim->end.ptr;
!       }
  
        /* Go back the specified number of bytes, or as far as the
         * start of the previous line, to try matching "\@<=" or
***************
*** 4784,4790 ****
      int               add_here;
      int               add_count;
      int               add_off;
-     garray_T  pimlist;
      int               toplevel = start->c == NFA_MOPEN;
  #ifdef NFA_REGEXP_DEBUG_LOG
      FILE      *debug = fopen(NFA_REGEXP_DEBUG_LOG, "a");
--- 4855,4860 ----
***************
*** 4796,4802 ****
      }
  #endif
      nfa_match = FALSE;
-     ga_init2(&pimlist, sizeof(nfa_pim_T), 5);
  
      /* Allocate memory for the lists of nodes. */
      size = (nstate + 1) * sizeof(nfa_thread_T);
--- 4866,4871 ----
***************
*** 4845,4854 ****
        else
            m->norm.list.line[0].start = reginput;
        m->norm.in_use = 1;
!       addstate(thislist, start->out, m, 0);
      }
      else
!       addstate(thislist, start, m, 0);
  
  #define       ADD_STATE_IF_MATCH(state)                       \
      if (result) {                                     \
--- 4914,4923 ----
        else
            m->norm.list.line[0].start = reginput;
        m->norm.in_use = 1;
!       addstate(thislist, start->out, m, NULL, 0);
      }
      else
!       addstate(thislist, start, m, NULL, 0);
  
  #define       ADD_STATE_IF_MATCH(state)                       \
      if (result) {                                     \
***************
*** 4890,4897 ****
        thislist->id = nfa_listid;
        nextlist->id = nfa_listid + 1;
  
-       pimlist.ga_len = 0;
- 
  #ifdef ENABLE_LOG
        fprintf(log_fd, "------------------------------------------\n");
        fprintf(log_fd, ">>> Reginput is \"%s\"\n", reginput);
--- 4959,4964 ----
***************
*** 4935,4942 ****
                else
                    col = (int)(t->subs.norm.list.line[0].start - regline);
                nfa_set_code(t->state->c);
!               fprintf(log_fd, "(%d) char %d %s (start col %d) ... \n",
!                       abs(t->state->id), (int)t->state->c, code, col);
            }
  #endif
  
--- 5002,5010 ----
                else
                    col = (int)(t->subs.norm.list.line[0].start - regline);
                nfa_set_code(t->state->c);
!               fprintf(log_fd, "(%d) char %d %s (start col %d)%s ... \n",
!                       abs(t->state->id), (int)t->state->c, code, col,
!                       pim_info(&t->pim));
            }
  #endif
  
***************
*** 5028,5048 ****
            case NFA_START_INVISIBLE_BEFORE:
            case NFA_START_INVISIBLE_BEFORE_NEG:
                {
-                   nfa_pim_T *pim;
                    int cout = t->state->out1->out->c;
  
                    /* Do it directly when what follows is possibly end of
                     * match (closing paren).
                     * Postpone when it is \@<= or \@<!, these are expensive.
-                    * TODO: remove the check for t->pim and check multiple
-                    * where it's used?
                     * Otherwise first do the one that has the highest chance
                     * of failing. */
                    if ((cout >= NFA_MCLOSE && cout <= NFA_MCLOSE9)
  #ifdef FEAT_SYN_HL
                            || (cout >= NFA_ZCLOSE && cout <= NFA_ZCLOSE9)
  #endif
!                           || t->pim != NULL
                            || (t->state->c != NFA_START_INVISIBLE_BEFORE
                                && t->state->c != NFA_START_INVISIBLE_BEFORE_NEG
                                && failure_chance(t->state->out1->out, 0)
--- 5096,5114 ----
            case NFA_START_INVISIBLE_BEFORE:
            case NFA_START_INVISIBLE_BEFORE_NEG:
                {
                    int cout = t->state->out1->out->c;
  
                    /* Do it directly when what follows is possibly end of
                     * match (closing paren).
+                    * Do it directly if there already is a PIM.
                     * Postpone when it is \@<= or \@<!, these are expensive.
                     * Otherwise first do the one that has the highest chance
                     * of failing. */
                    if ((cout >= NFA_MCLOSE && cout <= NFA_MCLOSE9)
  #ifdef FEAT_SYN_HL
                            || (cout >= NFA_ZCLOSE && cout <= NFA_ZCLOSE9)
  #endif
!                           || t->pim.result != NFA_PIM_UNUSED
                            || (t->state->c != NFA_START_INVISIBLE_BEFORE
                                && t->state->c != NFA_START_INVISIBLE_BEFORE_NEG
                                && failure_chance(t->state->out1->out, 0)
***************
*** 5052,5058 ****
                         * First try matching the invisible match, then what
                         * follows.
                         */
!                       result = recursive_regmatch(t->state, prog,
                                                       submatch, m, &listids);
  
                        /* for \@! and \@<! it is a match when the result is
--- 5118,5124 ----
                         * First try matching the invisible match, then what
                         * follows.
                         */
!                       result = recursive_regmatch(t->state, NULL, prog,
                                                       submatch, m, &listids);
  
                        /* for \@! and \@<! it is a match when the result is
***************
*** 5077,5102 ****
                    }
                    else
                    {
                        /*
!                        * First try matching what follows at the current
!                        * position.  Only if a match is found, before
!                        * addstate() is called, then verify the invisible
!                        * match matches.  Add a nfa_pim_T to the following
!                        * states, it contains info about the invisible match.
                         */
!                       if (ga_grow(&pimlist, 1) == FAIL)
!                           goto theend;
!                       pim = (nfa_pim_T *)pimlist.ga_data + pimlist.ga_len;
!                       ++pimlist.ga_len;
!                       pim->state = t->state;
!                       pim->pim = NULL;
!                       pim->result = NFA_PIM_TODO;
  
                        /* t->state->out1 is the corresponding END_INVISIBLE
                         * node; Add its out to the current list (zero-width
                         * match). */
                        addstate_here(thislist, t->state->out1->out, &t->subs,
!                                                              pim, &listidx);
                    }
                }
                break;
--- 5143,5175 ----
                    }
                    else
                    {
+                       nfa_pim_T pim;
+ 
                        /*
!                        * First try matching what follows.  Only if a match
!                        * is found verify the invisible match matches.  Add a
!                        * nfa_pim_T to the following states, it contains info
!                        * about the invisible match.
                         */
!                       pim.state = t->state;
!                       pim.result = NFA_PIM_TODO;
!                       pim.subs.norm.in_use = 0;
! #ifdef FEAT_SYN_HL
!                       pim.subs.synt.in_use = 0;
! #endif
!                       if (REG_MULTI)
!                       {
!                           pim.end.pos.col = (int)(reginput - regline);
!                           pim.end.pos.lnum = reglnum;
!                       }
!                       else
!                           pim.end.ptr = reginput;
  
                        /* t->state->out1 is the corresponding END_INVISIBLE
                         * node; Add its out to the current list (zero-width
                         * match). */
                        addstate_here(thislist, t->state->out1->out, &t->subs,
!                                                              &pim, &listidx);
                    }
                }
                break;
***************
*** 5144,5150 ****
                }
  
                /* First try matching the pattern. */
!               result = recursive_regmatch(t->state, prog,
                                                       submatch, m, &listids);
                if (result)
                {
--- 5217,5223 ----
                }
  
                /* First try matching the pattern. */
!               result = recursive_regmatch(t->state, NULL, prog,
                                                       submatch, m, &listids);
                if (result)
                {
***************
*** 5798,5809 ****
  
            if (add_state != NULL)
            {
!               /* Handle the postponed invisible match before advancing to
!                * the next character and for a zero-width match if the match
!                * might end without advancing. */
!               if (t->pim != NULL && (!add_here || match_follows(add_state, 
0)))
                {
!                   if (t->pim->result == NFA_PIM_TODO)
                    {
  #ifdef ENABLE_LOG
                        fprintf(log_fd, "\n");
--- 5871,5888 ----
  
            if (add_state != NULL)
            {
!               nfa_pim_T *pim;
! 
!               if (t->pim.result == NFA_PIM_UNUSED)
!                   pim = NULL;
!               else
!                   pim = &t->pim;
! 
!               /* Handle the postponed invisible match if the match might end
!                * without advancing and before the end of the line. */
!               if (pim != NULL && (clen == 0 || match_follows(add_state, 0)))
                {
!                   if (pim->result == NFA_PIM_TODO)
                    {
  #ifdef ENABLE_LOG
                        fprintf(log_fd, "\n");
***************
*** 5811,5868 ****
                        fprintf(log_fd, "Postponed recursive nfa_regmatch()\n");
                        fprintf(log_fd, "\n");
  #endif
!                       result = recursive_regmatch(t->pim->state,
                                                 prog, submatch, m, &listids);
!                       t->pim->result = result ? NFA_PIM_MATCH
!                                                           : NFA_PIM_NOMATCH;
                        /* for \@! and \@<! it is a match when the result is
                         * FALSE */
!                       if (result != (t->pim->state->c
!                                                   == NFA_START_INVISIBLE_NEG
!                                   || t->pim->state->c
                                           == NFA_START_INVISIBLE_BEFORE_NEG))
                        {
                            /* Copy submatch info from the recursive call */
!                           copy_sub_off(&t->pim->subs.norm, &m->norm);
  #ifdef FEAT_SYN_HL
                            if (nfa_has_zsubexpr)
!                               copy_sub_off(&t->pim->subs.synt, &m->synt);
  #endif
                        }
                    }
                    else
                    {
!                       result = (t->pim->result == NFA_PIM_MATCH);
  #ifdef ENABLE_LOG
                        fprintf(log_fd, "\n");
!                       fprintf(log_fd, "Using previous recursive 
nfa_regmatch() result, result == %d\n", t->pim->result);
                        fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : 
"FALSE");
                        fprintf(log_fd, "\n");
  #endif
                    }
  
                    /* for \@! and \@<! it is a match when result is FALSE */
!                   if (result != (t->pim->state->c == NFA_START_INVISIBLE_NEG
!                               || t->pim->state->c
                                           == NFA_START_INVISIBLE_BEFORE_NEG))
                    {
                        /* Copy submatch info from the recursive call */
!                       copy_sub_off(&t->subs.norm, &t->pim->subs.norm);
  #ifdef FEAT_SYN_HL
                        if (nfa_has_zsubexpr)
!                           copy_sub_off(&t->subs.synt, &t->pim->subs.synt);
  #endif
                    }
                    else
                        /* look-behind match failed, don't add the state */
                        continue;
                }
  
                if (add_here)
!                   addstate_here(thislist, add_state, &t->subs, t->pim, 
&listidx);
                else
                {
!                   addstate(nextlist, add_state, &t->subs, add_off);
                    if (add_count > 0)
                        nextlist->t[nextlist->n - 1].count = add_count;
                }
--- 5890,5949 ----
                        fprintf(log_fd, "Postponed recursive nfa_regmatch()\n");
                        fprintf(log_fd, "\n");
  #endif
!                       result = recursive_regmatch(pim->state, pim,
                                                 prog, submatch, m, &listids);
!                       pim->result = result ? NFA_PIM_MATCH : NFA_PIM_NOMATCH;
                        /* for \@! and \@<! it is a match when the result is
                         * FALSE */
!                       if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
!                                   || pim->state->c
                                           == NFA_START_INVISIBLE_BEFORE_NEG))
                        {
                            /* Copy submatch info from the recursive call */
!                           copy_sub_off(&pim->subs.norm, &m->norm);
  #ifdef FEAT_SYN_HL
                            if (nfa_has_zsubexpr)
!                               copy_sub_off(&pim->subs.synt, &m->synt);
  #endif
                        }
                    }
                    else
                    {
!                       result = (pim->result == NFA_PIM_MATCH);
  #ifdef ENABLE_LOG
                        fprintf(log_fd, "\n");
!                       fprintf(log_fd, "Using previous recursive 
nfa_regmatch() result, result == %d\n", pim->result);
                        fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : 
"FALSE");
                        fprintf(log_fd, "\n");
  #endif
                    }
  
                    /* for \@! and \@<! it is a match when result is FALSE */
!                   if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
!                               || pim->state->c
                                           == NFA_START_INVISIBLE_BEFORE_NEG))
                    {
                        /* Copy submatch info from the recursive call */
!                       copy_sub_off(&t->subs.norm, &pim->subs.norm);
  #ifdef FEAT_SYN_HL
                        if (nfa_has_zsubexpr)
!                           copy_sub_off(&t->subs.synt, &pim->subs.synt);
  #endif
                    }
                    else
                        /* look-behind match failed, don't add the state */
                        continue;
+ 
+                   /* Postponed invisible match was handled, don't add it to
+                    * following states. */
+                   pim = NULL;
                }
  
                if (add_here)
!                   addstate_here(thislist, add_state, &t->subs, pim, &listidx);
                else
                {
!                   addstate(nextlist, add_state, &t->subs, pim, add_off);
                    if (add_count > 0)
                        nextlist->t[nextlist->n - 1].count = add_count;
                }
***************
*** 5941,5951 ****
                                         (colnr_T)(reginput - regline) + clen;
                    else
                        m->norm.list.line[0].start = reginput + clen;
!                   addstate(nextlist, start->out, m, clen);
                }
            }
            else
!               addstate(nextlist, start, m, clen);
        }
  
  #ifdef ENABLE_LOG
--- 6022,6032 ----
                                         (colnr_T)(reginput - regline) + clen;
                    else
                        m->norm.list.line[0].start = reginput + clen;
!                   addstate(nextlist, start->out, m, NULL, clen);
                }
            }
            else
!               addstate(nextlist, start, m, NULL, clen);
        }
  
  #ifdef ENABLE_LOG
***************
*** 5982,5988 ****
      vim_free(list[0].t);
      vim_free(list[1].t);
      vim_free(listids);
-     ga_clear(&pimlist);
  #undef ADD_STATE_IF_MATCH
  #ifdef NFA_REGEXP_DEBUG_LOG
      fclose(debug);
--- 6063,6068 ----
*** ../vim-7.3.1152/src/version.c       2013-06-08 23:30:00.000000000 +0200
--- src/version.c       2013-06-09 15:21:03.000000000 +0200
***************
*** 730,731 ****
--- 730,733 ----
  {   /* Add new patch number below this line */
+ /**/
+     1153,
  /**/

-- 
"Computers in the future may weigh no more than 1.5 tons."
                                   Popular Mechanics, 1949

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Raspunde prin e-mail lui