update lpeg to 1.0.2 (#1557)

This commit is contained in:
caiyiheng
2022-03-29 16:16:51 +08:00
committed by GitHub
parent 5d48c02725
commit bee8a0e731
17 changed files with 180 additions and 131 deletions

View File

@@ -1,6 +1,10 @@
HISTORY for LPeg 1.0 HISTORY for LPeg 1.0.2
* Changes from version 0.12 to 1.0 * Changes from version 1.0.1 to 1.0.2
---------------------------------
+ some bugs fixed
* Changes from version 0.12 to 1.0.1
--------------------------------- ---------------------------------
+ group "names" can be any Lua value + group "names" can be any Lua value
+ some bugs fixed + some bugs fixed
@@ -13,14 +17,14 @@ HISTORY for LPeg 1.0
+ some bugs fixed + some bugs fixed
* Changes from version 0.10 to 0.11 * Changes from version 0.10 to 0.11
------------------------------- -------------------------------
+ complete reimplementation of the code generator + complete reimplementation of the code generator
+ new syntax for table captures + new syntax for table captures
+ new functions in module 're' + new functions in module 're'
+ other small improvements + other small improvements
* Changes from version 0.9 to 0.10 * Changes from version 0.9 to 0.10
------------------------------- -------------------------------
+ backtrack stack has configurable size + backtrack stack has configurable size
+ better error messages + better error messages
+ Notation for non-terminals in 're' back to A instead o <A> + Notation for non-terminals in 're' back to A instead o <A>
@@ -32,34 +36,34 @@ HISTORY for LPeg 1.0
- "and" predicates do not keep captures - "and" predicates do not keep captures
* Changes from version 0.8 to 0.9 * Changes from version 0.8 to 0.9
------------------------------- -------------------------------
+ The accumulator capture was replaced by a fold capture; + The accumulator capture was replaced by a fold capture;
programs that used the old 'lpeg.Ca' will need small changes. programs that used the old 'lpeg.Ca' will need small changes.
+ Some support for character classes from old C locales. + Some support for character classes from old C locales.
+ A new named-group capture. + A new named-group capture.
* Changes from version 0.7 to 0.8 * Changes from version 0.7 to 0.8
------------------------------- -------------------------------
+ New "match-time" capture. + New "match-time" capture.
+ New "argument capture" that allows passing arguments into the pattern. + New "argument capture" that allows passing arguments into the pattern.
+ Better documentation for 're'. + Better documentation for 're'.
+ Several small improvements for 're'. + Several small improvements for 're'.
+ The 're' module has an incompatibility with previous versions: + The 're' module has an incompatibility with previous versions:
now, any use of a non-terminal must be enclosed in angle brackets now, any use of a non-terminal must be enclosed in angle brackets
(like <B>). (like <B>).
* Changes from version 0.6 to 0.7 * Changes from version 0.6 to 0.7
------------------------------- -------------------------------
+ Several improvements in module 're': + Several improvements in module 're':
- better documentation; - better documentation;
- support for most captures (all but accumulator); - support for most captures (all but accumulator);
- limited repetitions p{n,m}. - limited repetitions p{n,m}.
+ Small improvements in efficiency. + Small improvements in efficiency.
+ Several small bugs corrected (special thanks to Hans Hagen + Several small bugs corrected (special thanks to Hans Hagen
and Taco Hoekwater). and Taco Hoekwater).
* Changes from version 0.5 to 0.6 * Changes from version 0.5 to 0.6
------------------------------- -------------------------------
+ Support for non-numeric indices in grammars. + Support for non-numeric indices in grammars.
+ Some bug fixes (thanks to the luatex team). + Some bug fixes (thanks to the luatex team).
+ Some new optimizations; (thanks to Mike Pall). + Some new optimizations; (thanks to Mike Pall).
@@ -67,7 +71,7 @@ HISTORY for LPeg 1.0
+ Minimal documentation for module 're'. + Minimal documentation for module 're'.
* Changes from version 0.4 to 0.5 * Changes from version 0.4 to 0.5
------------------------------- -------------------------------
+ Several optimizations. + Several optimizations.
+ lpeg.P now accepts booleans. + lpeg.P now accepts booleans.
+ Some new examples. + Some new examples.
@@ -75,18 +79,18 @@ HISTORY for LPeg 1.0
+ Several small improvements. + Several small improvements.
* Changes from version 0.3 to 0.4 * Changes from version 0.3 to 0.4
------------------------------- -------------------------------
+ Static check for loops in repetitions and grammars. + Static check for loops in repetitions and grammars.
+ Removed label option in captures. + Removed label option in captures.
+ The implementation of captures uses less memory. + The implementation of captures uses less memory.
* Changes from version 0.2 to 0.3 * Changes from version 0.2 to 0.3
------------------------------- -------------------------------
+ User-defined patterns in Lua. + User-defined patterns in Lua.
+ Several new captures. + Several new captures.
* Changes from version 0.1 to 0.2 * Changes from version 0.1 to 0.2
------------------------------- -------------------------------
+ Several small corrections. + Several small corrections.
+ Handles embedded zeros like any other character. + Handles embedded zeros like any other character.
+ Capture "name" can be any Lua value. + Capture "name" can be any Lua value.

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $ ** $Id: lpcap.c $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -271,15 +271,15 @@ int finddyncap (Capture *cap, Capture *last) {
/* /*
** Calls a runtime capture. Returns number of captures removed by ** Calls a runtime capture. Returns number of captures "removed" by the
** the call, including the initial Cgroup. (Captures to be added are ** call, that is, those inside the group capture. Captures to be added
** on the Lua stack.) ** are on the Lua stack.
*/ */
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) { int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
int n, id; int n, id;
lua_State *L = cs->L; lua_State *L = cs->L;
int otop = lua_gettop(L); int otop = lua_gettop(L);
Capture *open = findopen(close); Capture *open = findopen(close); /* get open group capture */
assert(captype(open) == Cgroup); assert(captype(open) == Cgroup);
id = finddyncap(open, close); /* get first dynamic capture argument */ id = finddyncap(open, close); /* get first dynamic capture argument */
close->kind = Cclose; /* closes the group */ close->kind = Cclose; /* closes the group */
@@ -299,7 +299,7 @@ int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
} }
else else
*rem = 0; /* no dynamic captures removed */ *rem = 0; /* no dynamic captures removed */
return close - open; /* number of captures of all kinds removed */ return close - open - 1; /* number of captures to be removed */
} }
@@ -441,70 +441,88 @@ static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
} }
#if !defined(MAXRECLEVEL)
#define MAXRECLEVEL 200
#endif
/* /*
** Push all values of the current capture into the stack; returns ** Push all values of the current capture into the stack; returns
** number of values pushed ** number of values pushed
*/ */
static int pushcapture (CapState *cs) { static int pushcapture (CapState *cs) {
lua_State *L = cs->L; lua_State *L = cs->L;
int res;
luaL_checkstack(L, 4, "too many captures"); luaL_checkstack(L, 4, "too many captures");
if (cs->reclevel++ > MAXRECLEVEL)
return luaL_error(L, "subcapture nesting too deep");
switch (captype(cs->cap)) { switch (captype(cs->cap)) {
case Cposition: { case Cposition: {
lua_pushinteger(L, cs->cap->s - cs->s + 1); lua_pushinteger(L, cs->cap->s - cs->s + 1);
cs->cap++; cs->cap++;
return 1; res = 1;
break;
} }
case Cconst: { case Cconst: {
pushluaval(cs); pushluaval(cs);
cs->cap++; cs->cap++;
return 1; res = 1;
break;
} }
case Carg: { case Carg: {
int arg = (cs->cap++)->idx; int arg = (cs->cap++)->idx;
if (arg + FIXEDARGS > cs->ptop) if (arg + FIXEDARGS > cs->ptop)
return luaL_error(L, "reference to absent extra argument #%d", arg); return luaL_error(L, "reference to absent extra argument #%d", arg);
lua_pushvalue(L, arg + FIXEDARGS); lua_pushvalue(L, arg + FIXEDARGS);
return 1; res = 1;
break;
} }
case Csimple: { case Csimple: {
int k = pushnestedvalues(cs, 1); int k = pushnestedvalues(cs, 1);
lua_insert(L, -k); /* make whole match be first result */ lua_insert(L, -k); /* make whole match be first result */
return k; res = k;
break;
} }
case Cruntime: { case Cruntime: {
lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */ lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */
return 1; res = 1;
break;
} }
case Cstring: { case Cstring: {
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
stringcap(&b, cs); stringcap(&b, cs);
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; res = 1;
break;
} }
case Csubst: { case Csubst: {
luaL_Buffer b; luaL_Buffer b;
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
substcap(&b, cs); substcap(&b, cs);
luaL_pushresult(&b); luaL_pushresult(&b);
return 1; res = 1;
break;
} }
case Cgroup: { case Cgroup: {
if (cs->cap->idx == 0) /* anonymous group? */ if (cs->cap->idx == 0) /* anonymous group? */
return pushnestedvalues(cs, 0); /* add all nested values */ res = pushnestedvalues(cs, 0); /* add all nested values */
else { /* named group: add no values */ else { /* named group: add no values */
nextcap(cs); /* skip capture */ nextcap(cs); /* skip capture */
return 0; res = 0;
} }
break;
} }
case Cbackref: return backrefcap(cs); case Cbackref: res = backrefcap(cs); break;
case Ctable: return tablecap(cs); case Ctable: res = tablecap(cs); break;
case Cfunction: return functioncap(cs); case Cfunction: res = functioncap(cs); break;
case Cnum: return numcap(cs); case Cnum: res = numcap(cs); break;
case Cquery: return querycap(cs); case Cquery: res = querycap(cs); break;
case Cfold: return foldcap(cs); case Cfold: res = foldcap(cs); break;
default: assert(0); return 0; default: assert(0); res = 0;
} }
cs->reclevel--;
return res;
} }
@@ -521,7 +539,7 @@ int getcaptures (lua_State *L, const char *s, const char *r, int ptop) {
int n = 0; int n = 0;
if (!isclosecap(capture)) { /* is there any capture? */ if (!isclosecap(capture)) { /* is there any capture? */
CapState cs; CapState cs;
cs.ocap = cs.cap = capture; cs.L = L; cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0;
cs.s = s; cs.valuecached = 0; cs.ptop = ptop; cs.s = s; cs.valuecached = 0; cs.ptop = ptop;
do { /* collect their values */ do { /* collect their values */
n += pushcapture(&cs); n += pushcapture(&cs);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcap.h,v 1.3 2016/09/13 17:45:58 roberto Exp $ ** $Id: lpcap.h $
*/ */
#if !defined(lpcap_h) #if !defined(lpcap_h)
@@ -44,6 +44,7 @@ typedef struct CapState {
int ptop; /* index of last argument to 'match' */ int ptop; /* index of last argument to 'match' */
const char *s; /* original string */ const char *s; /* original string */
int valuecached; /* value stored in cache slot */ int valuecached; /* value stored in cache slot */
int reclevel; /* recursion level */
} CapState; } CapState;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcode.c,v 1.24 2016/09/15 17:46:13 roberto Exp $ ** $Id: lpcode.c $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcode.h,v 1.8 2016/09/15 17:46:13 roberto Exp $ ** $Id: lpcode.h $
*/ */
#if !defined(lpcode_h) #if !defined(lpcode_h)

View File

@@ -10,7 +10,7 @@
</head> </head>
<body> <body>
<!-- $Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $ --> <!-- $Id: lpeg.html $ -->
<div id="container"> <div id="container">
@@ -1391,13 +1391,13 @@ and the new term for each repetition.
<h2><a name="download"></a>Download</h2> <h2><a name="download"></a>Download</h2>
<p>LPeg <p>LPeg
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.1.tar.gz">source code</a>.</p> <a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz">source code</a>.</p>
<h2><a name="license">License</a></h2> <h2><a name="license">License</a></h2>
<p> <p>
Copyright &copy; 2007-2017 Lua.org, PUC-Rio. Copyright &copy; 2007-2019 Lua.org, PUC-Rio.
</p> </p>
<p> <p>
Permission is hereby granted, free of charge, Permission is hereby granted, free of charge,
@@ -1433,12 +1433,6 @@ THE SOFTWARE.
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about">
<p><small>
$Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $
</small></p>
</div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpprint.c,v 1.10 2016/09/13 16:06:03 roberto Exp $ ** $Id: lpprint.c $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $ ** $Id: lpprint.h $
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lptree.c,v 1.22 2016/09/13 18:10:22 roberto Exp $ ** $Id: lptree.c $
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -716,6 +716,7 @@ static int capture_aux (lua_State *L, int cap, int labelidx) {
/* /*
** Fill a tree with an empty capture, using an empty (TTrue) sibling. ** Fill a tree with an empty capture, using an empty (TTrue) sibling.
** (The 'key' field must be filled by the caller to finish the tree.)
*/ */
static TTree *auxemptycap (TTree *tree, int cap) { static TTree *auxemptycap (TTree *tree, int cap) {
tree->tag = TCapture; tree->tag = TCapture;
@@ -726,15 +727,17 @@ static TTree *auxemptycap (TTree *tree, int cap) {
/* /*
** Create a tree for an empty capture ** Create a tree for an empty capture.
*/ */
static TTree *newemptycap (lua_State *L, int cap) { static TTree *newemptycap (lua_State *L, int cap, int key) {
return auxemptycap(newtree(L, 2), cap); TTree *tree = auxemptycap(newtree(L, 2), cap);
tree->key = key;
return tree;
} }
/* /*
** Create a tree for an empty capture with an associated Lua value ** Create a tree for an empty capture with an associated Lua value.
*/ */
static TTree *newemptycapkey (lua_State *L, int cap, int idx) { static TTree *newemptycapkey (lua_State *L, int cap, int idx) {
TTree *tree = auxemptycap(newtree(L, 2), cap); TTree *tree = auxemptycap(newtree(L, 2), cap);
@@ -795,16 +798,15 @@ static int lp_simplecapture (lua_State *L) {
static int lp_poscapture (lua_State *L) { static int lp_poscapture (lua_State *L) {
newemptycap(L, Cposition); newemptycap(L, Cposition, 0);
return 1; return 1;
} }
static int lp_argcapture (lua_State *L) { static int lp_argcapture (lua_State *L) {
int n = (int)luaL_checkinteger(L, 1); int n = (int)luaL_checkinteger(L, 1);
TTree *tree = newemptycap(L, Carg);
tree->key = n;
luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index"); luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index");
newemptycap(L, Carg, n);
return 1; return 1;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lptree.h,v 1.3 2016/09/13 18:07:51 roberto Exp $ ** $Id: lptree.h $
*/ */
#if !defined(lptree_h) #if !defined(lptree_h)

View File

@@ -1,7 +1,7 @@
/* /*
** $Id: lptypes.h,v 1.16 2017/01/13 13:33:17 roberto Exp $ ** $Id: lptypes.h $
** LPeg - PEG pattern matching for Lua ** LPeg - PEG pattern matching for Lua
** Copyright 2007-2017, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007-2019, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy ** written by Roberto Ierusalimschy
*/ */
@@ -9,17 +9,13 @@
#define lptypes_h #define lptypes_h
#if !defined(LPEG_DEBUG)
#define NDEBUG
#endif
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include "lua.h" #include "lua.h"
#define VERSION "1.0.1" #define VERSION "1.0.2"
#define PATTERN_T "lpeg-pattern" #define PATTERN_T "lpeg-pattern"

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpvm.c,v 1.9 2016/06/03 20:11:18 roberto Exp $ ** $Id: lpvm.c $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -45,18 +45,29 @@ typedef struct Stack {
/* /*
** Make the size of the array of captures 'cap' twice as large as needed ** Ensures the size of array 'capture' (with size '*capsize' and
** (which is 'captop'). ('n' is the number of new elements.) ** 'captop' elements being used) is enough to accomodate 'n' extra
** elements plus one. (Because several opcodes add stuff to the capture
** array, it is simpler to ensure the array always has at least one free
** slot upfront and check its size later.)
*/ */
static Capture *doublecap (lua_State *L, Capture *cap, int captop, static Capture *growcap (lua_State *L, Capture *capture, int *capsize,
int n, int ptop) { int captop, int n, int ptop) {
Capture *newc; if (*capsize - captop > n)
if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) return capture; /* no need to grow array */
luaL_error(L, "too many captures"); else { /* must grow */
newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); Capture *newc;
memcpy(newc, cap, (captop - n) * sizeof(Capture)); int newsize = captop + n + 1; /* minimum size needed */
lua_replace(L, caplistidx(ptop)); if (newsize < INT_MAX/((int)sizeof(Capture) * 2))
return newc; newsize *= 2; /* twice that size, if not too big */
else if (newsize >= INT_MAX/((int)sizeof(Capture)))
luaL_error(L, "too many captures");
newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture));
memcpy(newc, capture, captop * sizeof(Capture));
*capsize = newsize;
lua_replace(L, caplistidx(ptop));
return newc;
}
} }
@@ -109,24 +120,24 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) {
/* /*
** Add capture values returned by a dynamic capture to the capture list ** Add capture values returned by a dynamic capture to the list
** 'base', nested inside a group capture. 'fd' indexes the first capture ** 'capture', nested inside a group. 'fd' indexes the first capture
** value, 'n' is the number of values (at least 1). ** value, 'n' is the number of values (at least 1). The open group
** capture is already in 'capture', before the place for the new entries.
*/ */
static void adddyncaptures (const char *s, Capture *base, int n, int fd) { static void adddyncaptures (const char *s, Capture *capture, int n, int fd) {
int i; int i;
base[0].kind = Cgroup; /* create group capture */ assert(capture[-1].kind == Cgroup && capture[-1].siz == 0);
base[0].siz = 0; capture[-1].idx = 0; /* make group capture an anonymous group */
base[0].idx = 0; /* make it an anonymous group */ for (i = 0; i < n; i++) { /* add runtime captures */
for (i = 1; i <= n; i++) { /* add runtime captures */ capture[i].kind = Cruntime;
base[i].kind = Cruntime; capture[i].siz = 1; /* mark it as closed */
base[i].siz = 1; /* mark it as closed */ capture[i].idx = fd + i; /* stack index of capture value */
base[i].idx = fd + i - 1; /* stack index of capture value */ capture[i].s = s;
base[i].s = s;
} }
base[i].kind = Cclose; /* close group */ capture[n].kind = Cclose; /* close group */
base[i].siz = 1; capture[n].siz = 1;
base[i].s = s; capture[n].s = s;
} }
@@ -296,7 +307,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
CapState cs; CapState cs;
int rem, res, n; int rem, res, n;
int fr = lua_gettop(L) + 1; /* stack index of first result */ int fr = lua_gettop(L) + 1; /* stack index of first result */
cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop; cs.reclevel = 0; cs.L = L;
cs.s = o; cs.ocap = capture; cs.ptop = ptop;
n = runtimecap(&cs, capture + captop, s, &rem); /* call function */ n = runtimecap(&cs, capture + captop, s, &rem); /* call function */
captop -= n; /* remove nested captures */ captop -= n; /* remove nested captures */
ndyncap -= rem; /* update number of dynamic captures */ ndyncap -= rem; /* update number of dynamic captures */
@@ -307,15 +319,15 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
s = o + res; /* else update current position */ s = o + res; /* else update current position */
n = lua_gettop(L) - fr + 1; /* number of new captures */ n = lua_gettop(L) - fr + 1; /* number of new captures */
ndyncap += n; /* update number of dynamic captures */ ndyncap += n; /* update number of dynamic captures */
if (n > 0) { /* any new capture? */ if (n == 0) /* no new captures? */
captop--; /* remove open group */
else { /* new captures; keep original open group */
if (fr + n >= SHRT_MAX) if (fr + n >= SHRT_MAX)
luaL_error(L, "too many results in match-time capture"); luaL_error(L, "too many results in match-time capture");
if ((captop += n + 2) >= capsize) { /* add new captures + close group to 'capture' list */
capture = doublecap(L, capture, captop, n + 2, ptop); capture = growcap(L, capture, &capsize, captop, n + 1, ptop);
capsize = 2 * captop; adddyncaptures(s, capture + captop, n, fr);
} captop += n + 1; /* new captures + close group */
/* add new captures to 'capture' list */
adddyncaptures(s, capture + captop - n - 2, n, fr);
} }
p++; p++;
continue; continue;
@@ -347,10 +359,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
pushcapture: { pushcapture: {
capture[captop].idx = p->i.key; capture[captop].idx = p->i.key;
capture[captop].kind = getkind(p); capture[captop].kind = getkind(p);
if (++captop >= capsize) { captop++;
capture = doublecap(L, capture, captop, 0, ptop); capture = growcap(L, capture, &capsize, captop, 0, ptop);
capsize = 2 * captop;
}
p++; p++;
continue; continue;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpvm.h,v 1.3 2014/02/21 13:06:41 roberto Exp $ ** $Id: lpvm.h $
*/ */
#if !defined(lpvm_h) #if !defined(lpvm_h)

View File

@@ -1,8 +1,8 @@
LIBNAME = lpeg LIBNAME = lpeg
LUADIR = ../lua/ LUADIR = ../lua/
COPT = -O2 COPT = -O2 -DNDEBUG
# COPT = -DLPEG_DEBUG -g # COPT = -g
CWARNS = -Wall -Wextra -pedantic \ CWARNS = -Wall -Wextra -pedantic \
-Waggregate-return \ -Waggregate-return \
@@ -29,11 +29,11 @@ FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o
# For Linux # For Linux
linux: linux:
make lpeg.so "DLLFLAGS = -shared -fPIC" $(MAKE) lpeg.so "DLLFLAGS = -shared -fPIC"
# For Mac OS # For Mac OS
macosx: macosx:
make lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup" $(MAKE) lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup"
lpeg.so: $(FILES) lpeg.so: $(FILES)
env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so

View File

@@ -10,7 +10,7 @@
</head> </head>
<body> <body>
<!-- $Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $ --> <!-- $Id: re.html $ -->
<div id="container"> <div id="container">
@@ -93,6 +93,8 @@ Constructions are listed in order of decreasing precedence.
equivalent to <code>p / defs[name]</code></td></tr> equivalent to <code>p / defs[name]</code></td></tr>
<tr><td><code>p =&gt; name</code></td> <td>match-time capture <tr><td><code>p =&gt; name</code></td> <td>match-time capture
equivalent to <code>lpeg.Cmt(p, defs[name])</code></td></tr> equivalent to <code>lpeg.Cmt(p, defs[name])</code></td></tr>
<tr><td><code>p ~&gt; name</code></td> <td>fold capture
equivalent to <code>lpeg.Cf(p, defs[name])</code></td></tr>
<tr><td><code>& p</code></td> <td>and predicate</td></tr> <tr><td><code>& p</code></td> <td>and predicate</td></tr>
<tr><td><code>! p</code></td> <td>not predicate</td></tr> <tr><td><code>! p</code></td> <td>not predicate</td></tr>
<tr><td><code>p1 p2</code></td> <td>concatenation</td></tr> <tr><td><code>p1 p2</code></td> <td>concatenation</td></tr>
@@ -486,12 +488,6 @@ THE SOFTWARE.
</div> <!-- id="main" --> </div> <!-- id="main" -->
<div id="about">
<p><small>
$Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $
</small></p>
</div> <!-- id="about" -->
</div> <!-- id="container" --> </div> <!-- id="container" -->
</body> </body>

View File

@@ -1,4 +1,4 @@
-- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $ -- $Id: re.lua $
-- imported functions and modules -- imported functions and modules
local tonumber, type, print, error = tonumber, type, print, error local tonumber, type, print, error = tonumber, type, print, error
@@ -71,13 +71,6 @@ updatelocale()
local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end) local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
local function getdef (id, defs)
local c = defs and defs[id]
if not c then error("undefined name: " .. id) end
return c
end
local function patt_error (s, i) local function patt_error (s, i)
local msg = (#s < i + 20) and s:sub(i) local msg = (#s < i + 20) and s:sub(i)
or s:sub(i,i+20) .. "..." or s:sub(i,i+20) .. "..."
@@ -116,6 +109,20 @@ name = m.C(name)
-- a defined name only have meaning in a given environment -- a defined name only have meaning in a given environment
local Def = name * m.Carg(1) local Def = name * m.Carg(1)
local function getdef (id, defs)
local c = defs and defs[id]
if not c then error("undefined name: " .. id) end
return c
end
-- match a name and return a group of its corresponding definition
-- and 'f' (to be folded in 'Suffix')
local function defwithfunc (f)
return m.Cg(Def / getdef * m.Cc(f))
end
local num = m.C(m.R"09"^1) * S / tonumber local num = m.C(m.R"09"^1) * S / tonumber
local String = "'" * m.C((any - "'")^0) * "'" + local String = "'" * m.C((any - "'")^0) * "'" +
@@ -130,7 +137,7 @@ end
local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
local item = defined + Range + m.C(any) local item = (defined + Range + m.C(any)) / m.P
local Class = local Class =
"[" "["
@@ -176,9 +183,10 @@ local exp = m.P{ "Exp",
) )
+ "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div)) + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div))
+ m.P"{}" * m.Cc(nil, m.Ct) + m.P"{}" * m.Cc(nil, m.Ct)
+ m.Cg(Def / getdef * m.Cc(mt.__div)) + defwithfunc(mt.__div)
) )
+ "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt)) + "=>" * S * defwithfunc(m.Cmt)
+ "~>" * S * defwithfunc(m.Cf)
) * S ) * S
)^0, function (a,b,f) return f(a,b) end ); )^0, function (a,b,f) return f(a,b) end );
Primary = "(" * m.V"Exp" * ")" Primary = "(" * m.V"Exp" * ")"

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env lua #!/usr/bin/env lua
-- $Id: test.lua,v 1.112 2017/01/14 18:55:22 roberto Exp $ -- $Id: test.lua $
-- require"strict" -- just to be pedantic -- require"strict" -- just to be pedantic
@@ -424,6 +424,16 @@ do
end end
do
-- nesting of captures too deep
local p = m.C(1)
for i = 1, 300 do
p = m.Ct(p)
end
checkerr("too deep", p.match, p, "x")
end
-- tests for non-pattern as arguments to pattern functions -- tests for non-pattern as arguments to pattern functions
p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 } p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 }
@@ -1186,6 +1196,9 @@ assert(not match("abbcde", " [b-z] + "))
assert(match("abb\"de", '"abb"["]"de"') == 7) assert(match("abb\"de", '"abb"["]"de"') == 7)
assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee") assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee")
assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8) assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8)
assert(re.match("aaand", "[a]^2") == 3)
local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")} local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")}
checkeq(t, {4, 5, 7}) checkeq(t, {4, 5, 7})
local t = {match("abceefe", "((&&'e' {})? .)*")} local t = {match("abceefe", "((&&'e' {})? .)*")}
@@ -1360,6 +1373,13 @@ checkeq(x, {tag='x', 'hi', {tag = 'b', 'hello'}, 'but',
{'totheend'}}) {'totheend'}})
-- test for folding captures
c = re.compile([[
S <- (number (%s+ number)*) ~> add
number <- %d+ -> tonumber
]], {tonumber = tonumber, add = function (a,b) return a + b end})
assert(c:match("3 401 50") == 3 + 401 + 50)
-- tests for look-ahead captures -- tests for look-ahead captures
x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")} x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")}
checkeq(x, {"", "alo", ""}) checkeq(x, {"", "alo", ""})