/* ** Join the ktables from p1 and p2 the ktable for the new pattern at the ** top of the stack, reusing them when possible. */ static void joinktables (lua_State *L, int p1, TTree *t2, int p2) { int n1, n2; lua_getfenv(L, p1); /* get ktables */ lua_getfenv(L, p2); n1 = ktablelen(L, -2); n2 = ktablelen(L, -1); if (n1 == 0 && n2 == 0) /* are both tables empty? */ lua_pop(L, 2); /* nothing to be done; pop tables */ else if (n2 == 0 || lua_equal(L, -2, -1)) { /* 2nd table empty or equal? */ lua_pop(L, 1); /* pop 2nd table */ lua_setfenv(L, -2); /* set 1st ktable into new pattern */ } else if (n1 == 0) { /* first table is empty? */ lua_setfenv(L, -3); /* set 2nd table into new pattern */ lua_pop(L, 1); /* pop 1st table */ } else { lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */ /* stack: new p; ktable p1; ktable p2; new ktable */ concattable(L, -3, -1); /* from p1 into new ktable */ concattable(L, -2, -1); /* from p2 into new ktable */ lua_setfenv(L, -4); /* new ktable becomes 'p' environment */ lua_pop(L, 2); /* pop other ktables */ correctkeys(t2, n1); /* correction for indices from p2 */ } }
/* ** When joining 'ktables', constants from one of the subpatterns must ** be renumbered; 'correctkeys' corrects their indices (adding 'n' ** to each of them) */ static void correctkeys (TTree *tree, int n) { if (n == 0) return; /* no correction? */ tailcall: switch (tree->tag) { case TOpenCall: case TCall: case TRunTime: case TRule: { if (tree->key > 0) tree->key += n; break; } case TCapture: { if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum) tree->key += n; break; } default: break; } switch (numsiblings[tree->tag]) { case 1: /* correctkeys(sib1(tree), n); */ tree = sib1(tree); goto tailcall; case 2: correctkeys(sib1(tree), n); tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */ default: assert(numsiblings[tree->tag] == 0); break; } }
/* ** merge 'ktable' from 'stree' at stack index 'idx' into 'ktable' ** from tree at the top of the stack, and correct corresponding ** tree. */ static void mergektable (lua_State *L, int idx, TTree *stree) { int n; lua_getfenv(L, -1); /* get ktables */ lua_getfenv(L, idx); n = concattable(L, -1, -2); lua_pop(L, 2); /* remove both ktables */ correctkeys(stree, n); }
/* ** create a new tree, whith a new root and 2 siblings. ** Siblings must be on the Lua stack, first one at index 1. */ static TTree *newroot2sib (lua_State *L, int tag) { int s1, s2; TTree *tree1 = getpatt(L, 1, &s1); TTree *tree2 = getpatt(L, 2, &s2); TTree *tree = newtree(L, 1 + s1 + s2); /* create new tree */ tree->tag = tag; tree->u.ps = 1 + s1; memcpy(sib1(tree), tree1, s1 * sizeof(TTree)); memcpy(sib2(tree), tree2, s2 * sizeof(TTree)); correctkeys(sib2(tree), joinktables(L, 1, 2)); return tree; }
/* ** [t1 - t2] == Seq (Not t2) t1 ** If t1 and t2 are charsets, make their difference. */ static int lp_sub (lua_State *L) { Charset st1, st2; int s1, s2; TTree *t1 = getpatt(L, 1, &s1); TTree *t2 = getpatt(L, 2, &s2); if (tocharset(t1, &st1) && tocharset(t2, &st2)) { TTree *t = newcharset(L); loopset(i, treebuffer(t)[i] = st1.cs[i] & ~st2.cs[i]); } else { TTree *tree = newtree(L, 2 + s1 + s2); tree->tag = TSeq; /* sequence of... */ tree->u.ps = 2 + s2; sib1(tree)->tag = TNot; /* ...not... */ memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */ memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */ correctkeys(sib1(tree), joinktables(L, 1, 2)); } return 1; }