lpeg 1.0.1

This commit is contained in:
Cloud Wu
2017-04-11 13:09:24 +08:00
parent 6fa241453c
commit 8e7796a672
12 changed files with 253 additions and 118 deletions

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcap.h,v 1.2 2015/02/27 17:13:17 roberto Exp $ ** $Id: lpcap.h,v 1.3 2016/09/13 17:45:58 roberto Exp $
*/ */
#if !defined(lpcap_h) #if !defined(lpcap_h)
@@ -11,8 +11,21 @@
/* kinds of captures */ /* kinds of captures */
typedef enum CapKind { typedef enum CapKind {
Cclose, Cposition, Cconst, Cbackref, Carg, Csimple, Ctable, Cfunction, Cclose, /* not used in trees */
Cquery, Cstring, Cnum, Csubst, Cfold, Cruntime, Cgroup Cposition,
Cconst, /* ktable[key] is Lua constant */
Cbackref, /* ktable[key] is "name" of group to get capture */
Carg, /* 'key' is arg's number */
Csimple, /* next node is pattern */
Ctable, /* next node is pattern */
Cfunction, /* ktable[key] is function; next node is pattern */
Cquery, /* ktable[key] is table; next node is pattern */
Cstring, /* ktable[key] is string; next node is pattern */
Cnum, /* numbered capture; 'key' is number of value to return */
Csubst, /* substitution capture; next node is pattern */
Cfold, /* ktable[key] is function; next node is pattern */
Cruntime, /* not used in trees (is uses another type for tree) */
Cgroup /* ktable[key] is group's "name" */
} CapKind; } CapKind;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcode.c,v 1.23 2015/06/12 18:36:47 roberto Exp $ ** $Id: lpcode.c,v 1.24 2016/09/15 17:46:13 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -125,6 +125,27 @@ int tocharset (TTree *tree, Charset *cs) {
} }
/*
** Visit a TCall node taking care to stop recursion. If node not yet
** visited, return 'f(sib2(tree))', otherwise return 'def' (default
** value)
*/
static int callrecursive (TTree *tree, int f (TTree *t), int def) {
int key = tree->key;
assert(tree->tag == TCall);
assert(sib2(tree)->tag == TRule);
if (key == 0) /* node already visited? */
return def; /* return default value */
else { /* first visit */
int result;
tree->key = 0; /* mark call as already visited */
result = f(sib2(tree)); /* go to called rule */
tree->key = key; /* restore tree */
return result;
}
}
/* /*
** Check whether a pattern tree has captures ** Check whether a pattern tree has captures
*/ */
@@ -134,14 +155,17 @@ int hascaptures (TTree *tree) {
case TCapture: case TRunTime: case TCapture: case TRunTime:
return 1; return 1;
case TCall: case TCall:
tree = sib2(tree); goto tailcall; /* return hascaptures(sib2(tree)); */ return callrecursive(tree, hascaptures, 0);
case TRule: /* do not follow siblings */
tree = sib1(tree); goto tailcall;
case TOpenCall: assert(0); case TOpenCall: assert(0);
default: { default: {
switch (numsiblings[tree->tag]) { switch (numsiblings[tree->tag]) {
case 1: /* return hascaptures(sib1(tree)); */ case 1: /* return hascaptures(sib1(tree)); */
tree = sib1(tree); goto tailcall; tree = sib1(tree); goto tailcall;
case 2: case 2:
if (hascaptures(sib1(tree))) return 1; if (hascaptures(sib1(tree)))
return 1;
/* else return hascaptures(sib2(tree)); */ /* else return hascaptures(sib2(tree)); */
tree = sib2(tree); goto tailcall; tree = sib2(tree); goto tailcall;
default: assert(numsiblings[tree->tag] == 0); return 0; default: assert(numsiblings[tree->tag] == 0); return 0;
@@ -208,9 +232,9 @@ int checkaux (TTree *tree, int pred) {
/* /*
** number of characters to match a pattern (or -1 if variable) ** number of characters to match a pattern (or -1 if variable)
** ('count' avoids infinite loops for grammars)
*/ */
int fixedlenx (TTree *tree, int count, int len) { int fixedlen (TTree *tree) {
int len = 0; /* to accumulate in tail calls */
tailcall: tailcall:
switch (tree->tag) { switch (tree->tag) {
case TChar: case TSet: case TAny: case TChar: case TSet: case TAny:
@@ -220,26 +244,29 @@ int fixedlenx (TTree *tree, int count, int len) {
case TRep: case TRunTime: case TOpenCall: case TRep: case TRunTime: case TOpenCall:
return -1; return -1;
case TCapture: case TRule: case TGrammar: case TCapture: case TRule: case TGrammar:
/* return fixedlenx(sib1(tree), count); */ /* return fixedlen(sib1(tree)); */
tree = sib1(tree); goto tailcall; tree = sib1(tree); goto tailcall;
case TCall: case TCall: {
if (count++ >= MAXRULES) int n1 = callrecursive(tree, fixedlen, -1);
return -1; /* may be a loop */ if (n1 < 0)
/* else return fixedlenx(sib2(tree), count); */ return -1;
tree = sib2(tree); goto tailcall; else
return len + n1;
}
case TSeq: { case TSeq: {
len = fixedlenx(sib1(tree), count, len); int n1 = fixedlen(sib1(tree));
if (len < 0) return -1; if (n1 < 0)
/* else return fixedlenx(sib2(tree), count, len); */ return -1;
tree = sib2(tree); goto tailcall; /* else return fixedlen(sib2(tree)) + len; */
len += n1; tree = sib2(tree); goto tailcall;
} }
case TChoice: { case TChoice: {
int n1, n2; int n1 = fixedlen(sib1(tree));
n1 = fixedlenx(sib1(tree), count, len); int n2 = fixedlen(sib2(tree));
if (n1 < 0) return -1; if (n1 != n2 || n1 < 0)
n2 = fixedlenx(sib2(tree), count, len); return -1;
if (n1 == n2) return n1; else
else return -1; return len + n1;
} }
default: assert(0); return 0; default: assert(0); return 0;
}; };
@@ -710,9 +737,10 @@ static void codeand (CompileState *compst, TTree *tree, int tt) {
/* /*
** Captures: if pattern has fixed (and not too big) length, use ** Captures: if pattern has fixed (and not too big) length, and it
** a single IFullCapture instruction after the match; otherwise, ** has no nested captures, use a single IFullCapture instruction
** enclose the pattern with OpenCapture - CloseCapture. ** after the match; otherwise, enclose the pattern with OpenCapture -
** CloseCapture.
*/ */
static void codecapture (CompileState *compst, TTree *tree, int tt, static void codecapture (CompileState *compst, TTree *tree, int tt,
const Charset *fl) { const Charset *fl) {

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpcode.h,v 1.7 2015/06/12 18:24:45 roberto Exp $ ** $Id: lpcode.h,v 1.8 2016/09/15 17:46:13 roberto Exp $
*/ */
#if !defined(lpcode_h) #if !defined(lpcode_h)
@@ -13,7 +13,7 @@
int tocharset (TTree *tree, Charset *cs); int tocharset (TTree *tree, Charset *cs);
int checkaux (TTree *tree, int pred); int checkaux (TTree *tree, int pred);
int fixedlenx (TTree *tree, int count, int len); int fixedlen (TTree *tree);
int hascaptures (TTree *tree); int hascaptures (TTree *tree);
int lp_gc (lua_State *L); int lp_gc (lua_State *L);
Instruction *compile (lua_State *L, Pattern *p); Instruction *compile (lua_State *L, Pattern *p);
@@ -35,8 +35,6 @@ int sizei (const Instruction *i);
*/ */
#define nullable(t) checkaux(t, PEnullable) #define nullable(t) checkaux(t, PEnullable)
#define fixedlen(t) fixedlenx(t, 0, 0)
#endif #endif

View File

@@ -10,7 +10,7 @@
</head> </head>
<body> <body>
<!-- $Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $ --> <!-- $Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $ -->
<div id="container"> <div id="container">
@@ -577,8 +577,9 @@ It is equivalent to the following grammar in standard PEG notation:
<h2><a name="captures">Captures</a></h2> <h2><a name="captures">Captures</a></h2>
<p> <p>
A <em>capture</em> is a pattern that creates values A <em>capture</em> is a pattern that produces values
(the so called <em>semantic information</em>) when it matches. (the so called <em>semantic information</em>)
according to what it matches.
LPeg offers several kinds of captures, LPeg offers several kinds of captures,
which produces values based on matches and combine these values to which produces values based on matches and combine these values to
produce new values. produce new values.
@@ -632,10 +633,7 @@ or no value when <code>number</code> is zero.</td></tr>
</tbody></table> </tbody></table>
<p> <p>
A capture pattern produces its values every time it succeeds. A capture pattern produces its values only when it succeeds.
For instance,
a capture inside a loop produces as many values as matched by the loop.
A capture produces a value only when it succeeds.
For instance, For instance,
the pattern <code>lpeg.C(lpeg.P"a"^-1)</code> the pattern <code>lpeg.C(lpeg.P"a"^-1)</code>
produces the empty string when there is no <code>"a"</code> produces the empty string when there is no <code>"a"</code>
@@ -643,14 +641,20 @@ produces the empty string when there is no <code>"a"</code>
while the pattern <code>lpeg.C("a")^-1</code> while the pattern <code>lpeg.C("a")^-1</code>
does not produce any value when there is no <code>"a"</code> does not produce any value when there is no <code>"a"</code>
(because the pattern <code>"a"</code> fails). (because the pattern <code>"a"</code> fails).
A pattern inside a loop or inside a recursive structure
produces values for each match.
</p> </p>
<p> <p>
Usually, Usually,
LPeg evaluates all captures only after (and if) the entire match succeeds. LPeg does not specify when (and if) it evaluates its captures.
During <em>match time</em> it only gathers enough information (As an example,
to produce the capture values later. consider the pattern <code>lpeg.P"a" / func / 0</code>.
As a particularly important consequence, Because the "division" by 0 instructs LPeg to throw away the
results from the pattern,
LPeg may or may not call <code>func</code>.)
Therefore, captures should avoid side effects.
Moreover,
most captures cannot affect the way a pattern matches a subject. most captures cannot affect the way a pattern matches a subject.
The only exception to this rule is the The only exception to this rule is the
so-called <a href="#matchtime"><em>match-time capture</em></a>. so-called <a href="#matchtime"><em>match-time capture</em></a>.
@@ -700,6 +704,12 @@ An <em>Outermost</em> capture means that the capture is not inside
another complete capture. another complete capture.
</p> </p>
<p>
In the same way that LPeg does not specify when it evaluates captures,
it does not specify whether it reuses
values previously produced by the group
or re-evaluates them.
</p>
<h3><a name="cap-cc"></a><code>lpeg.Cc ([value, ...])</code></h3> <h3><a name="cap-cc"></a><code>lpeg.Cc ([value, ...])</code></h3>
<p> <p>
@@ -806,7 +816,7 @@ all replacements.
<h3><a name="cap-t"></a><code>lpeg.Ct (patt)</code></h3> <h3><a name="cap-t"></a><code>lpeg.Ct (patt)</code></h3>
<p> <p>
Creates a <em>table capture</em>. Creates a <em>table capture</em>.
This capture creates a table and puts all values from all anonymous captures This capture returns a table with all values from all anonymous captures
made by <code>patt</code> inside this table in successive integer keys, made by <code>patt</code> inside this table in successive integer keys,
starting at 1. starting at 1.
Moreover, Moreover,
@@ -872,7 +882,8 @@ there is no captured value.
<p> <p>
Creates a <em>match-time capture</em>. Creates a <em>match-time capture</em>.
Unlike all other captures, Unlike all other captures,
this one is evaluated immediately when a match occurs. this one is evaluated immediately when a match occurs
(even if it is part of a larger pattern that fails later).
It forces the immediate evaluation of all its nested captures It forces the immediate evaluation of all its nested captures
and then calls <code>function</code>. and then calls <code>function</code>.
</p> </p>
@@ -1380,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.0.tar.gz">source code</a>.</p> <a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.1.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-2015 Lua.org, PUC-Rio. Copyright &copy; 2007-2017 Lua.org, PUC-Rio.
</p> </p>
<p> <p>
Permission is hereby granted, free of charge, Permission is hereby granted, free of charge,
@@ -1424,7 +1435,7 @@ THE SOFTWARE.
<div id="about"> <div id="about">
<p><small> <p><small>
$Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $ $Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $
</small></p> </small></p>
</div> <!-- id="about" --> </div> <!-- id="about" -->

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpprint.c,v 1.9 2015/06/15 16:09:57 roberto Exp $ ** $Id: lpprint.c,v 1.10 2016/09/13 16:06:03 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -37,13 +37,13 @@ void printcharset (const byte *st) {
} }
static void printcapkind (int kind) { static const char *capkind (int kind) {
const char *const modes[] = { const char *const modes[] = {
"close", "position", "constant", "backref", "close", "position", "constant", "backref",
"argument", "simple", "table", "function", "argument", "simple", "table", "function",
"query", "string", "num", "substitution", "fold", "query", "string", "num", "substitution", "fold",
"runtime", "group"}; "runtime", "group"};
printf("%s", modes[kind]); return modes[kind];
} }
@@ -73,13 +73,12 @@ void printinst (const Instruction *op, const Instruction *p) {
break; break;
} }
case IFullCapture: { case IFullCapture: {
printcapkind(getkind(p)); printf("%s (size = %d) (idx = %d)",
printf(" (size = %d) (idx = %d)", getoff(p), p->i.key); capkind(getkind(p)), getoff(p), p->i.key);
break; break;
} }
case IOpenCapture: { case IOpenCapture: {
printcapkind(getkind(p)); printf("%s (idx = %d)", capkind(getkind(p)), p->i.key);
printf(" (idx = %d)", p->i.key);
break; break;
} }
case ISet: { case ISet: {
@@ -124,8 +123,8 @@ void printpatt (Instruction *p, int n) {
#if defined(LPEG_DEBUG) #if defined(LPEG_DEBUG)
static void printcap (Capture *cap) { static void printcap (Capture *cap) {
printcapkind(cap->kind); printf("%s (idx: %d - size: %d) -> %p\n",
printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s); capkind(cap->kind), cap->idx, cap->siz, cap->s);
} }
@@ -177,7 +176,8 @@ void printtree (TTree *tree, int ident) {
break; break;
} }
case TOpenCall: case TCall: { case TOpenCall: case TCall: {
printf(" key: %d\n", tree->key); assert(sib2(tree)->tag == TRule);
printf(" key: %d (rule: %d)\n", tree->key, sib2(tree)->cap);
break; break;
} }
case TBehind: { case TBehind: {
@@ -186,7 +186,7 @@ void printtree (TTree *tree, int ident) {
break; break;
} }
case TCapture: { case TCapture: {
printf(" cap: %d key: %d n: %d\n", tree->cap, tree->key, tree->u.n); printf(" kind: '%s' key: %d\n", capkind(tree->cap), tree->key);
printtree(sib1(tree), ident + 2); printtree(sib1(tree), ident + 2);
break; break;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lptree.c,v 1.21 2015/09/28 17:01:25 roberto Exp $ ** $Id: lptree.c,v 1.22 2016/09/13 18:10:22 roberto Exp $
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -64,7 +64,7 @@ static void fixonecall (lua_State *L, int postable, TTree *g, TTree *t) {
t->tag = TCall; t->tag = TCall;
t->u.ps = n - (t - g); /* position relative to node */ t->u.ps = n - (t - g); /* position relative to node */
assert(sib2(t)->tag == TRule); assert(sib2(t)->tag == TRule);
sib2(t)->key = t->key; sib2(t)->key = t->key; /* fix rule's key */
} }
@@ -935,7 +935,7 @@ static void buildgrammar (lua_State *L, TTree *grammar, int frule, int n) {
int rulesize; int rulesize;
TTree *rn = gettree(L, ridx, &rulesize); TTree *rn = gettree(L, ridx, &rulesize);
nd->tag = TRule; nd->tag = TRule;
nd->key = 0; nd->key = 0; /* will be fixed when rule is used */
nd->cap = i; /* rule number */ nd->cap = i; /* rule number */
nd->u.ps = rulesize + 1; /* point to next rule */ nd->u.ps = rulesize + 1; /* point to next rule */
memcpy(sib1(nd), rn, rulesize * sizeof(TTree)); /* copy rule */ memcpy(sib1(nd), rn, rulesize * sizeof(TTree)); /* copy rule */
@@ -969,6 +969,11 @@ static int checkloops (TTree *tree) {
} }
/*
** Give appropriate error message for 'verifyrule'. If a rule appears
** twice in 'passed', there is path from it back to itself without
** advancing the subject.
*/
static int verifyerror (lua_State *L, int *passed, int npassed) { static int verifyerror (lua_State *L, int *passed, int npassed) {
int i, j; int i, j;
for (i = npassed - 1; i >= 0; i--) { /* search for a repetition */ for (i = npassed - 1; i >= 0; i--) { /* search for a repetition */
@@ -990,6 +995,8 @@ static int verifyerror (lua_State *L, int *passed, int npassed) {
** is only relevant if the first is nullable. ** is only relevant if the first is nullable.
** Parameter 'nb' works as an accumulator, to allow tail calls in ** Parameter 'nb' works as an accumulator, to allow tail calls in
** choices. ('nb' true makes function returns true.) ** choices. ('nb' true makes function returns true.)
** Parameter 'passed' is a list of already visited rules, 'npassed'
** counts the elements in 'passed'.
** Assume ktable at the top of the stack. ** Assume ktable at the top of the stack.
*/ */
static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed, static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed,

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lptree.h,v 1.2 2013/03/24 13:51:12 roberto Exp $ ** $Id: lptree.h,v 1.3 2016/09/13 18:07:51 roberto Exp $
*/ */
#if !defined(lptree_h) #if !defined(lptree_h)
@@ -13,38 +13,43 @@
** types of trees ** types of trees
*/ */
typedef enum TTag { typedef enum TTag {
TChar = 0, TSet, TAny, /* standard PEG elements */ TChar = 0, /* 'n' = char */
TTrue, TFalse, TSet, /* the set is stored in next CHARSETSIZE bytes */
TRep, TAny,
TSeq, TChoice, TTrue,
TNot, TAnd, TFalse,
TCall, TRep, /* 'sib1'* */
TOpenCall, TSeq, /* 'sib1' 'sib2' */
TRule, /* sib1 is rule's pattern, sib2 is 'next' rule */ TChoice, /* 'sib1' / 'sib2' */
TGrammar, /* sib1 is initial (and first) rule */ TNot, /* !'sib1' */
TBehind, /* match behind */ TAnd, /* &'sib1' */
TCapture, /* regular capture */ TCall, /* ktable[key] is rule's key; 'sib2' is rule being called */
TRunTime /* run-time capture */ TOpenCall, /* ktable[key] is rule's key */
TRule, /* ktable[key] is rule's key (but key == 0 for unused rules);
'sib1' is rule's pattern;
'sib2' is next rule; 'cap' is rule's sequential number */
TGrammar, /* 'sib1' is initial (and first) rule */
TBehind, /* 'sib1' is pattern, 'n' is how much to go back */
TCapture, /* captures: 'cap' is kind of capture (enum 'CapKind');
ktable[key] is Lua value associated with capture;
'sib1' is capture body */
TRunTime /* run-time capture: 'key' is Lua function;
'sib1' is capture body */
} TTag; } TTag;
/* number of siblings for each tree */
extern const byte numsiblings[];
/* /*
** Tree trees ** Tree trees
** The first sibling of a tree (if there is one) is immediately after ** The first child of a tree (if there is one) is immediately after
** the tree. A reference to a second sibling (ps) is its position ** the tree. A reference to a second child (ps) is its position
** relative to the position of the tree itself. A key in ktable ** relative to the position of the tree itself.
** uses the (unique) address of the original tree that created that
** entry. NULL means no data.
*/ */
typedef struct TTree { typedef struct TTree {
byte tag; byte tag;
byte cap; /* kind of capture (if it is a capture) */ byte cap; /* kind of capture (if it is a capture) */
unsigned short key; /* key in ktable for Lua data (0 if no key) */ unsigned short key; /* key in ktable for Lua data (0 if no key) */
union { union {
int ps; /* occasional second sibling */ int ps; /* occasional second child */
int n; /* occasional counter */ int n; /* occasional counter */
} u; } u;
} TTree; } TTree;
@@ -61,10 +66,10 @@ typedef struct Pattern {
} Pattern; } Pattern;
/* number of siblings for each tree */ /* number of children for each tree */
extern const byte numsiblings[]; extern const byte numsiblings[];
/* access to siblings */ /* access to children */
#define sib1(t) ((t) + 1) #define sib1(t) ((t) + 1)
#define sib2(t) ((t) + (t)->u.ps) #define sib2(t) ((t) + (t)->u.ps)

View File

@@ -1,7 +1,7 @@
/* /*
** $Id: lptypes.h,v 1.14 2015/09/28 17:17:41 roberto Exp $ ** $Id: lptypes.h,v 1.16 2017/01/13 13:33:17 roberto Exp $
** LPeg - PEG pattern matching for Lua ** LPeg - PEG pattern matching for Lua
** Copyright 2007-2015, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007-2017, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy ** written by Roberto Ierusalimschy
*/ */
@@ -19,7 +19,7 @@
#include "lua.h" #include "lua.h"
#define VERSION "1.0.0" #define VERSION "1.0.1"
#define PATTERN_T "lpeg-pattern" #define PATTERN_T "lpeg-pattern"
@@ -55,9 +55,9 @@
#endif #endif
/* maximum number of rules in a grammar */ /* maximum number of rules in a grammar (limited by 'unsigned char') */
#if !defined(MAXRULES) #if !defined(MAXRULES)
#define MAXRULES 1000 #define MAXRULES 250
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lpvm.c,v 1.6 2015/09/28 17:01:25 roberto Exp $ ** $Id: lpvm.c,v 1.9 2016/06/03 20:11:18 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/ */
@@ -45,14 +45,16 @@ typedef struct Stack {
/* /*
** Double the size of the array of captures ** Make the size of the array of captures 'cap' twice as large as needed
** (which is 'captop'). ('n' is the number of new elements.)
*/ */
static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) { static Capture *doublecap (lua_State *L, Capture *cap, int captop,
int n, int ptop) {
Capture *newc; Capture *newc;
if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) if (captop >= INT_MAX/((int)sizeof(Capture) * 2))
luaL_error(L, "too many captures"); luaL_error(L, "too many captures");
newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture));
memcpy(newc, cap, captop * sizeof(Capture)); memcpy(newc, cap, (captop - n) * sizeof(Capture));
lua_replace(L, caplistidx(ptop)); lua_replace(L, caplistidx(ptop));
return newc; return newc;
} }
@@ -113,8 +115,8 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) {
*/ */
static void adddyncaptures (const char *s, Capture *base, int n, int fd) { static void adddyncaptures (const char *s, Capture *base, int n, int fd) {
int i; int i;
/* Cgroup capture is already there */ base[0].kind = Cgroup; /* create group capture */
assert(base[0].kind == Cgroup && base[0].siz == 0); base[0].siz = 0;
base[0].idx = 0; /* make it an anonymous group */ base[0].idx = 0; /* make it an anonymous group */
for (i = 1; i <= n; i++) { /* add runtime captures */ for (i = 1; i <= n; i++) { /* add runtime captures */
base[i].kind = Cruntime; base[i].kind = Cruntime;
@@ -157,10 +159,11 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
lua_pushlightuserdata(L, stackbase); lua_pushlightuserdata(L, stackbase);
for (;;) { for (;;) {
#if defined(DEBUG) #if defined(DEBUG)
printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ", printf("-------------------------------------\n");
s, stack - getstackbase(L, ptop), ndyncap, captop);
printinst(op, p);
printcaplist(capture, capture + captop); printcaplist(capture, capture + captop);
printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ",
s, (int)(stack - getstackbase(L, ptop)), ndyncap, captop);
printinst(op, p);
#endif #endif
assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop); assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop);
switch ((Opcode)p->i.code) { switch ((Opcode)p->i.code) {
@@ -284,6 +287,9 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
ndyncap -= removedyncap(L, capture, stack->caplevel, captop); ndyncap -= removedyncap(L, capture, stack->caplevel, captop);
captop = stack->caplevel; captop = stack->caplevel;
p = stack->p; p = stack->p;
#if defined(DEBUG)
printf("**FAIL**\n");
#endif
continue; continue;
} }
case ICloseRunTime: { case ICloseRunTime: {
@@ -293,16 +299,19 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop; cs.s = o; cs.L = L; 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 */
fr -= rem; /* 'rem' items were popped from Lua stack */ fr -= rem; /* 'rem' items were popped from Lua stack */
res = resdyncaptures(L, fr, s - o, e - o); /* get result */ res = resdyncaptures(L, fr, s - o, e - o); /* get result */
if (res == -1) /* fail? */ if (res == -1) /* fail? */
goto fail; goto fail;
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 - rem; /* update number of dynamic captures */ ndyncap += n; /* update number of dynamic captures */
if (n > 0) { /* any new capture? */ if (n > 0) { /* any new capture? */
if (fr + n >= SHRT_MAX)
luaL_error(L, "too many results in match-time capture");
if ((captop += n + 2) >= capsize) { if ((captop += n + 2) >= capsize) {
capture = doublecap(L, capture, captop, ptop); capture = doublecap(L, capture, captop, n + 2, ptop);
capsize = 2 * captop; capsize = 2 * captop;
} }
/* add new captures to 'capture' list */ /* add new captures to 'capture' list */
@@ -339,7 +348,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
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) { if (++captop >= capsize) {
capture = doublecap(L, capture, captop, ptop); capture = doublecap(L, capture, captop, 0, ptop);
capsize = 2 * captop; capsize = 2 * captop;
} }
p++; p++;

View File

@@ -10,7 +10,7 @@
</head> </head>
<body> <body>
<!-- $Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $ --> <!-- $Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $ -->
<div id="container"> <div id="container">
@@ -406,7 +406,7 @@ of patterns accepted by <code>re</code>.
p = [=[ p = [=[
pattern &lt;- exp !. pattern &lt;- exp !.
exp &lt;- S (alternative / grammar) exp &lt;- S (grammar / alternative)
alternative &lt;- seq ('/' S seq)* alternative &lt;- seq ('/' S seq)*
seq &lt;- prefix* seq &lt;- prefix*
@@ -488,7 +488,7 @@ THE SOFTWARE.
<div id="about"> <div id="about">
<p><small> <p><small>
$Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $ $Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $
</small></p> </small></p>
</div> <!-- id="about" --> </div> <!-- id="about" -->

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env lua #!/usr/bin/env lua
-- $Id: test.lua,v 1.109 2015/09/28 17:01:25 roberto Exp $ -- $Id: test.lua,v 1.112 2017/01/14 18:55:22 roberto Exp $
-- require"strict" -- just to be pedantic -- require"strict" -- just to be pedantic
@@ -202,6 +202,14 @@ do
end end
-- bug: loop in 'hascaptures'
do
local p = m.C(-m.P{m.P'x' * m.V(1) + m.P'y'})
assert(p:match("xxx") == "")
end
-- test for small capture boundary -- test for small capture boundary
for i = 250,260 do for i = 250,260 do
assert(#m.match(m.C(i), string.rep('a', i)) == i) assert(#m.match(m.C(i), string.rep('a', i)) == i)
@@ -517,6 +525,27 @@ assert(m.match(m.Cs((#((#m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
assert(m.match(m.Cs((- -m.P("a") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") assert(m.match(m.Cs((- -m.P("a") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
assert(m.match(m.Cs((-((-m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") assert(m.match(m.Cs((-((-m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
-- fixed length
do
-- 'and' predicate using fixed length
local p = m.C(#("a" * (m.P("bd") + "cd")) * 2)
assert(p:match("acd") == "ac")
p = #m.P{ "a" * m.V(2), m.P"b" } * 2
assert(p:match("abc") == 3)
p = #(m.P"abc" * m.B"c")
assert(p:match("abc") == 1 and not p:match("ab"))
p = m.P{ "a" * m.V(2), m.P"b"^1 }
checkerr("pattern may not have fixed length", m.B, p)
p = "abc" * (m.P"b"^1 + m.P"a"^0)
checkerr("pattern may not have fixed length", m.B, p)
end
p = -m.P'a' * m.Cc(1) + -m.P'b' * m.Cc(2) + -m.P'c' * m.Cc(3) p = -m.P'a' * m.Cc(1) + -m.P'b' * m.Cc(2) + -m.P'c' * m.Cc(3)
assert(p:match('a') == 2 and p:match('') == 1 and p:match('b') == 1) assert(p:match('a') == 2 and p:match('') == 1 and p:match('b') == 1)
@@ -1098,6 +1127,32 @@ do
assert(c == 11) assert(c == 11)
end end
-- Return a match-time capture that returns 'n' captures
local function manyCmt (n)
return m.Cmt("a", function ()
local a = {}; for i = 1, n do a[i] = n - i end
return true, unpack(a)
end)
end
-- bug in 1.0: failed match-time that used previous match-time results
do
local x
local function aux (...) x = #{...}; return false end
local res = {m.match(m.Cmt(manyCmt(20), aux) + manyCmt(10), "a")}
assert(#res == 10 and res[1] == 9 and res[10] == 0)
end
-- bug in 1.0: problems with math-times returning too many captures
do
local lim = 2^11 - 10
local res = {m.match(manyCmt(lim), "a")}
assert(#res == lim and res[1] == lim - 1 and res[lim] == 0)
checkerr("too many", m.match, manyCmt(2^15), "a")
end
p = (m.P(function () return true, "a" end) * 'a' p = (m.P(function () return true, "a" end) * 'a'
+ m.P(function (s, i) return i, "aa", 20 end) * 'b' + m.P(function (s, i) return i, "aa", 20 end) * 'b'
+ m.P(function (s,i) if i <= #s then return i, "aaa" end end) * 1)^0 + m.P(function (s,i) if i <= #s then return i, "aaa" end end) * 1)^0

View File

@@ -73,19 +73,28 @@ _query(const char * name) {
return NULL; return NULL;
} }
static int static void *
_open_sym(struct skynet_module *mod) { get_api(struct skynet_module *mod, const char *api_name) {
size_t name_size = strlen(mod->name); size_t name_size = strlen(mod->name);
char tmp[name_size + 9]; // create/init/release/signal , longest name is release (7) size_t api_size = strlen(api_name);
char tmp[name_size + api_size + 1];
memcpy(tmp, mod->name, name_size); memcpy(tmp, mod->name, name_size);
strcpy(tmp+name_size, "_create"); memcpy(tmp+name_size, api_name, api_size+1);
mod->create = dlsym(mod->module, tmp); char *ptr = strrchr(tmp, '.');
strcpy(tmp+name_size, "_init"); if (ptr == NULL) {
mod->init = dlsym(mod->module, tmp); ptr = tmp;
strcpy(tmp+name_size, "_release"); } else {
mod->release = dlsym(mod->module, tmp); ptr = ptr + 1;
strcpy(tmp+name_size, "_signal"); }
mod->signal = dlsym(mod->module, tmp); return dlsym(mod->module, ptr);
}
static int
open_sym(struct skynet_module *mod) {
mod->create = get_api(mod, "_create");
mod->init = get_api(mod, "_init");
mod->release = get_api(mod, "_release");
mod->signal = get_api(mod, "_signal");
return mod->init == NULL; return mod->init == NULL;
} }
@@ -107,7 +116,7 @@ skynet_module_query(const char * name) {
M->m[index].name = name; M->m[index].name = name;
M->m[index].module = dl; M->m[index].module = dl;
if (_open_sym(&M->m[index]) == 0) { if (open_sym(&M->m[index]) == 0) {
M->m[index].name = skynet_strdup(name); M->m[index].name = skynet_strdup(name);
M->count ++; M->count ++;
result = &M->m[index]; result = &M->m[index];