mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
update lpeg to 0.12.1
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lpcap.c,v 1.4 2013/03/21 20:25:12 roberto Exp $
|
** $Id: lpcap.c,v 1.5 2014/12/12 16:58:47 roberto Exp $
|
||||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -462,7 +462,7 @@ static int pushcapture (CapState *cs) {
|
|||||||
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 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lpcode.c,v 1.18 2013/04/12 16:30:33 roberto Exp $
|
** $Id: lpcode.c,v 1.21 2014/12/12 17:01:29 roberto Exp $
|
||||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -33,26 +33,30 @@ static const Charset *fullset = &fullset_;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether a charset is empty (IFail), singleton (IChar),
|
** Check whether a charset is empty (returns IFail), singleton (IChar),
|
||||||
** full (IAny), or none of those (ISet).
|
** full (IAny), or none of those (ISet). When singleton, '*c' returns
|
||||||
|
** which character it is. (When generic set, the set was the input,
|
||||||
|
** so there is no need to return it.)
|
||||||
*/
|
*/
|
||||||
static Opcode charsettype (const byte *cs, int *c) {
|
static Opcode charsettype (const byte *cs, int *c) {
|
||||||
int count = 0;
|
int count = 0; /* number of characters in the set */
|
||||||
int i;
|
int i;
|
||||||
int candidate = -1; /* candidate position for a char */
|
int candidate = -1; /* candidate position for the singleton char */
|
||||||
for (i = 0; i < CHARSETSIZE; i++) {
|
for (i = 0; i < CHARSETSIZE; i++) { /* for each byte */
|
||||||
int b = cs[i];
|
int b = cs[i];
|
||||||
if (b == 0) {
|
if (b == 0) { /* is byte empty? */
|
||||||
if (count > 1) return ISet; /* else set is still empty */
|
if (count > 1) /* was set neither empty nor singleton? */
|
||||||
|
return ISet; /* neither full nor empty nor singleton */
|
||||||
|
/* else set is still empty or singleton */
|
||||||
}
|
}
|
||||||
else if (b == 0xFF) {
|
else if (b == 0xFF) { /* is byte full? */
|
||||||
if (count < (i * BITSPERCHAR))
|
if (count < (i * BITSPERCHAR)) /* was set not full? */
|
||||||
return ISet;
|
return ISet; /* neither full nor empty nor singleton */
|
||||||
else count += BITSPERCHAR; /* set is still full */
|
else count += BITSPERCHAR; /* set is still full */
|
||||||
}
|
}
|
||||||
else if ((b & (b - 1)) == 0) { /* byte has only one bit? */
|
else if ((b & (b - 1)) == 0) { /* has byte only one bit? */
|
||||||
if (count > 0)
|
if (count > 0) /* was set not empty? */
|
||||||
return ISet; /* set is neither full nor empty */
|
return ISet; /* neither full nor empty nor singleton */
|
||||||
else { /* set has only one char till now; track it */
|
else { /* set has only one char till now; track it */
|
||||||
count++;
|
count++;
|
||||||
candidate = i;
|
candidate = i;
|
||||||
@@ -77,6 +81,7 @@ static Opcode charsettype (const byte *cs, int *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A few basic operations on Charsets
|
** A few basic operations on Charsets
|
||||||
*/
|
*/
|
||||||
@@ -84,16 +89,11 @@ static void cs_complement (Charset *cs) {
|
|||||||
loopset(i, cs->cs[i] = ~cs->cs[i]);
|
loopset(i, cs->cs[i] = ~cs->cs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int cs_equal (const byte *cs1, const byte *cs2) {
|
static int cs_equal (const byte *cs1, const byte *cs2) {
|
||||||
loopset(i, if (cs1[i] != cs2[i]) return 0);
|
loopset(i, if (cs1[i] != cs2[i]) return 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** computes whether sets cs1 and cs2 are disjoint
|
|
||||||
*/
|
|
||||||
static int cs_disjoint (const Charset *cs1, const Charset *cs2) {
|
static int cs_disjoint (const Charset *cs1, const Charset *cs2) {
|
||||||
loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;)
|
loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -101,7 +101,8 @@ static int cs_disjoint (const Charset *cs1, const Charset *cs2) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Convert a 'char' pattern (TSet, TChar, TAny) to a charset
|
** If 'tree' is a 'char' pattern (TSet, TChar, TAny), convert it into a
|
||||||
|
** charset and return 1; else return 0.
|
||||||
*/
|
*/
|
||||||
int tocharset (TTree *tree, Charset *cs) {
|
int tocharset (TTree *tree, Charset *cs) {
|
||||||
switch (tree->tag) {
|
switch (tree->tag) {
|
||||||
@@ -116,7 +117,7 @@ int tocharset (TTree *tree, Charset *cs) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case TAny: {
|
case TAny: {
|
||||||
loopset(i, cs->cs[i] = 0xFF); /* add all to the set */
|
loopset(i, cs->cs[i] = 0xFF); /* add all characters to the set */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
default: return 0;
|
default: return 0;
|
||||||
@@ -125,13 +126,16 @@ int tocharset (TTree *tree, Charset *cs) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Checks whether a pattern has captures
|
** Check whether a pattern tree has captures
|
||||||
*/
|
*/
|
||||||
int hascaptures (TTree *tree) {
|
int hascaptures (TTree *tree) {
|
||||||
tailcall:
|
tailcall:
|
||||||
switch (tree->tag) {
|
switch (tree->tag) {
|
||||||
case TCapture: case TRunTime:
|
case TCapture: case TRunTime:
|
||||||
return 1;
|
return 1;
|
||||||
|
case TCall:
|
||||||
|
tree = sib2(tree); goto tailcall; /* return hascaptures(sib2(tree)); */
|
||||||
|
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)); */
|
||||||
@@ -161,7 +165,7 @@ int hascaptures (TTree *tree) {
|
|||||||
** p is nullable => nullable(p)
|
** p is nullable => nullable(p)
|
||||||
** nofail(p) => p cannot fail
|
** nofail(p) => p cannot fail
|
||||||
** The function assumes that TOpenCall is not nullable;
|
** The function assumes that TOpenCall is not nullable;
|
||||||
** this will be checked again when the grammar is fixed.)
|
** this will be checked again when the grammar is fixed.
|
||||||
** Run-time captures can do whatever they want, so the result
|
** Run-time captures can do whatever they want, so the result
|
||||||
** is conservative.
|
** is conservative.
|
||||||
*/
|
*/
|
||||||
@@ -198,7 +202,7 @@ int checkaux (TTree *tree, int pred) {
|
|||||||
case TCall: /* return checkaux(sib2(tree), pred); */
|
case TCall: /* return checkaux(sib2(tree), pred); */
|
||||||
tree = sib2(tree); goto tailcall;
|
tree = sib2(tree); goto tailcall;
|
||||||
default: assert(0); return 0;
|
default: assert(0); return 0;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -245,16 +249,20 @@ int fixedlenx (TTree *tree, int count, int len) {
|
|||||||
/*
|
/*
|
||||||
** Computes the 'first set' of a pattern.
|
** Computes the 'first set' of a pattern.
|
||||||
** The result is a conservative aproximation:
|
** The result is a conservative aproximation:
|
||||||
** match p ax -> x' for some x ==> a in first(p).
|
** match p ax -> x (for some x) ==> a belongs to first(p)
|
||||||
|
** or
|
||||||
|
** a not in first(p) ==> match p ax -> fail (for all x)
|
||||||
|
**
|
||||||
** The set 'follow' is the first set of what follows the
|
** The set 'follow' is the first set of what follows the
|
||||||
** pattern (full set if nothing follows it).
|
** pattern (full set if nothing follows it).
|
||||||
** The function returns 0 when this set can be used for
|
**
|
||||||
** tests that avoid the pattern altogether.
|
** The function returns 0 when this resulting set can be used for
|
||||||
|
** test instructions that avoid the pattern altogether.
|
||||||
** A non-zero return can happen for two reasons:
|
** A non-zero return can happen for two reasons:
|
||||||
** 1) match p '' -> '' ==> returns 1.
|
** 1) match p '' -> '' ==> return has bit 1 set
|
||||||
** (tests cannot be used because they always fail for an empty input)
|
** (tests cannot be used because they would always fail for an empty input);
|
||||||
** 2) there is a match-time capture ==> returns 2.
|
** 2) there is a match-time capture ==> return has bit 2 set
|
||||||
** (match-time captures should not be avoided by optimizations)
|
** (optimizations should not bypass match-time captures).
|
||||||
*/
|
*/
|
||||||
static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
||||||
tailcall:
|
tailcall:
|
||||||
@@ -265,7 +273,7 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
|||||||
}
|
}
|
||||||
case TTrue: {
|
case TTrue: {
|
||||||
loopset(i, firstset->cs[i] = follow->cs[i]);
|
loopset(i, firstset->cs[i] = follow->cs[i]);
|
||||||
return 1;
|
return 1; /* accepts the empty string */
|
||||||
}
|
}
|
||||||
case TFalse: {
|
case TFalse: {
|
||||||
loopset(i, firstset->cs[i] = 0);
|
loopset(i, firstset->cs[i] = 0);
|
||||||
@@ -280,7 +288,8 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
|||||||
}
|
}
|
||||||
case TSeq: {
|
case TSeq: {
|
||||||
if (!nullable(sib1(tree))) {
|
if (!nullable(sib1(tree))) {
|
||||||
/* return getfirst(sib1(tree), fullset, firstset); */
|
/* when p1 is not nullable, p2 has nothing to contribute;
|
||||||
|
return getfirst(sib1(tree), fullset, firstset); */
|
||||||
tree = sib1(tree); follow = fullset; goto tailcall;
|
tree = sib1(tree); follow = fullset; goto tailcall;
|
||||||
}
|
}
|
||||||
else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */
|
else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */
|
||||||
@@ -324,7 +333,7 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
|||||||
/* else go through */
|
/* else go through */
|
||||||
}
|
}
|
||||||
case TBehind: { /* instruction gives no new information */
|
case TBehind: { /* instruction gives no new information */
|
||||||
/* call 'getfirst' to check for math-time captures */
|
/* call 'getfirst' only to check for math-time captures */
|
||||||
int e = getfirst(sib1(tree), follow, firstset);
|
int e = getfirst(sib1(tree), follow, firstset);
|
||||||
loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */
|
loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */
|
||||||
return e | 1; /* always can accept the empty string */
|
return e | 1; /* always can accept the empty string */
|
||||||
@@ -335,8 +344,8 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If it returns true, then pattern can fail only depending on the next
|
** If 'headfail(tree)' true, then 'tree' can fail only depending on the
|
||||||
** character of the subject
|
** next character of the subject.
|
||||||
*/
|
*/
|
||||||
static int headfail (TTree *tree) {
|
static int headfail (TTree *tree) {
|
||||||
tailcall:
|
tailcall:
|
||||||
@@ -403,9 +412,9 @@ int sizei (const Instruction *i) {
|
|||||||
switch((Opcode)i->i.code) {
|
switch((Opcode)i->i.code) {
|
||||||
case ISet: case ISpan: return CHARSETINSTSIZE;
|
case ISet: case ISpan: return CHARSETINSTSIZE;
|
||||||
case ITestSet: return CHARSETINSTSIZE + 1;
|
case ITestSet: return CHARSETINSTSIZE + 1;
|
||||||
case ITestChar: case ITestAny: case IChoice: case IJmp:
|
case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall:
|
||||||
case ICall: case IOpenCall: case ICommit: case IPartialCommit:
|
case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit:
|
||||||
case IBackCommit: return 2;
|
return 2;
|
||||||
default: return 1;
|
default: return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,7 +432,8 @@ typedef struct CompileState {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** code generation is recursive; 'opt' indicates that the code is
|
** code generation is recursive; 'opt' indicates that the code is
|
||||||
** being generated under a 'IChoice' operator jumping to its end.
|
** being generated under a 'IChoice' operator jumping to its end
|
||||||
|
** (that is, the match is "optional").
|
||||||
** 'tt' points to a previous test protecting this code. 'fl' is
|
** 'tt' points to a previous test protecting this code. 'fl' is
|
||||||
** the follow set of the pattern.
|
** the follow set of the pattern.
|
||||||
*/
|
*/
|
||||||
@@ -431,7 +441,7 @@ static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
|
|||||||
const Charset *fl);
|
const Charset *fl);
|
||||||
|
|
||||||
|
|
||||||
void reallocprog (lua_State *L, Pattern *p, int nsize) {
|
void realloccode (lua_State *L, Pattern *p, int nsize) {
|
||||||
void *ud;
|
void *ud;
|
||||||
lua_Alloc f = lua_getallocf(L, &ud);
|
lua_Alloc f = lua_getallocf(L, &ud);
|
||||||
void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction),
|
void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction),
|
||||||
@@ -446,7 +456,7 @@ void reallocprog (lua_State *L, Pattern *p, int nsize) {
|
|||||||
static int nextinstruction (CompileState *compst) {
|
static int nextinstruction (CompileState *compst) {
|
||||||
int size = compst->p->codesize;
|
int size = compst->p->codesize;
|
||||||
if (compst->ncode >= size)
|
if (compst->ncode >= size)
|
||||||
reallocprog(compst->L, compst->p, size * 2);
|
realloccode(compst->L, compst->p, size * 2);
|
||||||
return compst->ncode++;
|
return compst->ncode++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,6 +472,9 @@ static int addinstruction (CompileState *compst, Opcode op, int aux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add an instruction followed by space for an offset (to be set later)
|
||||||
|
*/
|
||||||
static int addoffsetinst (CompileState *compst, Opcode op) {
|
static int addoffsetinst (CompileState *compst, Opcode op) {
|
||||||
int i = addinstruction(compst, op, 0); /* instruction */
|
int i = addinstruction(compst, op, 0); /* instruction */
|
||||||
addinstruction(compst, (Opcode)0, 0); /* open space for offset */
|
addinstruction(compst, (Opcode)0, 0); /* open space for offset */
|
||||||
@@ -470,6 +483,9 @@ static int addoffsetinst (CompileState *compst, Opcode op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Set the offset of an instruction
|
||||||
|
*/
|
||||||
static void setoffset (CompileState *compst, int instruction, int offset) {
|
static void setoffset (CompileState *compst, int instruction, int offset) {
|
||||||
getinstr(compst, instruction + 1).offset = offset;
|
getinstr(compst, instruction + 1).offset = offset;
|
||||||
}
|
}
|
||||||
@@ -478,7 +494,7 @@ static void setoffset (CompileState *compst, int instruction, int offset) {
|
|||||||
/*
|
/*
|
||||||
** Add a capture instruction:
|
** Add a capture instruction:
|
||||||
** 'op' is the capture instruction; 'cap' the capture kind;
|
** 'op' is the capture instruction; 'cap' the capture kind;
|
||||||
** 'key' the key into ktable; 'aux' is optional offset
|
** 'key' the key into ktable; 'aux' is the optional capture offset
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
static int addinstcap (CompileState *compst, Opcode op, int cap, int key,
|
static int addinstcap (CompileState *compst, Opcode op, int cap, int key,
|
||||||
@@ -494,12 +510,18 @@ static int addinstcap (CompileState *compst, Opcode op, int cap, int key,
|
|||||||
#define target(code,i) ((i) + code[i + 1].offset)
|
#define target(code,i) ((i) + code[i + 1].offset)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Patch 'instruction' to jump to 'target'
|
||||||
|
*/
|
||||||
static void jumptothere (CompileState *compst, int instruction, int target) {
|
static void jumptothere (CompileState *compst, int instruction, int target) {
|
||||||
if (instruction >= 0)
|
if (instruction >= 0)
|
||||||
setoffset(compst, instruction, target - instruction);
|
setoffset(compst, instruction, target - instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Patch 'instruction' to jump to current position
|
||||||
|
*/
|
||||||
static void jumptohere (CompileState *compst, int instruction) {
|
static void jumptohere (CompileState *compst, int instruction) {
|
||||||
jumptothere(compst, instruction, gethere(compst));
|
jumptothere(compst, instruction, gethere(compst));
|
||||||
}
|
}
|
||||||
@@ -863,7 +885,8 @@ static int codeseq1 (CompileState *compst, TTree *p1, TTree *p2,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Main code-generation function: dispatch to auxiliar functions
|
** Main code-generation function: dispatch to auxiliar functions
|
||||||
** according to kind of tree
|
** according to kind of tree. ('needfollow' should return true
|
||||||
|
** only for consructions that use 'fl'.)
|
||||||
*/
|
*/
|
||||||
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
|
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
|
||||||
const Charset *fl) {
|
const Charset *fl) {
|
||||||
@@ -906,6 +929,7 @@ static void peephole (CompileState *compst) {
|
|||||||
Instruction *code = compst->p->code;
|
Instruction *code = compst->p->code;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < compst->ncode; i += sizei(&code[i])) {
|
for (i = 0; i < compst->ncode; i += sizei(&code[i])) {
|
||||||
|
redo:
|
||||||
switch (code[i].i.code) {
|
switch (code[i].i.code) {
|
||||||
case IChoice: case ICall: case ICommit: case IPartialCommit:
|
case IChoice: case ICall: case ICommit: case IPartialCommit:
|
||||||
case IBackCommit: case ITestChar: case ITestSet:
|
case IBackCommit: case ITestChar: case ITestSet:
|
||||||
@@ -927,8 +951,7 @@ static void peephole (CompileState *compst) {
|
|||||||
int fft = finallabel(code, ft);
|
int fft = finallabel(code, ft);
|
||||||
code[i] = code[ft]; /* jump becomes that instruction... */
|
code[i] = code[ft]; /* jump becomes that instruction... */
|
||||||
jumptothere(compst, i, fft); /* but must correct its offset */
|
jumptothere(compst, i, fft); /* but must correct its offset */
|
||||||
i--; /* reoptimize its label */
|
goto redo; /* reoptimize its label */
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
jumptothere(compst, i, ft); /* optimize label */
|
jumptothere(compst, i, ft); /* optimize label */
|
||||||
@@ -950,10 +973,10 @@ static void peephole (CompileState *compst) {
|
|||||||
Instruction *compile (lua_State *L, Pattern *p) {
|
Instruction *compile (lua_State *L, Pattern *p) {
|
||||||
CompileState compst;
|
CompileState compst;
|
||||||
compst.p = p; compst.ncode = 0; compst.L = L;
|
compst.p = p; compst.ncode = 0; compst.L = L;
|
||||||
reallocprog(L, p, 2); /* minimum initial size */
|
realloccode(L, p, 2); /* minimum initial size */
|
||||||
codegen(&compst, p->tree, 0, NOINST, fullset);
|
codegen(&compst, p->tree, 0, NOINST, fullset);
|
||||||
addinstruction(&compst, IEnd, 0);
|
addinstruction(&compst, IEnd, 0);
|
||||||
reallocprog(L, p, compst.ncode); /* set final size */
|
realloccode(L, p, compst.ncode); /* set final size */
|
||||||
peephole(&compst);
|
peephole(&compst);
|
||||||
return p->code;
|
return p->code;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lpcode.h,v 1.5 2013/04/04 21:24:45 roberto Exp $
|
** $Id: lpcode.h,v 1.6 2013/11/28 14:56:02 roberto Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(lpcode_h)
|
#if !defined(lpcode_h)
|
||||||
@@ -17,7 +17,7 @@ int fixedlenx (TTree *tree, int count, int len);
|
|||||||
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);
|
||||||
void reallocprog (lua_State *L, Pattern *p, int nsize);
|
void realloccode (lua_State *L, Pattern *p, int nsize);
|
||||||
int sizei (const Instruction *i);
|
int sizei (const Instruction *i);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- $Id: lpeg.html,v 1.71 2013/04/11 19:17:41 roberto Exp $ -->
|
<!-- $Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $ -->
|
||||||
|
|
||||||
<div id="container">
|
<div id="container">
|
||||||
|
|
||||||
@@ -1375,13 +1375,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-0.12.tar.gz">source code</a>.</p>
|
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-0.12.1.tar.gz">source code</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
<h2><a name="license">License</a></h2>
|
<h2><a name="license">License</a></h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Copyright © 2013 Lua.org, PUC-Rio.
|
Copyright © 2014 Lua.org, PUC-Rio.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Permission is hereby granted, free of charge,
|
Permission is hereby granted, free of charge,
|
||||||
@@ -1419,7 +1419,7 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<p><small>
|
<p><small>
|
||||||
$Id: lpeg.html,v 1.71 2013/04/11 19:17:41 roberto Exp $
|
$Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $
|
||||||
</small></p>
|
</small></p>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lptree.c,v 1.10 2013/04/12 16:30:33 roberto Exp $
|
** $Id: lptree.c,v 1.13 2014/12/12 16:59:10 roberto Exp $
|
||||||
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -209,9 +209,11 @@ static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) {
|
|||||||
/*
|
/*
|
||||||
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
|
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
|
||||||
** create new 'ktable' if necessary. Return index of new element.
|
** create new 'ktable' if necessary. Return index of new element.
|
||||||
|
** If new element is nil, does not add it to table (as it would be
|
||||||
|
** useless) and returns 0, as ktable[0] is always nil.
|
||||||
*/
|
*/
|
||||||
static int addtoktable (lua_State *L, int idx) {
|
static int addtoktable (lua_State *L, int idx) {
|
||||||
if (idx == 0 || lua_isnil(L, idx)) /* no actual value to insert? */
|
if (idx == 0) /* no actual value to insert? */
|
||||||
return 0;
|
return 0;
|
||||||
else {
|
else {
|
||||||
int n;
|
int n;
|
||||||
@@ -220,11 +222,15 @@ static int addtoktable (lua_State *L, int idx) {
|
|||||||
if (n == 0) { /* is it empty/non-existent? */
|
if (n == 0) { /* is it empty/non-existent? */
|
||||||
lua_pop(L, 1); /* remove it */
|
lua_pop(L, 1); /* remove it */
|
||||||
lua_createtable(L, 1, 0); /* create a fresh table */
|
lua_createtable(L, 1, 0); /* create a fresh table */
|
||||||
|
lua_pushvalue(L, -1); /* make a copy */
|
||||||
|
lua_setfenv(L, -3); /* set it as 'ktable' for pattern */
|
||||||
}
|
}
|
||||||
lua_pushvalue(L, idx); /* element to be added */
|
if (!lua_isnil(L, idx)) { /* non-nil value? */
|
||||||
lua_rawseti(L, -2, n + 1);
|
lua_pushvalue(L, idx); /* element to be added */
|
||||||
lua_setfenv(L, -2); /* set it as ktable for pattern */
|
lua_rawseti(L, -2, ++n);
|
||||||
return n + 1;
|
}
|
||||||
|
lua_pop(L, 1); /* remove 'ktable' */
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,7 +531,7 @@ static int lp_choice (lua_State *L) {
|
|||||||
static int lp_star (lua_State *L) {
|
static int lp_star (lua_State *L) {
|
||||||
int size1;
|
int size1;
|
||||||
int n = (int)luaL_checkinteger(L, 2);
|
int n = (int)luaL_checkinteger(L, 2);
|
||||||
TTree *tree1 = gettree(L, 1, &size1);
|
TTree *tree1 = getpatt(L, 1, &size1);
|
||||||
if (n >= 0) { /* seq tree1 (seq tree1 ... (seq tree1 (rep tree1))) */
|
if (n >= 0) { /* seq tree1 (seq tree1 ... (seq tree1 (rep tree1))) */
|
||||||
TTree *tree = newtree(L, (n + 1) * (size1 + 1));
|
TTree *tree = newtree(L, (n + 1) * (size1 + 1));
|
||||||
if (nullable(tree1))
|
if (nullable(tree1))
|
||||||
@@ -634,8 +640,8 @@ static int lp_behind (lua_State *L) {
|
|||||||
TTree *tree;
|
TTree *tree;
|
||||||
TTree *tree1 = getpatt(L, 1, NULL);
|
TTree *tree1 = getpatt(L, 1, NULL);
|
||||||
int n = fixedlen(tree1);
|
int n = fixedlen(tree1);
|
||||||
luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures");
|
|
||||||
luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length");
|
luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length");
|
||||||
|
luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures");
|
||||||
luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind");
|
luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind");
|
||||||
tree = newroot1sib(L, TBehind);
|
tree = newroot1sib(L, TBehind);
|
||||||
tree->u.n = n;
|
tree->u.n = n;
|
||||||
@@ -1139,7 +1145,7 @@ static int lp_type (lua_State *L) {
|
|||||||
int lp_gc (lua_State *L) {
|
int lp_gc (lua_State *L) {
|
||||||
Pattern *p = getpattern(L, 1);
|
Pattern *p = getpattern(L, 1);
|
||||||
if (p->codesize > 0)
|
if (p->codesize > 0)
|
||||||
reallocprog(L, p, 0);
|
realloccode(L, p, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lptypes.h,v 1.8 2013/04/12 16:26:38 roberto Exp $
|
** $Id: lptypes.h,v 1.10 2014/12/12 17:11:35 roberto Exp $
|
||||||
** LPeg - PEG pattern matching for Lua
|
** LPeg - PEG pattern matching for Lua
|
||||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
** Copyright 2007-2014, 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 "0.12"
|
#define VERSION "0.12.1"
|
||||||
|
|
||||||
|
|
||||||
#define PATTERN_T "lpeg-pattern"
|
#define PATTERN_T "lpeg-pattern"
|
||||||
@@ -56,7 +56,9 @@
|
|||||||
|
|
||||||
|
|
||||||
/* maximum number of rules in a grammar */
|
/* maximum number of rules in a grammar */
|
||||||
#define MAXRULES 200
|
#if !defined(MAXRULES)
|
||||||
|
#define MAXRULES 1000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lpvm.h,v 1.2 2013/04/03 20:37:18 roberto Exp $
|
** $Id: lpvm.h,v 1.3 2014/02/21 13:06:41 roberto Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(lpvm_h)
|
#if !defined(lpvm_h)
|
||||||
@@ -49,14 +49,9 @@ typedef union Instruction {
|
|||||||
} Instruction;
|
} Instruction;
|
||||||
|
|
||||||
|
|
||||||
int getposition (lua_State *L, int t, int i);
|
|
||||||
void printpatt (Instruction *p, int n);
|
void printpatt (Instruction *p, int n);
|
||||||
const char *match (lua_State *L, const char *o, const char *s, const char *e,
|
const char *match (lua_State *L, const char *o, const char *s, const char *e,
|
||||||
Instruction *op, Capture *capture, int ptop);
|
Instruction *op, Capture *capture, int ptop);
|
||||||
int verify (lua_State *L, Instruction *op, const Instruction *p,
|
|
||||||
Instruction *e, int postable, int rule);
|
|
||||||
void checkrule (lua_State *L, Instruction *op, int from, int to,
|
|
||||||
int postable, int rule);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
LIBNAME = lpeg
|
LIBNAME = lpeg
|
||||||
LUADIR = /usr/include/lua5.1/
|
LUADIR = ../lua/
|
||||||
|
|
||||||
COPT = -O2
|
COPT = -O2
|
||||||
# COPT = -DLPEG_DEBUG -g
|
# COPT = -DLPEG_DEBUG -g
|
||||||
@@ -22,7 +22,7 @@ CWARNS = -Wall -Wextra -pedantic \
|
|||||||
# -Wunreachable-code \
|
# -Wunreachable-code \
|
||||||
|
|
||||||
|
|
||||||
CFLAGS = $(CWARNS) $(COPT) -ansi -I$(LUADIR) -fPIC
|
CFLAGS = $(CWARNS) $(COPT) -std=c99 -I$(LUADIR) -fPIC
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o
|
FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env lua5.1
|
#!/usr/bin/env lua5.1
|
||||||
|
|
||||||
-- $Id: test.lua,v 1.101 2013/04/12 16:30:33 roberto Exp $
|
-- $Id: test.lua,v 1.105 2014/12/12 17:00:39 roberto Exp $
|
||||||
|
|
||||||
-- require"strict" -- just to be pedantic
|
-- require"strict" -- just to be pedantic
|
||||||
|
|
||||||
@@ -170,8 +170,8 @@ assert(m.match( basiclookfor((#m.P(b) * 1) * m.Cp()), " ( (a)") == 7)
|
|||||||
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "123")}
|
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "123")}
|
||||||
checkeq(a, {"123", "d"})
|
checkeq(a, {"123", "d"})
|
||||||
|
|
||||||
a = {m.match(m.C(digit^1) * "d" * -1 + m.C(letter^1 * m.Cc"l"), "123d")}
|
-- bug in LPeg 0.12 (nil value does not create a 'ktable')
|
||||||
checkeq(a, {"123"})
|
assert(m.match(m.Cc(nil), "") == nil)
|
||||||
|
|
||||||
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "abcd")}
|
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "abcd")}
|
||||||
checkeq(a, {"abcd", "l"})
|
checkeq(a, {"abcd", "l"})
|
||||||
@@ -194,6 +194,16 @@ checkeq(a, {1, 5})
|
|||||||
t = {m.match({[1] = m.C(m.C(1) * m.V(1) + -1)}, "abc")}
|
t = {m.match({[1] = m.C(m.C(1) * m.V(1) + -1)}, "abc")}
|
||||||
checkeq(t, {"abc", "a", "bc", "b", "c", "c", ""})
|
checkeq(t, {"abc", "a", "bc", "b", "c", "c", ""})
|
||||||
|
|
||||||
|
-- bug in 0.12 ('hascapture' did not check for captures inside a rule)
|
||||||
|
do
|
||||||
|
local pat = m.P{
|
||||||
|
'S';
|
||||||
|
S1 = m.C('abc') + 3,
|
||||||
|
S = #m.V('S1') -- rule has capture, but '#' must ignore it
|
||||||
|
}
|
||||||
|
assert(pat:match'abc' == 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- test for small capture boundary
|
-- test for small capture boundary
|
||||||
for i = 250,260 do
|
for i = 250,260 do
|
||||||
@@ -201,9 +211,8 @@ for i = 250,260 do
|
|||||||
assert(#m.match(m.C(m.C(i)), string.rep('a', i)) == i)
|
assert(#m.match(m.C(m.C(i)), string.rep('a', i)) == i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- tests for any*n and any*-n
|
-- tests for any*n and any*-n
|
||||||
for n = 1, 550 do
|
for n = 1, 550, 13 do
|
||||||
local x_1 = string.rep('x', n - 1)
|
local x_1 = string.rep('x', n - 1)
|
||||||
local x = x_1 .. 'a'
|
local x = x_1 .. 'a'
|
||||||
assert(not m.P(n):match(x_1))
|
assert(not m.P(n):match(x_1))
|
||||||
@@ -345,8 +354,9 @@ checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'})
|
|||||||
|
|
||||||
|
|
||||||
-- test for error messages
|
-- test for error messages
|
||||||
local function checkerr (msg, ...)
|
local function checkerr (msg, f, ...)
|
||||||
assert(m.match({ m.P(msg) + 1 * m.V(1) }, select(2, pcall(...))))
|
local st, err = pcall(f, ...)
|
||||||
|
assert(not st and m.match({ m.P(msg) + 1 * m.V(1) }, err))
|
||||||
end
|
end
|
||||||
|
|
||||||
checkerr("rule '1' may be left recursive", m.match, { m.V(1) * 'a' }, "a")
|
checkerr("rule '1' may be left recursive", m.match, { m.V(1) * 'a' }, "a")
|
||||||
@@ -370,6 +380,13 @@ p = {'a',
|
|||||||
}
|
}
|
||||||
checkerr("rule 'a' may be left recursive", m.match, p, "a")
|
checkerr("rule 'a' may be left recursive", m.match, p, "a")
|
||||||
|
|
||||||
|
-- Bug in peephole optimization of LPeg 0.12 (IJmp -> ICommit)
|
||||||
|
-- the next grammar has an original sequence IJmp -> ICommit -> IJmp L1
|
||||||
|
-- that is optimized to ICommit L1
|
||||||
|
|
||||||
|
p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' }
|
||||||
|
assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc')
|
||||||
|
|
||||||
|
|
||||||
-- tests for non-pattern as arguments to pattern functions
|
-- tests for non-pattern as arguments to pattern functions
|
||||||
|
|
||||||
@@ -488,7 +505,10 @@ assert(m.match(1 * m.B(1), 'a') == 2)
|
|||||||
assert(m.match(-m.B(1), 'a') == 1)
|
assert(m.match(-m.B(1), 'a') == 1)
|
||||||
assert(m.match(m.B(250), string.rep('a', 250)) == nil)
|
assert(m.match(m.B(250), string.rep('a', 250)) == nil)
|
||||||
assert(m.match(250 * m.B(250), string.rep('a', 250)) == 251)
|
assert(m.match(250 * m.B(250), string.rep('a', 250)) == 251)
|
||||||
assert(not pcall(m.B, 260))
|
|
||||||
|
-- look-behind with an open call
|
||||||
|
checkerr("pattern may not have fixed length", m.B, m.V'S1')
|
||||||
|
checkerr("too long to look behind", m.B, 260)
|
||||||
|
|
||||||
B = #letter * -m.B(letter) + -letter * m.B(letter)
|
B = #letter * -m.B(letter) + -letter * m.B(letter)
|
||||||
x = m.Ct({ (B * m.Cp())^-1 * (1 * m.V(1) + m.P(true)) })
|
x = m.Ct({ (B * m.Cp())^-1 * (1 * m.V(1) + m.P(true)) })
|
||||||
@@ -555,11 +575,11 @@ assert(not p:match(string.rep("011", 10001)))
|
|||||||
-- this grammar does need backtracking info.
|
-- this grammar does need backtracking info.
|
||||||
local lim = 10000
|
local lim = 10000
|
||||||
p = m.P{ '0' * m.V(1) + '0' }
|
p = m.P{ '0' * m.V(1) + '0' }
|
||||||
assert(not pcall(m.match, p, string.rep("0", lim)))
|
checkerr("too many pending", m.match, p, string.rep("0", lim))
|
||||||
m.setmaxstack(2*lim)
|
m.setmaxstack(2*lim)
|
||||||
assert(not pcall(m.match, p, string.rep("0", lim)))
|
checkerr("too many pending", m.match, p, string.rep("0", lim))
|
||||||
m.setmaxstack(2*lim + 4)
|
m.setmaxstack(2*lim + 4)
|
||||||
assert(pcall(m.match, p, string.rep("0", lim)))
|
assert(m.match(p, string.rep("0", lim)) == lim + 1)
|
||||||
|
|
||||||
-- this repetition should not need stack space (only the call does)
|
-- this repetition should not need stack space (only the call does)
|
||||||
p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' }
|
p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' }
|
||||||
@@ -588,10 +608,10 @@ print("+")
|
|||||||
|
|
||||||
|
|
||||||
-- tests for argument captures
|
-- tests for argument captures
|
||||||
assert(not pcall(m.Carg, 0))
|
checkerr("invalid argument", m.Carg, 0)
|
||||||
assert(not pcall(m.Carg, -1))
|
checkerr("invalid argument", m.Carg, -1)
|
||||||
assert(not pcall(m.Carg, 2^18))
|
checkerr("invalid argument", m.Carg, 2^18)
|
||||||
assert(not pcall(m.match, m.Carg(1), 'a', 1))
|
checkerr("absent extra argument #1", m.match, m.Carg(1), 'a', 1)
|
||||||
assert(m.match(m.Carg(1), 'a', 1, print) == print)
|
assert(m.match(m.Carg(1), 'a', 1, print) == print)
|
||||||
x = {m.match(m.Carg(1) * m.Carg(2), '', 1, 10, 20)}
|
x = {m.match(m.Carg(1) * m.Carg(2), '', 1, 10, 20)}
|
||||||
checkeq(x, {10, 20})
|
checkeq(x, {10, 20})
|
||||||
@@ -644,14 +664,16 @@ assert(m.match(p, "aaaa") == 5)
|
|||||||
assert(m.match(p, "abaa") == 2)
|
assert(m.match(p, "abaa") == 2)
|
||||||
assert(not m.match(p, "baaa"))
|
assert(not m.match(p, "baaa"))
|
||||||
|
|
||||||
assert(not pcall(m.match, function () return 2^20 end, s))
|
checkerr("invalid position", m.match, function () return 2^20 end, s)
|
||||||
assert(not pcall(m.match, function () return 0 end, s))
|
checkerr("invalid position", m.match, function () return 0 end, s)
|
||||||
assert(not pcall(m.match, function (s, i) return i - 1 end, s))
|
checkerr("invalid position", m.match, function (s, i) return i - 1 end, s)
|
||||||
assert(not pcall(m.match, m.P(1)^0 * function (_, i) return i - 1 end, s))
|
checkerr("invalid position", m.match,
|
||||||
|
m.P(1)^0 * function (_, i) return i - 1 end, s)
|
||||||
assert(m.match(m.P(1)^0 * function (_, i) return i end * -1, s))
|
assert(m.match(m.P(1)^0 * function (_, i) return i end * -1, s))
|
||||||
assert(not pcall(m.match, m.P(1)^0 * function (_, i) return i + 1 end, s))
|
checkerr("invalid position", m.match,
|
||||||
|
m.P(1)^0 * function (_, i) return i + 1 end, s)
|
||||||
assert(m.match(m.P(function (s, i) return s:len() + 1 end) * -1, s))
|
assert(m.match(m.P(function (s, i) return s:len() + 1 end) * -1, s))
|
||||||
assert(not pcall(m.match, m.P(function (s, i) return s:len() + 2 end) * -1, s))
|
checkerr("invalid position", m.match, m.P(function (s, i) return s:len() + 2 end) * -1, s)
|
||||||
assert(not m.match(m.P(function (s, i) return s:len() end) * -1, s))
|
assert(not m.match(m.P(function (s, i) return s:len() end) * -1, s))
|
||||||
assert(m.match(m.P(1)^0 * function (_, i) return true end, s) ==
|
assert(m.match(m.P(1)^0 * function (_, i) return true end, s) ==
|
||||||
string.len(s) + 1)
|
string.len(s) + 1)
|
||||||
@@ -734,9 +756,9 @@ assert(m.match(m.Cs((m.P(1) / ".xx")^0), "abcd") == ".xx.xx.xx.xx")
|
|||||||
assert(m.match(m.Cp() * m.P(3) * m.Cp()/"%2%1%1 - %0 ", "abcde") ==
|
assert(m.match(m.Cp() * m.P(3) * m.Cp()/"%2%1%1 - %0 ", "abcde") ==
|
||||||
"411 - abc ")
|
"411 - abc ")
|
||||||
|
|
||||||
assert(pcall(m.match, m.P(1)/"%0", "abc"))
|
assert(m.match(m.P(1)/"%0", "abc") == "a")
|
||||||
assert(not pcall(m.match, m.P(1)/"%1", "abc")) -- out of range
|
checkerr("invalid capture index", m.match, m.P(1)/"%1", "abc")
|
||||||
assert(not pcall(m.match, m.P(1)/"%9", "abc")) -- out of range
|
checkerr("invalid capture index", m.match, m.P(1)/"%9", "abc")
|
||||||
|
|
||||||
p = m.C(1)
|
p = m.C(1)
|
||||||
p = p * p; p = p * p; p = p * p * m.C(1) / "%9 - %1"
|
p = p * p; p = p * p; p = p * p * m.C(1) / "%9 - %1"
|
||||||
@@ -754,7 +776,7 @@ assert(m.match(m.C(1)^0 / "%9-%1-%0-%3", s) == "9-1-" .. s .. "-3")
|
|||||||
p = m.Cc('alo') * m.C(1) / "%1 - %2 - %1"
|
p = m.Cc('alo') * m.C(1) / "%1 - %2 - %1"
|
||||||
assert(p:match'x' == 'alo - x - alo')
|
assert(p:match'x' == 'alo - x - alo')
|
||||||
|
|
||||||
assert(not pcall(m.match, m.Cc(true) / "%1", "a"))
|
checkerr("invalid capture value (a boolean)", m.match, m.Cc(true) / "%1", "a")
|
||||||
|
|
||||||
-- long strings for string capture
|
-- long strings for string capture
|
||||||
l = 10000
|
l = 10000
|
||||||
@@ -782,35 +804,37 @@ checkeq(t, {a="b", c="du", xux="yuy"})
|
|||||||
|
|
||||||
-- errors in accumulator capture
|
-- errors in accumulator capture
|
||||||
|
|
||||||
-- very long match (forces fold to be a pair open-close) producing with
|
|
||||||
-- no initial capture
|
-- no initial capture
|
||||||
assert(not pcall(m.match, m.Cf(m.P(500), print), string.rep('a', 600)))
|
checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa')
|
||||||
|
-- no initial capture (very long match forces fold to be a pair open-close)
|
||||||
|
checkerr("no initial value", m.match, m.Cf(m.P(500), print),
|
||||||
|
string.rep('a', 600))
|
||||||
|
|
||||||
-- nested capture produces no initial value
|
-- nested capture produces no initial value
|
||||||
assert(not pcall(m.match, m.Cf(m.P(1) / {}, print), "alo"))
|
checkerr("no initial value", m.match, m.Cf(m.P(1) / {}, print), "alo")
|
||||||
|
|
||||||
|
|
||||||
-- tests for loop checker
|
-- tests for loop checker
|
||||||
|
|
||||||
local function haveloop (p)
|
local function isnullable (p)
|
||||||
assert(not pcall(function (p) return p^0 end, m.P(p)))
|
checkerr("may accept empty string", function (p) return p^0 end, m.P(p))
|
||||||
end
|
end
|
||||||
|
|
||||||
haveloop(m.P("x")^-4)
|
isnullable(m.P("x")^-4)
|
||||||
assert(m.match(((m.P(0) + 1) * m.S"al")^0, "alo") == 3)
|
assert(m.match(((m.P(0) + 1) * m.S"al")^0, "alo") == 3)
|
||||||
assert(m.match((("x" + #m.P(1))^-4 * m.S"al")^0, "alo") == 3)
|
assert(m.match((("x" + #m.P(1))^-4 * m.S"al")^0, "alo") == 3)
|
||||||
haveloop("")
|
isnullable("")
|
||||||
haveloop(m.P("x")^0)
|
isnullable(m.P("x")^0)
|
||||||
haveloop(m.P("x")^-1)
|
isnullable(m.P("x")^-1)
|
||||||
haveloop(m.P("x") + 1 + 2 + m.P("a")^-1)
|
isnullable(m.P("x") + 1 + 2 + m.P("a")^-1)
|
||||||
haveloop(-m.P("ab"))
|
isnullable(-m.P("ab"))
|
||||||
haveloop(- -m.P("ab"))
|
isnullable(- -m.P("ab"))
|
||||||
haveloop(# #(m.P("ab") + "xy"))
|
isnullable(# #(m.P("ab") + "xy"))
|
||||||
haveloop(- #m.P("ab")^0)
|
isnullable(- #m.P("ab")^0)
|
||||||
haveloop(# -m.P("ab")^1)
|
isnullable(# -m.P("ab")^1)
|
||||||
haveloop(#m.V(3))
|
isnullable(#m.V(3))
|
||||||
haveloop(m.V(3) + m.V(1) + m.P('a')^-1)
|
isnullable(m.V(3) + m.V(1) + m.P('a')^-1)
|
||||||
haveloop({[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(0)})
|
isnullable({[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(0)})
|
||||||
assert(m.match(m.P{[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(1)}^0, "abc")
|
assert(m.match(m.P{[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(1)}^0, "abc")
|
||||||
== 3)
|
== 3)
|
||||||
assert(m.match(m.P""^-3, "a") == 1)
|
assert(m.match(m.P""^-3, "a") == 1)
|
||||||
@@ -894,8 +918,8 @@ print"+"
|
|||||||
|
|
||||||
|
|
||||||
-- tests for back references
|
-- tests for back references
|
||||||
assert(not pcall(m.match, m.Cb('x'), ''))
|
checkerr("back reference 'x' not found", m.match, m.Cb('x'), '')
|
||||||
assert(not pcall(m.match, m.Cg(1, 'a') * m.Cb('b'), 'a'))
|
checkerr("back reference 'b' not found", m.match, m.Cg(1, 'a') * m.Cb('b'), 'a')
|
||||||
|
|
||||||
p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k"))
|
p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k"))
|
||||||
t = p:match("ab")
|
t = p:match("ab")
|
||||||
@@ -1370,8 +1394,7 @@ assert(rev:match"0123456789" == "9876543210")
|
|||||||
-- testing error messages in re
|
-- testing error messages in re
|
||||||
|
|
||||||
local function errmsg (p, err)
|
local function errmsg (p, err)
|
||||||
local s, msg = pcall(re.compile, p)
|
checkerr(err, re.compile, p)
|
||||||
assert(not s and string.find(msg, err))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
errmsg('aaaa', "rule 'aaaa'")
|
errmsg('aaaa', "rule 'aaaa'")
|
||||||
|
|||||||
Reference in New Issue
Block a user