diff options
Diffstat (limited to 'lpvm.c')
-rw-r--r-- | lpvm.c | 88 |
1 files changed, 49 insertions, 39 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lpvm.c,v 1.9 2016/06/03 20:11:18 roberto Exp $ | 2 | ** $Id: lpvm.c $ |
3 | ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) | 3 | ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -47,18 +47,29 @@ typedef struct Stack { | |||
47 | 47 | ||
48 | 48 | ||
49 | /* | 49 | /* |
50 | ** Make the size of the array of captures 'cap' twice as large as needed | 50 | ** Ensures the size of array 'capture' (with size '*capsize' and |
51 | ** (which is 'captop'). ('n' is the number of new elements.) | 51 | ** 'captop' elements being used) is enough to accomodate 'n' extra |
52 | ** elements plus one. (Because several opcodes add stuff to the capture | ||
53 | ** array, it is simpler to ensure the array always has at least one free | ||
54 | ** slot upfront and check its size later.) | ||
52 | */ | 55 | */ |
53 | static Capture *doublecap (lua_State *L, Capture *cap, int captop, | 56 | static Capture *growcap (lua_State *L, Capture *capture, int *capsize, |
54 | int n, int ptop) { | 57 | int captop, int n, int ptop) { |
55 | Capture *newc; | 58 | if (*capsize - captop > n) |
56 | if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) | 59 | return capture; /* no need to grow array */ |
57 | luaL_error(L, "too many captures"); | 60 | else { /* must grow */ |
58 | newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); | 61 | Capture *newc; |
59 | memcpy(newc, cap, (captop - n) * sizeof(Capture)); | 62 | int newsize = captop + n + 1; /* minimum size needed */ |
60 | lua_replace(L, caplistidx(ptop)); | 63 | if (newsize < INT_MAX/((int)sizeof(Capture) * 2)) |
61 | return newc; | 64 | newsize *= 2; /* twice that size, if not too big */ |
65 | else if (newsize >= INT_MAX/((int)sizeof(Capture))) | ||
66 | luaL_error(L, "too many captures"); | ||
67 | newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture)); | ||
68 | memcpy(newc, capture, captop * sizeof(Capture)); | ||
69 | *capsize = newsize; | ||
70 | lua_replace(L, caplistidx(ptop)); | ||
71 | return newc; | ||
72 | } | ||
62 | } | 73 | } |
63 | 74 | ||
64 | 75 | ||
@@ -111,24 +122,24 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) { | |||
111 | 122 | ||
112 | 123 | ||
113 | /* | 124 | /* |
114 | ** Add capture values returned by a dynamic capture to the capture list | 125 | ** Add capture values returned by a dynamic capture to the list |
115 | ** 'base', nested inside a group capture. 'fd' indexes the first capture | 126 | ** 'capture', nested inside a group. 'fd' indexes the first capture |
116 | ** value, 'n' is the number of values (at least 1). | 127 | ** value, 'n' is the number of values (at least 1). The open group |
128 | ** capture is already in 'capture', before the place for the new entries. | ||
117 | */ | 129 | */ |
118 | static void adddyncaptures (const char *s, Capture *base, int n, int fd) { | 130 | static void adddyncaptures (const char *s, Capture *capture, int n, int fd) { |
119 | int i; | 131 | int i; |
120 | base[0].kind = Cgroup; /* create group capture */ | 132 | assert(capture[-1].kind == Cgroup && capture[-1].siz == 0); |
121 | base[0].siz = 0; | 133 | capture[-1].idx = 0; /* make group capture an anonymous group */ |
122 | base[0].idx = 0; /* make it an anonymous group */ | 134 | for (i = 0; i < n; i++) { /* add runtime captures */ |
123 | for (i = 1; i <= n; i++) { /* add runtime captures */ | 135 | capture[i].kind = Cruntime; |
124 | base[i].kind = Cruntime; | 136 | capture[i].siz = 1; /* mark it as closed */ |
125 | base[i].siz = 1; /* mark it as closed */ | 137 | capture[i].idx = fd + i; /* stack index of capture value */ |
126 | base[i].idx = fd + i - 1; /* stack index of capture value */ | 138 | capture[i].s = s; |
127 | base[i].s = s; | ||
128 | } | 139 | } |
129 | base[i].kind = Cclose; /* close group */ | 140 | capture[n].kind = Cclose; /* close group */ |
130 | base[i].siz = 1; | 141 | capture[n].siz = 1; |
131 | base[i].s = s; | 142 | capture[n].s = s; |
132 | } | 143 | } |
133 | 144 | ||
134 | 145 | ||
@@ -374,7 +385,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
374 | CapState cs; | 385 | CapState cs; |
375 | int rem, res, n; | 386 | int rem, res, n; |
376 | int fr = lua_gettop(L) + 1; /* stack index of first result */ | 387 | int fr = lua_gettop(L) + 1; /* stack index of first result */ |
377 | cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop; | 388 | cs.reclevel = 0; cs.L = L; |
389 | cs.s = o; cs.ocap = capture; cs.ptop = ptop; | ||
378 | n = runtimecap(&cs, capture + captop, s, &rem); /* call function */ | 390 | n = runtimecap(&cs, capture + captop, s, &rem); /* call function */ |
379 | captop -= n; /* remove nested captures */ | 391 | captop -= n; /* remove nested captures */ |
380 | ndyncap -= rem; /* update number of dynamic captures */ | 392 | ndyncap -= rem; /* update number of dynamic captures */ |
@@ -388,15 +400,15 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
388 | s = o + res; /* else update current position */ | 400 | s = o + res; /* else update current position */ |
389 | n = lua_gettop(L) - fr + 1; /* number of new captures */ | 401 | n = lua_gettop(L) - fr + 1; /* number of new captures */ |
390 | ndyncap += n; /* update number of dynamic captures */ | 402 | ndyncap += n; /* update number of dynamic captures */ |
391 | if (n > 0) { /* any new capture? */ | 403 | if (n == 0) /* no new captures? */ |
404 | captop--; /* remove open group */ | ||
405 | else { /* new captures; keep original open group */ | ||
392 | if (fr + n >= SHRT_MAX) | 406 | if (fr + n >= SHRT_MAX) |
393 | luaL_error(L, "too many results in match-time capture"); | 407 | luaL_error(L, "too many results in match-time capture"); |
394 | if ((captop += n + 2) >= capsize) { | 408 | /* add new captures + close group to 'capture' list */ |
395 | capture = doublecap(L, capture, captop, n + 2, ptop); | 409 | capture = growcap(L, capture, &capsize, captop, n + 1, ptop); |
396 | capsize = 2 * captop; | 410 | adddyncaptures(s, capture + captop, n, fr); |
397 | } | 411 | captop += n + 1; /* new captures + close group */ |
398 | /* add new captures to 'capture' list */ | ||
399 | adddyncaptures(s, capture + captop - n - 2, n, fr); | ||
400 | } | 412 | } |
401 | p++; | 413 | p++; |
402 | continue; | 414 | continue; |
@@ -428,10 +440,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
428 | pushcapture: { | 440 | pushcapture: { |
429 | capture[captop].idx = p->i.key; | 441 | capture[captop].idx = p->i.key; |
430 | capture[captop].kind = getkind(p); | 442 | capture[captop].kind = getkind(p); |
431 | if (++captop >= capsize) { | 443 | captop++; |
432 | capture = doublecap(L, capture, captop, 0, ptop); | 444 | capture = growcap(L, capture, &capsize, captop, 0, ptop); |
433 | capsize = 2 * captop; | ||
434 | } | ||
435 | p++; | 445 | p++; |
436 | continue; | 446 | continue; |
437 | } | 447 | } |