From 28dc8403a12e4287330f6b6f4e02bee0b3c1af3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E9=A3=8E?= Date: Tue, 4 Sep 2012 11:25:10 +0800 Subject: [PATCH] remove lpeg & pbc --- Makefile | 23 - lpeg/HISTORY | 77 - lpeg/lpeg-128.gif | Bin 4923 -> 0 bytes lpeg/lpeg.c | 2405 -------------------------------- lpeg/lpeg.h | 38 - lpeg/lpeg.html | 1423 ------------------- lpeg/lpeg.o | Bin 48688 -> 0 bytes lpeg/makefile | 42 - lpeg/re.html | 486 ------- lpeg/re.lua | 248 ---- lpeg/test.lua | 1188 ---------------- lua-protobuf/Makefile | 14 - lua-protobuf/README | 2 - lua-protobuf/addressbook.proto | 39 - lua-protobuf/alloc.c | 84 -- lua-protobuf/alloc.h | 25 - lua-protobuf/array.c | 139 -- lua-protobuf/array.h | 31 - lua-protobuf/bootstrap.c | 303 ---- lua-protobuf/bootstrap.h | 10 - lua-protobuf/context.c | 278 ---- lua-protobuf/context.h | 140 -- lua-protobuf/decode.c | 349 ----- lua-protobuf/descriptor.pbc.h | 271 ---- lua-protobuf/map.c | 477 ------- lua-protobuf/map.h | 33 - lua-protobuf/pattern.c | 1131 --------------- lua-protobuf/pattern.h | 26 - lua-protobuf/pbc-lua.c | 1005 ------------- lua-protobuf/pbc.h | 104 -- lua-protobuf/proto.c | 252 ---- lua-protobuf/proto.h | 64 - lua-protobuf/register.c | 335 ----- lua-protobuf/rmessage.c | 455 ------ lua-protobuf/stringpool.c | 60 - lua-protobuf/stringpool.h | 10 - lua-protobuf/test.lua | 30 - lua-protobuf/varint.c | 110 -- lua-protobuf/varint.h | 20 - lua-protobuf/wmessage.c | 509 ------- lualib/protobuf.lua | 592 -------- lualib/protobuf/parser.lua | 397 ------ 42 files changed, 13225 deletions(-) delete mode 100644 lpeg/HISTORY delete mode 100644 lpeg/lpeg-128.gif delete mode 100644 lpeg/lpeg.c delete mode 100644 lpeg/lpeg.h delete mode 100644 lpeg/lpeg.html delete mode 100644 lpeg/lpeg.o delete mode 100644 lpeg/makefile delete mode 100644 lpeg/re.html delete mode 100644 lpeg/re.lua delete mode 100755 lpeg/test.lua delete mode 100644 lua-protobuf/Makefile delete mode 100644 lua-protobuf/README delete mode 100644 lua-protobuf/addressbook.proto delete mode 100644 lua-protobuf/alloc.c delete mode 100644 lua-protobuf/alloc.h delete mode 100644 lua-protobuf/array.c delete mode 100644 lua-protobuf/array.h delete mode 100644 lua-protobuf/bootstrap.c delete mode 100644 lua-protobuf/bootstrap.h delete mode 100644 lua-protobuf/context.c delete mode 100644 lua-protobuf/context.h delete mode 100644 lua-protobuf/decode.c delete mode 100644 lua-protobuf/descriptor.pbc.h delete mode 100644 lua-protobuf/map.c delete mode 100644 lua-protobuf/map.h delete mode 100644 lua-protobuf/pattern.c delete mode 100644 lua-protobuf/pattern.h delete mode 100644 lua-protobuf/pbc-lua.c delete mode 100644 lua-protobuf/pbc.h delete mode 100644 lua-protobuf/proto.c delete mode 100644 lua-protobuf/proto.h delete mode 100644 lua-protobuf/register.c delete mode 100644 lua-protobuf/rmessage.c delete mode 100644 lua-protobuf/stringpool.c delete mode 100644 lua-protobuf/stringpool.h delete mode 100644 lua-protobuf/test.lua delete mode 100644 lua-protobuf/varint.c delete mode 100644 lua-protobuf/varint.h delete mode 100644 lua-protobuf/wmessage.c delete mode 100644 lualib/protobuf.lua delete mode 100644 lualib/protobuf/parser.lua diff --git a/Makefile b/Makefile index 9c352e38..8386e155 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,6 @@ all : \ service/connection.so \ client \ lualib/socket.so \ - lualib/lpeg.so \ - lualib/protobuf.so \ lualib/int64.so \ service/master.so \ service/multicast.so \ @@ -69,27 +67,6 @@ service/connection.so : connection/connection.c connection/main.c lualib/socket.so : connection/lua-socket.c gcc $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iconnection -lualib/lpeg.so : lpeg/lpeg.c - gcc $(CFLAGS) $(SHARED) -O2 $^ -o $@ -Ilpeg - -PROTOBUFSRC = \ - lua-protobuf/context.c \ - lua-protobuf/varint.c \ - lua-protobuf/array.c \ - lua-protobuf/pattern.c \ - lua-protobuf/register.c \ - lua-protobuf/proto.c \ - lua-protobuf/map.c \ - lua-protobuf/alloc.c \ - lua-protobuf/rmessage.c \ - lua-protobuf/wmessage.c \ - lua-protobuf/bootstrap.c \ - lua-protobuf/stringpool.c \ - lua-protobuf/decode.c - -lualib/protobuf.so : $(PROTOBUFSRC) lua-protobuf/pbc-lua.c - gcc $(CFLAGS) $(SHARED) -O2 $^ -o $@ - lualib/int64.so : lua-int64/int64.c gcc $(CFLAGS) $(SHARED) -O2 $^ -o $@ diff --git a/lpeg/HISTORY b/lpeg/HISTORY deleted file mode 100644 index 0b8b7577..00000000 --- a/lpeg/HISTORY +++ /dev/null @@ -1,77 +0,0 @@ -HISTORY for LPeg 0.10 - -* Changes from version 0.9 to 0.10 - ------------------------------- - + backtrack stack has configurable size - + better error messages - + Notation for non-terminals in 're' back to A instead o - + experimental look-behind pattern - + support for external extensions - + works with Lua 5.2 - + consumes less C stack - - - "and" predicates do not keep captures - -* Changes from version 0.8 to 0.9 - ------------------------------- - + The accumulator capture was replaced by a fold capture; - programs that used the old 'lpeg.Ca' will need small changes. - + Some support for character classes from old C locales. - + A new named-group capture. - -* Changes from version 0.7 to 0.8 - ------------------------------- - + New "match-time" capture. - + New "argument capture" that allows passing arguments into the pattern. - + Better documentation for 're'. - + Several small improvements for 're'. - + The 're' module has an incompatibility with previous versions: - now, any use of a non-terminal must be enclosed in angle brackets - (like ). - -* Changes from version 0.6 to 0.7 - ------------------------------- - + Several improvements in module 're': - - better documentation; - - support for most captures (all but accumulator); - - limited repetitions p{n,m}. - + Small improvements in efficiency. - + Several small bugs corrected (special thanks to Hans Hagen - and Taco Hoekwater). - -* Changes from version 0.5 to 0.6 - ------------------------------- - + Support for non-numeric indices in grammars. - + Some bug fixes (thanks to the luatex team). - + Some new optimizations; (thanks to Mike Pall). - + A new page layout (thanks to Andre Carregal). - + Minimal documentation for module 're'. - -* Changes from version 0.4 to 0.5 - ------------------------------- - + Several optimizations. - + lpeg.P now accepts booleans. - + Some new examples. - + A proper license. - + Several small improvements. - -* Changes from version 0.3 to 0.4 - ------------------------------- - + Static check for loops in repetitions and grammars. - + Removed label option in captures. - + The implementation of captures uses less memory. - -* Changes from version 0.2 to 0.3 - ------------------------------- - + User-defined patterns in Lua. - + Several new captures. - -* Changes from version 0.1 to 0.2 - ------------------------------- - + Several small corrections. - + Handles embedded zeros like any other character. - + Capture "name" can be any Lua value. - + Unlimited number of captures. - + Match gets an optional initial position. - -(end of HISTORY) diff --git a/lpeg/lpeg-128.gif b/lpeg/lpeg-128.gif deleted file mode 100644 index bbf5e78b88e71044bd341a2476dcec756c252ae4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4923 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 -#include -#include -#include -#include - -#include "lua.h" -#include "lauxlib.h" - -#include "lpeg.h" - - -#define VERSION "0.10" -#define PATTERN_T "lpeg-pattern" -#define MAXSTACKIDX "lpeg-maxstack" - - -/* -** compatibility with Lua 5.2 -*/ -#if (LUA_VERSION_NUM == 502) - -#undef lua_equal -#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) - -#undef lua_getfenv -#define lua_getfenv lua_getuservalue -#undef lua_setfenv -#define lua_setfenv lua_setuservalue - -#undef lua_objlen -#define lua_objlen lua_rawlen - -#undef luaL_register -#define luaL_register(L,n,f) \ - { if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); } - -#endif - - - -/* initial size for call/backtrack stack */ -#define INITBACK 100 - -/* default maximum size for call/backtrack stack */ -#define MAXBACK INITBACK - -/* size for call/backtrack stack for verifier */ -#define MAXBACKVER 200 - -/* initial size for capture's list */ -#define INITCAPSIZE 32 - - -/* index, on Lua stack, for subject */ -#define SUBJIDX 2 - -/* number of fixed arguments to 'match' (before capture arguments) */ -#define FIXEDARGS 3 - -/* index, on Lua stack, for substitution value cache */ -#define subscache(cs) ((cs)->ptop + 1) - -/* index, on Lua stack, for capture list */ -#define caplistidx(ptop) ((ptop) + 2) - -/* index, on Lua stack, for pattern's fenv */ -#define penvidx(ptop) ((ptop) + 3) - -/* index, on Lua stack, for backtracking stack */ -#define stackidx(ptop) ((ptop) + 4) - - - -typedef unsigned char byte; - - -#define CHARSETSIZE ((UCHAR_MAX/CHAR_BIT) + 1) - - -typedef byte Charset[CHARSETSIZE]; - - -/* Virtual Machine's instructions */ -typedef enum Opcode { - IAny, IChar, ISet, ISpan, - IBack, - IRet, IEnd, - IChoice, IJmp, ICall, IOpenCall, - ICommit, IPartialCommit, IBackCommit, IFailTwice, IFail, IGiveup, - IFunc, - IFullCapture, IEmptyCapture, IEmptyCaptureIdx, - IOpenCapture, ICloseCapture, ICloseRunTime -} Opcode; - - -#define ISJMP 0x1 -#define ISCHECK 0x2 -#define ISFIXCHECK 0x4 -#define ISNOFAIL 0x8 -#define ISCAPTURE 0x10 -#define ISMOVABLE 0x20 -#define ISFENVOFF 0x40 - -static const int opproperties[] = { - /* IAny */ ISCHECK | ISFIXCHECK | ISJMP, - /* IChar */ ISCHECK | ISFIXCHECK | ISJMP, - /* ISet */ ISCHECK | ISFIXCHECK | ISJMP, - /* ISpan */ ISNOFAIL, - /* IBack */ 0, - /* IRet */ 0, - /* IEnd */ 0, - /* IChoice */ ISJMP, - /* IJmp */ ISJMP | ISNOFAIL, - /* ICall */ ISJMP, - /* IOpenCall */ ISFENVOFF, - /* ICommit */ ISJMP, - /* IPartialCommit */ ISJMP, - /* IBackCommit */ ISJMP, - /* IFailTwice */ 0, - /* IFail */ 0, - /* IGiveup */ 0, - /* IFunc */ ISCHECK | ISJMP, - /* IFullCapture */ ISCAPTURE | ISNOFAIL | ISFENVOFF, - /* IEmptyCapture */ ISCAPTURE | ISNOFAIL | ISMOVABLE, - /* IEmptyCaptureIdx */ISCAPTURE | ISNOFAIL | ISMOVABLE | ISFENVOFF, - /* IOpenCapture */ ISCAPTURE | ISNOFAIL | ISMOVABLE | ISFENVOFF, - /* ICloseCapture */ ISCAPTURE | ISNOFAIL | ISMOVABLE | ISFENVOFF, - /* ICloseRunTime */ ISCAPTURE | ISFENVOFF -}; - - -typedef union Instruction { - struct Inst { - byte code; - byte aux; - short offset; - } i; - PattFunc f; - int iv; - byte buff[1]; -} Instruction; - -static const Instruction giveup = {{IGiveup, 0, 0}}; - -#define getkind(op) ((op)->i.aux & 0xF) -#define getoff(op) (((op)->i.aux >> 4) & 0xF) - -#define dest(p,x) ((x) + ((p)+(x))->i.offset) - -#define MAXOFF 0xF -#define MAXAUX 0xFF - -/* maximum size (in elements) for a pattern */ -#define MAXPATTSIZE (SHRT_MAX - 10) - - -#define isprop(op,p) (opproperties[(op)->i.code] & (p)) -#define isjmp(op) (isprop(op, ISJMP) && (op)->i.offset != 0) -#define iscapture(op) isprop(op, ISCAPTURE) -#define ischeck(op) (isprop(op, ISCHECK) && (op)->i.offset == 0) -#define isfixcheck(op) (isprop(op, ISFIXCHECK) && (op)->i.offset == 0) -#define istest(op) (isprop(op, ISCHECK) && (op)->i.offset != 0) -#define isnofail(op) isprop(op, ISNOFAIL) -#define ismovable(op) isprop(op, ISMOVABLE) -#define isfenvoff(op) isprop(op, ISFENVOFF) - - -/* kinds of captures */ -typedef enum CapKind { - Cclose, Cposition, Cconst, Cbackref, Carg, Csimple, Ctable, Cfunction, - Cquery, Cstring, Csubst, Cfold, Cruntime, Cgroup -} CapKind; - -#define iscapnosize(k) ((k) == Cposition || (k) == Cconst) - - -typedef struct Capture { - const char *s; /* position */ - short idx; - byte kind; - byte siz; -} Capture; - - -/* size (in elements) for an instruction plus extra l bytes */ -#define instsize(l) (((l) + sizeof(Instruction) - 1)/sizeof(Instruction) + 1) - - -/* size (in elements) for a ISet instruction */ -#define CHARSETINSTSIZE instsize(CHARSETSIZE) - -/* size (in elements) for a IFunc instruction */ -#define funcinstsize(p) ((p)->i.aux + 2) - - -#define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) b; } - - -#define testchar(st,c) (((int)(st)[((c) >> 3)] & (1 << ((c) & 7)))) -#define setchar(st,c) ((st)[(c) >> 3] |= (1 << ((c) & 7))) - - -static int target (Instruction *p, int i); - - -static int sizei (const Instruction *i) { - switch((Opcode)i->i.code) { - case ISet: case ISpan: return CHARSETINSTSIZE; - case IFunc: return funcinstsize(i); - default: return 1; - } -} - - -static const char *val2str (lua_State *L, int idx) { - const char *k = lua_tostring(L, idx); - if (k != NULL) - return lua_pushfstring(L, "rule '%s'", k); - else - return lua_pushfstring(L, "rule ", luaL_typename(L, idx)); -} - - -static int getposition (lua_State *L, int t, int i) { - int res; - lua_getfenv(L, -1); - lua_rawgeti(L, -1, i); /* get key from pattern's environment */ - lua_gettable(L, t); /* get position from positions table */ - res = lua_tointeger(L, -1); - if (res == 0) { /* key has no registered position? */ - lua_rawgeti(L, -2, i); /* get key again */ - return luaL_error(L, "%s is not defined in given grammar", val2str(L, -1)); - } - lua_pop(L, 2); /* remove environment and position */ - return res; -} - - -/* -** {====================================================== -** Printing patterns (for debugging) -** ======================================================= -*/ - - -static void printcharset (const Charset st) { - int i; - printf("["); - for (i = 0; i <= UCHAR_MAX; i++) { - int first = i; - while (testchar(st, i) && i <= UCHAR_MAX) i++; - if (i - 1 == first) /* unary range? */ - printf("(%02x)", first); - else if (i - 1 > first) /* non-empty range? */ - printf("(%02x-%02x)", first, i - 1); - } - printf("]"); -} - - -static void printcapkind (int kind) { - const char *const modes[] = { - "close", "position", "constant", "backref", - "argument", "simple", "table", "function", - "query", "string", "substitution", "fold", - "runtime", "group"}; - printf("%s", modes[kind]); -} - - -static void printjmp (const Instruction *op, const Instruction *p) { - printf("-> "); - if (p->i.offset == 0) printf("FAIL"); - else printf("%d", (int)(dest(0, p) - op)); -} - - -static void printinst (const Instruction *op, const Instruction *p) { - const char *const names[] = { - "any", "char", "set", "span", "back", - "ret", "end", - "choice", "jmp", "call", "open_call", - "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup", - "func", - "fullcapture", "emptycapture", "emptycaptureidx", "opencapture", - "closecapture", "closeruntime" - }; - printf("%02ld: %s ", (long)(p - op), names[p->i.code]); - switch ((Opcode)p->i.code) { - case IChar: { - printf("'%c'", p->i.aux); - printjmp(op, p); - break; - } - case IAny: { - printf("* %d", p->i.aux); - printjmp(op, p); - break; - } - case IFullCapture: case IOpenCapture: - case IEmptyCapture: case IEmptyCaptureIdx: - case ICloseCapture: case ICloseRunTime: { - printcapkind(getkind(p)); - printf("(n = %d) (off = %d)", getoff(p), p->i.offset); - break; - } - case ISet: { - printcharset((p+1)->buff); - printjmp(op, p); - break; - } - case ISpan: { - printcharset((p+1)->buff); - break; - } - case IOpenCall: { - printf("-> %d", p->i.offset); - break; - } - case IChoice: { - printjmp(op, p); - printf(" (%d)", p->i.aux); - break; - } - case IJmp: case ICall: case ICommit: - case IPartialCommit: case IBackCommit: { - printjmp(op, p); - break; - } - default: break; - } - printf("\n"); -} - - -static void printpatt (Instruction *p) { - Instruction *op = p; - for (;;) { - printinst(op, p); - if ((Opcode)p->i.code == IEnd) break; - p += sizei(p); - } -} - - -#if 0 -static void printcap (Capture *cap) { - printcapkind(cap->kind); - printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s); -} - - -static void printcaplist (Capture *cap) { - for (; cap->s; cap++) printcap(cap); -} -#endif - -/* }====================================================== */ - - -/* -** {====================================================== -** Virtual Machine -** ======================================================= -*/ - - -typedef struct Stack { - const char *s; - const Instruction *p; - int caplevel; -} Stack; - - -#define getstackbase(L, ptop) ((Stack *)lua_touserdata(L, stackidx(ptop))) - - -static int runtimecap (lua_State *L, Capture *close, Capture *ocap, - const char *o, const char *s, int ptop); - - -static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) { - Capture *newc; - if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) - luaL_error(L, "too many captures"); - newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); - memcpy(newc, cap, captop * sizeof(Capture)); - lua_replace(L, caplistidx(ptop)); - return newc; -} - - -static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) { - Stack *stack = getstackbase(L, ptop); - Stack *newstack; - int n = *stacklimit - stack; - int max, newn; - lua_getfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); - max = lua_tointeger(L, -1); - lua_pop(L, 1); - if (n >= max) - luaL_error(L, "too many pending calls/choices"); - newn = 2*n; if (newn > max) newn = max; - newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack)); - memcpy(newstack, stack, n * sizeof(Stack)); - lua_replace(L, stackidx(ptop)); - *stacklimit = newstack + newn; - return newstack + n; - -} - - -static void adddyncaptures (const char *s, Capture *base, int n, int fd) { - int i; - assert(base[0].kind == Cruntime && base[0].siz == 0); - base[0].idx = fd; /* first returned capture */ - for (i = 1; i < n; i++) { /* add extra captures */ - base[i].siz = 1; /* mark it as closed */ - base[i].s = s; - base[i].kind = Cruntime; - base[i].idx = fd + i; /* stack index */ - } - base[n].kind = Cclose; /* add closing entry */ - base[n].siz = 1; - base[n].s = s; -} - - -#define condfailed(p) { int f = p->i.offset; if (f) p+=f; else goto fail; } - -static const char *match (lua_State *L, - const char *o, const char *s, const char *e, - Instruction *op, Capture *capture, int ptop) { - Stack stackbase[INITBACK]; - Stack *stacklimit = stackbase + INITBACK; - Stack *stack = stackbase; /* point to first empty slot in stack */ - int capsize = INITCAPSIZE; - int captop = 0; /* point to first empty slot in captures */ - const Instruction *p = op; - stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++; - lua_pushlightuserdata(L, stackbase); - for (;;) { -#if defined(DEBUG) - printf("s: |%s| stck: %d c: %d ", - s, stack - getstackbase(L, ptop), captop); - printinst(op, p); -#endif - switch ((Opcode)p->i.code) { - case IEnd: { - assert(stack == getstackbase(L, ptop) + 1); - capture[captop].kind = Cclose; - capture[captop].s = NULL; - return s; - } - case IGiveup: { - assert(stack == getstackbase(L, ptop)); - return NULL; - } - case IRet: { - assert(stack > getstackbase(L, ptop) && (stack - 1)->s == NULL); - p = (--stack)->p; - continue; - } - case IAny: { - int n = p->i.aux; - if (n <= e - s) { p++; s += n; } - else condfailed(p); - continue; - } - case IChar: { - if ((byte)*s == p->i.aux && s < e) { p++; s++; } - else condfailed(p); - continue; - } - case ISet: { - int c = (byte)*s; - if (testchar((p+1)->buff, c) && s < e) - { p += CHARSETINSTSIZE; s++; } - else condfailed(p); - continue; - } - case IBack: { - int n = p->i.aux; - if (n > s - o) goto fail; - s -= n; p++; - continue; - } - case ISpan: { - for (; s < e; s++) { - int c = (byte)*s; - if (!testchar((p+1)->buff, c)) break; - } - p += CHARSETINSTSIZE; - continue; - } - case IFunc: { - const char *r = (p+1)->f(s, e, o, (p+2)->buff); - if (r != NULL) { s = r; p += funcinstsize(p); } - else condfailed(p); - continue; - } - case IJmp: { - p += p->i.offset; - continue; - } - case IChoice: { - if (stack == stacklimit) - stack = doublestack(L, &stacklimit, ptop); - stack->p = dest(0, p); - stack->s = s - p->i.aux; - stack->caplevel = captop; - stack++; - p++; - continue; - } - case ICall: { - if (stack == stacklimit) - stack = doublestack(L, &stacklimit, ptop); - stack->s = NULL; - stack->p = p + 1; /* save return address */ - stack++; - p += p->i.offset; - continue; - } - case ICommit: { - assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); - stack--; - p += p->i.offset; - continue; - } - case IPartialCommit: { - assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); - (stack - 1)->s = s; - (stack - 1)->caplevel = captop; - p += p->i.offset; - continue; - } - case IBackCommit: { - assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); - s = (--stack)->s; - captop = stack->caplevel; - p += p->i.offset; - continue; - } - case IFailTwice: - assert(stack > getstackbase(L, ptop)); - stack--; - /* go through */ - case IFail: - fail: { /* pattern failed: try to backtrack */ - do { /* remove pending calls */ - assert(stack > getstackbase(L, ptop)); - s = (--stack)->s; - } while (s == NULL); - captop = stack->caplevel; - p = stack->p; - continue; - } - case ICloseRunTime: { - int fr = lua_gettop(L) + 1; /* stack index of first result */ - int ncap = runtimecap(L, capture + captop, capture, o, s, ptop); - lua_Integer res = lua_tointeger(L, fr) - 1; /* offset */ - int n = lua_gettop(L) - fr; /* number of new captures */ - if (res == -1) { /* may not be a number */ - if (!lua_toboolean(L, fr)) { /* false value? */ - lua_settop(L, fr - 1); /* remove results */ - goto fail; /* and fail */ - } - else if (lua_isboolean(L, fr)) /* true? */ - res = s - o; /* keep current position */ - } - if (res < s - o || res > e - o) - luaL_error(L, "invalid position returned by match-time capture"); - s = o + res; /* update current position */ - captop -= ncap; /* remove nested captures */ - lua_remove(L, fr); /* remove first result (offset) */ - if (n > 0) { /* captures? */ - if ((captop += n + 1) >= capsize) { - capture = doublecap(L, capture, captop, ptop); - capsize = 2 * captop; - } - adddyncaptures(s, capture + captop - n - 1, n, fr); - } - p++; - continue; - } - case ICloseCapture: { - const char *s1 = s - getoff(p); - assert(captop > 0); - if (capture[captop - 1].siz == 0 && - s1 - capture[captop - 1].s < UCHAR_MAX) { - capture[captop - 1].siz = s1 - capture[captop - 1].s + 1; - p++; - continue; - } - else { - capture[captop].siz = 1; /* mark entry as closed */ - goto capture; - } - } - case IEmptyCapture: case IEmptyCaptureIdx: - capture[captop].siz = 1; /* mark entry as closed */ - goto capture; - case IOpenCapture: - capture[captop].siz = 0; /* mark entry as open */ - goto capture; - case IFullCapture: - capture[captop].siz = getoff(p) + 1; /* save capture size */ - capture: { - capture[captop].s = s - getoff(p); - capture[captop].idx = p->i.offset; - capture[captop].kind = getkind(p); - if (++captop >= capsize) { - capture = doublecap(L, capture, captop, ptop); - capsize = 2 * captop; - } - p++; - continue; - } - case IOpenCall: { - lua_rawgeti(L, penvidx(ptop), p->i.offset); - luaL_error(L, "reference to %s outside a grammar", val2str(L, -1)); - } - default: assert(0); return NULL; - } - } -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Verifier -** ======================================================= -*/ - - -/* -** check whether pattern may go from 'p' to 'e' without consuming any -** input. Raises an error if it detects a left recursion. 'op' points -** the beginning of the pattern. If pattern belongs to a grammar, -** 'rule' is the stack index where is its corresponding key (only for -** error messages) and 'posttable' is the stack index with a table -** mapping rule keys to the position of their code in the pattern. -*/ -static int verify (lua_State *L, Instruction *op, const Instruction *p, - Instruction *e, int postable, int rule) { - static const char dummy[] = ""; - Stack back[MAXBACKVER]; - int backtop = 0; /* point to first empty slot in back */ - while (p != e) { - switch ((Opcode)p->i.code) { - case IRet: { - p = back[--backtop].p; - continue; - } - case IChoice: { - if (backtop >= MAXBACKVER) - return luaL_error(L, "too many pending calls/choices"); - back[backtop].p = dest(0, p); - back[backtop++].s = dummy; - p++; - continue; - } - case ICall: { - assert((p + 1)->i.code != IRet); /* no tail call */ - if (backtop >= MAXBACKVER) - return luaL_error(L, "too many pending calls/choices"); - back[backtop].s = NULL; - back[backtop++].p = p + 1; - goto dojmp; - } - case IOpenCall: { - int i; - if (postable == 0) /* grammar still not fixed? */ - goto fail; /* to be verified later */ - for (i = 0; i < backtop; i++) { - if (back[i].s == NULL && back[i].p == p + 1) - return luaL_error(L, "%s is left recursive", val2str(L, rule)); - } - if (backtop >= MAXBACKVER) - return luaL_error(L, "too many pending calls/choices"); - back[backtop].s = NULL; - back[backtop++].p = p + 1; - p = op + getposition(L, postable, p->i.offset); - continue; - } - case IBackCommit: - case ICommit: { - assert(backtop > 0 && p->i.offset > 0); - backtop--; - goto dojmp; - } - case IPartialCommit: { - assert(backtop > 0); - if (p->i.offset > 0) goto dojmp; /* forward jump */ - else { /* loop will be detected when checking corresponding rule */ - assert(postable != 0); - backtop--; - p++; /* just go on now */ - continue; - } - } - case IBack: { - if (p->i.aux == 1 && isfixcheck(p + 1)) { /* char test? */ - p++; /* skip back instruction */ - p += sizei(p); /* skip char test */ - } - else { /* standard lookbehind code */ - assert((Opcode)(p - 1)->i.code == IChoice); /* look behind */ - backtop--; - p += (p - 1)->i.offset; - assert((Opcode)(p - 1)->i.code == IFail); /* look behind */ - } - continue; - } - case IAny: - case IChar: - case ISet: { - const Instruction *next = p + sizei(p); - if ((Opcode)next->i.code == IBack) - p = next + 1; /* continue after the back instruction */ - else if (p->i.offset == 0) goto fail; - else /* jump */ - p += p->i.offset; - continue; - } - case IJmp: - dojmp: { - p += p->i.offset; - continue; - } - case IFailTwice: /* 'not' predicate */ - goto fail; /* body could have failed; try to backtrack it */ - case IFail: { - if (p > op && (p - 1)->i.code == IBackCommit) { /* 'and' predicate? */ - p++; /* pretend it succeeded and go ahead */ - continue; - } - /* else failed: go through */ - } - fail: { /* pattern failed: try to backtrack */ - do { - if (backtop-- == 0) - return 1; /* no more backtracking */ - } while (back[backtop].s == NULL); - p = back[backtop].p; - continue; - } - case ISpan: - case IOpenCapture: case ICloseCapture: - case IEmptyCapture: case IEmptyCaptureIdx: - case IFullCapture: { - p += sizei(p); - continue; - } - case ICloseRunTime: { - goto fail; /* be liberal in this case */ - } - case IFunc: { - const char *r = (p+1)->f(dummy, dummy, dummy, (p+2)->buff); - if (r != NULL) { p += funcinstsize(p); } - else condfailed(p); - continue; - } - case IEnd: /* cannot happen (should stop before it) */ - default: assert(0); return 0; - } - } - assert(backtop == 0); - return 0; -} - - -static void checkrule (lua_State *L, Instruction *op, int from, int to, - int postable, int rule) { - int i; - int lastopen = 0; /* more recent OpenCall seen in the code */ - for (i = from; i < to; i += sizei(op + i)) { - if (op[i].i.code == IPartialCommit && op[i].i.offset < 0) { /* loop? */ - int start = dest(op, i); - assert(op[start - 1].i.code == IChoice && - dest(op, start - 1) == target(op, i + 1)); - if (start <= lastopen) { /* loop does contain an open call? */ - if (!verify(L, op, op + start, op + i, postable, rule)) /* check body */ - luaL_error(L, "possible infinite loop in %s", val2str(L, rule)); - } - } - else if (op[i].i.code == IOpenCall) - lastopen = i; - } - assert(op[i - 1].i.code == IRet); - verify(L, op, op + from, op + to - 1, postable, rule); -} - - - - -/* }====================================================== */ - - -/* -** {====================================================== -** Building Patterns -** ======================================================= -*/ - -enum charsetanswer { NOINFO, ISCHARSET, VALIDSTARTS }; - -typedef struct CharsetTag { - enum charsetanswer tag; - Charset cs; -} CharsetTag; - - -static Instruction *getpatt (lua_State *L, int idx, int *size); - - -static void check2test (Instruction *p, int n) { - assert(ischeck(p) && n != 0); - p->i.offset = n; -} - - -/* -** invert array slice p[0]-p[e] (both inclusive) -*/ -static void invert (Instruction *p, int e) { - int i; - for (i = 0; i < e; i++, e--) { - Instruction temp = p[i]; - p[i] = p[e]; - p[e] = temp; - } -} - - -/* -** rotate array slice p[0]-p[e] (both inclusive) 'n' steps -** to the 'left' -*/ -static void rotate (Instruction *p, int e, int n) { - invert(p, n - 1); - invert(p + n, e - n); - invert(p, e); -} - - -#define op_step(p) ((p)->i.code == IAny ? (p)->i.aux : 1) - - -static int skipchecks (Instruction *p, int up, int *pn) { - int i, n = 0; - for (i = 0; isfixcheck(p + i); i += sizei(p + i)) { - int st = op_step(p + i); - if (n + st > MAXOFF - up) break; - n += st; - } - *pn = n; - return i; -} - - -#define ismovablecap(op) (ismovable(op) && getoff(op) < MAXOFF) - -static void optimizecaptures (Instruction *p) { - int i; - int limit = 0; - for (i = 0; p[i].i.code != IEnd; i += sizei(p + i)) { - if (isjmp(p + i) && dest(p, i) >= limit) - limit = dest(p, i) + 1; /* do not optimize jump targets */ - else if (i >= limit && ismovablecap(p + i) && isfixcheck(p + i + 1)) { - int end, n, j; /* found a border capture|check */ - int maxoff = getoff(p + i); - int start = i; - /* find first capture in the group */ - while (start > limit && ismovablecap(p + start - 1)) { - start--; - if (getoff(p + start) > maxoff) maxoff = getoff(p + start); - } - end = skipchecks(p + i + 1, maxoff, &n) + i; /* find last check */ - if (n == 0) continue; /* first check is too big to move across */ - assert(n <= MAXOFF && start <= i && i < end); - for (j = start; j <= i; j++) - p[j].i.aux += (n << 4); /* correct offset of captures to be moved */ - rotate(p + start, end - start, i - start + 1); /* move them up */ - i = end; - assert(isfixcheck(p + start) && iscapture(p + i)); - } - } -} - - -static int target (Instruction *p, int i) { - while (p[i].i.code == IJmp) i += p[i].i.offset; - return i; -} - - -static void optimizejumps (Instruction *p) { - int i; - for (i = 0; p[i].i.code != IEnd; i += sizei(p + i)) { - if (isjmp(p + i)) - p[i].i.offset = target(p, dest(p, i)) - i; - } -} - - -static void optimizechoice (Instruction *p) { - assert(p->i.code == IChoice); - if (isfixcheck(p + 1)) { - int lc = sizei(p + 1); - rotate(p, lc, 1); - assert(isfixcheck(p) && (p + lc)->i.code == IChoice); - (p + lc)->i.aux = op_step(p); - check2test(p, (p + lc)->i.offset); - (p + lc)->i.offset -= lc; - } -} - - -/* -** A 'headfail' pattern is a pattern that can only fails in its first -** instruction, which must be a check. -*/ -static int isheadfail (Instruction *p) { - if (!ischeck(p)) return 0; - /* check that other operations cannot fail */ - for (p += sizei(p); p->i.code != IEnd; p += sizei(p)) - if (!isnofail(p)) return 0; - return 1; -} - - -#define checkpattern(L, idx) ((Instruction *)luaL_checkudata(L, idx, PATTERN_T)) - - -/* -** Return the number of elements in the ktable of a pattern. -** in Lua 5.2, default "environment" for patterns is nil, not -** a table. Treat it as an empty table. -*/ -static int ktablelen (lua_State *L, int idx) { - if (!lua_istable(L, idx)) return 0; - else return lua_objlen(L, idx); -} - - -/* -** join the elements of the ktable from pattern 'p1' into the ktable of -** the pattern at the top of the stack ('p'). If 'p1' has no elements, -** 'p' keeps its original ktable. If 'p' has no elements, it shares -** 'p1' ktable. Otherwise, this function creates a new ktable for 'p'. -** Return the offset of original 'p' elements in the new ktable. -*/ -static int jointable (lua_State *L, int p1) { - int n, n1, i; - lua_getfenv(L, p1); - n1 = ktablelen(L, -1); /* number of elements in p1's env */ - lua_getfenv(L, -2); - if (n1 == 0 || lua_equal(L, -2, -1)) { - lua_pop(L, 2); - return 0; /* no need to change anything */ - } - n = ktablelen(L, -1); /* number of elements in p's env */ - if (n == 0) { - lua_pop(L, 1); /* removes p env */ - lua_setfenv(L, -2); /* p now shares p1's env */ - return 0; /* no need to correct anything */ - } - lua_createtable(L, n + n1, 0); - /* stack: p; p1 env; p env; new p env */ - for (i = 1; i <= n; i++) { - lua_rawgeti(L, -2, i); - lua_rawseti(L, -2, i); - } - for (i = 1; i <= n1; i++) { - lua_rawgeti(L, -3, i); - lua_rawseti(L, -2, n + i); - } - lua_setfenv(L, -4); /* new table becomes p env */ - lua_pop(L, 2); /* remove p1 env and old p env */ - return n; -} - - -#define copypatt(p1,p2,sz) memcpy(p1, p2, (sz) * sizeof(Instruction)); - -#define pattsize(L,idx) (lua_objlen(L, idx)/sizeof(Instruction) - 1) - - -static int addpatt (lua_State *L, Instruction *p, int p1idx) { - Instruction *p1 = (Instruction *)lua_touserdata(L, p1idx); - int sz = pattsize(L, p1idx); - int corr = jointable(L, p1idx); - copypatt(p, p1, sz + 1); - if (corr != 0) { - Instruction *px; - for (px = p; px < p + sz; px += sizei(px)) { - if (isfenvoff(px) && px->i.offset != 0) - px->i.offset += corr; - } - } - return sz; -} - - -static void setinstaux (Instruction *i, Opcode op, int offset, int aux) { - assert(aux <= MAXAUX); - i->i.code = op; - i->i.offset = offset; - i->i.aux = aux; -} - -#define setinst(i,op,off) setinstaux(i,op,off,0) - -#define setinstcap(i,op,idx,k,n) setinstaux(i,op,idx,((k) | ((n) << 4))) - - -/* -** create a new ktable for pattern at the stack top, mapping -** '1' to the value at stack position 'vidx'. -*/ -static int value2fenv (lua_State *L, int vidx) { - lua_createtable(L, 1, 0); - lua_pushvalue(L, vidx); - lua_rawseti(L, -2, 1); - lua_setfenv(L, -2); - return 1; -} - - -static Instruction *newpatt (lua_State *L, size_t n) { - Instruction *p; - if (n >= MAXPATTSIZE - 1) - luaL_error(L, "pattern too big"); - p = (Instruction *)lua_newuserdata(L, (n + 1) * sizeof(Instruction)); - luaL_getmetatable(L, PATTERN_T); - lua_setmetatable(L, -2); - setinst(p + n, IEnd, 0); - return p; -} - - -static void fillcharset (Instruction *p, Charset cs) { - switch (p[0].i.code) { - case ISet: { - loopset(i, cs[i] = p[1].buff[i]); - break; - } - case IChar: { - loopset(i, cs[i] = 0); - setchar(cs, p[0].i.aux); - break; - } - default: { /* any char may start unhandled instructions */ - loopset(i, cs[i] = 0xff); - break; - } - } -} - - -/* -** Function 'tocharset' gets information about which chars may be a -** valid start for a pattern. -*/ - -static enum charsetanswer tocharset (Instruction *p, CharsetTag *c) { - if (isfixcheck(p)) { - fillcharset(p, c->cs); - if ((p + sizei(p))->i.code == IEnd && op_step(p) == 1) - c->tag = ISCHARSET; - else - c->tag = VALIDSTARTS; - } - else - c->tag = NOINFO; - return c->tag; -} - - -static int exclusiveset (Charset c1, Charset c2) { - /* non-empty intersection? */ - loopset(i, {if ((c1[i] & c2[i]) != 0) return 0;}); - return 1; /* no intersection */ -} - - -static int exclusive (CharsetTag *c1, CharsetTag *c2) { - if (c1->tag == NOINFO || c2->tag == NOINFO) - return 0; /* one of them is not filled */ - else return exclusiveset(c1->cs, c2->cs); -} - - -static Instruction *newcharset (lua_State *L) { - Instruction *p = newpatt(L, CHARSETINSTSIZE); - p[0].i.code = ISet; - p[0].i.offset = 0; - loopset(i, p[1].buff[i] = 0); - return p; -} - - -static int set_l (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - if (l == 1) - getpatt(L, 1, NULL); /* a unit set is equivalent to a literal */ - else { - Instruction *p = newcharset(L); - while (l--) { - setchar(p[1].buff, (byte)(*s)); - s++; - } - } - return 1; -} - - -static int range_l (lua_State *L) { - int arg; - int top = lua_gettop(L); - Instruction *p = newcharset(L); - for (arg = 1; arg <= top; arg++) { - int c; - size_t l; - const char *r = luaL_checklstring(L, arg, &l); - luaL_argcheck(L, l == 2, arg, "range must have two characters"); - for (c = (byte)r[0]; c <= (byte)r[1]; c++) - setchar(p[1].buff, c); - } - return 1; -} - - -static int nter_l (lua_State *L) { - Instruction *p; - luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected"); - p = newpatt(L, 1); - setinst(p, IOpenCall, value2fenv(L, 1)); - return 1; -} - - - -static int testpattern (lua_State *L, int idx) { - if (lua_touserdata(L, idx)) { /* value is a userdata? */ - if (lua_getmetatable(L, idx)) { /* does it have a metatable? */ - luaL_getmetatable(L, PATTERN_T); - if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ - lua_pop(L, 2); /* remove both metatables */ - return 1; - } - } - } - return 0; -} - - -static Instruction *fix_l (lua_State *L, int t) { - Instruction *p; - int i; - int totalsize = 2; /* include initial call and jump */ - int n = 0; /* number of rules */ - int base = lua_gettop(L); - lua_newtable(L); /* to store relative positions of each rule */ - lua_pushinteger(L, 1); /* default initial rule */ - /* collect patterns and compute sizes */ - lua_pushnil(L); - while (lua_next(L, t) != 0) { - int l; - if (lua_tonumber(L, -2) == 1 && lua_isstring(L, -1)) { - lua_replace(L, base + 2); /* use this value as initial rule */ - continue; - } - if (!testpattern(L, -1)) - luaL_error(L, "%s is not a pattern", val2str(L, -2)); - l = pattsize(L, -1) + 1; /* space for pattern + ret */ - if (totalsize >= MAXPATTSIZE - l) - luaL_error(L, "grammar too large"); - luaL_checkstack(L, LUA_MINSTACK, "grammar has too many rules"); - lua_insert(L, -2); /* put key on top */ - lua_pushvalue(L, -1); /* duplicate key (for lua_next) */ - lua_pushvalue(L, -1); /* duplicate key (to index positions table)) */ - lua_pushinteger(L, totalsize); /* position for this rule */ - lua_settable(L, base + 1); /* store key=>position in positions table */ - totalsize += l; - n++; - } - luaL_argcheck(L, n > 0, t, "empty grammar"); - p = newpatt(L, totalsize); /* create new pattern */ - p++; /* save space for call */ - setinst(p++, IJmp, totalsize - 1); /* after call, jumps to the end */ - for (i = 1; i <= n; i++) { /* copy all rules into new pattern */ - p += addpatt(L, p, base + 1 + i*2); - setinst(p++, IRet, 0); - } - p -= totalsize; /* back to first position */ - totalsize = 2; /* go through each rule's position */ - for (i = 1; i <= n; i++) { /* check all rules */ - int l = pattsize(L, base + 1 + i*2) + 1; - checkrule(L, p, totalsize, totalsize + l, base + 1, base + 2 + i*2); - totalsize += l; - } - lua_pushvalue(L, base + 2); /* get initial rule */ - lua_gettable(L, base + 1); /* get its position in postions table */ - i = lua_tonumber(L, -1); /* convert to number */ - lua_pop(L, 1); - if (i == 0) /* is it defined? */ - luaL_error(L, "initial rule not defined in given grammar"); - setinst(p, ICall, i); /* first instruction calls initial rule */ - /* correct calls */ - for (i = 0; i < totalsize; i += sizei(p + i)) { - if (p[i].i.code == IOpenCall) { - int pos = getposition(L, base + 1, p[i].i.offset); - p[i].i.code = (p[target(p, i + 1)].i.code == IRet) ? IJmp : ICall; - p[i].i.offset = pos - i; - } - } - optimizejumps(p); - lua_replace(L, t); /* put new pattern in old's position */ - lua_settop(L, base); /* remove rules and positions table */ - return p; -} - - -static Instruction *any (lua_State *L, int n, int extra, int *offsetp) { - int offset = offsetp ? *offsetp : 0; - Instruction *p = newpatt(L, (n - 1)/UCHAR_MAX + extra + 1); - Instruction *p1 = p + offset; - for (; n > UCHAR_MAX; n -= UCHAR_MAX) - setinstaux(p1++, IAny, 0, UCHAR_MAX); - setinstaux(p1++, IAny, 0, n); - if (offsetp) *offsetp = p1 - p; - return p; -} - - -static Instruction *getpatt (lua_State *L, int idx, int *size) { - Instruction *p; - switch (lua_type(L, idx)) { - case LUA_TSTRING: { - size_t i, len; - const char *s = lua_tolstring(L, idx, &len); - p = newpatt(L, len); - for (i = 0; i < len; i++) - setinstaux(p + i, IChar, 0, (byte)s[i]); - lua_replace(L, idx); - break; - } - case LUA_TNUMBER: { - int n = lua_tointeger(L, idx); - if (n == 0) /* empty pattern? */ - p = newpatt(L, 0); - else if (n > 0) - p = any(L, n, 0, NULL); - else if (-n <= UCHAR_MAX) { - p = newpatt(L, 2); - setinstaux(p, IAny, 2, -n); - setinst(p + 1, IFail, 0); - } - else { - int offset = 2; /* space for ITestAny & IChoice */ - p = any(L, -n - UCHAR_MAX, 3, &offset); - setinstaux(p, IAny, offset + 1, UCHAR_MAX); - setinstaux(p + 1, IChoice, offset, UCHAR_MAX); - setinst(p + offset, IFailTwice, 0); - } - lua_replace(L, idx); - break; - } - case LUA_TBOOLEAN: { - if (lua_toboolean(L, idx)) /* true? */ - p = newpatt(L, 0); /* empty pattern (always succeeds) */ - else { - p = newpatt(L, 1); - setinst(p, IFail, 0); - } - lua_replace(L, idx); - break; - } - case LUA_TTABLE: { - p = fix_l(L, idx); - break; - } - case LUA_TFUNCTION: { - p = newpatt(L, 2); - setinstcap(p, IOpenCapture, value2fenv(L, idx), Cruntime, 0); - setinstcap(p + 1, ICloseRunTime, 0, Cclose, 0); - lua_replace(L, idx); - break; - } - default: { - p = checkpattern(L, idx); - break; - } - } - if (size) *size = pattsize(L, idx); - return p; -} - - -static int getpattl (lua_State *L, int idx) { - int size; - getpatt(L, idx, &size); - return size; -} - - -static int pattern_l (lua_State *L) { - lua_settop(L, 1); - getpatt(L, 1, NULL); - return 1; -} - - -#define isany(p) ((p)->i.code == IAny && ((p) + 1)->i.code == IEnd) -#define isfail(p) ((p)->i.code == IFail) -#define issucc(p) ((p)->i.code == IEnd) - -static int concat_l (lua_State *L) { - /* p1; p2; */ - int l1, l2; - Instruction *p1 = getpatt(L, 1, &l1); - Instruction *p2 = getpatt(L, 2, &l2); - if (isfail(p1) || issucc(p2)) - lua_pushvalue(L, 1); /* fail * x == fail; x * true == x */ - else if (isfail(p2) || issucc(p1)) - lua_pushvalue(L, 2); /* x * fail == fail; true * x == x */ - else if (isany(p1) && isany(p2)) - any(L, p1->i.aux + p2->i.aux, 0, NULL); - else { - Instruction *op = newpatt(L, l1 + l2); - Instruction *p = op + addpatt(L, op, 1); - addpatt(L, p, 2); - optimizecaptures(op); - } - return 1; -} - - -static int diff_l (lua_State *L) { - int l1, l2; - Instruction *p1 = getpatt(L, 1, &l1); - Instruction *p2 = getpatt(L, 2, &l2); - CharsetTag st1, st2; - if (tocharset(p1, &st1) == ISCHARSET && tocharset(p2, &st2) == ISCHARSET) { - Instruction *p = newcharset(L); - loopset(i, p[1].buff[i] = st1.cs[i] & ~st2.cs[i]); - } - else if (isheadfail(p2)) { - Instruction *p = newpatt(L, l2 + 1 + l1); - p += addpatt(L, p, 2); - check2test(p - l2, l2 + 1); - setinst(p++, IFail, 0); - addpatt(L, p, 1); - } - else { /* !e2 . e1 */ - /* !e -> choice L1; e; failtwice; L1: ... */ - Instruction *p = newpatt(L, 1 + l2 + 1 + l1); - Instruction *pi = p; - setinst(p++, IChoice, 1 + l2 + 1); - p += addpatt(L, p, 2); - setinst(p++, IFailTwice, 0); - addpatt(L, p, 1); - optimizechoice(pi); - } - return 1; -} - - -static int unm_l (lua_State *L) { - Instruction *p = getpatt(L, 1, NULL); - if (isfail(p)) { /* -false? */ - newpatt(L, 0); /* true */ - return 1; - } - else if (issucc(p)) { /* -true? */ - Instruction *p1 = newpatt(L, 1); /* false */ - setinst(p1, IFail, 0); - return 1; - } - else { /* -A == '' - A */ - lua_pushliteral(L, ""); - lua_insert(L, 1); - return diff_l(L); - } -} - - -static int pattand_l (lua_State *L) { - int l1; - CharsetTag st1; - Instruction *p1 = getpatt(L, 1, &l1); - if (isfail(p1) || issucc(p1)) - lua_pushvalue(L, 1); /* &fail == fail; &true == true */ - else if (tocharset(p1, &st1) == ISCHARSET) { - Instruction *p = newpatt(L, l1 + 1); - copypatt(p, p1, l1); p += l1; - setinstaux(p, IBack, 0, 1); - } - else { /* Choice L1; p1; BackCommit L2; L1: Fail; L2: */ - Instruction *p = newpatt(L, 1 + l1 + 2); - setinst(p++, IChoice, 1 + l1 + 1); - p += addpatt(L, p, 1); - setinst(p++, IBackCommit, 2); - setinst(p, IFail, 0); - } - return 1; -} - - -static int nocalls (const Instruction *p) { - for (; (Opcode)p->i.code != IEnd; p += sizei(p)) - if ((Opcode)p->i.code == IOpenCall) return 0; - return 1; -} - - -static int pattbehind (lua_State *L) { - int l1; - CharsetTag st1; - Instruction *p1 = getpatt(L, 1, &l1); - int n = luaL_optint(L, 2, 1); - luaL_argcheck(L, n <= MAXAUX, 2, "lookbehind delta too large"); - if (!nocalls(p1)) - luaL_error(L, "lookbehind pattern cannot contain non terminals"); - if (isfail(p1) || issucc(p1)) - lua_pushvalue(L, 1); /* tag == NOINFO) return 1; - assert(p1->i.offset != 0); - switch (p1->i.code) { - case IChar: return testchar(st2->cs, p1->i.aux); - case ISet: return !exclusiveset(st2->cs, (p1 + 1)->buff); - default: assert(p1->i.code == IAny); return 1; - } -} - - -static Instruction *basicUnion (lua_State *L, Instruction *p1, int l1, - int l2, int *size, CharsetTag *st2) { - Instruction *op; - CharsetTag st1; - tocharset(p1, &st1); - if (st1.tag == ISCHARSET && st2->tag == ISCHARSET) { - Instruction *p = auxnew(L, &op, size, CHARSETINSTSIZE); - setinst(p, ISet, 0); - loopset(i, p[1].buff[i] = st1.cs[i] | st2->cs[i]); - } - else if (exclusive(&st1, st2) || isheadfail(p1)) { - Instruction *p = auxnew(L, &op, size, l1 + 1 + l2); - copypatt(p, p1, l1); - check2test(p, l1 + 1); - p += l1; - setinst(p++, IJmp, l2 + 1); - addpatt(L, p, 2); - } - else { - /* choice L1; e1; commit L2; L1: e2; L2: ... */ - Instruction *p = auxnew(L, &op, size, 1 + l1 + 1 + l2); - setinst(p++, IChoice, 1 + l1 + 1); - copypatt(p, p1, l1); p += l1; - setinst(p++, ICommit, 1 + l2); - addpatt(L, p, 2); - optimizechoice(p - (1 + l1 + 1)); - } - return op; -} - - -static Instruction *separateparts (lua_State *L, Instruction *p1, int l1, - int l2, int *size, CharsetTag *st2) { - int sp = firstpart(p1, l1); - if (sp == 0) /* first part is entire p1? */ - return basicUnion(L, p1, l1, l2, size, st2); - else if ((p1 + sp - 1)->i.code == ICommit || !interfere(p1, sp, st2)) { - Instruction *p; - int init = *size; - int end = init + sp; - *size = end; - p = separateparts(L, p1 + sp, l1 - sp, l2, size, st2); - copypatt(p + init, p1, sp); - (p + end - 1)->i.offset = *size - (end - 1); - return p; - } - else { /* must change back to non-optimized choice */ - Instruction *p; - int init = *size; - int end = init + sp + 1; /* needs one extra instruction (choice) */ - int sizefirst = sizei(p1); /* size of p1's first instruction (the test) */ - *size = end; - p = separateparts(L, p1 + sp, l1 - sp, l2, size, st2); - copypatt(p + init, p1, sizefirst); /* copy the test */ - (p + init)->i.offset++; /* correct jump (because of new instruction) */ - init += sizefirst; - setinstaux(p + init, IChoice, sp - sizefirst + 1, 1); init++; - copypatt(p + init, p1 + sizefirst, sp - sizefirst - 1); - init += sp - sizefirst - 1; - setinst(p + init, ICommit, *size - (end - 1)); - return p; - } -} - - -static int union_l (lua_State *L) { - int l1, l2; - int size = 0; - Instruction *p1 = getpatt(L, 1, &l1); - Instruction *p2 = getpatt(L, 2, &l2); - CharsetTag st2; - if (isfail(p1)) /* check for simple identities */ - lua_pushvalue(L, 2); /* fail / a == a */ - else if (isfail(p2) || issucc(p1)) - lua_pushvalue(L, 1); /* a / fail == a; true / a == true */ - else { - tocharset(p2, &st2); - separateparts(L, p1, l1, l2, &size, &st2); - } - return 1; -} - - -static int repeatcharset (lua_State *L, Charset cs, int l1, int n) { - /* e; ...; e; span; */ - int i; - Instruction *p = newpatt(L, n*l1 + CHARSETINSTSIZE); - for (i = 0; i < n; i++) { - p += addpatt(L, p, 1); - } - setinst(p, ISpan, 0); - loopset(k, p[1].buff[k] = cs[k]); - return 1; -} - - -static Instruction *repeatheadfail (lua_State *L, int l1, int n) { - /* e; ...; e; L2: e'(L1); jump L2; L1: ... */ - int i; - Instruction *p = newpatt(L, (n + 1)*l1 + 1); - Instruction *op = p; - for (i = 0; i < n; i++) { - p += addpatt(L, p, 1); - } - p += addpatt(L, p, 1); - check2test(p - l1, l1 + 1); - setinst(p, IJmp, -l1); - return op; -} - - -static Instruction *repeats (lua_State *L, Instruction *p1, int l1, int n) { - /* e; ...; e; choice L1; L2: e; partialcommit L2; L1: ... */ - int i; - Instruction *op = newpatt(L, (n + 1)*l1 + 2); - Instruction *p = op; - if (!verify(L, p1, p1, p1 + l1, 0, 0)) - luaL_error(L, "loop body may accept empty string"); - for (i = 0; i < n; i++) { - p += addpatt(L, p, 1); - } - setinst(p++, IChoice, 1 + l1 + 1); - p += addpatt(L, p, 1); - setinst(p, IPartialCommit, -l1); - return op; -} - - -static void optionalheadfail (lua_State *L, int l1, int n) { - Instruction *op = newpatt(L, n * l1); - Instruction *p = op; - int i; - for (i = 0; i < n; i++) { - p += addpatt(L, p, 1); - check2test(p - l1, (n - i)*l1); - } -} - - -static void optionals (lua_State *L, int l1, int n) { - /* choice L1; e; partialcommit L2; L2: ... e; L1: commit L3; L3: ... */ - int i; - Instruction *op = newpatt(L, n*(l1 + 1) + 1); - Instruction *p = op; - setinst(p++, IChoice, 1 + n*(l1 + 1)); - for (i = 0; i < n; i++) { - p += addpatt(L, p, 1); - setinst(p++, IPartialCommit, 1); - } - setinst(p - 1, ICommit, 1); /* correct last commit */ - optimizechoice(op); -} - - -static int star_l (lua_State *L) { - int l1; - int n = luaL_checkint(L, 2); - Instruction *p1 = getpatt(L, 1, &l1); - if (n >= 0) { - CharsetTag st; - Instruction *op; - if (tocharset(p1, &st) == ISCHARSET) - return repeatcharset(L, st.cs, l1, n); - if (isheadfail(p1)) - op = repeatheadfail(L, l1, n); - else - op = repeats(L, p1, l1, n); - optimizecaptures(op); - optimizejumps(op); - } - else { - if (isheadfail(p1)) - optionalheadfail(L, l1, -n); - else - optionals(L, l1, -n); - } - return 1; -} - - -static int getlabel (lua_State *L, int labelidx) { - if (labelidx == 0) return 0; - else return value2fenv(L, labelidx); -} - - -static int capture_aux (lua_State *L, int kind, int labelidx) { - int l1, n; - Instruction *p1 = getpatt(L, 1, &l1); - int lc = skipchecks(p1, 0, &n); - if (lc == l1) { /* got whole pattern? */ - /* may use a IFullCapture instruction at its end */ - Instruction *p = newpatt(L, l1 + 1); - int label = getlabel(L, labelidx); - p += addpatt(L, p, 1); - setinstcap(p, IFullCapture, label, kind, n); - } - else { /* must use open-close pair */ - Instruction *op = newpatt(L, 1 + l1 + 1); - Instruction *p = op; - setinstcap(p++, IOpenCapture, getlabel(L, labelidx), kind, 0); - p += addpatt(L, p, 1); - setinstcap(p, ICloseCapture, 0, Cclose, 0); - optimizecaptures(op); - } - return 1; -} - - -static int capture_l (lua_State *L) { return capture_aux(L, Csimple, 0); } -static int tcapture_l (lua_State *L) { return capture_aux(L, Ctable, 0); } -static int capsubst_l (lua_State *L) { return capture_aux(L, Csubst, 0); } - -static int rcapture_l (lua_State *L) { - switch (lua_type(L, 2)) { - case LUA_TFUNCTION: return capture_aux(L, Cfunction, 2); - case LUA_TTABLE: return capture_aux(L, Cquery, 2); - case LUA_TSTRING: return capture_aux(L, Cstring, 2); - default: return luaL_argerror(L, 2, "invalid replacement value"); - } -} - - -static int fold_l (lua_State *L) { - luaL_checktype(L, 2, LUA_TFUNCTION); - return capture_aux(L, Cfold, 2); -} - - -static int group_l (lua_State *L) { - if (lua_isnoneornil(L, 2)) - return capture_aux(L, Cgroup, 0); - else { - luaL_checkstring(L, 2); - return capture_aux(L, Cgroup, 2); - } -} - - -static int position_l (lua_State *L) { - Instruction *p = newpatt(L, 1); - setinstcap(p, IEmptyCapture, 0, Cposition, 0); - return 1; -} - - -static int backref_l (lua_State *L) { - Instruction *p = newpatt(L, 1); - int n = getlabel(L, 1); - setinstcap(p, IEmptyCaptureIdx, n, Cbackref, 0); - return 1; -} - - -static int argcap_l (lua_State *L) { - int n = luaL_checkint(L, 1); - Instruction *p = newpatt(L, 1); - luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index"); - setinstcap(p, IEmptyCapture, n, Carg, 0); - return 1; -} - - -static int matchtime_l (lua_State *L) { - int l1 = getpattl(L, 1); - Instruction *op = newpatt(L, 1 + l1 + 1); - Instruction *p = op; - luaL_checktype(L, 2, LUA_TFUNCTION); - setinstcap(p++, IOpenCapture, value2fenv(L, 2), Cruntime, 0); - p += addpatt(L, p, 1); - setinstcap(p, ICloseRunTime, 0, Cclose, 0); - optimizecaptures(op); - return 1; -} - - -static int capconst_l (lua_State *L) { - int i, j; - int n = lua_gettop(L); - Instruction *p = newpatt(L, n > 1 ? n + 2 : n); - lua_createtable(L, n, 0); /* new environment for the new pattern */ - if (n > 1) setinstcap(p++, IOpenCapture, 0, Cgroup, 0); - for (i = j = 1; i <= n; i++) { - if (lua_isnil(L, i)) - setinstcap(p++, IEmptyCaptureIdx, 0, Cconst, 0); - else { - setinstcap(p++, IEmptyCaptureIdx, j, Cconst, 0); - lua_pushvalue(L, i); - lua_rawseti(L, -2, j++); - } - } - if (n > 1) setinstcap(p++, ICloseCapture, 0, Cclose, 0); - lua_setfenv(L, -2); /* set environment */ - return 1; -} - - -/* }====================================================== */ - - -/* -** {====================================================== -** User-Defined Patterns -** ======================================================= -*/ - -static void l_newpf (lua_State *L, PattFunc f, const void *ud, size_t l) { - int n = instsize(l) + 1; - Instruction *p = newpatt(L, n); - if (n > MAXAUX) luaL_error(L, "pattern data too long"); - p[0].i.code = IFunc; - p[0].i.aux = n - 2; - p[0].i.offset = 0; - p[1].f = f; - memcpy(p[2].buff, ud, l); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Captures -** ======================================================= -*/ - - -typedef struct CapState { - Capture *cap; /* current capture */ - Capture *ocap; /* (original) capture list */ - lua_State *L; - int ptop; /* index of last argument to 'match' */ - const char *s; /* original string */ - int valuecached; /* value stored in cache slot */ -} CapState; - - -#define captype(cap) ((cap)->kind) - -#define isclosecap(cap) (captype(cap) == Cclose) - -#define closeaddr(c) ((c)->s + (c)->siz - 1) - -#define isfullcap(cap) ((cap)->siz != 0) - -#define getfromenv(cs,v) lua_rawgeti((cs)->L, penvidx((cs)->ptop), v) -#define pushluaval(cs) getfromenv(cs, (cs)->cap->idx) - -#define pushsubject(cs, c) lua_pushlstring((cs)->L, (c)->s, (c)->siz - 1) - - -#define updatecache(cs,v) { if ((v) != (cs)->valuecached) updatecache_(cs,v); } - - -static void updatecache_ (CapState *cs, int v) { - getfromenv(cs, v); - lua_replace(cs->L, subscache(cs)); - cs->valuecached = v; -} - - -static int pushcapture (CapState *cs); - - -static Capture *findopen (Capture *cap) { - int n = 0; - for (;;) { - cap--; - if (isclosecap(cap)) n++; - else if (!isfullcap(cap)) - if (n-- == 0) return cap; - } -} - - -static Capture *nextcap (Capture *cap) { - if (isfullcap(cap)) return cap + 1; - else { - int n = 0; - for (;;) { - cap++; - if (isclosecap(cap)) { - if (n-- == 0) return cap + 1; - } - else if (!isfullcap(cap)) n++; - } - } -} - - -static int pushallvalues (CapState *cs, int addextra) { - Capture *co = cs->cap; - int n = 0; - if (isfullcap(cs->cap++)) { - pushsubject(cs, co); /* push whole match */ - return 1; - } - while (!isclosecap(cs->cap)) - n += pushcapture(cs); - if (addextra || n == 0) { /* need extra? */ - lua_pushlstring(cs->L, co->s, cs->cap->s - co->s); /* push whole match */ - n++; - } - cs->cap++; /* skip close entry */ - return n; -} - - -static Capture *findback (CapState *cs, Capture *cap) { - lua_State *L = cs->L; - for (;;) { - if (cap == cs->ocap) { /* not found */ - const char *s = lua_tostring(L, -1); - if (s == NULL) s = lua_pushfstring(L, "(a %s)", luaL_typename(L, -1)); - luaL_error(L, "back reference '%s' not found", s); - } - cap--; - if (isclosecap(cap)) - cap = findopen(cap); - else if (!isfullcap(cap)) - continue; /* opening an enclosing capture: skip and get previous */ - if (captype(cap) == Cgroup) { - getfromenv(cs, cap->idx); /* get group name */ - if (lua_equal(L, -2, -1)) { /* right group? */ - lua_pop(L, 2); /* remove reference name and group name */ - return cap; - } - else lua_pop(L, 1); /* remove group name */ - } - } -} - - -static int backrefcap (CapState *cs) { - int n; - Capture *curr = cs->cap; - pushluaval(cs); /* reference name */ - cs->cap = findback(cs, curr); - n = pushallvalues(cs, 0); - cs->cap = curr + 1; - return n; -} - - -static int tablecap (CapState *cs) { - lua_State *L = cs->L; - int n = 0; - lua_newtable(L); - if (isfullcap(cs->cap++)) - return 1; /* table is empty */ - while (!isclosecap(cs->cap)) { - if (captype(cs->cap) == Cgroup && cs->cap->idx != 0) { /* named group? */ - int k; - pushluaval(cs); /* push group name */ - k = pushallvalues(cs, 0); - if (k == 0) { /* no value? */ - lua_pop(L, 1); /* remove group name */ - continue; /* and go on */ - } - else if (k > 1) - lua_pop(L, k - 1); /* keep just one value */ - lua_settable(L, -3); - } - else { - int i; - int k = pushcapture(cs); - for (i = k; i > 0; i--) - lua_rawseti(L, -(i + 1), n + i); - n += k; - } - } - cs->cap++; /* skip close entry */ - return 1; -} - - -static int querycap (CapState *cs) { - int idx = cs->cap->idx; - int n = pushallvalues(cs, 0); - if (n > 1) /* extra captures? */ - lua_pop(cs->L, n - 1); /* throw them away */ - updatecache(cs, idx); - lua_gettable(cs->L, subscache(cs)); - if (!lua_isnil(cs->L, -1)) - return 1; - else { - lua_pop(cs->L, 1); /* remove value */ - return 0; - } -} - - -static int foldcap (CapState *cs) { - int n; - lua_State *L = cs->L; - int idx = cs->cap->idx; - if (isfullcap(cs->cap++) || isclosecap(cs->cap) || (n = pushcapture(cs)) == 0) - return luaL_error(L, "no initial value for fold capture"); - if (n > 1) - lua_pop(L, n - 1); /* leave only one result */ - while (!isclosecap(cs->cap)) { - updatecache(cs, idx); - lua_pushvalue(L, subscache(cs)); /* get folding function */ - lua_insert(L, -2); /* put it before accumulator */ - n = pushcapture(cs); /* get other captures */ - lua_call(L, n + 1, 1); /* call folding function */ - } - cs->cap++; /* skip close entry */ - return 1; -} - - -static int functioncap (CapState *cs) { - int n; - int top = lua_gettop(cs->L); - pushluaval(cs); - n = pushallvalues(cs, 0); - lua_call(cs->L, n, LUA_MULTRET); - return lua_gettop(cs->L) - top; -} - - -static int runtimecap (lua_State *L, Capture *close, Capture *ocap, - const char *o, const char *s, int ptop) { - CapState cs; - int n; - Capture *open = findopen(close); - assert(captype(open) == Cruntime); - close->kind = Cclose; - close->s = s; - cs.ocap = ocap; cs.cap = open; cs.L = L; - cs.s = o; cs.valuecached = 0; cs.ptop = ptop; - luaL_checkstack(L, 4, "too many runtime captures"); - pushluaval(&cs); - lua_pushvalue(L, SUBJIDX); /* push original subject */ - lua_pushinteger(L, s - o + 1); /* current position */ - n = pushallvalues(&cs, 0); - lua_call(L, n + 2, LUA_MULTRET); - return close - open; -} - - - -typedef struct StrAux { - int isstring; - union { - Capture *cp; - struct { - const char *s; - const char *e; - } s; - } u; -} StrAux; - -#define MAXSTRCAPS 10 - -static int getstrcaps (CapState *cs, StrAux *cps, int n) { - int k = n++; - cps[k].isstring = 1; - cps[k].u.s.s = cs->cap->s; - if (!isfullcap(cs->cap++)) { - while (!isclosecap(cs->cap)) { - if (n >= MAXSTRCAPS) /* too many captures? */ - cs->cap = nextcap(cs->cap); /* skip it */ - else if (captype(cs->cap) == Csimple) - n = getstrcaps(cs, cps, n); - else { - cps[n].isstring = 0; - cps[n].u.cp = cs->cap; - cs->cap = nextcap(cs->cap); - n++; - } - } - cs->cap++; /* skip close */ - } - cps[k].u.s.e = closeaddr(cs->cap - 1); - return n; -} - - -/* -** add next capture (which should be a string) to buffer -*/ -static int addonestring (luaL_Buffer *b, CapState *cs, const char *what); - - -static void stringcap (luaL_Buffer *b, CapState *cs) { - StrAux cps[MAXSTRCAPS]; - int n; - size_t len, i; - const char *c; - updatecache(cs, cs->cap->idx); - c = lua_tolstring(cs->L, subscache(cs), &len); - n = getstrcaps(cs, cps, 0) - 1; - for (i = 0; i < len; i++) { - if (c[i] != '%' || c[++i] < '0' || c[i] > '9') - luaL_addchar(b, c[i]); - else { - int l = c[i] - '0'; - if (l > n) - luaL_error(cs->L, "invalid capture index (%d)", l); - else if (cps[l].isstring) - luaL_addlstring(b, cps[l].u.s.s, cps[l].u.s.e - cps[l].u.s.s); - else { - Capture *curr = cs->cap; - cs->cap = cps[l].u.cp; - if (addonestring(b, cs, "capture") == 0) - luaL_error(cs->L, "no values in capture index %d", l); - cs->cap = curr; - } - } - } -} - - -static void substcap (luaL_Buffer *b, CapState *cs) { - const char *curr = cs->cap->s; - if (isfullcap(cs->cap)) /* no nested captures? */ - luaL_addlstring(b, curr, cs->cap->siz - 1); /* keep original text */ - else { - cs->cap++; - while (!isclosecap(cs->cap)) { - const char *next = cs->cap->s; - luaL_addlstring(b, curr, next - curr); /* add text up to capture */ - if (addonestring(b, cs, "replacement") == 0) /* no capture value? */ - curr = next; /* keep original text in final result */ - else - curr = closeaddr(cs->cap - 1); /* continue after match */ - } - luaL_addlstring(b, curr, cs->cap->s - curr); /* add last piece of text */ - } - cs->cap++; /* go to next capture */ -} - - -static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) { - switch (captype(cs->cap)) { - case Cstring: - stringcap(b, cs); /* add capture directly to buffer */ - return 1; - case Csubst: - substcap(b, cs); /* add capture directly to buffer */ - return 1; - default: { - lua_State *L = cs->L; - int n = pushcapture(cs); - if (n > 0) { - if (n > 1) lua_pop(L, n - 1); /* only one result */ - if (!lua_isstring(L, -1)) - luaL_error(L, "invalid %s value (a %s)", what, luaL_typename(L, -1)); - luaL_addvalue(b); - } - return n; - } - } -} - - -static int pushcapture (CapState *cs) { - luaL_checkstack(cs->L, 4, "too many captures"); - switch (captype(cs->cap)) { - case Cposition: { - lua_pushinteger(cs->L, cs->cap->s - cs->s + 1); - cs->cap++; - return 1; - } - case Cconst: { - pushluaval(cs); - cs->cap++; - return 1; - } - case Carg: { - int arg = (cs->cap++)->idx; - if (arg + FIXEDARGS > cs->ptop) - return luaL_error(cs->L, "reference to absent argument #%d", arg); - lua_pushvalue(cs->L, arg + FIXEDARGS); - return 1; - } - case Csimple: { - int k = pushallvalues(cs, 1); - if (k > 1) - lua_insert(cs->L, -k); /* whole match is first result */ - return k; - } - case Cruntime: { - int n = 0; - while (!isclosecap(cs->cap++)) { - luaL_checkstack(cs->L, 4, "too many captures"); - lua_pushvalue(cs->L, (cs->cap - 1)->idx); - n++; - } - return n; - } - case Cstring: { - luaL_Buffer b; - luaL_buffinit(cs->L, &b); - stringcap(&b, cs); - luaL_pushresult(&b); - return 1; - } - case Csubst: { - luaL_Buffer b; - luaL_buffinit(cs->L, &b); - substcap(&b, cs); - luaL_pushresult(&b); - return 1; - } - case Cgroup: { - if (cs->cap->idx == 0) /* anonymous group? */ - return pushallvalues(cs, 0); /* add all nested values */ - else { /* named group: add no values */ - cs->cap = nextcap(cs->cap); /* skip capture */ - return 0; - } - } - case Cbackref: return backrefcap(cs); - case Ctable: return tablecap(cs); - case Cfunction: return functioncap(cs); - case Cquery: return querycap(cs); - case Cfold: return foldcap(cs); - default: assert(0); return 0; - } -} - - -static int getcaptures (lua_State *L, const char *s, const char *r, int ptop) { - Capture *capture = (Capture *)lua_touserdata(L, caplistidx(ptop)); - int n = 0; - if (!isclosecap(capture)) { /* is there any capture? */ - CapState cs; - cs.ocap = cs.cap = capture; cs.L = L; - cs.s = s; cs.valuecached = 0; cs.ptop = ptop; - do { /* collect their values */ - n += pushcapture(&cs); - } while (!isclosecap(cs.cap)); - } - if (n == 0) { /* no capture values? */ - lua_pushinteger(L, r - s + 1); /* return only end position */ - n = 1; - } - return n; -} - -/* }====================================================== */ - - -static int version_l (lua_State *L) { - lua_pushstring(L, VERSION); - return 1; -} - - -static int type_l (lua_State *L) { - if (testpattern(L, 1)) - lua_pushliteral(L, "pattern"); - else - lua_pushnil(L); - return 1; -} - - -static void createcat (lua_State *L, const char *catname, int (catf) (int)) { - Instruction *p = newcharset(L); - int i; - for (i = 0; i < CHAR_MAX; i++) - if (catf(i)) setchar(p[1].buff, i); - lua_setfield(L, -2, catname); -} - - -static int locale_l (lua_State *L) { - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 0); - lua_createtable(L, 0, 12); - } - else { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); - } - createcat(L, "alnum", isalnum); - createcat(L, "alpha", isalpha); - createcat(L, "cntrl", iscntrl); - createcat(L, "digit", isdigit); - createcat(L, "graph", isgraph); - createcat(L, "lower", islower); - createcat(L, "print", isprint); - createcat(L, "punct", ispunct); - createcat(L, "space", isspace); - createcat(L, "upper", isupper); - createcat(L, "xdigit", isxdigit); - return 1; -} - - -static int setmax (lua_State *L) { - luaL_optinteger(L, 1, -1); - lua_settop(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); - return 0; -} - - -static int printpat_l (lua_State *L) { - Instruction *p = getpatt(L, 1, NULL); - int n, i; - lua_getfenv(L, 1); - n = ktablelen(L, -1); - printf("["); - for (i = 1; i <= n; i++) { - printf("%d = ", i); - lua_rawgeti(L, -1, i); - if (lua_isstring(L, -1)) - printf("%s ", lua_tostring(L, -1)); - else - printf("%s ", lua_typename(L, lua_type(L, -1))); - lua_pop(L, 1); - } - printf("]\n"); - printpatt(p); - return 0; -} - - -static int matchl (lua_State *L) { - Capture capture[INITCAPSIZE]; - const char *r; - size_t l; - Instruction *p = getpatt(L, 1, NULL); - const char *s = luaL_checklstring(L, SUBJIDX, &l); - int ptop = lua_gettop(L); - lua_Integer ii = luaL_optinteger(L, 3, 1); - size_t i = (ii > 0) ? - (((size_t)ii <= l) ? (size_t)ii - 1 : l) : - (((size_t)-ii <= l) ? l - ((size_t)-ii) : 0); - lua_pushnil(L); /* subscache */ - lua_pushlightuserdata(L, capture); /* caplistidx */ - lua_getfenv(L, 1); /* penvidx */ - r = match(L, s, s + i, s + l, p, capture, ptop); - if (r == NULL) { - lua_pushnil(L); - return 1; - } - return getcaptures(L, s, r, ptop); -} - - -static struct luaL_Reg pattreg[] = { - {"match", matchl}, - {"print", printpat_l}, - {"locale", locale_l}, - {"setmaxstack", setmax}, - {"B", pattbehind}, - {"C", capture_l}, - {"Cf", fold_l}, - {"Cc", capconst_l}, - {"Cg", group_l}, - {"Cp", position_l}, - {"Cb", backref_l}, - {"Carg", argcap_l}, - {"Cmt", matchtime_l}, - {"Cs", capsubst_l}, - {"Ct", tcapture_l}, - {"P", pattern_l}, - {"R", range_l}, - {"S", set_l}, - {"V", nter_l}, - {"type", type_l}, - {"version", version_l}, - {NULL, NULL} -}; - - -static struct luaL_Reg metapattreg[] = { - {"__add", union_l}, - {"__pow", star_l}, - {"__sub", diff_l}, - {"__mul", concat_l}, - {"__div", rcapture_l}, - {"__unm", unm_l}, - {"__len", pattand_l}, - {NULL, NULL} -}; - - -int luaopen_lpeg (lua_State *L); -int luaopen_lpeg (lua_State *L) { - lua_pushcfunction(L, (lua_CFunction)&l_newpf); /* new-pattern function */ - lua_setfield(L, LUA_REGISTRYINDEX, KEYNEWPATT); /* register it */ - luaL_newmetatable(L, PATTERN_T); - lua_pushnumber(L, MAXBACK); - lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); - luaL_register(L, NULL, metapattreg); - luaL_register(L, "lpeg", pattreg); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); - lua_settable(L, -4); - return 1; -} - diff --git a/lpeg/lpeg.h b/lpeg/lpeg.h deleted file mode 100644 index 13d7acef..00000000 --- a/lpeg/lpeg.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** $Id: lpeg.h,v 1.1 2009/12/23 16:15:36 roberto Exp $ -** LPeg - PEG pattern matching for Lua -** Copyright 2009, Lua.org & PUC-Rio (see 'lpeg.html' for license) -** written by Roberto Ierusalimschy -*/ - -#ifndef lpeg_h -#define lpeg_h - -#include "lua.h" - - -#define KEYNEWPATT "lpeg.newpf" - - -/* -** type of extension functions that define new "patterns" for LPEG -** It should return the new current position or NULL if match fails -*/ -typedef const char *(*PattFunc) (const char *s, /* current position */ - const char *e, /* string end */ - const char *o, /* string start */ - const void *ud); /* user data */ - -/* -** function to create new patterns based on 'PattFunc' functions. -** This function is available at *registry[KEYNEWPATT]. (Notice -** the extra indirection; the userdata at the registry points to -** a variable that points to the function. In ANSI C a void* cannot -** point to a function.) -*/ -typedef void (*Newpf) (lua_State *L, - PattFunc f, /* pattern */ - const void *ud, /* (user) data to be passed to 'f' */ - size_t l); /* size of data to be passed to 'f' */ - -#endif diff --git a/lpeg/lpeg.html b/lpeg/lpeg.html deleted file mode 100644 index bb92b279..00000000 --- a/lpeg/lpeg.html +++ /dev/null @@ -1,1423 +0,0 @@ - - - - LPeg - Parsing Expression Grammars For Lua - - - - - - - -
- -
- -
LPeg
-
- Parsing Expression Grammars For Lua, version 0.10 -
-
- -
- - - -
- - -

Introduction

- -

-LPeg is a new pattern-matching library for Lua, -based on - -Parsing Expression Grammars (PEGs). -This text is a reference manual for the library. -For a more formal treatment of LPeg, -as well as some discussion about its implementation, -see - -A Text Pattern-Matching Tool based on Parsing Expression Grammars. -(You may also be interested in my -talk about LPeg -given at the III Lua Workshop.) -

- -

-Following the Snobol tradition, -LPeg defines patterns as first-class objects. -That is, patterns are regular Lua values -(represented by userdata). -The library offers several functions to create -and compose patterns. -With the use of metamethods, -several of these functions are provided as infix or prefix -operators. -On the one hand, -the result is usually much more verbose than the typical -encoding of patterns using the so called -regular expressions -(which typically are not regular expressions in the formal sense). -On the other hand, -first-class patterns allow much better documentation -(as it is easy to comment the code, -to break complex definitions in smaller parts, etc.) -and are extensible, -as we can define new functions to create and compose patterns. -

- -

-For a quick glance of the library, -the following table summarizes its basic operations -for creating patterns: -

- - - - - - - - - - - - - - - - - - - - - - - - - - -
OperatorDescription
lpeg.P(string)Matches string literally
lpeg.P(n)Matches exactly n characters
lpeg.S(string)Matches any character in string (Set)
lpeg.R("xy")Matches any character between x and y (Range)
patt^nMatches at least n repetitions of patt
patt^-nMatches at most n repetitions of patt
patt1 * patt2Matches patt1 followed by patt2
patt1 + patt2Matches patt1 or patt2 - (ordered choice)
patt1 - patt2Matches patt1 if patt2 does not match
-pattEquivalent to ("" - patt)
#pattMatches patt but consumes no input
lpeg.B(patt, n)Matches patt n characters behind - the current position, consuming no input
- -

As a very simple example, -lpeg.R("09")^1 creates a pattern that -matches a non-empty sequence of digits. -As a not so simple example, --lpeg.P(1) -(which can be written as lpeg.P(-1) -or simply -1 for operations expecting a pattern) -matches an empty string only if it cannot match a single character; -so, it succeeds only at the subject's end. -

- -

-LPeg also offers the re module, -which implements patterns following a regular-expression style -(e.g., [09]+). -(This module is 250 lines of Lua code, -and of course uses LPeg to parse regular expressions and -translate them to regular LPeg patterns.) -

- - -

Functions

- - -

lpeg.match (pattern, subject [, init])

-

-The matching function. -It attempts to match the given pattern against the subject string. -If the match succeeds, -returns the index in the subject of the first character after the match, -or the captured values -(if the pattern captured any value). -

- -

-An optional numeric argument init makes the match -starts at that position in the subject string. -As usual in Lua libraries, -a negative value counts from the end. -

- -

-Unlike typical pattern-matching functions, -match works only in anchored mode; -that is, it tries to match the pattern with a prefix of -the given subject string (at position init), -not with an arbitrary substring of the subject. -So, if we want to find a pattern anywhere in a string, -we must either write a loop in Lua or write a pattern that -matches anywhere. -This second approach is easy and quite efficient; -see examples. -

- -

lpeg.type (value)

-

-If the given value is a pattern, -returns the string "pattern". -Otherwise returns nil. -

- -

lpeg.version ()

-

-Returns a string with the running version of LPeg. -

- -

lpeg.setmaxstack (max)

-

-Sets the maximum size for the backtrack stack used by LPeg to -track calls and choices. -Most well-written patterns need little backtrack levels and -therefore you seldom need to change this maximum; -but a few useful patterns may need more space. -Before changing this maximum you should try to rewrite your -pattern to avoid the need for extra space. -

- - -

Basic Constructions

- -

-The following operations build patterns. -All operations that expect a pattern as an argument -may receive also strings, tables, numbers, booleans, or functions, -which are translated to patterns according to -the rules of function lpeg.P. -

- - - -

lpeg.P (value)

-

-Converts the given value into a proper pattern, -according to the following rules: -

-
    - -
  • -If the argument is a pattern, -it is returned unmodified. -

  • - -
  • -If the argument is a string, -it is translated to a pattern that matches literally the string. -

  • - -
  • -If the argument is a non-negative number n, -the result is a pattern that matches exactly n characters. -

  • - -
  • -If the argument is a negative number -n, -the result is a pattern that -succeeds only if the input string does not have n characters: -lpeg.P(-n) -is equivalent to -lpeg.P(n) -(see the unary minus operation). -

  • - -
  • -If the argument is a boolean, -the result is a pattern that always succeeds or always fails -(according to the boolean value), -without consuming any input. -

  • - -
  • -If the argument is a table, -it is interpreted as a grammar -(see Grammars). -

  • - -
  • -If the argument is a function, -returns a pattern equivalent to a -match-time capture over the empty string. -

  • - -
- - -

lpeg.B(patt [, n])

-

-Returns a pattern that -matches only if the input string matches patt -starting n positions behind the current position. -(The default value for n is 1.) -If the current position is less than or equal to n, -this pattern fails. -

- -

-Like the and predicate, -this pattern never consumes any input, -independently of success or failure, -and it never produces any capture. -

- -

-The pattern patt cannot contain any open reference -to grammar rules (see grammars). -

- -

-(This is an experimental feature. -There is a good chance it will change in future versions.) -

- - -

lpeg.R ({range})

-

-Returns a pattern that matches any single character -belonging to one of the given ranges. -Each range is a string xy of length 2, -representing all characters with code -between the codes of x and y -(both inclusive). -

- -

-As an example, the pattern -lpeg.R("09") matches any digit, -and lpeg.R("az", "AZ") matches any ASCII letter. -

- - -

lpeg.S (string)

-

-Returns a pattern that matches any single character that -appears in the given string. -(The S stands for Set.) -

- -

-As an example, the pattern -lpeg.S("+-*/") matches any arithmetic operator. -

- -

-Note that, if s is a character -(that is, a string of length 1), -then lpeg.P(s) is equivalent to lpeg.S(s) -which is equivalent to lpeg.R(s..s). -Note also that both lpeg.S("") and lpeg.R() -are patterns that always fail. -

- - -

lpeg.V (v)

-

-This operation creates a non-terminal (a variable) -for a grammar. -The created non-terminal refers to the rule indexed by v -in the enclosing grammar. -(See Grammars for details.) -

- - -

lpeg.locale ([table])

-

-Returns a table with patterns for matching some character classes -according to the current locale. -The table has fields named -alnum, -alpha, -cntrl, -digit, -graph, -lower, -print, -punct, -space, -upper, and -xdigit, -each one containing a correspondent pattern. -Each pattern matches any single character that belongs to its class. -

- -

-If called with an argument table, -then it creates those fields inside the given table and -returns that table. -

- - -

#patt

-

-Returns a pattern that -matches only if the input string matches patt, -but without consuming any input, -independently of success or failure. -(This pattern is called an and predicate -and it is equivalent to -&patt in the original PEG notation.) -

- - -

-This pattern never produces any capture. -

. - - -

-patt

-

-Returns a pattern that -matches only if the input string does not match patt. -It does not consume any input, -independently of success or failure. -(This pattern is equivalent to -!patt in the original PEG notation.) -

- -

-As an example, the pattern --lpeg.P(1) matches only the end of string. -

- -

-This pattern never produces any captures, -because either patt fails -or -patt fails. -(A failing pattern never produces captures.) -

- - -

patt1 + patt2

-

-Returns a pattern equivalent to an ordered choice -of patt1 and patt2. -(This is denoted by patt1 / patt2 in the original PEG notation, -not to be confused with the / operation in LPeg.) -It matches either patt1 or patt2, -with no backtracking once one of them succeeds. -The identity element for this operation is the pattern -lpeg.P(false), -which always fails. -

- -

-If both patt1 and patt2 are -character sets, -this operation is equivalent to set union. -

-
-lower = lpeg.R("az")
-upper = lpeg.R("AZ")
-letter = lower + upper
-
- - -

patt1 - patt2

-

-Returns a pattern equivalent to !patt2 patt1. -This pattern asserts that the input does not match -patt2 and then matches patt1. -

- -

-When succeeded, -this pattern produces all captures from patt1. -It never produces any capture from patt2 -(as either patt2 fails or -patt1 - patt2 fails). -

- -

-If both patt1 and patt2 are -character sets, -this operation is equivalent to set difference. -Note that -patt is equivalent to "" - patt -(or 0 - patt). -If patt is a character set, -1 - patt is its complement. -

- - -

patt1 * patt2

-

-Returns a pattern that matches patt1 -and then matches patt2, -starting where patt1 finished. -The identity element for this operation is the -pattern lpeg.P(true), -which always succeeds. -

- -

-(LPeg uses the * operator -[instead of the more obvious ..] -both because it has -the right priority and because in formal languages it is -common to use a dot for denoting concatenation.) -

- - -

patt^n

-

-If n is nonnegative, -this pattern is -equivalent to pattn patt*. -It matches at least n occurrences of patt. -

- -

-Otherwise, when n is negative, -this pattern is equivalent to (patt?)-n. -That is, it matches at most |n| -occurrences of patt. -

- -

-In particular, patt^0 is equivalent to patt*, -patt^1 is equivalent to patt+, -and patt^-1 is equivalent to patt? -in the original PEG notation. -

- -

-In all cases, -the resulting pattern is greedy with no backtracking -(also called a possessive repetition). -That is, it matches only the longest possible sequence -of matches for patt. -

- - - -

Grammars

- -

-With the use of Lua variables, -it is possible to define patterns incrementally, -with each new pattern using previously defined ones. -However, this technique does not allow the definition of -recursive patterns. -For recursive patterns, -we need real grammars. -

- -

-LPeg represents grammars with tables, -where each entry is a rule. -

- -

-The call lpeg.V(v) -creates a pattern that represents the nonterminal -(or variable) with index v in a grammar. -Because the grammar still does not exist when -this function is evaluated, -the result is an open reference to the respective rule. -

- -

-A table is fixed when it is converted to a pattern -(either by calling lpeg.P or by using it wherein a -pattern is expected). -Then every open reference created by lpeg.V(v) -is corrected to refer to the rule indexed by v in the table. -

- -

-When a table is fixed, -the result is a pattern that matches its initial rule. -The entry with index 1 in the table defines its initial rule. -If that entry is a string, -it is assumed to be the name of the initial rule. -Otherwise, LPeg assumes that the entry 1 itself is the initial rule. -

- -

-As an example, -the following grammar matches strings of a's and b's that -have the same number of a's and b's: -

-
-equalcount = lpeg.P{
-  "S";   -- initial rule name
-  S = "a" * lpeg.V"B" + "b" * lpeg.V"A" + "",
-  A = "a" * lpeg.V"S" + "b" * lpeg.V"A" * lpeg.V"A",
-  B = "b" * lpeg.V"S" + "a" * lpeg.V"B" * lpeg.V"B",
-} * -1
-
-

-It is equivalent to the following grammar in standard PEG notation: -

-
-  S <- 'a' B / 'b' A / ''
-  A <- 'a' S / 'b' A A
-  B <- 'b' S / 'a' B B
-
- - -

Captures

- -

-A capture is a pattern that creates values -(the so called semantic information) when it matches. -LPeg offers several kinds of captures, -which produces values based on matches and combine these values to -produce new values. -Each capture may produce zero or more values. -

- -

-The following table summarizes the basic captures: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OperationWhat it Produces
lpeg.C(patt)the match for patt plus all captures - made by patt
lpeg.Carg(n)the value of the nth extra argument to - lpeg.match (matches the empty string)
lpeg.Cb(name)the values produced by the previous - group capture named name - (matches the empty string)
lpeg.Cc(values)the given values (matches the empty string)
lpeg.Cf(patt, func)a folding of the captures from patt
lpeg.Cg(patt [, name])the values produced by patt, - optionally tagged with name
lpeg.Cp()the current position (matches the empty string)
lpeg.Cs(patt)the match for patt - with the values from nested captures replacing their matches
lpeg.Ct(patt)a table with all captures from patt
patt / stringstring, with some marks replaced by captures - of patt
patt / tabletable[c], where c is the (first) - capture of patt
patt / functionthe returns of function applied to the captures - of patt
lpeg.Cmt(patt, function)the returns of function applied to the captures - of patt; the application is done at match time
- -

-A capture pattern produces its values every time 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, -the pattern lpeg.C(lpeg.P"a"^-1) -produces the empty string when there is no "a" -(because the pattern "a"? succeeds), -while the pattern lpeg.C("a")^-1 -does not produce any value when there is no "a" -(because the pattern "a" fails). -

- -

-Usually, -LPeg evaluates all captures only after (and if) the entire match succeeds. -During the match time it only gathers enough information -to produce the capture values later. -As a particularly important consequence, -most captures cannot affect the way a pattern matches a subject. -The only exception to this rule is the -so-called match-time capture. -When a match-time capture matches, -it forces the immediate evaluation of all its nested captures -and then calls its corresponding function, -which tells whether the match succeeds and also -what values are produced. -

- -

lpeg.C (patt)

-

-Creates a simple capture, -which captures the substring of the subject that matches patt. -The captured value is a string. -If patt has other captures, -their values are returned after this one. -

- - -

lpeg.Carg (n)

-

-Creates an argument capture. -This pattern matches the empty string and -produces the value given as the nth extra -argument given in the call to lpeg.match. -

- - -

lpeg.Cb (name)

-

-Creates a back capture. -This pattern matches the empty string and -produces the values produced by the most recent -group capture named name. -

- -

-Most recent means the last -complete -outermost -group capture with the given name. -A Complete capture means that the entire pattern -corresponding to the capture has matched. -An Outermost capture means that the capture is not inside -another complete capture. -

- - -

lpeg.Cc ([value, ...])

-

-Creates a constant capture. -This pattern matches the empty string and -produces all given values as its captured values. -

- - -

lpeg.Cf (patt, func)

-

-Creates a fold capture. -If patt produces a list of captures -C1 C2 ... Cn, -this capture will produce the value -func(...func(func(C1, C2), C3)..., - Cn), -that is, it will fold -(or accumulate, or reduce) -the captures from patt using function func. -

- -

-This capture assumes that patt should produce -at least one capture with at least one value (of any type), -which becomes the initial value of an accumulator. -(If you need a specific initial value, -you may prefix a constant capture to patt.) -For each subsequent capture -LPeg calls func -with this accumulator as the first argument and all values produced -by the capture as extra arguments; -the value returned by this call -becomes the new value for the accumulator. -The final value of the accumulator becomes the captured value. -

- -

-As an example, -the following pattern matches a list of numbers separated -by commas and returns their addition: -

-
--- matches a numeral and captures its value
-number = lpeg.R"09"^1 / tonumber
-
--- matches a list of numbers, captures their values
-list = number * ("," * number)^0
-
--- auxiliary function to add two numbers
-function add (acc, newvalue) return acc + newvalue end
-
--- folds the list of numbers adding them
-sum = lpeg.Cf(list, add)
-
--- example of use
-print(sum:match("10,30,43"))   --> 83
-
- - -

lpeg.Cg (patt [, name])

-

-Creates a group capture. -It groups all values returned by patt -into a single capture. -The group may be anonymous (if no name is given) -or named with the given name. -

- -

-An anonymous group serves to join values from several captures into -a single capture. -A named group has a different behavior. -In most situations, a named group returns no values at all. -Its values are only relevant for a following -back capture or when used -inside a table capture. -

- - -

lpeg.Cp ()

-

-Creates a position capture. -It matches the empty string and -captures the position in the subject where the match occurs. -The captured value is a number. -

- - -

lpeg.Cs (patt)

-

-Creates a substitution capture, -which captures the substring of the subject that matches patt, -with substitutions. -For any capture inside patt with a value, -the substring that matched the capture is replaced by the capture value -(which should be a string). -The final captured value is the string resulting from -all replacements. -

- - -

lpeg.Ct (patt)

-

-Creates a table capture. -This capture creates a table and puts all values from all anonymous captures -made by patt inside this table in successive integer keys, -starting at 1. -Moreover, -for each named capture group created by patt, -the first value of the group is put into the table -with the group name as its key. -The captured value is only the table. -

- - -

patt / string

-

-Creates a string capture. -It creates a capture string based on string. -The captured value is a copy of string, -except that the character % works as an escape character: -any sequence in string of the form %n, -with n between 1 and 9, -stands for the match of the n-th capture in patt. -The sequence %0 stands for the whole match. -The sequence %% stands for a single %. - - -

patt / table

-

-Creates a query capture. -It indexes the given table using as key the first value captured by -patt, -or the whole match if patt produced no value. -The value at that index is the final value of the capture. -If the table does not have that key, -there is no captured value. -

- - -

patt / function

-

-Creates a function capture. -It calls the given function passing all captures made by -patt as arguments, -or the whole match if patt made no capture. -The values returned by the function -are the final values of the capture. -In particular, -if function returns no value, -there is no captured value. -

- - -

lpeg.Cmt(patt, function)

-

-Creates a match-time capture. -Unlike all other captures, -this one is evaluated immediately when a match occurs. -It forces the immediate evaluation of all its nested captures -and then calls function. -

- -

-The given function gets as arguments the entire subject, -the current position (after the match of patt), -plus any capture values produced by patt. -

- -

-The first value returned by function -defines how the match happens. -If the call returns a number, -the match succeeds -and the returned number becomes the new current position. -(Assuming a subject s and current position i, -the returned number must be in the range [i, len(s) + 1].) -If the call returns true, -the match succeeds without consuming any input. -(So, to return true is equivalent to return i.) -If the call returns false, nil, or no value, -the match fails. -

- -

-Any extra values returned by the function become the -values produced by the capture. -

- - - - -

Some Examples

- -

Using a Pattern

-

-This example shows a very simple but complete program -that builds and uses a pattern: -

-
-local lpeg = require "lpeg"
-
--- matches a word followed by end-of-string
-p = lpeg.R"az"^1 * -1
-
-print(p:match("hello"))        --> 6
-print(lpeg.match(p, "hello"))  --> 6
-print(p:match("1 hello"))      --> nil
-
-

-The pattern is simply a sequence of one or more lower-case letters -followed by the end of string (-1). -The program calls match both as a method -and as a function. -In both sucessful cases, -the match returns -the index of the first character after the match, -which is the string length plus one. -

- - -

Name-value lists

-

-This example parses a list of name-value pairs and returns a table -with those pairs: -

-
-lpeg.locale(lpeg)   -- adds locale entries into 'lpeg' table
-
-local space = lpeg.space^0
-local name = lpeg.C(lpeg.alpha^1) * space
-local sep = lpeg.S(",;") * space
-local pair = lpeg.Cg(name * "=" * space * name) * sep^-1
-local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
-t = list:match("a=b, c = hi; next = pi")  --> { a = "b", c = "hi", next = "pi" }
-
-

-Each pair has the format name = name followed by -an optional separator (a comma or a semicolon). -The pair pattern encloses the pair in a group pattern, -so that the names become the values of a single capture. -The list pattern then folds these captures. -It starts with an empty table, -created by a table capture matching an empty string; -then for each capture (a pair of names) it applies rawset -over the accumulator (the table) and the capture values (the pair of names). -rawset returns the table itself, -so the accumulator is always the table. -

- -

Splitting a string

-

-The following code builds a pattern that -splits a string using a given pattern -sep as a separator: -

-
-function split (s, sep)
-  sep = lpeg.P(sep)
-  local elem = lpeg.C((1 - sep)^0)
-  local p = elem * (sep * elem)^0
-  return lpeg.match(p, s)
-end
-
-

-First the function ensures that sep is a proper pattern. -The pattern elem is a repetition of zero of more -arbitrary characters as long as there is not a match against -the separator. It also captures its result. -The pattern p matches a list of elements separated -by sep. -

- -

-If the split results in too many values, -it may overflow the maximum number of values -that can be returned by a Lua function. -In this case, -we should collect these values in a table: -

-
-function split (s, sep)
-  sep = lpeg.P(sep)
-  local elem = lpeg.C((1 - sep)^0)
-  local p = lpeg.Ct(elem * (sep * elem)^0)   -- make a table capture
-  return lpeg.match(p, s)
-end
-
- - -

Searching for a pattern

-

-The primitive match works only in anchored mode. -If we want to find a pattern anywhere in a string, -we must write a pattern that matches anywhere. -

- -

-Because patterns are composable, -we can write a function that, -given any arbitrary pattern p, -returns a new pattern that searches for p -anywhere in a string. -There are several ways to do the search. -One way is like this: -

-
-function anywhere (p)
-  return lpeg.P{ p + 1 * lpeg.V(1) }
-end
-
-

-This grammar has a straight reading: -it matches p or skips one character and tries again. -

- -

-If we want to know where the pattern is in the string -(instead of knowing only that it is there somewhere), -we can add position captures to the pattern: -

-
-local I = lpeg.Cp()
-function anywhere (p)
-  return lpeg.P{ I * p * I + 1 * lpeg.V(1) }
-end
-
- -

-Another option for the search is like this: -

-
-local I = lpeg.Cp()
-function anywhere (p)
-  return (1 - lpeg.P(p))^0 * I * p * I
-end
-
-

-Again the pattern has a straight reading: -it skips as many characters as possible while not matching p, -and then matches p (plus appropriate captures). -

- -

-If we want to look for a pattern only at word boundaries, -we can use the following transformer: -

- -
-local t = lpeg.locale()
-
-function atwordboundary (p)
-  return lpeg.P{
-    [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1)
-  }
-end
-
- - -

Balanced parentheses

-

-The following pattern matches only strings with balanced parentheses: -

-
-b = lpeg.P{ "(" * ((1 - lpeg.S"()") + lpeg.V(1))^0 * ")" }
-
-

-Reading the first (and only) rule of the given grammar, -we have that a balanced string is -an open parenthesis, -followed by zero or more repetitions of either -a non-parenthesis character or -a balanced string (lpeg.V(1)), -followed by a closing parenthesis. -

- - -

Global substitution

-

-The next example does a job somewhat similar to string.gsub. -It receives a pattern and a replacement value, -and substitutes the replacement value for all occurrences of the pattern -in a given string: -

-
-function gsub (s, patt, repl)
-  patt = lpeg.P(patt)
-  patt = lpeg.Cs((patt / repl + 1)^0)
-  return lpeg.match(patt, s)
-end
-
-

-As in string.gsub, -the replacement value can be a string, -a function, or a table. -

- - -

Comma-Separated Values (CSV)

-

-This example breaks a string into comma-separated values, -returning all fields: -

-
-local field = '"' * lpeg.Cs(((lpeg.P(1) - '"') + lpeg.P'""' / '"')^0) * '"' +
-                    lpeg.C((1 - lpeg.S',\n"')^0)
-
-local record = field * (',' * field)^0 * (lpeg.P'\n' + -1)
-
-function csv (s)
-  return lpeg.match(record, s)
-end
-
-

-A field is either a quoted field -(which may contain any character except an individual quote, -which may be written as two quotes that are replaced by one) -or an unquoted field -(which cannot contain commas, newlines, or quotes). -A record is a list of fields separated by commas, -ending with a newline or the string end (-1). -

- -

-As it is, -the previous pattern returns each field as a separated result. -If we add a table capture in the definition of record, -the pattern will return instead a single table -containing all fields: -

-
-local record = lpeg.Ct(field * (',' * field)^0) * (lpeg.P'\n' + -1)
-
- - -

UTF-8 and Latin 1

-

-It is not difficult to use LPeg to convert a string from -UTF-8 encoding to Latin 1 (ISO 8859-1): -

- -
--- convert a two-byte UTF-8 sequence to a Latin 1 character
-local function f2 (s)
-  local c1, c2 = string.byte(s, 1, 2)
-  return string.char(c1 * 64 + c2 - 12416)
-end
-
-local utf8 = lpeg.R("\0\127")
-           + lpeg.R("\194\195") * lpeg.R("\128\191") / f2
-
-local decode_pattern = lpeg.Cs(utf8^0) * -1
-
-

-In this code, -the definition of UTF-8 is already restricted to the -Latin 1 range (from 0 to 255). -Any encoding outside this range (as well as any invalid encoding) -will not match that pattern. -

- -

-As the definition of decode_pattern demands that -the pattern matches the whole input (because of the -1 at its end), -any invalid string will simply fail to match, -without any useful information about the problem. -We can improve this situation redefining decode_pattern -as follows: -

-
-local function er (_, i) error("invalid encoding at position " .. i) end
-
-local decode_pattern = lpeg.Cs(utf8^0) * (-1 + lpeg.P(er))
-
-

-Now, if the pattern utf8^0 stops -before the end of the string, -an appropriate error function is called. -

- - -

UTF-8 and Unicode

-

-We can extend the previous patterns to handle all Unicode code points. -Of course, -we cannot translate them to Latin 1 or any other one-byte encoding. -Instead, our translation results in a array with the code points -represented as numbers. -The full code is here: -

-
--- decode a two-byte UTF-8 sequence
-local function f2 (s)
-  local c1, c2 = string.byte(s, 1, 2)
-  return c1 * 64 + c2 - 12416
-end
-
--- decode a three-byte UTF-8 sequence
-local function f3 (s)
-  local c1, c2, c3 = string.byte(s, 1, 3)
-  return (c1 * 64 + c2) * 64 + c3 - 925824
-end
-
--- decode a four-byte UTF-8 sequence
-local function f4 (s)
-  local c1, c2, c3, c4 = string.byte(s, 1, 4)
-  return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
-end
-
-local cont = lpeg.R("\128\191")   -- continuation byte
-
-local utf8 = lpeg.R("\0\127") / string.byte
-           + lpeg.R("\194\223") * cont / f2
-           + lpeg.R("\224\239") * cont * cont / f3
-           + lpeg.R("\240\244") * cont * cont * cont / f4
-
-local decode_pattern = lpeg.Ct(utf8^0) * -1
-
- - -

Lua's long strings

-

-A long string in Lua starts with the pattern [=*[ -and ends at the first occurrence of ]=*] with -exactly the same number of equal signs. -If the opening brackets are followed by a newline, -this newline is discharged -(that is, it is not part of the string). -

- -

-To match a long string in Lua, -the pattern must capture the first repetition of equal signs and then, -whenever it finds a candidate for closing the string, -check whether it has the same number of equal signs. -

- -
-equals = lpeg.P"="^0
-open = "[" * lpeg.Cg(equals, "init") * "[" * lpeg.P"\n"^-1
-close = "]" * lpeg.C(equals) * "]"
-closeeq = lpeg.Cmt(close * lpeg.Cb("init"), function (s, i, a, b) return a == b end)
-string = open * lpeg.C((lpeg.P(1) - closeeq)^0) * close /
-  function (s, o) return s end
-
- -

-The open pattern matches [=*[, -capturing the repetitions of equal signs in a group named init; -it also discharges an optional newline, if present. -The close pattern matches ]=*], -also capturing the repetitions of equal signs. -The closeeq pattern first matches close; -then it uses a back capture to recover the capture made -by the previous open, -which is named init; -finally it uses a match-time capture to check -whether both captures are equal. -The string pattern starts with an open, -then it goes as far as possible until matching closeeq, -and then matches the final close. -The final function capture simply discards -the capture made by close. -

- - -

Arithmetic expressions

-

-This example is a complete parser and evaluator for simple -arithmetic expressions. -We write it in two styles. -The first approach first builds a syntax tree and then -traverses this tree to compute the expression value: -

-
--- Lexical Elements
-local Space = lpeg.S(" \n\t")^0
-local Number = lpeg.C(lpeg.P"-"^-1 * lpeg.R("09")^1) * Space
-local FactorOp = lpeg.C(lpeg.S("+-")) * Space
-local TermOp = lpeg.C(lpeg.S("*/")) * Space
-local Open = "(" * Space
-local Close = ")" * Space
-
--- Grammar
-local Exp, Term, Factor = lpeg.V"Exp", lpeg.V"Term", lpeg.V"Factor"
-G = lpeg.P{ Exp,
-  Exp = lpeg.Ct(Factor * (FactorOp * Factor)^0);
-  Factor = lpeg.Ct(Term * (TermOp * Term)^0);
-  Term = Number + Open * Exp * Close;
-}
-
-G = Space * G * -1
-
--- Evaluator
-function eval (x)
-  if type(x) == "string" then
-    return tonumber(x)
-  else
-    local op1 = eval(x[1])
-    for i = 2, #x, 2 do
-      local op = x[i]
-      local op2 = eval(x[i + 1])
-      if (op == "+") then op1 = op1 + op2
-      elseif (op == "-") then op1 = op1 - op2
-      elseif (op == "*") then op1 = op1 * op2
-      elseif (op == "/") then op1 = op1 / op2
-      end
-    end
-    return op1
-  end
-end
-
--- Parser/Evaluator
-function evalExp (s)
-  local t = lpeg.match(G, s)
-  if not t then error("syntax error", 2) end
-  return eval(t)
-end
-
--- small example
-print(evalExp"3 + 5*9 / (1+1) - 12")   --> 13.5
-
- -

-The second style computes the expression value on the fly, -without building the syntax tree. -The following grammar takes this approach. -(It assumes the same lexical elements as before.) -

-
--- Auxiliary function
-function eval (v1, op, v2)
-  if (op == "+") then return v1 + v2
-  elseif (op == "-") then return v1 - v2
-  elseif (op == "*") then return v1 * v2
-  elseif (op == "/") then return v1 / v2
-  end
-end
-
--- Grammar
-local V = lpeg.V
-G = lpeg.P{ "Exp",
-  Exp = lpeg.Cf(V"Factor" * lpeg.Cg(FactorOp * V"Factor")^0, eval);
-  Factor = lpeg.Cf(V"Term" * lpeg.Cg(TermOp * V"Term")^0, eval);
-  Term = Number / tonumber + Open * V"Exp" * Close;
-}
-
--- small example
-print(lpeg.match(G, "3 + 5*9 / (1+1) - 12"))   --> 13.5
-
-

-Note the use of the fold (accumulator) capture. -To compute the value of an expression, -the accumulator starts with the value of the first factor, -and then applies eval over -the accumulator, the operator, -and the new factor for each repetition. -

- - - -

Download

- -

LPeg -source code.

- - -

License

- -

-Copyright © 2008 Lua.org, PUC-Rio. -

-

-Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), -to deal in the Software without restriction, -including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, -and to permit persons to whom the Software is -furnished to do so, -subject to the following conditions: -

- -

-The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. -

- -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -

- -
- -
- -
-

-$Id: lpeg.html,v 1.64 2011/02/16 15:01:58 roberto Exp $ -

-
- -
- - - diff --git a/lpeg/lpeg.o b/lpeg/lpeg.o deleted file mode 100644 index f566774f7a0f7769007dcbf23f29e0c825361d1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48688 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 diff --git a/lpeg/makefile b/lpeg/makefile deleted file mode 100644 index 87169a22..00000000 --- a/lpeg/makefile +++ /dev/null @@ -1,42 +0,0 @@ -LIBNAME = lpeg -LUADIR = /usr/include/lua5.1/ - -COPT = -O2 -DNDEBUG - -CWARNS = -Wall -Wextra -pedantic \ - -Waggregate-return \ - -Wbad-function-cast \ - -Wcast-align \ - -Wcast-qual \ - -Wdeclaration-after-statement \ - -Wdisabled-optimization \ - -Wmissing-prototypes \ - -Wnested-externs \ - -Wpointer-arith \ - -Wshadow \ - -Wsign-compare \ - -Wstrict-prototypes \ - -Wundef \ - -Wwrite-strings \ - # -Wunreachable-code \ - - -CFLAGS = $(CWARNS) $(COPT) -ansi -I$(LUADIR) -CC = gcc - -# For Linux -DLLFLAGS = -shared -fpic -ENV = - -# For Mac OS -# ENV = MACOSX_DEPLOYMENT_TARGET=10.4 -# DLLFLAGS = -bundle -undefined dynamic_lookup - -lpeg.so: lpeg.o - env $(ENV) $(CC) $(DLLFLAGS) lpeg.o -o lpeg.so - -lpeg.o: makefile lpeg.c lpeg.h - -test: test.lua re.lua lpeg.so - test.lua - diff --git a/lpeg/re.html b/lpeg/re.html deleted file mode 100644 index d67e23a3..00000000 --- a/lpeg/re.html +++ /dev/null @@ -1,486 +0,0 @@ - - - - LPeg.re - Regex syntax for LPEG - - - - - - - -
- -
- -
LPeg.re
-
- Regex syntax for LPEG -
-
- -
- - - -
- -

The re Module

- -

-The re module -(provided by file re.lua in the distribution) -supports a somewhat conventional regex syntax -for pattern usage within LPeg. -

- -

-The next table summarizes re's syntax. -A p represents an arbitrary pattern; -num represents a number ([0-9]+); -name represents an identifier -([a-zA-Z][a-zA-Z0-9_]*). -Constructions are listed in order of decreasing precedence. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SyntaxDescription
( p ) grouping
'string' literal string
"string" literal string
[class] character class
. any character
%namepattern defs[name] or a pre-defined pattern
namenon terminal
<name>non terminal
{} position capture
{ p } simple capture
{: p :} anonymous group capture
{:name: p :} named group capture
{~ p ~} substitution capture
=name back reference -
p ? optional match
p * zero or more repetitions
p + one or more repetitions
p^num exactly n repetitions
p^+numat least n repetitions
p^-numat most n repetitions
p -> 'string' string capture
p -> "string" string capture
p -> {} table capture
p -> name function/query/string capture -equivalent to p / defs[name]
p => name match-time capture -equivalent to lpeg.Cmt(p, defs[name])
& p and predicate
! p not predicate
p1 p2 concatenation
p1 / p2 ordered choice
(name <- p)+ grammar
-

-Any space appearing in a syntax description can be -replaced by zero or more space characters and Lua-style comments -(-- until end of line). -

- -

-Character classes define sets of characters. -An initial ^ complements the resulting set. -A range x-y includes in the set -all characters with codes between the codes of x and y. -A pre-defined class %name includes all -characters of that class. -A simple character includes itself in the set. -The only special characters inside a class are ^ -(special only if it is the first character); -] -(can be included in the set as the first character, -after the optional ^); -% (special only if followed by a letter); -and - -(can be included in the set as the first or the last character). -

- -

-Currently the pre-defined classes are similar to those from the -Lua's string library -(%a for letters, -%A for non letters, etc.). -There is also a class %nl -containing only the newline character, -which is particularly handy for grammars written inside long strings, -as long strings do not interpret escape sequences like \n. -

- - -

Functions

- -

re.compile (string, [, defs])

-

-Compiles the given string and -returns an equivalent LPeg pattern. -The given string may define either an expression or a grammar. -The optional defs table provides extra Lua values -to be used by the pattern. -

- -

re.find (subject, pattern [, init])

-

-Searches the given pattern in the given subject. -If it finds a match, -returns the index where this occurrence starts, -plus the captures made by the pattern (if any). -Otherwise, returns nil. -

- -

-An optional numeric argument init makes the search -starts at that position in the subject string. -As usual in Lua libraries, -a negative value counts from the end. -

- -

re.match (subject, pattern)

-

-Matches the given pattern against the given subject. -

- -

re.updatelocale ()

-

-Updates the pre-defined character classes to the current locale. -

- - -

Some Examples

- -

A complete simple program

-

-The next code shows a simple complete Lua program using -the re module: -

-
-local re = require"re"
-
--- find the position of the first number in a string
-print(re.find("the number 423 is odd", "[0-9]+"))  --> 12
-
--- similar, but also captures (and returns) the number
-print(re.find("the number 423 is odd", "{[0-9]+}"))  --> 12    423
-
--- returns all words in a string
-print(re.match("the number 423 is odd", "({%a+} / .)*"))
---> the    number    is    odd
-
- - -

Balanced parentheses

-

-The following call will produce the same pattern produced by the -Lua expression in the -balanced parentheses example: -

-
-b = re.compile[[  balanced <- "(" ([^()] / balanced)* ")"  ]]
-
- -

String reversal

-

-The next example reverses a string: -

-
-rev = re.compile[[ R <- (!.) -> '' / ({.} R) -> '%2%1']]
-print(rev:match"0123456789")   --> 9876543210
-
- -

CSV decoder

-

-The next example replicates the CSV decoder: -

-
-record = re.compile[[
-  record <- ( field (',' field)* ) -> {} (%nl / !.)
-  field <- escaped / nonescaped
-  nonescaped <- { [^,"%nl]* }
-  escaped <- '"' {~ ([^"] / '""' -> '"')* ~} '"'
-]]
-
- -

Lua's long strings

-

-The next example matches Lua long strings: -

-
-c = re.compile([[
-  longstring <- ('[' {:eq: '='* :} '[' close) -> void
-  close <- ']' =eq ']' / . close
-]], {void = function () end})
-
-print(c:match'[==[]]===]]]]==]===[]')   --> 17
-
- -

Abstract Syntax Trees

-

-This example shows a simple way to build an -abstract syntax tree (AST) for a given grammar. -To keep our example simple, -let us consider the following grammar -for lists of names: -

-
-p = re.compile[[
-      listname <- (name s)*
-      name <- [a-z][a-z]*
-      s <- %s*
-]]
-
-

-Now, we will add captures to build a corresponding AST. -As a first step, the pattern will build a table to -represent each non terminal; -terminals will be represented by their corresponding strings: -

-
-c = re.compile[[
-      listname <- (name s)* -> {}
-      name <- {[a-z][a-z]*} -> {}
-      s <- %s*
-]]
-
-

-Now, a match against "hi hello bye" -results in the table -{{"hi"}, {"hello"}, {"bye"}}. -

-

-For such a simple grammar, -this AST is more than enough; -actually, the tables around each single name -are already overkilling. -More complex grammars, -however, may need some more structure. -Specifically, -it would be useful if each table had -a tag field telling what non terminal -that table represents. -We can add such a tag using -named group captures: -

-
-x = re.compile[[
-      listname <- ({:tag: '' -> 'list':} (name s)*) -> {}
-      name <- ({:tag: '' -> 'id':} {[a-z][a-z]*}) -> {}
-      s <- ' '*
-]]
-
-

-With these group captures, -a match against "hi hello bye" -results in the following table: -

-
-{tag="list",
-  {tag="id", "hi"},
-  {tag="id", "hello"},
-  {tag="id", "bye"}
-}
-
- - -

Indented blocks

-

-This example breaks indented blocks into tables, -respecting the indentation: -

-
-p = re.compile[[
-  block <- ({:ident:' '*:} line
-           ((=ident !' ' line) / &(=ident ' ') block)*) -> {}
-  line <- {[^%nl]*} %nl
-]]
-
-

-As an example, -consider the following text: -

-
-t = p:match[[
-first line
-  subline 1
-  subline 2
-second line
-third line
-  subline 3.1
-    subline 3.1.1
-  subline 3.2
-]]
-
-

-The resulting table t will be like this: -

-
-   {'first line'; {'subline 1'; 'subline 2'; ident = '  '};
-    'second line';
-    'third line'; { 'subline 3.1'; {'subline 3.1.1'; ident = '    '};
-                    'subline 3.2'; ident = '  '};
-    ident = ''}
-
- -

Macro expander

-

-This example implements a simple macro expander. -Macros must be defined as part of the pattern, -following some simple rules: -

-
-p = re.compile[[
-      text <- {~ item* ~}
-      item <- macro / [^()] / '(' item* ')'
-      arg <- ' '* {~ (!',' item)* ~}
-      args <- '(' arg (',' arg)* ')'
-      -- now we define some macros
-      macro <- ('apply' args) -> '%1(%2)'
-             / ('add' args) -> '%1 + %2'
-             / ('mul' args) -> '%1 * %2'
-]]
-
-print(p:match"add(mul(a,b), apply(f,x))")   --> a * b + f(x)
-
-

-A text is a sequence of items, -wherein we apply a substitution capture to expand any macros. -An item is either a macro, -any character different from parentheses, -or a parenthesized expression. -A macro argument (arg) is a sequence -of items different from a comma. -(Note that a comma may appear inside an item, -e.g., inside a parenthesized expression.) -Again we do a substitution capture to expand any macro -in the argument before expanding the outer macro. -args is a list of arguments separated by commas. -Finally we define the macros. -Each macro is a string substitution; -it replaces the macro name and its arguments by its corresponding string, -with each %n replaced by the n-th argument. -

- -

Patterns

-

-This example shows the complete syntax -of patterns accepted by re. -

-
-p = [=[
-
-pattern         <- exp !.
-exp             <- S (alternative / grammar)
-
-alternative     <- seq ('/' S seq)*
-seq             <- prefix*
-prefix          <- '&' S prefix / '!' S prefix / suffix
-suffix          <- primary S (([+*?]
-                            / '^' [+-]? num
-                            / '->' S (string / '{}' / name)
-                            / '=>' S name) S)*
-
-primary         <- '(' exp ')' / string / class / defined
-                 / '{:' (name ':')? exp ':}'
-                 / '=' name
-                 / '{}'
-                 / '{~' exp '~}'
-                 / '{' exp '}'
-                 / '.'
-                 / name S !arrow
-                 / '<' name '>'          -- old-style non terminals
-
-grammar         <- definition+
-definition      <- name S arrow exp
-
-class           <- '[' '^'? item (!']' item)* ']'
-item            <- defined / range / .
-range           <- . '-' [^]]
-
-S               <- (%s / '--' [^%nl]*)*   -- spaces and comments
-name            <- [A-Za-z][A-Za-z0-9_]*
-arrow           <- '<-'
-num             <- [0-9]+
-string          <- '"' [^"]* '"' / "'" [^']* "'"
-defined         <- '%' name
-
-]=]
-
-print(re.match(p, p))   -- a self description must match itself
-
- - - -

License

- -

-Copyright © 2008-2010 Lua.org, PUC-Rio. -

-

-Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), -to deal in the Software without restriction, -including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, -and to permit persons to whom the Software is -furnished to do so, -subject to the following conditions: -

- -

-The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. -

- -

-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -

- -
- -
- -
-

-$Id: re.html,v 1.17 2011/01/10 15:08:06 roberto Exp $ -

-
- -
- - - diff --git a/lpeg/re.lua b/lpeg/re.lua deleted file mode 100644 index 2320c206..00000000 --- a/lpeg/re.lua +++ /dev/null @@ -1,248 +0,0 @@ --- $Id: re.lua,v 1.39 2010/11/04 19:44:18 roberto Exp $ - --- imported functions and modules -local tonumber, type, print, error = tonumber, type, print, error -local setmetatable = setmetatable -local m = require"lpeg" - --- 'm' will be used to parse expressions, and 'mm' will be used to --- create expressions; that is, 're' runs on 'm', creating patterns --- on 'mm' -local mm = m - --- pattern's metatable -local mt = getmetatable(mm.P(0)) - - - --- No more global accesses after this point -local version = _VERSION -if version == "Lua 5.2" then _ENV = nil end - - -local any = m.P(1) - - --- Pre-defined names -local Predef = { nl = m.P"\n" } - - -local mem -local fmem -local gmem - - -local function updatelocale () - mm.locale(Predef) - Predef.a = Predef.alpha - Predef.c = Predef.cntrl - Predef.d = Predef.digit - Predef.g = Predef.graph - Predef.l = Predef.lower - Predef.p = Predef.punct - Predef.s = Predef.space - Predef.u = Predef.upper - Predef.w = Predef.alnum - Predef.x = Predef.xdigit - Predef.A = any - Predef.a - Predef.C = any - Predef.c - Predef.D = any - Predef.d - Predef.G = any - Predef.g - Predef.L = any - Predef.l - Predef.P = any - Predef.p - Predef.S = any - Predef.s - Predef.U = any - Predef.u - Predef.W = any - Predef.w - Predef.X = any - Predef.x - mem = {} -- restart memoization - fmem = {} - gmem = {} - local mt = {__mode = "v"} - setmetatable(mem, mt) - setmetatable(fmem, mt) - setmetatable(gmem, mt) -end - - -updatelocale() - - - -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 msg = (#s < i + 20) and s:sub(i) - or s:sub(i,i+20) .. "..." - msg = ("pattern error near '%s'"):format(msg) - error(msg, 2) -end - -local function mult (p, n) - local np = mm.P(true) - while n >= 1 do - if n%2 >= 1 then np = np * p end - p = p * p - n = n/2 - end - return np -end - -local function equalcap (s, i, c) - if type(c) ~= "string" then return nil end - local e = #c + i - if s:sub(i, e - 1) == c then return e else return nil end -end - - -local S = (m.S(" \f\n\r\t\v") + "--" * (any - Predef.nl)^0)^0 - -local name = m.R("AZ", "az") * m.R("AZ", "az", "__", "09")^0 - -local arrow = S * "<-" - -local exp_follow = m.P"/" + ")" + "}" + ":}" + "~}" + (name * arrow) + -1 - -name = m.C(name) - - --- identifiers only have meaning in a given environment -local Identifier = name * m.Carg(1) - -local num = m.C(m.R"09"^1) * S / tonumber - -local String = "'" * m.C((any - "'")^0) * "'" + - '"' * m.C((any - '"')^0) * '"' - - -local defined = "%" * Identifier / function (c,Defs) - local cat = Defs and Defs[c] or Predef[c] - if not cat then error ("name '" .. c .. "' undefined") end - return cat -end - -local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R - -local item = defined + Range + m.C(any) - -local Class = - "[" - * (m.C(m.P"^"^-1)) -- optional complement symbol - * m.Cf(item * (item - "]")^0, mt.__add) / - function (c, p) return c == "^" and any - p or p end - * "]" - -local function adddef (t, k, Defs, exp) - if t[k] then - error("'"..k.."' already defined as a rule") - else - t[k] = exp - end - return t -end - -local function firstdef (n, Defs, r) return adddef({n}, n, Defs, r) end - - - -local exp = m.P{ "Exp", - Exp = S * ( m.V"Grammar" - + m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) ); - Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul) - * (#exp_follow + patt_error); - Prefix = "&" * S * m.V"Prefix" / mt.__len - + "!" * S * m.V"Prefix" / mt.__unm - + m.V"Suffix"; - Suffix = m.Cf(m.V"Primary" * S * - ( ( m.P"+" * m.Cc(1, mt.__pow) - + m.P"*" * m.Cc(0, mt.__pow) - + m.P"?" * m.Cc(-1, mt.__pow) - + "^" * ( m.Cg(num * m.Cc(mult)) - + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)) - ) - + "->" * S * ( m.Cg(String * m.Cc(mt.__div)) - + m.P"{}" * m.Cc(nil, m.Ct) - + m.Cg(Identifier / getdef * m.Cc(mt.__div)) - ) - + "=>" * S * m.Cg(Identifier / getdef * m.Cc(m.Cmt)) - ) * S - )^0, function (a,b,f) return f(a,b) end ); - Primary = "(" * m.V"Exp" * ")" - + String / mm.P - + Class - + defined - + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" / - function (n, p) return mm.Cg(p, n) end - + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end - + m.P"{}" / mm.Cp - + "{~" * m.V"Exp" * "~}" / mm.Cs - + "{" * m.V"Exp" * "}" / mm.C - + m.P"." * m.Cc(any) - + name * -arrow / mm.V - + "<" * name * ">" / mm.V; - Definition = Identifier * arrow * m.V"Exp"; - Grammar = m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, adddef) / - mm.P -} - -local pattern = S * exp / mm.P * (-any + patt_error) - - -local function compile (p, defs) - if mm.type(p) == "pattern" then return p end -- already compiled - local cp = pattern:match(p, 1, defs) - if not cp then error("incorrect pattern", 3) end - return cp -end - -local function match (s, p, i) - local cp = mem[p] - if not cp then - cp = compile(p) - mem[p] = cp - end - return cp:match(s, i or 1) -end - -local function find (s, p, i) - local cp = fmem[p] - if not cp then - cp = compile(p) - cp = mm.P{ mm.Cp() * cp + 1 * mm.V(1) } - fmem[p] = cp - end - return cp:match(s, i or 1) -end - -local function gsub (s, p, rep) - local g = gmem[p] or {} -- ensure gmem[p] is not collected while here - gmem[p] = g - local cp = g[rep] - if not cp then - cp = compile(p) - cp = mm.Cs((cp / rep + 1)^0) - g[rep] = cp - end - return cp:match(s) -end - - --- exported names -local re = { - compile = compile, - match = match, - find = find, - gsub = gsub, - updatelocale = updatelocale, -} - -if version == "Lua 5.1" then _G.re = re end - -return re diff --git a/lpeg/test.lua b/lpeg/test.lua deleted file mode 100755 index 533a6d2d..00000000 --- a/lpeg/test.lua +++ /dev/null @@ -1,1188 +0,0 @@ -#!/usr/bin/env lua5.1 - --- $Id: test.lua,v 1.82 2010/12/03 14:49:54 roberto Exp $ - -require"strict" -- just to be pedantic - -local m = require"lpeg" - -local debug = require"debug" - - --- compatibility with Lua 5.2 -local unpack = table.unpack or unpack - - --- most tests here do not need much stack space -m.setmaxstack(5) - -any = m.P(1) -space = m.S" \t\n"^0 - -local function checkeq (x, y, p) -if p then print(x,y) end - if type(x) ~= "table" then assert(x == y) - else - for k,v in pairs(x) do checkeq(v, y[k], p) end - for k,v in pairs(y) do checkeq(v, x[k], p) end - end -end - - -mt = getmetatable(m.P(1)) - - -local allchar = {} -for i=0,255 do allchar[i + 1] = i end -allchar = string.char(unpack(allchar)) -assert(#allchar == 256) - -local function cs2str (c) - return m.match(m.Cs((c + m.P(1)/"")^0), allchar) -end - -local function eqcharset (c1, c2) - assert(cs2str(c1) == cs2str(c2)) -end - - -print"General tests for LPeg library" - -assert(type(m.version()) == "string") -print("version " .. m.version()) -assert(m.type("alo") ~= "pattern") -assert(m.type(io.input) ~= "pattern") -assert(m.type(m.P"alo") == "pattern") - --- tests for some basic optimizations -assert(m.match(m.P(false) + "a", "a") == 2) -assert(m.match(m.P(true) + "a", "a") == 1) -assert(m.match("a" + m.P(false), "b") == nil) -assert(m.match("a" + m.P(true), "b") == 1) - -assert(m.match(m.P(false) * "a", "a") == nil) -assert(m.match(m.P(true) * "a", "a") == 2) -assert(m.match("a" * m.P(false), "a") == nil) -assert(m.match("a" * m.P(true), "a") == 2) - -assert(m.match(#m.P(false) * "a", "a") == nil) -assert(m.match(#m.P(true) * "a", "a") == 2) -assert(m.match("a" * #m.P(false), "a") == nil) -assert(m.match("a" * #m.P(true), "a") == 2) - - --- tests for locale -do - assert(m.locale(m) == m) - local t = {} - assert(m.locale(t, m) == t) - local x = m.locale() - for n,v in pairs(x) do - assert(type(n) == "string") - eqcharset(v, m[n]) - end -end - - - -assert(m.match(3, "aaaa")) -assert(m.match(4, "aaaa")) -assert(not m.match(5, "aaaa")) -assert(m.match(-3, "aa")) -assert(not m.match(-3, "aaa")) -assert(not m.match(-3, "aaaa")) -assert(not m.match(-4, "aaaa")) -assert(m.P(-5):match"aaaa") - -assert(m.match("a", "alo") == 2) -assert(m.match("al", "alo") == 3) -assert(not m.match("alu", "alo")) -assert(m.match(true, "") == 1) - -digit = m.S"0123456789" -upper = m.S"ABCDEFGHIJKLMNOPQRSTUVWXYZ" -lower = m.S"abcdefghijklmnopqrstuvwxyz" -letter = m.S"" + upper + lower -alpha = letter + digit + m.R() - -eqcharset(m.S"", m.P(false)) -eqcharset(upper, m.R("AZ")) -eqcharset(lower, m.R("az")) -eqcharset(upper + lower, m.R("AZ", "az")) -eqcharset(upper + lower, m.R("AZ", "cz", "aa", "bb", "90")) -eqcharset(digit, m.S"01234567" + "8" + "9") -eqcharset(upper, letter - lower) -eqcharset(m.S(""), m.R()) -assert(cs2str(m.S("")) == "") - -eqcharset(m.S"\0", "\0") -eqcharset(m.S"\1\0\2", m.R"\0\2") -eqcharset(m.S"\1\0\2", m.R"\1\2" + "\0") -eqcharset(m.S"\1\0\2" - "\0", m.R"\1\2") - -word = alpha^1 * (1 - alpha)^0 - -assert((word^0 * -1):match"alo alo") -assert(m.match(word^1 * -1, "alo alo")) -assert(m.match(word^2 * -1, "alo alo")) -assert(not m.match(word^3 * -1, "alo alo")) - -assert(not m.match(word^-1 * -1, "alo alo")) -assert(m.match(word^-2 * -1, "alo alo")) -assert(m.match(word^-3 * -1, "alo alo")) - -eos = m.P(-1) - -assert(m.match(digit^0 * letter * digit * eos, "1298a1")) -assert(not m.match(digit^0 * letter * eos, "1257a1")) - -b = { - [1] = "(" * (((1 - m.S"()") + #m.P"(" * m.V(1))^0) * ")" -} - -assert(m.match(b, "(al())()")) -assert(not m.match(b * eos, "(al())()")) -assert(m.match(b * eos, "((al())()(é))")) -assert(not m.match(b, "(al()()")) - -assert(not m.match(letter^1 - "for", "foreach")) -assert(m.match(letter^1 - ("for" * eos), "foreach")) -assert(not m.match(letter^1 - ("for" * eos), "for")) - -function basiclookfor (p) - return m.P { - [1] = p + (1 * m.V(1)) - } -end - -function caplookfor (p) - return basiclookfor(p:C()) -end - -assert(m.match(caplookfor(letter^1), " 4achou123...") == "achou") -a = {m.match(caplookfor(letter^1)^0, " two words, one more ")} -checkeq(a, {"two", "words", "one", "more"}) - -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")} -checkeq(a, {"123", "d"}) - -a = {m.match(m.C(digit^1) * "d" * -1 + m.C(letter^1 * m.Cc"l"), "123d")} -checkeq(a, {"123"}) - -a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "abcd")} -checkeq(a, {"abcd", "l"}) - -a = {m.match(m.Cc(10,20,30) * 'a' * m.Cp(), 'aaa')} -checkeq(a, {10,20,30,2}) -a = {m.match(m.Cp() * m.Cc(10,20,30) * 'a' * m.Cp(), 'aaa')} -checkeq(a, {1,10,20,30,2}) -a = m.match(m.Ct(m.Cp() * m.Cc(10,20,30) * 'a' * m.Cp()), 'aaa') -checkeq(a, {1,10,20,30,2}) -a = m.match(m.Ct(m.Cp() * m.Cc(7,8) * m.Cc(10,20,30) * 'a' * m.Cp()), 'aaa') -checkeq(a, {1,7,8,10,20,30,2}) -a = {m.match(m.Cc() * m.Cc() * m.Cc(1) * m.Cc(2,3,4) * m.Cc() * 'a', 'aaa')} -checkeq(a, {1,2,3,4}) - -a = {m.match(m.Cp() * letter^1 * m.Cp(), "abcd")} -checkeq(a, {1, 5}) - - -t = {m.match({[1] = m.C(m.C(1) * m.V(1) + -1)}, "abc")} -checkeq(t, {"abc", "a", "bc", "b", "c", "c", ""}) - - --- test for small capture boundary -for i = 250,260 do - assert(#m.match(m.C(i), string.rep('a', i)) == i) - assert(#m.match(m.C(m.C(i)), string.rep('a', i)) == i) -end - - --- tests for any*n -for n = 1, 550 do - local x_1 = string.rep('x', n - 1) - local x = x_1 .. 'a' - assert(not m.P(n):match(x_1)) - assert(m.P(n):match(x) == n + 1) - assert(n < 4 or m.match(m.P(n) + "xxx", x_1) == 4) - assert(m.C(n):match(x) == x) - assert(m.C(m.C(n)):match(x) == x) - assert(m.P(-n):match(x_1) == 1) - assert(not m.P(-n):match(x)) - assert(n < 13 or m.match(m.Cc(20) * ((n - 13) * m.P(10)) * 3, x) == 20) - local n3 = math.floor(n/3) - assert(m.match(n3 * m.Cp() * n3 * n3, x) == n3 + 1) -end - -assert(m.P(0):match("x") == 1) -assert(m.P(0):match("") == 1) -assert(m.C(0):match("x") == "") -assert(m.match(m.Cc(0) * m.P(10) + m.Cc(1) * "xuxu", "xuxu") == 1) -assert(m.match(m.Cc(0) * m.P(10) + m.Cc(1) * "xuxu", "xuxuxuxuxu") == 0) -assert(m.match(m.C(m.P(2)^1), "abcde") == "abcd") -p = m.Cc(0) * 1 + m.Cc(1) * 2 + m.Cc(2) * 3 + m.Cc(3) * 4 - - --- test for alternation optimization -assert(m.match(m.P"a"^1 + "ab" + m.P"x"^0, "ab") == 2) -assert(m.match((m.P"a"^1 + "ab" + m.P"x"^0 * 1)^0, "ab") == 3) -assert(m.match(m.P"ab" + "cd" + "" + "cy" + "ak", "98") == 1) -assert(m.match(m.P"ab" + "cd" + "ax" + "cy", "ax") == 3) -assert(m.match("a" * m.P"b"^0 * "c" + "cd" + "ax" + "cy", "ax") == 3) -assert(m.match((m.P"ab" + "cd" + "ax" + "cy")^0, "ax") == 3) -assert(m.match(m.P(1) * "x" + m.S"" * "xu" + "ay", "ay") == 3) -assert(m.match(m.P"abc" + "cde" + "aka", "aka") == 4) -assert(m.match(m.S"abc" * "x" + "cde" + "aka", "ax") == 3) -assert(m.match(m.S"abc" * "x" + "cde" + "aka", "aka") == 4) -assert(m.match(m.S"abc" * "x" + "cde" + "aka", "cde") == 4) -assert(m.match(m.S"abc" * "x" + "ide" + m.S"ab" * "ka", "aka") == 4) -assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "ax") == 3) -assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "aka") == 4) -assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "cde") == 4) -assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "ide" + m.S"ab" * "ka", "aka") == 4) -assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "ide" + m.S"ab" * "ka", "ax") == 3) -assert(m.match(m.P(1) * "x" + "cde" + m.S"ab" * "ka", "aka") == 4) -assert(m.match(m.P(1) * "x" + "cde" + m.P(1) * "ka", "aka") == 4) -assert(m.match(m.P(1) * "x" + "cde" + m.P(1) * "ka", "cde") == 4) -assert(m.match(m.P"eb" + "cd" + m.P"e"^0 + "x", "ee") == 3) -assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "abcd") == 3) -assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "eeex") == 4) -assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "cd") == 3) -assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "x") == 1) -assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x" + "", "zee") == 1) -assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "abcd") == 3) -assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "eeex") == 4) -assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "cd") == 3) -assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "x") == 2) -assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x" + "", "zee") == 1) - -pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510" -assert(m.match(m.Cs((m.P"1" / "a" + m.P"5" / "b" + m.P"9" / "c" + 1)^0), pi) == - m.match(m.Cs((m.P(1) / {["1"] = "a", ["5"] = "b", ["9"] = "c"})^0), pi)) -print"+" - - --- tests for capture optimizations -assert(m.match((m.P(3) + 4 * m.Cp()) * "a", "abca") == 5) -t = {m.match(((m.P"a" + m.Cp()) * m.P"x")^0, "axxaxx")} -checkeq(t, {3, 6}) - --- test for table captures -t = m.match(m.Ct(letter^1), "alo") -checkeq(t, {}) - -t, n = m.match(m.Ct(m.C(letter)^1) * m.Cc"t", "alo") -assert(n == "t" and table.concat(t) == "alo") - -t = m.match(m.Ct(m.C(m.C(letter)^1)), "alo") -assert(table.concat(t, ";") == "alo;a;l;o") - -t = m.match(m.Ct(m.C(m.C(letter)^1)), "alo") -assert(table.concat(t, ";") == "alo;a;l;o") - -t = m.match(m.Ct(m.Ct((m.Cp() * letter * m.Cp())^1)), "alo") -assert(table.concat(t[1], ";") == "1;2;2;3;3;4") - -t = m.match(m.Ct(m.C(m.C(1) * 1 * m.C(1))), "alo") -checkeq(t, {"alo", "a", "o"}) - - --- tests for groups -p = m.Cg(1) -- no capture -assert(p:match('x') == 'x') -p = m.Cg(m.P(true)/function () end * 1) -- no value -assert(p:match('x') == 'x') -p = m.Cg(m.Cg(m.Cg(m.C(1)))) -assert(p:match('x') == 'x') -p = m.Cg(m.Cg(m.Cg(m.C(1))^0) * m.Cg(m.Cc(1) * m.Cc(2))) -t = {p:match'abc'} -checkeq(t, {'a', 'b', 'c', 1, 2}) - --- test 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 } -assert(m.match(p, "aaabaac") == 7) - --- a large table capture -t = m.match(m.Ct(m.C('a')^0), string.rep("a", 10000)) -assert(#t == 10000 and t[1] == 'a' and t[#t] == 'a') - - --- test for errors -local function checkerr (msg, ...) - assert(m.match({ m.P(msg) + 1 * m.V(1) }, select(2, pcall(...)))) -end - --- checkerr("rule '1' is left recursive", m.match, { m.V(1) * 'a' }, "a") -checkerr("rule '1' outside a grammar", m.match, m.V(1), "") -checkerr("rule 'hiii' outside a grammar", m.match, m.V('hiii'), "") -checkerr("rule 'hiii' is not defined", m.match, { m.V('hiii') }, "") -checkerr("rule is not defined", m.match, { m.V{} }, "") - -checkerr("rule 'A' is not a pattern", m.P, { A = {} }) -checkerr("rule is not a pattern", m.P, { [print] = {} }) - --- test 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 } -assert(m.match(p, "aaabaac") == 7) - --- a large table capture -t = m.match(m.Ct(m.C('a')^0), string.rep("a", 10000)) -assert(#t == 10000 and t[1] == 'a' and t[#t] == 'a') - - --- test for errors -local function checkerr (msg, ...) - assert(m.match({ m.P(msg) + 1 * m.V(1) }, select(2, pcall(...)))) -end - -checkerr("rule '1' is left recursive", m.match, { m.V(1) * 'a' }, "a") -checkerr("rule '1' outside a grammar", m.match, m.V(1), "") -checkerr("rule 'hiii' outside a grammar", m.match, m.V('hiii'), "") -checkerr("rule 'hiii' is not defined", m.match, { m.V('hiii') }, "") -checkerr("rule is not defined", m.match, { m.V({}) }, "") - -print('+') - - --- bug in 0.10 (rechecking a grammar, after tail-call optimization) -m.P{ m.P { (m.P(3) + "xuxu")^0 * m.V"xuxu", xuxu = m.P(1) } } - -local V = m.V - -local Space = m.S(" \n\t")^0 -local Number = m.C(m.R("09")^1) * Space -local FactorOp = m.C(m.S("+-")) * Space -local TermOp = m.C(m.S("*/")) * Space -local Open = "(" * Space -local Close = ")" * Space - - -local function f_factor (v1, op, v2, d) - assert(d == nil) - if op == "+" then return v1 + v2 - else return v1 - v2 - end -end - - -local function f_term (v1, op, v2, d) - assert(d == nil) - if op == "*" then return v1 * v2 - else return v1 / v2 - end -end - -G = m.P{ "Exp", - Exp = m.Cf(V"Factor" * m.Cg(FactorOp * V"Factor")^0, f_factor); - Factor = m.Cf(V"Term" * m.Cg(TermOp * V"Term")^0, f_term); - Term = Number / tonumber + Open * V"Exp" * Close; -} - -G = Space * G * -1 - -for _, s in ipairs{" 3 + 5*9 / (1+1) ", "3+4/2", "3+3-3- 9*2+3*9/1- 8"} do - assert(m.match(G, s) == loadstring("return "..s)()) -end - - --- test for grammars (errors deep in calling non-terminals) -g = m.P{ - [1] = m.V(2) + "a", - [2] = "a" * m.V(3) * "x", - [3] = "b" * m.V(3) + "c" -} - -assert(m.match(g, "abbbcx") == 7) -assert(m.match(g, "abbbbx") == 2) - - --- tests for \0 -assert(m.match(m.R("\0\1")^1, "\0\1\0") == 4) -assert(m.match(m.S("\0\1ab")^1, "\0\1\0a") == 5) -assert(m.match(m.P(1)^3, "\0\1\0a") == 5) -assert(not m.match(-4, "\0\1\0a")) -assert(m.match("\0\1\0a", "\0\1\0a") == 5) -assert(m.match("\0\0\0", "\0\0\0") == 4) -assert(not m.match("\0\0\0", "\0\0")) - - --- tests for predicates -assert(not m.match(-m.P("a") * 2, "alo")) -assert(m.match(- -m.P("a") * 2, "alo") == 3) -assert(m.match(#m.P("a") * 2, "alo") == 3) -assert(m.match(##m.P("a") * 2, "alo") == 3) -assert(not m.match(##m.P("c") * 2, "alo")) -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.") - - --- look-behind predicate -assert(not m.match(m.B'a', 'a')) -assert(m.match(1 * m.B'a', 'a') == 2) -assert(not m.match(m.B(1), 'a')) -assert(m.match(1 * m.B(1), 'a') == 2) -assert(m.match(-m.B(1), 'a') == 1) - -B = #letter * -m.B(letter) + -letter * m.B(letter) -x = m.Ct({ (B * m.Cp())^-1 * (1 * m.V(1) + m.P(true)) }) -checkeq(m.match(x, 'ar cal c'), {1,3,4,7,9,10}) -checkeq(m.match(x, ' ar cal '), {2,4,5,8}) -checkeq(m.match(x, ' '), {}) -checkeq(m.match(x, 'aloalo'), {1,7}) - -assert(m.match(B, "a") == 1) -assert(m.match(1 * B, "a") == 2) -assert(not m.B(-letter):match("")) -assert((-m.B(letter)):match("") == 1) - -assert((4 * m.B(letter, 4)):match("aaaaaaaa") == 5) -assert(not (4 * m.B(letter, 5)):match("aaaaaaaa")) -assert((4 * -m.B(letter, 5)):match("aaaaaaaa") == 5) - -assert((3 * m.B(m.C(1))):match("12345") == 4) - - --- bug in 0.9 -assert(m.match(('a' * #m.P'b'), "ab") == 2) -assert(not m.match(('a' * #m.P'b'), "a")) - -assert(not m.match(#m.S'567', "")) -assert(m.match(#m.S'567' * 1, "6") == 2) - - --- tests for Tail Calls - --- create a grammar for a simple DFA for even number of 0s and 1s --- finished in '$': --- --- ->1 <---0---> 2 --- ^ ^ --- | | --- 1 1 --- | | --- V V --- 3 <---0---> 4 --- --- this grammar should keep no backtracking information - -p = m.P{ - [1] = '0' * m.V(2) + '1' * m.V(3) + '$', - [2] = '0' * m.V(1) + '1' * m.V(4), - [3] = '0' * m.V(4) + '1' * m.V(1), - [4] = '0' * m.V(3) + '1' * m.V(2), -} - -assert(p:match(string.rep("00", 10000) .. "$")) -assert(p:match(string.rep("01", 10000) .. "$")) -assert(p:match(string.rep("011", 10000) .. "$")) -assert(not p:match(string.rep("011", 10001) .. "$")) - - --- this grammar does need backtracking info. -local lim = 10000 -p = m.P{ '0' * m.V(1) + '0' } -assert(not pcall(m.match, p, string.rep("0", lim))) -m.setmaxstack(2*lim) -assert(not pcall(m.match, p, string.rep("0", lim))) -m.setmaxstack(2*lim + 2) -assert(pcall(m.match, p, string.rep("0", lim))) - --- tests for optional start position -assert(m.match("a", "abc", 1)) -assert(m.match("b", "abc", 2)) -assert(m.match("c", "abc", 3)) -assert(not m.match(1, "abc", 4)) -assert(m.match("a", "abc", -3)) -assert(m.match("b", "abc", -2)) -assert(m.match("c", "abc", -1)) -assert(m.match("abc", "abc", -4)) -- truncate to position 1 - -assert(m.match("", "abc", 10)) -- empty string is everywhere! -assert(m.match("", "", 10)) -assert(not m.match(1, "", 1)) -assert(not m.match(1, "", -1)) -assert(not m.match(1, "", 0)) - -print("+") - - --- tests for argument captures -assert(not pcall(m.Carg, 0)) -assert(not pcall(m.Carg, -1)) -assert(not pcall(m.Carg, 2^18)) -assert(not pcall(m.match, m.Carg(1), 'a', 1)) -assert(m.match(m.Carg(1), 'a', 1, print) == print) -x = {m.match(m.Carg(1) * m.Carg(2), '', 1, 10, 20)} -checkeq(x, {10, 20}) - -assert(m.match(m.Cmt(m.Cg(m.Carg(3), "a") * - m.Cmt(m.Cb("a"), function (s,i,x) - assert(s == "a" and i == 1); - return i, x+1 - end) * - m.Carg(2), function (s,i,a,b,c) - assert(s == "a" and i == 1 and c == nil); - return i, 2*a + 3*b - end) * "a", - "a", 1, false, 100, 1000) == 2*1001 + 3*100) - - --- tests for Lua functions - -t = {} -s = "" -p = function (s1, i) assert(s == s1); t[#t + 1] = i; return nil end -s = "hi, this is a test" -assert(m.match(((p - m.P(-1)) + 2)^0, s) == string.len(s) + 1) -assert(#t == string.len(s)/2 and t[1] == 1 and t[2] == 3) - -assert(not m.match(p, s)) - -p = mt.__add(function (s, i) return i end, function (s, i) return nil end) -assert(m.match(p, "alo")) - -p = mt.__mul(function (s, i) return i end, function (s, i) return nil end) -assert(not m.match(p, "alo")) - - -t = {} -p = function (s1, i) assert(s == s1); t[#t + 1] = i; return i end -s = "hi, this is a test" -assert(m.match((m.P(1) * p)^0, s) == string.len(s) + 1) -assert(#t == string.len(s) and t[1] == 2 and t[2] == 3) - -t = {} -p = m.P(function (s1, i) assert(s == s1); t[#t + 1] = i; - return i <= s1:len() and i + 1 end) -s = "hi, this is a test" -assert(m.match(p^0, s) == string.len(s) + 1) -assert(#t == string.len(s) + 1 and t[1] == 1 and t[2] == 2) - -p = function (s1, i) return m.match(m.P"a"^1, s1, i) end -assert(m.match(p, "aaaa") == 5) -assert(m.match(p, "abaa") == 2) -assert(not m.match(p, "baaa")) - -assert(not pcall(m.match, function () return 2^20 end, s)) -assert(not pcall(m.match, function () return 0 end, s)) -assert(not pcall(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)) -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)) -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)) -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) == - string.len(s) + 1) -for i = 1, string.len(s) + 1 do - assert(m.match(function (_, _) return i end, s) == i) -end - -p = (m.P(function (s, i) return i%2 == 0 and i + 1 end) - + m.P(function (s, i) return i%2 ~= 0 and i + 2 <= s:len() and i + 3 end))^0 - * -1 -assert(p:match(string.rep('a', 14000))) - --- tests for Function Replacements -f = function (a, ...) if a ~= "x" then return {a, ...} end end - -t = m.match(m.C(1)^0/f, "abc") -checkeq(t, {"a", "b", "c"}) - -t = m.match(m.C(1)^0/f/f, "abc") -checkeq(t, {{"a", "b", "c"}}) - -t = m.match(m.P(1)^0/f/f, "abc") -- no capture -checkeq(t, {{"abc"}}) - -t = m.match((m.P(1)^0/f * m.Cp())/f, "abc") -checkeq(t, {{"abc"}, 4}) - -t = m.match((m.C(1)^0/f * m.Cp())/f, "abc") -checkeq(t, {{"a", "b", "c"}, 4}) - -t = m.match((m.C(1)^0/f * m.Cp())/f, "xbc") -checkeq(t, {4}) - -t = m.match(m.C(m.C(1)^0)/f, "abc") -checkeq(t, {"abc", "a", "b", "c"}) - -g = function (...) return 1, ... end -t = {m.match(m.C(1)^0/g/g, "abc")} -checkeq(t, {1, 1, "a", "b", "c"}) - -t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")} -t1 = {1,1,nil,nil,4,nil,3,nil,nil} -for i=1,10 do assert(t[i] == t1[i]) end - -t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")} -checkeq(t, {"a", "ax", "b", "bx", "c", "cx"}) - -t = m.match(m.Ct((m.C(1) / function (x,y) return y, x end * m.Cc(1))^0), "abc") -checkeq(t, {nil, "a", 1, nil, "b", 1, nil, "c", 1}) - --- tests for Query Replacements - -assert(m.match(m.C(m.C(1)^0)/{abc = 10}, "abc") == 10) -assert(m.match(m.C(1)^0/{a = 10}, "abc") == 10) -assert(m.match(m.S("ba")^0/{ab = 40}, "abc") == 40) -t = m.match(m.Ct((m.S("ba")/{a = 40})^0), "abc") -checkeq(t, {40}) - -assert(m.match(m.Cs((m.C(1)/{a=".", d=".."})^0), "abcdde") == ".bc....e") -assert(m.match(m.Cs((m.C(1)/{f="."})^0), "abcdde") == "abcdde") -assert(m.match(m.Cs((m.C(1)/{d="."})^0), "abcdde") == "abc..e") -assert(m.match(m.Cs((m.C(1)/{e="."})^0), "abcdde") == "abcdd.") -assert(m.match(m.Cs((m.C(1)/{e=".", f="+"})^0), "eefef") == "..+.+") -assert(m.match(m.Cs((m.C(1))^0), "abcdde") == "abcdde") -assert(m.match(m.Cs(m.C(m.C(1)^0)), "abcdde") == "abcdde") -assert(m.match(1 * m.Cs(m.P(1)^0), "abcdde") == "bcdde") -assert(m.match(m.Cs((m.C('0')/'x' + 1)^0), "abcdde") == "abcdde") -assert(m.match(m.Cs((m.C('0')/'x' + 1)^0), "0ab0b0") == "xabxbx") -assert(m.match(m.Cs((m.C('0')/'x' + m.P(1)/{b=3})^0), "b0a0b") == "3xax3") -assert(m.match(m.P(1)/'%0%0'/{aa = -3} * 'x', 'ax') == -3) -assert(m.match(m.C(1)/'%0%1'/{aa = 'z'}/{z = -3} * 'x', 'ax') == -3) - -assert(m.match(m.Cs(m.Cc(0) * (m.P(1)/"")), "4321") == "0") - -assert(m.match(m.Cs((m.P(1) / "%0")^0), "abcd") == "abcd") -assert(m.match(m.Cs((m.P(1) / "%0.%0")^0), "abcd") == "a.ab.bc.cd.d") -assert(m.match(m.Cs((m.P("a") / "%0.%0" + 1)^0), "abcad") == "a.abca.ad") -assert(m.match(m.C("a") / "%1%%%0", "a") == "a%a") -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") == - "411 - abc ") - -assert(pcall(m.match, m.P(1)/"%0", "abc")) -assert(not pcall(m.match, m.P(1)/"%1", "abc")) -- out of range -assert(not pcall(m.match, m.P(1)/"%9", "abc")) -- out of range - -p = m.C(1) -p = p * p; p = p * p; p = p * p * m.C(1) / "%9 - %1" -assert(p:match("1234567890") == "9 - 1") - -assert(m.match(m.Cc(print), "") == print) - --- too many captures (just ignore extra ones) -p = m.C(1)^0 / "%2-%9-%0-%9" -assert(p:match"01234567890123456789" == "1-8-01234567890123456789-8") -s = string.rep("12345678901234567890", 20) -assert(m.match(m.C(1)^0 / "%9-%1-%0-%3", s) == "9-1-" .. s .. "-3") - --- string captures with non-string subcaptures -p = m.Cc('alo') * m.C(1) / "%1 - %2 - %1" -assert(p:match'x' == 'alo - x - alo') - -assert(not pcall(m.match, m.Cc(true) / "%1", "a")) - --- long strings for string capture -l = 10000 -s = string.rep('a', l) .. string.rep('b', l) .. string.rep('c', l) - -p = (m.C(m.P'a'^1) * m.C(m.P'b'^1) * m.C(m.P'c'^1)) / '%3%2%1' - -assert(p:match(s) == string.rep('c', l) .. - string.rep('b', l) .. - string.rep('a', l)) - -print"+" - --- accumulator capture -function f (x) return x + 1 end -assert(m.match(m.Cf(m.Cc(0) * m.C(1)^0, f), "alo alo") == 7) - -t = {m.match(m.Cf(m.Cc(1,2,3), error), "")} -checkeq(t, {1}) -p = m.Cf(m.Ct(true) * m.Cg(m.C(m.R"az"^1) * "=" * m.C(m.R"az"^1) * ";")^0, - rawset) -t = p:match("a=b;c=du;xux=yuy;") -checkeq(t, {a="b", c="du", xux="yuy"}) - - --- tests for loop checker - -local function haveloop (p) - assert(not pcall(function (p) return p^0 end, m.P(p))) -end - -haveloop(m.P("x")^-4) -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) -haveloop("") -haveloop(m.P("x")^0) -haveloop(m.P("x")^-1) -haveloop(m.P("x") + 1 + 2 + m.P("a")^-1) -haveloop(-m.P("ab")) -haveloop(- -m.P("ab")) -haveloop(# #(m.P("ab") + "xy")) -haveloop(- #m.P("ab")^0) -haveloop(# -m.P("ab")^1) -haveloop(#m.V(3)) -haveloop(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)}) -assert(m.match(m.P{[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(1)}^0, "abc") - == 3) -assert(m.match(m.P""^-3, "a") == 1) - -local function find (p, s) - return m.match(basiclookfor(p), s) -end - - -local function badgrammar (g, exp) - local err, msg = pcall(m.P, g) - assert(not err) - if exp then assert(find(exp, msg)) end -end - -badgrammar({[1] = m.V(1)}, "rule '1'") -badgrammar({[1] = m.V(2)}, "rule '2'") -- invalid non-terminal -badgrammar({[1] = m.V"x"}, "rule 'x'") -- invalid non-terminal -badgrammar({[1] = m.V{}}, "rule ") -- invalid non-terminal -badgrammar({[1] = #m.P("a") * m.V(1)}, "rule '1'") -badgrammar({[1] = -m.P("a") * m.V(1)}, "rule '1'") -badgrammar({[1] = -1 * m.V(1)}, "rule '1'") -badgrammar({[1] = 1 * m.V(2), [2] = m.V(2)}, "rule '2'") -badgrammar({[1] = m.P(0), [2] = 1 * m.V(1)^0}, "loop in rule '2'") -badgrammar({ m.V(2), m.V(3)^0, m.P"" }, "rule '2'") -badgrammar({ m.V(2) * m.V(3)^0, m.V(3)^0, m.P"" }, "rule '1'") -badgrammar({ #(m.V(1) * 'a') }, "rule '1'") -badgrammar({ -(m.V(1) * 'a') }, "rule '1'") - -assert(m.match({'a' * -m.V(1)}, "aaa") == 2) -assert(m.match({'a' * -m.V(1)}, "aaaa") == nil) - - --- simple tests for maximum sizes: -local p = m.P"a" -for i=1,14 do p = p * p end - -p = {} -for i=1,100 do p[i] = m.P"a" end -p = m.P(p) - - --- strange values for rule labels - -p = m.P{ "print", - print = m.V(print), - [print] = m.V(_G), - [_G] = m.P"a", - } - -assert(p:match("a")) - --- initial rule -g = {} -for i = 1, 10 do g["i"..i] = "a" * m.V("i"..i+1) end -g.i11 = m.P"" -for i = 1, 10 do - g[1] = "i"..i - local p = m.P(g) - assert(p:match("aaaaaaaaaaa") == 11 - i + 1) -end - -print"+" - - --- tests for back references -assert(not pcall(m.match, m.Cb('x'), '')) -assert(not pcall(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")) -t = p:match("ab") -checkeq(t, {"a", "b"}) - - -t = {} -function foo (p) t[#t + 1] = p; return p .. "x" end - -p = m.Cg(m.C(2) / foo, "x") * m.Cb"x" * - m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" * - m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" * - m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" -x = {p:match'ab'} -checkeq(x, {'abx', 'abxx', 'abxxx', 'abxxxx'}) -checkeq(t, {'ab', - 'ab', 'abx', - 'ab', 'abx', 'abxx', - 'ab', 'abx', 'abxx', 'abxxx'}) - - - --- tests for match-time captures - -local function id (s, i, ...) - return true, ... -end - -assert(m.Cmt(m.Cs((m.Cmt(m.S'abc' / { a = 'x', c = 'y' }, id) + - m.R'09'^1 / string.char + - m.P(1))^0), id):match"acb98+68c" == "xyb\98+\68y") - -p = m.P{'S', - S = m.V'atom' * space - + m.Cmt(m.Ct("(" * space * (m.Cmt(m.V'S'^1, id) + m.P(true)) * ")" * space), id), - atom = m.Cmt(m.C(m.R("AZ", "az", "09")^1), id) -} -x = p:match"(a g () ((b) c) (d (e)))" -checkeq(x, {'a', 'g', {}, {{'b'}, 'c'}, {'d', {'e'}}}); - -x = {(m.Cmt(1, id)^0):match(string.rep('a', 500))} -assert(#x == 500) - -local function id(s, i, x) - if x == 'a' then return i + 1, 1, 3, 7 - else return nil, 2, 4, 6, 8 - end -end - -p = ((m.P(id) + m.Cmt(2, id) + m.Cmt(1, id)))^0 -assert(table.concat{p:match('abababab')} == string.rep('137', 4)) - -local function ref (s, i, x) - return m.match(x, s, i - x:len()) -end - -assert(m.Cmt(m.P(1)^0, ref):match('alo') == 4) -assert((m.P(1) * m.Cmt(m.P(1)^0, ref)):match('alo') == 4) -assert(not (m.P(1) * m.Cmt(m.C(1)^0, ref)):match('alo')) - -ref = function (s,i,x) return i == tonumber(x) and i, 'xuxu' end - -assert(m.Cmt(1, ref):match'2') -assert(not m.Cmt(1, ref):match'1') -assert(m.Cmt(m.P(1)^0, ref):match'03') - -function ref (s, i, a, b) - if a == b then return i, a:upper() end -end - -p = m.Cmt(m.C(m.R"az"^1) * "-" * m.C(m.R"az"^1), ref) -p = (any - p)^0 * p * any^0 * -1 - -assert(p:match'abbbc-bc ddaa' == 'BC') - - -c = '[' * m.Cg(m.P'='^0, "init") * '[' * - { m.Cmt(']' * m.C(m.P'='^0) * ']' * m.Cb("init"), function (_, _, s1, s2) - return s1 == s2 end) - + 1 * m.V(1) } / function () end - -assert(c:match'[==[]]====]]]]==]===[]' == 18) -assert(c:match'[[]=]====]=]]]==]===[]' == 14) -assert(not c:match'[[]=]====]=]=]==]===[]') - - - -------------------------------------------------------------------- --- Tests for 're' module -------------------------------------------------------------------- - -local re = require "re" - -local match, compile = re.match, re.compile - - - -assert(match("a", ".") == 2) -assert(match("a", "''") == 1) -assert(match("", " ! . ") == 1) -assert(not match("a", " ! . ")) -assert(match("abcde", " ( . . ) * ") == 5) -assert(match("abbcde", " [a-c] +") == 5) -assert(match("0abbc1de", "'0' [a-c]+ '1'") == 7) -assert(match("0zz1dda", "'0' [^a-c]+ 'a'") == 8) -assert(match("abbc--", " [a-c] + +") == 5) -assert(match("abbc--", " [ac-] +") == 2) -assert(match("abbc--", " [-acb] + ") == 7) -assert(not match("abbcde", " [b-z] + ")) -assert(match("abb\"de", '"abb"["]"de"') == 7) -assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee") -assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8) -local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")} -checkeq(t, {4, 5, 7}) -local t = {match("abceefe", "((&&'e' {})? .)*")} -checkeq(t, {4, 5, 7}) -local t = {match("abceefe", "( ( ! ! 'e' {} ) ? . ) *")} -checkeq(t, {4, 5, 7}) -local t = {match("abceefe", "(( & ! & ! 'e' {})? .)*")} -checkeq(t, {4, 5, 7}) - -assert(match("cccx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 5) -assert(match("cdx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 4) -assert(match("abcdcdx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 8) - -assert(match("abc", "a <- (. a)?") == 4) -b = "balanced <- '(' ([^()] / balanced)* ')'" -assert(match("(abc)", b)) -assert(match("(a(b)((c) (d)))", b)) -assert(not match("(a(b ((c) (d)))", b)) - -b = compile[[ balanced <- "(" ([^()] / balanced)* ")" ]] -assert(b == m.P(b)) -assert(b:match"((((a))(b)))") - -local g = [[ - S <- "0" B / "1" A / "" -- balanced strings - A <- "0" S / "1" A A -- one more 0 - B <- "1" S / "0" B B -- one more 1 -]] -assert(match("00011011", g) == 9) - -local g = [[ - S <- ("0" B / "1" A)* - A <- "0" / "1" A A - B <- "1" / "0" B B -]] -assert(match("00011011", g) == 9) -assert(match("000110110", g) == 9) -assert(match("011110110", g) == 3) -assert(match("000110010", g) == 1) - -s = "aaaaaaaaaaaaaaaaaaaaaaaa" -assert(match(s, "'a'^3") == 4) -assert(match(s, "'a'^0") == 1) -assert(match(s, "'a'^+3") == s:len() + 1) -assert(not match(s, "'a'^+30")) -assert(match(s, "'a'^-30") == s:len() + 1) -assert(match(s, "'a'^-5") == 6) -for i = 1, s:len() do - assert(match(s, string.format("'a'^+%d", i)) >= i + 1) - assert(match(s, string.format("'a'^-%d", i)) <= i + 1) - assert(match(s, string.format("'a'^%d", i)) == i + 1) -end -assert(match("01234567890123456789", "[0-9]^3+") == 19) - - -assert(match("01234567890123456789", "({....}{...}) -> '%2%1'") == "4560123") -t = match("0123456789", "{.}*->{}") -checkeq(t, {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}) -assert(match("012345", "( (..) -> '%0%0' ) -> {}")[1] == "0101") - -eqcharset(compile"[]]", "]") -eqcharset(compile"[][]", m.S"[]") -eqcharset(compile"[]-]", m.S"-]") -eqcharset(compile"[-]", m.S"-") -eqcharset(compile"[az-]", m.S"a-z") -eqcharset(compile"[-az]", m.S"a-z") -eqcharset(compile"[a-z]", m.R"az") -eqcharset(compile"[]['\"]", m.S[[]['"]]) - -eqcharset(compile"[^]]", any - "]") -eqcharset(compile"[^][]", any - m.S"[]") -eqcharset(compile"[^]-]", any - m.S"-]") -eqcharset(compile"[^]-]", any - m.S"-]") -eqcharset(compile"[^-]", any - m.S"-") -eqcharset(compile"[^az-]", any - m.S"a-z") -eqcharset(compile"[^-az]", any - m.S"a-z") -eqcharset(compile"[^a-z]", any - m.R"az") -eqcharset(compile"[^]['\"]", any - m.S[[]['"]]) - --- tests for comments in 're' -e = compile[[ -A <- B -- \t \n %nl .<> <- -> -- -B <- 'x' --]] -assert(e:match'xy' == 2) - --- tests for 're' with pre-definitions -defs = {digits = m.R"09", letters = m.R"az"} -e = compile("%letters (%letters / %digits)*", defs) -assert(e:match"x123" == 5) - -e = compile([[ - S <- A+ - A <- %letters+ B - B <- %digits+ -]], defs) - -e = compile("{[0-9]+'.'?[0-9]*} -> sin", math) -assert(e:match("2.34") == math.sin(2.34)) - - -function eq (_, _, a, b) return a == b end - -c = re.compile([[ - longstring <- '[' {:init: '='* :} '[' close - close <- ']' =init ']' / . close -]]) - -assert(c:match'[==[]]===]]]]==]===[]' == 17) -assert(c:match'[[]=]====]=]]]==]===[]' == 14) -assert(not c:match'[[]=]====]=]=]==]===[]') - -c = re.compile" '[' {:init: '='* :} '[' (!(']' =init ']') .)* ']' =init ']' !. " - -assert(c:match'[==[]]===]]]]==]') -assert(c:match'[[]=]====]=][]==]===[]]') -assert(not c:match'[[]=]====]=]=]==]===[]') - -assert(re.find("hi alalo", "{:x:..:} =x") == 4) -assert(re.find("hi alalo", "{:x:..:} =x", 4) == 4) -assert(not re.find("hi alalo", "{:x:..:} =x", 5)) -assert(re.find("hi alalo", "'al'", 5) == 6) -assert(re.find("hi aloalolo", "{:x:..:} =x") == 8) -assert(re.find("alo alohi x x", "{:word:%w+:}%W*(=word)!%w") == 11) - -assert(re.gsub("alo alo", "[abc]", "x") == "xlo xlo") -assert(re.gsub("alo alo", "%w+", ".") == ". .") -assert(re.gsub("hi, how are you", "[aeiou]", string.upper) == - "hI, hOw ArE yOU") - -s = 'hi [[a comment[=]=] ending here]] and [=[another]]=]]' -c = re.compile" '[' {:i: '='* :} '[' (!(']' =i ']') .)* ']' { =i } ']' " -assert(re.gsub(s, c, "%2") == 'hi and =]') -assert(re.gsub(s, c, "%0") == s) -assert(re.gsub('[=[hi]=]', c, "%2") == '=') - -assert(re.find("", "!.") == 1) -assert(re.find("alo", "!.") == 4) - -function addtag (s, i, t, tag) t.tag = tag; return i, t end - -c = re.compile([[ - doc <- block !. - block <- (start (block / { [^<]+ })* -> {} end?) => addtag - start <- '<' {:tag: [a-z]+ :} '>' - end <- '' -]], {addtag = addtag}) - -x = c:match[[ -hihellobuttotheend]] -checkeq(x, {tag='x', 'hi', {tag = 'b', 'hello'}, 'but', - {'totheend'}}) - -assert(not pcall(compile, "x <- 'a' x <- 'b'")) -assert(not pcall(compile, "'x' -> x", {x = 3})) - - --- tests for look-ahead captures -x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")} -checkeq(x, {"", "alo", ""}) - -assert(re.match("aloalo", - "{~ (((&'al' {.}) -> 'A%1' / (&%l {.}) -> '%1%1') / .)* ~}") - == "AallooAalloo") - --- bug in 0.9 (and older versions), due to captures in look-aheads -x = re.compile[[ {~ (&(. ([a-z]* -> '*')) ([a-z]+ -> '+') ' '*)* ~} ]] -assert(x:match"alo alo" == "+ +") - --- valid capture in look-ahead (used inside the look-ahead itself) -x = re.compile[[ - S <- &({:two: .. :} . =two) {[a-z]+} / . S -]] -assert(x:match("hello aloaLo aloalo xuxu") == "aloalo") - - -p = re.compile[[ - block <- ({:ident:' '*:} line - ((=ident !' ' line) / &(=ident ' ') block)*) -> {} - line <- {[^%nl]*} %nl -]] - -t= p:match[[ -1 - 1.1 - 1.2 - 1.2.1 - -2 - 2.1 -]] -checkeq(t, {"1", {"1.1", "1.2", {"1.2.1", "", ident = " "}, ident = " "}, - "2", {"2.1", ident = " "}, ident = ""}) - - --- nested grammars -p = re.compile[[ - s <- a b !. - b <- ( x <- ('b' x)? ) - a <- ( x <- 'a' x? ) -]] - -assert(p:match'aaabbb') -assert(p:match'aaa') -assert(not p:match'bbb') -assert(not p:match'aaabbba') - --- testing groups -t = {re.match("abc", "{:S <- {:.:} {S} / '':}")} -checkeq(t, {"a", "bc", "b", "c", "c", ""}) - -t = re.match("1234", "({:a:.:} {:b:.:} {:c:.{.}:}) -> {}") -checkeq(t, {a="1", b="2", c="4"}) -t = re.match("1234", "({:a:.:} {:b:{.}{.}:} {:c:{.}:}) -> {}") -checkeq(t, {a="1", b="2", c="4"}) -t = re.match("12345", "({:.:} {:b:{.}{.}:} {:{.}{.}:}) -> {}") -checkeq(t, {"1", b="2", "4", "5"}) -t = re.match("12345", "({:.:} {:{:b:{.}{.}:}:} {:{.}{.}:}) -> {}") -checkeq(t, {"1", "23", "4", "5"}) -t = re.match("12345", "({:.:} {{:b:{.}{.}:}} {:{.}{.}:}) -> {}") -checkeq(t, {"1", "23", "4", "5"}) - - --- testing pre-defined names -assert(os.setlocale("C") == "C") - -function eqlpeggsub (p1, p2) - local s1 = cs2str(re.compile(p1)) - local s2 = string.gsub(allchar, "[^" .. p2 .. "]", "") -if s1 ~= s2 then print(s1,s2) end - assert(s1 == s2) -end - - -eqlpeggsub("%w", "%w") -eqlpeggsub("%a", "%a") -eqlpeggsub("%l", "%l") -eqlpeggsub("%u", "%u") -eqlpeggsub("%p", "%p") -eqlpeggsub("%d", "%d") -eqlpeggsub("%x", "%x") -eqlpeggsub("%s", "%s") - -eqlpeggsub("%W", "%W") -eqlpeggsub("%A", "%A") -eqlpeggsub("%L", "%L") -eqlpeggsub("%U", "%U") -eqlpeggsub("%P", "%P") -eqlpeggsub("%D", "%D") -eqlpeggsub("%X", "%X") -eqlpeggsub("%S", "%S") - -eqlpeggsub("[%w]", "%w") -eqlpeggsub("[_%w]", "_%w") -eqlpeggsub("[^%w]", "%W") -eqlpeggsub("[%W%S]", "%W%S") - -re.updatelocale() - - --- testing nested substitutions x string captures - -p = re.compile[[ - text <- {~ item* ~} - item <- macro / [^()] / '(' item* ')' - arg <- ' '* {~ (!',' item)* ~} - args <- '(' arg (',' arg)* ')' - macro <- ('apply' args) -> '%1(%2)' - / ('add' args) -> '%1 + %2' - / ('mul' args) -> '%1 * %2' -]] - -assert(p:match"add(mul(a,b), apply(f,x))" == "a * b + f(x)") - -rev = re.compile[[ R <- (!.) -> '' / ({.} R) -> '%2%1']] - -assert(rev:match"0123456789" == "9876543210") - -print"OK" - - diff --git a/lua-protobuf/Makefile b/lua-protobuf/Makefile deleted file mode 100644 index 94f837e7..00000000 --- a/lua-protobuf/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -.PHONY : all clean - -all : protobuf.so addressbook.pb - -LIBSRCS = context.c varint.c array.c pattern.c register.c proto.c map.c alloc.c rmessage.c wmessage.c bootstrap.c stringpool.c decode.c - -protobuf.so : pbc-lua.c $(LIBSRCS) - gcc -O2 -Wall --shared -fPIC -o $@ $^ - -addressbook.pb : addressbook.proto - protoc -o$@ $< - -clean : - rm protobuf.so addressbook.pb \ No newline at end of file diff --git a/lua-protobuf/README b/lua-protobuf/README deleted file mode 100644 index 94a03da5..00000000 --- a/lua-protobuf/README +++ /dev/null @@ -1,2 +0,0 @@ -See https://github.com/cloudwu/pbc - diff --git a/lua-protobuf/addressbook.proto b/lua-protobuf/addressbook.proto deleted file mode 100644 index 883a7881..00000000 --- a/lua-protobuf/addressbook.proto +++ /dev/null @@ -1,39 +0,0 @@ -// See README.txt for information and build instructions. - -package tutorial; - -option java_package = "com.example.tutorial"; -option java_outer_classname = "AddressBookProtos"; - -message Person { - required string name = 1; - required int32 id = 2; // Unique ID number for this person. - optional string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - required string number = 1; - optional PhoneType type = 2 [default = HOME]; - } - - repeated PhoneNumber phone = 4; - repeated int32 test = 5 [packed=true]; - - extensions 10 to max; -} - -message Ext { - extend Person { - optional int32 test = 10; - } -} - -// Our address book file is just one of these. -message AddressBook { - repeated Person person = 1; -} diff --git a/lua-protobuf/alloc.c b/lua-protobuf/alloc.c deleted file mode 100644 index e8d4320e..00000000 --- a/lua-protobuf/alloc.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include - -static int _g = 0; - -void * _pbcM_malloc(size_t sz) { - ++ _g; - return malloc(sz); -} - -void _pbcM_free(void *p) { - if (p) { - -- _g; - free(p); - } -} - -void* _pbcM_realloc(void *p, size_t sz) { - return realloc(p,sz); -} - -void _pbcM_memory() { - printf("%d\n",_g); -} - -struct heap_page { - struct heap_page * next; -}; - -struct heap { - struct heap_page *current; - int size; - int used; -}; - -struct heap * -_pbcH_new(int pagesize) { - int cap = 1024; - while(cap < pagesize) { - cap *= 2; - } - struct heap * h = _pbcM_malloc(sizeof(struct heap)); - h->current = _pbcM_malloc(sizeof(struct heap_page) + cap); - h->size = cap; - h->used = 0; - h->current->next = NULL; - return h; -} - -void -_pbcH_delete(struct heap *h) { - struct heap_page * p = h->current; - struct heap_page * next = p->next; - for(;;) { - _pbcM_free(p); - if (next == NULL) - break; - p = next; - next = p->next; - } - _pbcM_free(h); -} - -void* -_pbcH_alloc(struct heap *h, int size) { - size = (size + 3) & ~3; - if (h->size - h->used < size) { - struct heap_page * p; - if (size < h->size) { - p = _pbcM_malloc(sizeof(struct heap_page) + h->size); - } else { - p = _pbcM_malloc(sizeof(struct heap_page) + size); - } - p->next = h->current; - h->current = p; - h->used = size; - return (p+1); - } else { - char * buffer = (char *)(h->current + 1); - buffer += h->used; - h->used += size; - return buffer; - } -} diff --git a/lua-protobuf/alloc.h b/lua-protobuf/alloc.h deleted file mode 100644 index 036acbbe..00000000 --- a/lua-protobuf/alloc.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef PROTOBUF_C_ALLOC_H -#define PROTOBUF_C_ALLOC_H - -#include -#include - -void * _pbcM_malloc(size_t sz); -void _pbcM_free(void *p); -void * _pbcM_realloc(void *p, size_t sz); -void _pbcM_memory(); - -struct heap; - -struct heap * _pbcH_new(int pagesize); -void _pbcH_delete(struct heap *); -void* _pbcH_alloc(struct heap *, int size); - -#define HMALLOC(size) ((h) ? _pbcH_alloc(h, size) : _pbcM_malloc(size)) - -#define malloc _pbcM_malloc -#define free _pbcM_free -#define realloc _pbcM_realloc -#define memory _pbcM_memory - -#endif diff --git a/lua-protobuf/array.c b/lua-protobuf/array.c deleted file mode 100644 index b6004d0c..00000000 --- a/lua-protobuf/array.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "pbc.h" -#include "array.h" -#include "alloc.h" - -#include -#include - -struct array { - int number; - struct heap *heap; - union _pbc_var * a; -}; - -#define INNER_FIELD ((PBC_ARRAY_CAP - sizeof(struct array)) / sizeof(pbc_var)) - -void -_pbcA_open(pbc_array _array) { - struct array * a = (struct array *)_array; - a->number = 0; - a->heap = NULL; - a->a = (union _pbc_var *)(a+1); -} - -void -_pbcA_open_heap(pbc_array _array, struct heap *h) { - struct array * a = (struct array *)_array; - a->number = 0; - a->heap = h; - a->a = (union _pbc_var *)(a+1); -} - -void -_pbcA_close(pbc_array _array) { - struct array * a = (struct array *)_array; - if (a->heap == NULL && a->a != NULL && (union _pbc_var *)(a+1) != a->a) { - _pbcM_free(a->a); - a->a = NULL; - } -} - -void -_pbcA_push(pbc_array _array, pbc_var var) { - struct array * a = (struct array *)_array; - if (a->number == 0) { - a->a = (union _pbc_var *)(a+1); - } else if (a->number >= INNER_FIELD) { - if (a->number == INNER_FIELD) { - int cap = 1; - while (cap <= a->number + 1) - cap *= 2; - struct heap * h = a->heap; - union _pbc_var * outer = HMALLOC(cap * sizeof(union _pbc_var)); - memcpy(outer , a->a , INNER_FIELD * sizeof(pbc_var)); - a->a = outer; - } else { - int size=a->number; - if (((size + 1) ^ size) > size) { - struct heap * h = a->heap; - if (h) { - void * old = a->a; - a->a = _pbcH_alloc(h, sizeof(union _pbc_var) * (size+1) * 2); - memcpy(a->a, old, sizeof(union _pbc_var) * size); - } else { - a->a=_pbcM_realloc(a->a,sizeof(union _pbc_var) * (size+1) * 2); - } - } - } - } - a->a[a->number] = *var; - ++ a->number; -} - -void -_pbcA_index(pbc_array _array, int idx, pbc_var var) -{ - struct array * a = (struct array *)_array; - var[0] = a->a[idx]; -} - -void * -_pbcA_index_p(pbc_array _array, int idx) -{ - struct array * a = (struct array *)_array; - return &(a->a[idx]); -} - -int -pbc_array_size(pbc_array _array) { - struct array * a = (struct array *)_array; - return a->number; -} - -uint32_t -pbc_array_integer(pbc_array array, int index, uint32_t *hi) { - pbc_var var; - _pbcA_index(array , index , var); - if (hi) { - *hi = var->integer.hi; - } - return var->integer.low; -} - -double -pbc_array_real(pbc_array array, int index) { - pbc_var var; - _pbcA_index(array , index , var); - return var->real; -} - -struct pbc_slice * -pbc_array_slice(pbc_array _array, int index) { - struct array * a = (struct array *)_array; - if (index <0 || index > a->number) { - return NULL; - } - return (struct pbc_slice *) &(a->a[index]); -} - -void -pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi) { - pbc_var var; - var->integer.low = low; - var->integer.hi = hi; - _pbcA_push(array,var); -} - -void -pbc_array_push_slice(pbc_array array, struct pbc_slice *s) { - pbc_var var; - var->m = *s; - _pbcA_push(array,var); -} - -void -pbc_array_push_real(pbc_array array, double v) { - pbc_var var; - var->real = v; - _pbcA_push(array,var); -} diff --git a/lua-protobuf/array.h b/lua-protobuf/array.h deleted file mode 100644 index cc7f0a9a..00000000 --- a/lua-protobuf/array.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PROTOBUF_C_ARRAY_H -#define PROTOBUF_C_ARRAY_H - -#include "varint.h" -#include "pbc.h" -#include "alloc.h" - -typedef union _pbc_var { - struct longlong integer; - double real; - struct { - const char * str; - int len; - } s; - struct { - int id; - const char * name; - } e; - struct pbc_slice m; - void * p[2]; -} pbc_var[1]; - -void _pbcA_open(pbc_array); -void _pbcA_open_heap(pbc_array, struct heap *h); -void _pbcA_close(pbc_array); - -void _pbcA_push(pbc_array, pbc_var var); -void _pbcA_index(pbc_array , int idx, pbc_var var); -void * _pbcA_index_p(pbc_array _array, int idx); - -#endif diff --git a/lua-protobuf/bootstrap.c b/lua-protobuf/bootstrap.c deleted file mode 100644 index a2b790ec..00000000 --- a/lua-protobuf/bootstrap.c +++ /dev/null @@ -1,303 +0,0 @@ -#include "pbc.h" -#include "map.h" -#include "context.h" -#include "pattern.h" -#include "proto.h" -#include "alloc.h" -#include "bootstrap.h" -#include "stringpool.h" -#include "array.h" -#include "descriptor.pbc.h" - -#include -#include -#include -#include - -/* - -// Descriptor - -// google.protobuf.Descriptor.proto encoded in descriptor.pbc.h with proto pbc.file . - -package pbc; - -message field { - optional string name = 1; - optional int32 id = 2; - optional int32 label = 3; // 0 optional 1 required 2 repeated - optional int32 type = 4; // type_id - optional string type_name = 5; - optional int32 default_int = 6; - optional string default_string = 7; - optional double default_real = 8; -} - -message file { - optional string name = 1; - repeated string dependency = 2; - - repeated string message_name = 3; - repeated int32 message_size = 4; - repeated field message_field = 5; - - repeated string enum_name = 6; - repeated int32 enum_size = 7; - repeated string enum_string = 8; - repeated int32 enum_id = 9; -} - -*/ - -struct field_t { - struct pbc_slice name; - int32_t id; - int32_t label; - int32_t type; - struct pbc_slice type_name; - int32_t default_integer; - struct pbc_slice default_string; - double default_real; -}; - -struct file_t { - struct pbc_slice name; // string - pbc_array dependency; // string - pbc_array message_name; // string - pbc_array message_size; // int32 - pbc_array message_field; // field_t - pbc_array enum_name; // string - pbc_array enum_size; // int32 - pbc_array enum_string; // string - pbc_array enum_id; // int32 -}; - -static void -set_enum_one(struct pbc_env *p, struct file_t *file, const char *name, int start, int sz) { - struct map_kv *table = malloc(sz * sizeof(struct map_kv)); - int i; - for (i=0;ienum_id, start+i, id); - _pbcA_index(file->enum_string, start+i, string); - table[i].id = (int)id->integer.low; - table[i].pointer = (void *)string->s.str; - } - _pbcP_push_enum(p,name,table,sz); - - free(table); -} - -static void -set_enums(struct pbc_env *p, struct file_t *file) { - int n = pbc_array_size(file->enum_size); - int i; - int start = 0; - for (i=0;ienum_name,i,name); - pbc_var var; - _pbcA_index(file->enum_size,i,var); - set_enum_one(p, file, name->s.str, start , (int)var->integer.low); - start += var->integer.low; - } -} - -static void -set_default(struct _field *f, struct field_t *input) { - switch (f->type) { - case PTYPE_DOUBLE: - case PTYPE_FLOAT: - f->default_v->real = input->default_real; - break; - case PTYPE_STRING: - case PTYPE_ENUM: - f->default_v->m = input->default_string; - break; - default: - f->default_v->integer.low = input->default_integer; - break; - } -} - -static void -set_msg_one(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file, const char *name, int start, int sz , pbc_array queue) { - int i; - for (i=0;imessage_field, start+i, _field); - struct field_t field; - - int ret = pbc_pattern_unpack(FIELD_T, &_field->m, &field); - if (ret != 0) { - continue; - } - struct _field f; - f.id = field.id; - f.name = field.name.buffer; - f.type = field.type; - f.label = field.label; - f.type_name.n = field.type_name.buffer; - set_default(&f, &field); - - _pbcP_push_message(p,name, &f , queue); - - // don't need to close pattern since no array - } - _pbcP_init_message(p, name); -} - -static void -set_msgs(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file , pbc_array queue) { - int n = pbc_array_size(file->message_size); - int i; - int start = 0; - for (i=0;imessage_name,i,name); - pbc_var sz; - _pbcA_index(file->message_size,i,sz); - set_msg_one(FIELD_T, p, file, name->s.str, start , (int)sz->integer.low , queue); - start += sz->integer.low; - } -} - -static void -set_field_one(struct pbc_env *p, struct _field *f) { - const char * type_name = f->type_name.n; - if (f->type == PTYPE_MESSAGE) { - f->type_name.m = _pbcM_sp_query(p->msgs, type_name); -// printf("MESSAGE: %s %p\n",type_name, f->type_name.m); - } else if (f->type == PTYPE_ENUM) { - f->type_name.e = _pbcM_sp_query(p->enums, type_name); -// printf("ENUM: %s %p ",type_name, f->type_name.e); - const char * str = f->default_v->s.str; - if (str && str[0]) { - int err = _pbcM_si_query(f->type_name.e->name, str , &(f->default_v->e.id)); - if (err < 0) - goto _default; - f->default_v->e.name = _pbcM_ip_query(f->type_name.e->id, f->default_v->e.id); -// printf("[%s %d]\n",str,f->default_v->e.id); - } else { -_default: - memcpy(f->default_v, f->type_name.e->default_v, sizeof(pbc_var)); -// printf("(%s %d)\n",f->default_v->e.name,f->default_v->e.id); - } - } -} - -void -_pbcB_register_fields(struct pbc_env *p, pbc_array queue) { - int sz = pbc_array_size(queue); - int i; - for (i=0;im.buffer; - set_field_one(p, f); - } -} - -static void -_set_string(struct _pattern_field * f) { - f->ptype = PTYPE_STRING; - f->ctype = CTYPE_VAR; - f->defv->s.str = ""; - f->defv->s.len = 0; -} - -static void -_set_int32(struct _pattern_field * f) { - f->ptype = PTYPE_INT32; - f->ctype = CTYPE_INT32; -} - -static void -_set_double(struct _pattern_field * f) { - f->ptype = PTYPE_DOUBLE; - f->ctype = CTYPE_DOUBLE; -} - -static void -_set_message_array(struct _pattern_field *f) { - f->ptype = PTYPE_MESSAGE; - f->ctype = CTYPE_ARRAY; -} - -static void -_set_string_array(struct _pattern_field * f) { - f->ptype = PTYPE_STRING; - f->ctype = CTYPE_ARRAY; -} - -static void -_set_int32_array(struct _pattern_field * f) { - f->ptype = PTYPE_INT32; - f->ctype = CTYPE_ARRAY; -} - -#define SET_PATTERN(pat , idx , pat_type, field_name , type) \ - pat->f[idx].id = idx+1 ; \ - pat->f[idx].offset = offsetof(struct pat_type, field_name); \ - _set_##type(&pat->f[idx]); - -#define F(idx,field_name,type) SET_PATTERN(FIELD_T, idx, field_t ,field_name, type) -#define D(idx,field_name,type) SET_PATTERN(FILE_T, idx, file_t ,field_name, type) - -static int -register_internal(struct pbc_env * p, struct pbc_slice *slice) { - struct pbc_pattern * FIELD_T = _pbcP_new(p,8); - F(0,name,string); - F(1,id,int32); - F(2,label,int32); - F(3,type,int32); - F(4,type_name,string); - F(5,default_integer,int32); - F(6,default_string,string); - F(7,default_real,double); - - struct pbc_pattern * FILE_T = _pbcP_new(p,10); - - D(0,name,string); - D(1,dependency,string_array); - D(2,message_name,string_array); - D(3,message_size,int32_array); - D(4,message_field,message_array); - D(5,enum_name,string_array); - D(6,enum_size,int32_array); - D(7,enum_string,string_array); - D(8,enum_id,int32_array); - - int ret = 0; - - struct file_t file; - int r = pbc_pattern_unpack(FILE_T, slice, &file); - if (r != 0) { - ret = 1; - goto _return; - } - - _pbcM_sp_insert(p->files , file.name.buffer, NULL); - - pbc_array queue; - _pbcA_open(queue); - - set_enums(p, &file); - set_msgs(FIELD_T, p, &file, queue); - _pbcB_register_fields(p, queue); - - _pbcA_close(queue); - pbc_pattern_close_arrays(FILE_T, &file); - -_return: - free(FIELD_T); - free(FILE_T); - return ret; -} - -void -_pbcB_init(struct pbc_env * p) { - struct pbc_slice slice = { pbc_descriptor,sizeof(pbc_descriptor) }; - register_internal(p,&slice); -} diff --git a/lua-protobuf/bootstrap.h b/lua-protobuf/bootstrap.h deleted file mode 100644 index 48566f58..00000000 --- a/lua-protobuf/bootstrap.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef PROTOBUF_C_BOOTSTRAP_H -#define PROTOBUF_C_BOOTSTRAP_H - -#include "proto.h" -#include "pbc.h" - -void _pbcB_init(struct pbc_env *); -void _pbcB_register_fields(struct pbc_env *, pbc_array queue); - -#endif diff --git a/lua-protobuf/context.c b/lua-protobuf/context.c deleted file mode 100644 index ac40cdec..00000000 --- a/lua-protobuf/context.c +++ /dev/null @@ -1,278 +0,0 @@ -#include "pbc.h" -#include "alloc.h" -#include "varint.h" -#include "context.h" - -#include -#include -#include -#include - -#define INNER_ATOM ((PBC_CONTEXT_CAP - sizeof(struct context)) / sizeof(struct atom)) - -static char * -wiretype_decode(uint8_t *buffer, int cap , struct atom *a , int start) -{ - uint8_t temp[10]; - struct longlong r; - int len; - if (cap >= 10) { - len = _pbcV_decode(buffer, &r); - if (r.hi !=0) - return NULL; - } else { - memcpy(temp, buffer , cap); - len = _pbcV_decode(temp, &r); - if (len > cap || r.hi !=0) - return NULL; - } - - int wiretype = r.low & 7; - a->wire_id = r.low; - buffer += len; - start += len; - cap -=len; - - switch (wiretype) { - case WT_VARINT : - if (cap >=10) { - len = _pbcV_decode(buffer, &a->v.i); - } else { - memcpy(temp, buffer , cap); - len = _pbcV_decode(temp, &a->v.i); - if (cap < len) - return NULL; - } - return (char *)buffer+len; - case WT_BIT64 : - if (cap < 8) - return NULL; - a->v.i.low = buffer[0] | - buffer[1] << 8 | - buffer[2] << 16 | - buffer[3] << 24; - a->v.i.hi = buffer[4] | - buffer[5] << 8 | - buffer[6] << 16 | - buffer[7] << 24; - return (char *)buffer + 8; - case WT_LEND : - if (cap >=10) { - len = _pbcV_decode(buffer, &r); - } else { - memcpy(temp, buffer , cap); - len = _pbcV_decode(temp, &r); - } - if (cap < len + r.low || r.hi !=0) - return NULL; - a->v.s.start = start + len; - a->v.s.end = start + len + r.low; - return (char *)buffer + len + r.low; - case WT_BIT32 : - if (cap < 4) - return NULL; - a->v.i.low = buffer[0] | - buffer[1] << 8 | - buffer[2] << 16 | - buffer[3] << 24; - a->v.i.hi = 0; - return (char *)buffer + 4; - default: - return NULL; - } -} - -static inline int -_decode_varint(uint8_t * buffer, int size , struct atom * a) { - a->wire_id = WT_VARINT; - if (size < 10) { - uint8_t temp[10]; - memcpy(temp,buffer,size); - return _pbcV_decode(temp , &(a->v.i)); - } else { - return _pbcV_decode(buffer , &(a->v.i)); - } -} - -static int -_open_packed_varint(struct context * ctx , uint8_t * buffer, int size) { - struct atom * a = (struct atom *)(ctx + 1); - - int i; - - for (i=0;ia = a; - } else { - int cap = 64; - ctx->a = malloc(cap * sizeof(struct atom)); - while (size > 0) { - if (i >= cap) { - cap = cap + 64; - ctx->a = realloc(ctx->a, cap * sizeof(struct atom)); - continue; - } - int len = _decode_varint(buffer, size, &a[i]); - buffer += len; - size -= len; - - ++i; - } - memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); - } - ctx->number = i; - - return i; -} - -int -_pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size) { - struct context * ctx = (struct context *)_ctx; - ctx->buffer = buffer; - ctx->size = size; - ctx->number = 0; - ctx->a = NULL; - - if (buffer == NULL || size == 0) { - return 0; - } - - int bits = 0; - - switch (ptype) { - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_BOOL: - case PTYPE_UINT32: - case PTYPE_ENUM: - case PTYPE_SINT32: - case PTYPE_SINT64: - return _open_packed_varint(ctx , buffer, size); - case PTYPE_DOUBLE: - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - ctx->number = size / 8; - bits = 64; - break; - case PTYPE_FLOAT: - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - ctx->number = size / 4; - bits = 32; - break; - default: - return 0; - } - - struct atom * a = (struct atom *)(ctx + 1); - - if (ctx->number > INNER_ATOM) { - ctx->a = malloc(ctx->number * sizeof(struct atom)); - a = ctx->a; - } else { - ctx->a = a; - } - - int i; - if (bits == 64) { - uint8_t * data = buffer; - for (i=0;inumber;i++) { - a[i].wire_id = WT_BIT64; - a[i].v.i.low = data[0] | - data[1] << 8 | - data[2] << 16 | - data[3] << 24; - a[i].v.i.hi = data[4] | - data[5] << 8 | - data[6] << 16 | - data[7] << 24; - data += 8; - } - } else { - uint8_t * data = buffer; - for (i=0;inumber;i++) { - a[i].wire_id = WT_BIT32; - a[i].v.i.low = data[0] | - data[1] << 8 | - data[2] << 16 | - data[3] << 24; - a[i].v.i.hi = 0; - data += 4; - } - } - - return ctx->number; -} - -int -_pbcC_open(pbc_ctx _ctx , void *buffer, int size) { - struct context * ctx = (struct context *)_ctx; - ctx->buffer = buffer; - ctx->size = size; - - if (buffer == NULL || size == 0) { - ctx->number = 0; - ctx->a = NULL; - return 0; - } - - struct atom * a = (struct atom *)(ctx + 1); - - int i; - int start = 0; - - ctx->a = a; - - for (i=0;i 0) { - int cap = 64; - ctx->a = malloc(cap * sizeof(struct atom)); - while (size > 0) { - if (i >= cap) { - cap = cap + 64; - ctx->a = realloc(ctx->a, cap * sizeof(struct atom)); - continue; - } - char * next = wiretype_decode(buffer, size , &ctx->a[i] , start); - if (next == NULL) { - return -i; - } - start += next - (char *)buffer; - size -= next - (char *)buffer; - buffer = next; - ++i; - } - memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); - } - ctx->number = i; - - return i; -} - - -void -_pbcC_close(pbc_ctx _ctx) { - struct context * ctx = (struct context *)_ctx; - if (ctx->a != NULL && (struct atom *)(ctx+1) != ctx->a) { - free(ctx->a); - ctx->a = NULL; - } -} diff --git a/lua-protobuf/context.h b/lua-protobuf/context.h deleted file mode 100644 index e19ed91c..00000000 --- a/lua-protobuf/context.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef PROTOBUF_C_CONTEXT_H -#define PROTOBUF_C_CONTEXT_H - -#include - -#include "array.h" - -#define PBC_CONTEXT_CAP 256 - -// wiretype - -#define WT_VARINT 0 -#define WT_BIT64 1 -#define WT_LEND 2 -#define WT_BIT32 5 - -#define CTYPE_INT32 1 -#define CTYPE_INT64 2 -#define CTYPE_DOUBLE 3 -#define CTYPE_FLOAT 4 -#define CTYPE_POINTER 5 -#define CTYPE_BOOL 6 -#define CTYPE_INT8 7 -#define CTYPE_INT16 8 -#define CTYPE_ARRAY 9 -#define CTYPE_VAR 10 -#define CTYPE_PACKED 11 - -#define PTYPE_DOUBLE 1 -#define PTYPE_FLOAT 2 -#define PTYPE_INT64 3 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if negative values are likely. -#define PTYPE_UINT64 4 -#define PTYPE_INT32 5 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if negative values are likely. -#define PTYPE_FIXED64 6 -#define PTYPE_FIXED32 7 -#define PTYPE_BOOL 8 -#define PTYPE_STRING 9 -#define PTYPE_GROUP 10 // Tag-delimited aggregate. -#define PTYPE_MESSAGE 11 // Length-delimited aggregate. -#define PTYPE_BYTES 12 -#define PTYPE_UINT32 13 -#define PTYPE_ENUM 14 -#define PTYPE_SFIXED32 15 -#define PTYPE_SFIXED64 16 -#define PTYPE_SINT32 17 // Uses ZigZag encoding. -#define PTYPE_SINT64 18 // Uses ZigZag encoding. - -struct slice { - int start; - int end; -}; - -struct atom { - int wire_id; - union { - struct slice s; - struct longlong i; - } v; -}; - -struct context { - char * buffer; - int size; - int number; - struct atom * a; -}; - -typedef struct _pbc_ctx { char _data[PBC_CONTEXT_CAP]; } pbc_ctx[1]; - -int _pbcC_open(pbc_ctx , void *buffer, int size); // <=0 failed -int _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size); -void _pbcC_close(pbc_ctx); - -static inline double -read_double(struct atom * a) { - union { - uint64_t i; - double d; - } u; - u.i = (uint64_t) a->v.i.low | (uint64_t) a->v.i.hi << 32; - return u.d; -} - -static inline float -read_float(struct atom * a) { - union { - uint32_t i; - float f; - } u; - u.i = a->v.i.low; - return u.f; -} - -static inline void -double_encode(double v , uint8_t * buffer) { - union { - double v; - uint64_t e; - } u; - u.v = v; - buffer[0] = (uint8_t) (u.e & 0xff); - buffer[1] = (uint8_t) (u.e >> 8 & 0xff); - buffer[2] = (uint8_t) (u.e >> 16 & 0xff); - buffer[3] = (uint8_t) (u.e >> 24 & 0xff); - buffer[4] = (uint8_t) (u.e >> 32 & 0xff); - buffer[5] = (uint8_t) (u.e >> 40 & 0xff); - buffer[6] = (uint8_t) (u.e >> 48 & 0xff); - buffer[7] = (uint8_t) (u.e >> 56 & 0xff); -} - -static inline void -float_encode(float v , uint8_t * buffer) { - union { - float v; - uint32_t e; - } u; - u.v = v; - buffer[0] = (uint8_t) (u.e & 0xff); - buffer[1] = (uint8_t) (u.e >> 8 & 0xff); - buffer[2] = (uint8_t) (u.e >> 16 & 0xff); - buffer[3] = (uint8_t) (u.e >> 24 & 0xff); -} - -#define CHECK_LEND(a,err) if ((a->wire_id & 7) != WT_LEND) return err; - -#if 0 -/* maybe we don't need check these wire type */ -#define CHECK_VARINT(a,err) if ((a->wire_id & 7) != WT_VARINT) return err; -#define CHECK_BIT32(a,err) if ((a->wire_id & 7) != WT_BIT32) return err; -#define CHECK_BIT64(a,err) if ((a->wire_id & 7) != WT_BIT64) return err; - -#else - -#define CHECK_VARINT(a,err) -#define CHECK_BIT32(a,err) -#define CHECK_BIT64(a,err) - -#endif - -#endif diff --git a/lua-protobuf/decode.c b/lua-protobuf/decode.c deleted file mode 100644 index 440cfbb3..00000000 --- a/lua-protobuf/decode.c +++ /dev/null @@ -1,349 +0,0 @@ -#include "pbc.h" -#include "alloc.h" -#include "context.h" -#include "proto.h" -#include "varint.h" - -#include - -static const char * TYPENAME[] = { - "invalid", // 0 - "integer", // 1 - "real", // 2 - "boolean", // 3 - "enum", // 4 - "string", // 5 - "message", // 6 - "fixed64", // 7 - "fixed32", // 8 - "bytes", // 9 - "int64", // 10 - "uint", // 11 -}; - -static int -call_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) { - union pbc_value v; - switch (a->wire_id) { - case WT_VARINT: - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - f(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL); - break; - case WT_BIT64: - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - f(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL); - break; - case WT_LEND: - v.s.buffer = (char*)start + a->v.s.start; - v.s.len = a->v.s.end - a->v.s.start; - f(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL); - break; - case WT_BIT32: - v.i.low = a->v.i.low; - v.i.hi = 0; - f(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL); - break; - default: - return 1; - } - return 0; -} - -static int -call_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) { - union pbc_value v; - const char * typename = NULL; - int type = _pbcP_type(f, &typename); - assert(type != 0); - if (typename == NULL) { - typename = TYPENAME[type & ~PBC_REPEATED]; - } - switch (f->type) { - case PTYPE_DOUBLE: - CHECK_BIT64(a, -1); - v.f = read_double(a); - break; - case PTYPE_FLOAT: - CHECK_BIT32(a, -1); - v.f = (double) read_float(a); - break; - case PTYPE_ENUM: - CHECK_VARINT(a, -1); - v.e.id = a->v.i.low; - v.e.name = _pbcM_ip_query(f->type_name.e->id , v.e.id); - break; - case PTYPE_INT64: - case PTYPE_UINT64: - CHECK_VARINT(a, -1); - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - break; - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - CHECK_BIT64(a, -1); - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - break; - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_BOOL: - CHECK_VARINT(a, -1); - v.i.low = a->v.i.low; - v.i.hi = 0; - break; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - CHECK_BIT32(a, -1); - v.i.low = a->v.i.low; - v.i.hi = 0; - break; - case PTYPE_SINT32: - CHECK_VARINT(a, -1); - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - _pbcV_dezigzag32((struct longlong *)&(v.i)); - break; - case PTYPE_SINT64: - CHECK_VARINT(a, -1); - v.i.low = a->v.i.low; - v.i.hi = a->v.i.hi; - _pbcV_dezigzag64((struct longlong *)&(v.i)); - break; - case PTYPE_STRING: - case PTYPE_BYTES: - case PTYPE_MESSAGE: - CHECK_LEND(a, -1); - v.s.buffer = start + a->v.s.start; - v.s.len = a->v.s.end - a->v.s.start; - break; - default: - assert(0); - break; - } - pd(ud, type, typename, &v, f->id, f->name); - return 0; -} - -static int -call_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) { - union pbc_value v; - const char * typename = NULL; - int type = _pbcP_type(f, &typename); - assert(type != 0); - if (typename == NULL) { - typename = TYPENAME[type & ~PBC_REPEATED]; - } - v.i.hi = 0; - int i; - switch(f->type) { - case PTYPE_DOUBLE: - if (size % 8 != 0) { - return -1; - } - for (i=0;iid, f->name); - } - return size/8; - case PTYPE_FLOAT: - if (size % 4 != 0) - return -1; - for (i=0;iid, f->name); - } - return size/4; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - if (size % 4 != 0) - return -1; - for (i=0;iid, f->name); - } - return size/4; - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - if (size % 8 != 0) - return -1; - for (i=0;iid, f->name); - } - return size/8; - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_BOOL: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - if (len > size) - return -1; - } - pd(ud, type , typename, &v, f->id, f->name); - buffer += len; - size -= len; - ++n; - } - return n; - } - case PTYPE_ENUM: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - if (len > size) - return -1; - } - v.e.id = v.i.low; - v.e.name = _pbcM_ip_query(f->type_name.e->id , v.i.low); - pd(ud, type , typename, &v, f->id, f->name); - buffer += len; - size -= len; - ++n; - } - return n; - } - case PTYPE_SINT32: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - _pbcV_dezigzag32((struct longlong *)&(v.i)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - if (len > size) - return -1; - _pbcV_dezigzag32((struct longlong *)&(v.i)); - } - pd(ud, type , typename, &v, f->id, f->name); - buffer += len; - size -= len; - ++n; - } - return n; - } - case PTYPE_SINT64: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - _pbcV_dezigzag64((struct longlong *)&(v.i)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); - if (len > size) - return -1; - _pbcV_dezigzag64((struct longlong *)&(v.i)); - } - pd(ud, type , typename, &v, f->id, f->name); - buffer += len; - size -= len; - ++n; - } - return n; - } - default: - return -1; - } -} - -int -pbc_decode(struct pbc_env * env, const char * typename , struct pbc_slice * slice, pbc_decoder pd, void *ud) { - struct _message * msg = _pbcP_get_message(env, typename); - if (msg == NULL) { - env->lasterror = "Proto not found"; - return -1; - } - if (slice->len == 0) { - return 0; - } - pbc_ctx _ctx; - int count = _pbcC_open(_ctx,slice->buffer,slice->len); - if (count <= 0) { - env->lasterror = "decode context error"; - _pbcC_close(_ctx); - return count - 1; - } - struct context * ctx = (struct context *)_ctx; - uint8_t * start = slice->buffer; - - int i; - for (i=0;inumber;i++) { - int id = ctx->a[i].wire_id >> 3; - struct _field * f = _pbcM_ip_query(msg->id , id); - if (f==NULL) { - int err = call_unknown(pd,ud,id,&ctx->a[i],start); - if (err) { - _pbcC_close(_ctx); - return -i-1; - } - } else if (f->label == LABEL_PACKED) { - struct atom * a = &ctx->a[i]; - int n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start); - if (n < 0) { - _pbcC_close(_ctx); - return -i-1; - } - } else { - if (call_type(pd,ud,f,&ctx->a[i],start) != 0) { - _pbcC_close(_ctx); - return -i-1; - } - } - } - - _pbcC_close(_ctx); - return ctx->number; -} - diff --git a/lua-protobuf/descriptor.pbc.h b/lua-protobuf/descriptor.pbc.h deleted file mode 100644 index 88dca861..00000000 --- a/lua-protobuf/descriptor.pbc.h +++ /dev/null @@ -1,271 +0,0 @@ -static unsigned char pbc_descriptor[] = { -72,1,72,2,72,3,72,4,72,5,72,6,72,7,72,8, -72,9,72,10,72,11,72,12,72,13,72,14,72,15,72,16, -72,17,72,18,72,1,72,2,72,3,72,1,72,2,72,3, -72,0,72,1,72,2,50,42,103,111,111,103,108,101,46,112, -114,111,116,111,98,117,102,46,70,105,101,108,100,68,101,115, -99,114,105,112,116,111,114,80,114,111,116,111,46,84,121,112, -101,0,50,43,103,111,111,103,108,101,46,112,114,111,116,111, -98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, -116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,50, -41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, -46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,116, -105,109,105,122,101,77,111,100,101,0,50,35,103,111,111,103, -108,101,46,112,114,111,116,111,98,117,102,46,70,105,101,108, -100,79,112,116,105,111,110,115,46,67,84,121,112,101,0,66, -12,84,89,80,69,95,68,79,85,66,76,69,0,66,11,84, -89,80,69,95,70,76,79,65,84,0,66,11,84,89,80,69, -95,73,78,84,54,52,0,66,12,84,89,80,69,95,85,73, -78,84,54,52,0,66,11,84,89,80,69,95,73,78,84,51, -50,0,66,13,84,89,80,69,95,70,73,88,69,68,54,52, -0,66,13,84,89,80,69,95,70,73,88,69,68,51,50,0, -66,10,84,89,80,69,95,66,79,79,76,0,66,12,84,89, -80,69,95,83,84,82,73,78,71,0,66,11,84,89,80,69, -95,71,82,79,85,80,0,66,13,84,89,80,69,95,77,69, -83,83,65,71,69,0,66,11,84,89,80,69,95,66,89,84, -69,83,0,66,12,84,89,80,69,95,85,73,78,84,51,50, -0,66,10,84,89,80,69,95,69,78,85,77,0,66,14,84, -89,80,69,95,83,70,73,88,69,68,51,50,0,66,14,84, -89,80,69,95,83,70,73,88,69,68,54,52,0,66,12,84, -89,80,69,95,83,73,78,84,51,50,0,66,12,84,89,80, -69,95,83,73,78,84,54,52,0,66,15,76,65,66,69,76, -95,79,80,84,73,79,78,65,76,0,66,15,76,65,66,69, -76,95,82,69,81,85,73,82,69,68,0,66,15,76,65,66, -69,76,95,82,69,80,69,65,84,69,68,0,66,6,83,80, -69,69,68,0,66,10,67,79,68,69,95,83,73,90,69,0, -66,13,76,73,84,69,95,82,85,78,84,73,77,69,0,66, -7,83,84,82,73,78,71,0,66,5,67,79,82,68,0,66, -13,83,84,82,73,78,71,95,80,73,69,67,69,0,56,18, -56,3,56,3,56,3,10,11,100,101,115,99,114,105,112,116, -111,114,0,32,1,32,9,32,7,32,2,32,8,32,3,32, -3,32,3,32,4,32,9,32,3,32,5,32,1,32,1,32, -1,32,1,32,7,32,2,32,1,32,2,42,51,24,2,16, -1,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, -111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,112, -116,111,114,80,114,111,116,111,0,10,5,102,105,108,101,0, -42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,42, -16,32,9,24,0,10,8,112,97,99,107,97,103,101,0,16, -2,42,19,32,9,24,2,10,11,100,101,112,101,110,100,101, -110,99,121,0,16,3,42,55,24,2,16,4,32,11,42,32, -103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, -68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, -10,13,109,101,115,115,97,103,101,95,116,121,112,101,0,42, -56,24,2,16,5,32,11,42,36,103,111,111,103,108,101,46, -112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,115, -99,114,105,112,116,111,114,80,114,111,116,111,0,10,10,101, -110,117,109,95,116,121,112,101,0,42,57,24,2,16,6,32, -11,42,39,103,111,111,103,108,101,46,112,114,111,116,111,98, -117,102,46,83,101,114,118,105,99,101,68,101,115,99,114,105, -112,116,111,114,80,114,111,116,111,0,10,8,115,101,114,118, -105,99,101,0,42,57,24,2,16,7,32,11,42,37,103,111, -111,103,108,101,46,112,114,111,116,111,98,117,102,46,70,105, -101,108,100,68,101,115,99,114,105,112,116,111,114,80,114,111, -116,111,0,10,10,101,120,116,101,110,115,105,111,110,0,42, -46,24,0,16,8,32,11,42,28,103,111,111,103,108,101,46, -112,114,111,116,111,98,117,102,46,70,105,108,101,79,112,116, -105,111,110,115,0,10,8,111,112,116,105,111,110,115,0,42, -58,24,0,16,9,32,11,42,31,103,111,111,103,108,101,46, -112,114,111,116,111,98,117,102,46,83,111,117,114,99,101,67, -111,100,101,73,110,102,111,0,10,17,115,111,117,114,99,101, -95,99,111,100,101,95,105,110,102,111,0,42,13,32,9,24, -0,10,5,110,97,109,101,0,16,1,42,53,24,2,16,2, -32,11,42,37,103,111,111,103,108,101,46,112,114,111,116,111, -98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, -116,111,114,80,114,111,116,111,0,10,6,102,105,101,108,100, -0,42,57,24,2,16,6,32,11,42,37,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, -68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, -10,10,101,120,116,101,110,115,105,111,110,0,42,54,24,2, -16,3,32,11,42,32,103,111,111,103,108,101,46,112,114,111, -116,111,98,117,102,46,68,101,115,99,114,105,112,116,111,114, -80,114,111,116,111,0,10,12,110,101,115,116,101,100,95,116, -121,112,101,0,42,56,24,2,16,4,32,11,42,36,103,111, -111,103,108,101,46,112,114,111,116,111,98,117,102,46,69,110, -117,109,68,101,115,99,114,105,112,116,111,114,80,114,111,116, -111,0,10,10,101,110,117,109,95,116,121,112,101,0,42,73, -24,2,16,5,32,11,42,47,103,111,111,103,108,101,46,112, -114,111,116,111,98,117,102,46,68,101,115,99,114,105,112,116, -111,114,80,114,111,116,111,46,69,120,116,101,110,115,105,111, -110,82,97,110,103,101,0,10,16,101,120,116,101,110,115,105, -111,110,95,114,97,110,103,101,0,42,49,24,0,16,7,32, -11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, -117,102,46,77,101,115,115,97,103,101,79,112,116,105,111,110, -115,0,10,8,111,112,116,105,111,110,115,0,42,14,32,5, -24,0,10,6,115,116,97,114,116,0,16,1,42,12,32,5, -24,0,10,4,101,110,100,0,16,2,42,13,32,9,24,0, -10,5,110,97,109,101,0,16,1,42,15,32,5,24,0,10, -7,110,117,109,98,101,114,0,16,3,42,59,24,0,16,4, -32,14,42,43,103,111,111,103,108,101,46,112,114,111,116,111, -98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, -116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,10, -6,108,97,98,101,108,0,42,57,24,0,16,5,32,14,42, -42,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, -46,70,105,101,108,100,68,101,115,99,114,105,112,116,111,114, -80,114,111,116,111,46,84,121,112,101,0,10,5,116,121,112, -101,0,42,18,32,9,24,0,10,10,116,121,112,101,95,110, -97,109,101,0,16,6,42,17,32,9,24,0,10,9,101,120, -116,101,110,100,101,101,0,16,2,42,22,32,9,24,0,10, -14,100,101,102,97,117,108,116,95,118,97,108,117,101,0,16, -7,42,47,24,0,16,8,32,11,42,29,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, -79,112,116,105,111,110,115,0,10,8,111,112,116,105,111,110, -115,0,42,13,32,9,24,0,10,5,110,97,109,101,0,16, -1,42,57,24,2,16,2,32,11,42,41,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,69,110,117,109,86, -97,108,117,101,68,101,115,99,114,105,112,116,111,114,80,114, -111,116,111,0,10,6,118,97,108,117,101,0,42,46,24,0, -16,3,32,11,42,28,103,111,111,103,108,101,46,112,114,111, -116,111,98,117,102,46,69,110,117,109,79,112,116,105,111,110, -115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, -24,0,10,5,110,97,109,101,0,16,1,42,15,32,5,24, -0,10,7,110,117,109,98,101,114,0,16,2,42,51,24,0, -16,3,32,11,42,33,103,111,111,103,108,101,46,112,114,111, -116,111,98,117,102,46,69,110,117,109,86,97,108,117,101,79, -112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,115, -0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,1, -42,55,24,2,16,2,32,11,42,38,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,77,101,116,104,111,100, -68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, -10,7,109,101,116,104,111,100,0,42,49,24,0,16,3,32, -11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, -117,102,46,83,101,114,118,105,99,101,79,112,116,105,111,110, -115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, -24,0,10,5,110,97,109,101,0,16,1,42,19,32,9,24, -0,10,11,105,110,112,117,116,95,116,121,112,101,0,16,2, -42,20,32,9,24,0,10,12,111,117,116,112,117,116,95,116, -121,112,101,0,16,3,42,48,24,0,16,4,32,11,42,30, -103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, -77,101,116,104,111,100,79,112,116,105,111,110,115,0,10,8, -111,112,116,105,111,110,115,0,42,21,32,9,24,0,10,13, -106,97,118,97,95,112,97,99,107,97,103,101,0,16,1,42, -29,32,9,24,0,10,21,106,97,118,97,95,111,117,116,101, -114,95,99,108,97,115,115,110,97,109,101,0,16,8,42,30, -24,0,16,10,32,8,10,20,106,97,118,97,95,109,117,108, -116,105,112,108,101,95,102,105,108,101,115,0,48,0,42,40, -24,0,16,20,32,8,10,30,106,97,118,97,95,103,101,110, -101,114,97,116,101,95,101,113,117,97,108,115,95,97,110,100, -95,104,97,115,104,0,48,0,42,72,24,0,16,9,32,14, -42,41,103,111,111,103,108,101,46,112,114,111,116,111,98,117, -102,46,70,105,108,101,79,112,116,105,111,110,115,46,79,112, -116,105,109,105,122,101,77,111,100,101,0,10,13,111,112,116, -105,109,105,122,101,95,102,111,114,0,58,6,83,80,69,69, -68,0,42,30,24,0,16,16,32,8,10,20,99,99,95,103, -101,110,101,114,105,99,95,115,101,114,118,105,99,101,115,0, -48,0,42,32,24,0,16,17,32,8,10,22,106,97,118,97, -95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, -115,0,48,0,42,30,24,0,16,18,32,8,10,20,112,121, -95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, -115,0,48,0,42,68,24,2,16,231,7,32,11,42,36,103, -111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,85, -110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,105, -111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,116, -101,100,95,111,112,116,105,111,110,0,42,34,24,0,16,1, -32,8,10,24,109,101,115,115,97,103,101,95,115,101,116,95, -119,105,114,101,95,102,111,114,109,97,116,0,48,0,42,42, -24,0,16,2,32,8,10,32,110,111,95,115,116,97,110,100, -97,114,100,95,100,101,115,99,114,105,112,116,111,114,95,97, -99,99,101,115,115,111,114,0,48,0,42,68,24,2,16,231, -7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, -111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,116, -101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,116, -101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,0, -42,60,24,0,16,1,32,14,42,35,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,79, -112,116,105,111,110,115,46,67,84,121,112,101,0,10,6,99, -116,121,112,101,0,58,7,83,84,82,73,78,71,0,42,15, -32,8,24,0,10,7,112,97,99,107,101,100,0,16,2,42, -21,24,0,16,3,32,8,10,11,100,101,112,114,101,99,97, -116,101,100,0,48,0,42,29,32,9,24,0,10,21,101,120, -112,101,114,105,109,101,110,116,97,108,95,109,97,112,95,107, -101,121,0,16,9,42,68,24,2,16,231,7,32,11,42,36, -103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, -85,110,105,110,116,101,114,112,114,101,116,101,100,79,112,116, -105,111,110,0,10,21,117,110,105,110,116,101,114,112,114,101, -116,101,100,95,111,112,116,105,111,110,0,42,68,24,2,16, -231,7,32,11,42,36,103,111,111,103,108,101,46,112,114,111, -116,111,98,117,102,46,85,110,105,110,116,101,114,112,114,101, -116,101,100,79,112,116,105,111,110,0,10,21,117,110,105,110, -116,101,114,112,114,101,116,101,100,95,111,112,116,105,111,110, -0,42,68,24,2,16,231,7,32,11,42,36,103,111,111,103, -108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, -116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, -10,21,117,110,105,110,116,101,114,112,114,101,116,101,100,95, -111,112,116,105,111,110,0,42,68,24,2,16,231,7,32,11, -42,36,103,111,111,103,108,101,46,112,114,111,116,111,98,117, -102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, -112,116,105,111,110,0,10,21,117,110,105,110,116,101,114,112, -114,101,116,101,100,95,111,112,116,105,111,110,0,42,68,24, -2,16,231,7,32,11,42,36,103,111,111,103,108,101,46,112, -114,111,116,111,98,117,102,46,85,110,105,110,116,101,114,112, -114,101,116,101,100,79,112,116,105,111,110,0,10,21,117,110, -105,110,116,101,114,112,114,101,116,101,100,95,111,112,116,105, -111,110,0,42,60,24,2,16,2,32,11,42,45,103,111,111, -103,108,101,46,112,114,111,116,111,98,117,102,46,85,110,105, -110,116,101,114,112,114,101,116,101,100,79,112,116,105,111,110, -46,78,97,109,101,80,97,114,116,0,10,5,110,97,109,101, -0,42,25,32,9,24,0,10,17,105,100,101,110,116,105,102, -105,101,114,95,118,97,108,117,101,0,16,3,42,27,32,4, -24,0,10,19,112,111,115,105,116,105,118,101,95,105,110,116, -95,118,97,108,117,101,0,16,4,42,27,32,3,24,0,10, -19,110,101,103,97,116,105,118,101,95,105,110,116,95,118,97, -108,117,101,0,16,5,42,21,32,1,24,0,10,13,100,111, -117,98,108,101,95,118,97,108,117,101,0,16,6,42,21,32, -12,24,0,10,13,115,116,114,105,110,103,95,118,97,108,117, -101,0,16,7,42,24,32,9,24,0,10,16,97,103,103,114, -101,103,97,116,101,95,118,97,108,117,101,0,16,8,42,18, -32,9,24,1,10,10,110,97,109,101,95,112,97,114,116,0, -16,1,42,21,32,8,24,1,10,13,105,115,95,101,120,116, -101,110,115,105,111,110,0,16,2,42,59,24,2,16,1,32, -11,42,40,103,111,111,103,108,101,46,112,114,111,116,111,98, -117,102,46,83,111,117,114,99,101,67,111,100,101,73,110,102, -111,46,76,111,99,97,116,105,111,110,0,10,9,108,111,99, -97,116,105,111,110,0,42,13,32,5,24,2,10,5,112,97, -116,104,0,16,1,42,13,32,5,24,2,10,5,115,112,97, -110,0,16,2,26,34,103,111,111,103,108,101,46,112,114,111, -116,111,98,117,102,46,70,105,108,101,68,101,115,99,114,105, -112,116,111,114,83,101,116,0,26,36,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,70,105,108,101,68,101, -115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,32, -103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, -68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, -26,47,103,111,111,103,108,101,46,112,114,111,116,111,98,117, -102,46,68,101,115,99,114,105,112,116,111,114,80,114,111,116, -111,46,69,120,116,101,110,115,105,111,110,82,97,110,103,101, -0,26,37,103,111,111,103,108,101,46,112,114,111,116,111,98, -117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,116, -111,114,80,114,111,116,111,0,26,36,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,69,110,117,109,68,101, -115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,41, -103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, -69,110,117,109,86,97,108,117,101,68,101,115,99,114,105,112, -116,111,114,80,114,111,116,111,0,26,39,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, -99,101,68,101,115,99,114,105,112,116,111,114,80,114,111,116, -111,0,26,38,103,111,111,103,108,101,46,112,114,111,116,111, -98,117,102,46,77,101,116,104,111,100,68,101,115,99,114,105, -112,116,111,114,80,114,111,116,111,0,26,28,103,111,111,103, -108,101,46,112,114,111,116,111,98,117,102,46,70,105,108,101, -79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,77,101,115,115,97,103, -101,79,112,116,105,111,110,115,0,26,29,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, -79,112,116,105,111,110,115,0,26,28,103,111,111,103,108,101, -46,112,114,111,116,111,98,117,102,46,69,110,117,109,79,112, -116,105,111,110,115,0,26,33,103,111,111,103,108,101,46,112, -114,111,116,111,98,117,102,46,69,110,117,109,86,97,108,117, -101,79,112,116,105,111,110,115,0,26,31,103,111,111,103,108, -101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, -99,101,79,112,116,105,111,110,115,0,26,30,103,111,111,103, -108,101,46,112,114,111,116,111,98,117,102,46,77,101,116,104, -111,100,79,112,116,105,111,110,115,0,26,36,103,111,111,103, -108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, -116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, -26,45,103,111,111,103,108,101,46,112,114,111,116,111,98,117, -102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, -112,116,105,111,110,46,78,97,109,101,80,97,114,116,0,26, -31,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, -46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,0, -26,40,103,111,111,103,108,101,46,112,114,111,116,111,98,117, -102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,111, -46,76,111,99,97,116,105,111,110,0, -}; \ No newline at end of file diff --git a/lua-protobuf/map.c b/lua-protobuf/map.c deleted file mode 100644 index 8c75b9ee..00000000 --- a/lua-protobuf/map.c +++ /dev/null @@ -1,477 +0,0 @@ -#include "map.h" -#include "alloc.h" - -#include -#include - -struct _pbcM_ip_slot { - int id; - void * pointer; - int next; -}; - -struct map_ip { - size_t array_size; - void ** array; - size_t hash_size; - struct _pbcM_ip_slot * slot; -}; - -struct _pbcM_si_slot { - const char *key; - size_t hash; - int id; - int next; -}; - -struct map_si { - size_t size; - struct _pbcM_si_slot slot[1]; -}; - -static size_t -calc_hash(const char *name) -{ - size_t len = strlen(name); - size_t h = len; - size_t step = (len>>5)+1; - size_t i; - for (i=len; i>=step; i-=step) - h = h ^ ((h<<5)+(h>>2)+(size_t)name[i-1]); - return h; -} - -struct map_si * -_pbcM_si_new(struct map_kv * table, int size) -{ - size_t sz = sizeof(struct map_si) + (size-1) * sizeof(struct _pbcM_si_slot); - struct map_si * ret = (struct map_si *)malloc(sz); - memset(ret,0,sz); - - ret->size = (size_t)size; - - int empty = 0; - int i; - - for (i=0;islot[hash]; - if (slot->key == NULL) { - slot->key = table[i].pointer; - slot->id = table[i].id; - slot->hash = hash_full; - } else { - while(ret->slot[empty].key != NULL) { - ++empty; - } - struct _pbcM_si_slot * empty_slot = &ret->slot[empty]; - empty_slot->next = slot->next; - slot->next = empty + 1; - empty_slot->id = table[i].id; - empty_slot->key = table[i].pointer; - empty_slot->hash = hash_full; - } - } - - return ret; -} - -void -_pbcM_si_delete(struct map_si *map) -{ - free(map); -} - -int -_pbcM_si_query(struct map_si *map, const char *key, int *result) -{ - size_t hash_full = calc_hash(key); - size_t hash = hash_full % map->size; - - struct _pbcM_si_slot * slot = &map->slot[hash]; - for (;;) { - if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { - *result = slot->id; - return 0; - } - if (slot->next == 0) { - return 1; - } - slot = &map->slot[slot->next-1]; - } -} - -static struct map_ip * -_pbcM_ip_new_hash(struct map_kv * table, int size) -{ - struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); - ret->array = NULL; - ret->array_size = 0; - ret->hash_size = (size_t)size; - ret->slot = malloc(sizeof(struct _pbcM_ip_slot) * size); - memset(ret->slot,0,sizeof(struct _pbcM_ip_slot) * size); - int empty = 0; - int i; - for (i=0;islot[hash]; - if (slot->pointer == NULL) { - slot->pointer = table[i].pointer; - slot->id = table[i].id; - } else { - while(ret->slot[empty].pointer != NULL) { - ++empty; - } - struct _pbcM_ip_slot * empty_slot = &ret->slot[empty]; - empty_slot->next = slot->next; - slot->next = empty + 1; - empty_slot->id = table[i].id; - empty_slot->pointer = table[i].pointer; - } - } - return ret; -} - -struct map_ip * -_pbcM_ip_new(struct map_kv * table, int size) -{ - int i; - int max = table[0].id; - if (max > size * 2 || max < 0) - return _pbcM_ip_new_hash(table,size); - for (i=1;i max) { - max = table[i].id; - if (max > size * 2) - return _pbcM_ip_new_hash(table,size); - } - } - struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); - ret->hash_size = size; - ret->slot = NULL; - ret->array_size = max + 1; - ret->array = (void **)malloc((max+1) * sizeof(void *)); - memset(ret->array,0,(max+1) * sizeof(void *)); - for (i=0;iarray[table[i].id] = table[i].pointer; - } - return ret; -} - -void -_pbcM_ip_delete(struct map_ip * map) -{ - if (map) { - free(map->array); - free(map->slot); - free(map); - } -} - -static void -_inject(struct map_kv * table, struct map_ip *map) -{ - if (map->array) { - int n = 0; - int i; - for (i=0;i<(int)map->array_size;i++) { - if (map->array[i]) { - table[n].id = i; - table[n].pointer = map->array[i]; - ++ n; - } - } - } else { - int i; - for (i=0;i<(int)map->hash_size;i++) { - table[i].id = map->slot[i].id; - table[i].pointer = map->slot[i].pointer; - } - } -} - -struct map_ip * -_pbcM_ip_combine(struct map_ip *a, struct map_ip *b) -{ - int sz = (int)(a->hash_size + b->hash_size); - struct map_kv * table = malloc(sz * sizeof(struct map_kv)); - memset(table , 0 , sz * sizeof(struct map_kv)); - _inject(table, a); - _inject(table + a->hash_size, b); - struct map_ip * r = _pbcM_ip_new(table, sz); - free(table); - return r; -} - -void * -_pbcM_ip_query(struct map_ip * map, int id) -{ - if (map == NULL) - return NULL; - if (map->array) { - if (id>=0 && id<(int)map->array_size) - return map->array[id]; - return NULL; - } - int hash = (unsigned)id % map->hash_size; - struct _pbcM_ip_slot * slot = &map->slot[hash]; - for (;;) { - if (slot->id == id) { - return slot->pointer; - } - if (slot->next == 0) { - return NULL; - } - slot = &map->slot[slot->next-1]; - } -} - -struct _pbcM_sp_slot { - const char *key; - size_t hash; - void *pointer; - int next; -}; - -struct map_sp { - size_t cap; - size_t size; - struct heap *heap; - struct _pbcM_sp_slot * slot; -}; - -struct map_sp * -_pbcM_sp_new(int max , struct heap *h) -{ - struct map_sp * ret = (struct map_sp *)HMALLOC(sizeof(struct map_sp)); - int cap = 1; - while (cap < max) { - cap *=2; - } - ret->cap = cap; - ret->size = 0; - ret->slot = (struct _pbcM_sp_slot *)HMALLOC(ret->cap * sizeof(struct _pbcM_sp_slot)); - memset(ret->slot,0,sizeof(struct _pbcM_sp_slot) * ret->cap); - ret->heap = h; - return ret; -} - -void -_pbcM_sp_delete(struct map_sp *map) -{ - if (map && map->heap == NULL) { - _pbcM_free(map->slot); - _pbcM_free(map); - } -} - -static void _pbcM_sp_rehash(struct map_sp *map); - -static void -_pbcM_sp_insert_hash(struct map_sp *map, const char *key, size_t hash_full, void * value) -{ - if (map->cap > map->size) { - size_t hash = hash_full & (map->cap-1); - struct _pbcM_sp_slot * slot = &map->slot[hash]; - if (slot->key == NULL) { - slot->key = key; - slot->pointer = value; - slot->hash = hash_full; - } else { - int empty = (hash + 1) & (map->cap-1); - while(map->slot[empty].key != NULL) { - empty = (empty + 1) & (map->cap-1); - } - struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; - empty_slot->next = slot->next; - slot->next = empty + 1; - empty_slot->pointer = value; - empty_slot->key = key; - empty_slot->hash = hash_full; - } - map->size++; - return; - } - _pbcM_sp_rehash(map); - _pbcM_sp_insert_hash(map, key, hash_full, value); -} - -static void -_pbcM_sp_rehash(struct map_sp *map) { - struct heap * h = map->heap; - struct _pbcM_sp_slot * old_slot = map->slot; - size_t size = map->size; - map->size = 0; - map->cap *= 2; - map->slot = (struct _pbcM_sp_slot *)HMALLOC(sizeof(struct _pbcM_sp_slot)*map->cap); - memset(map->slot,0,sizeof(struct _pbcM_sp_slot)*map->cap); - size_t i; - for (i=0;icap-1); - struct _pbcM_sp_slot * slot = &map->slot[hash]; - if (slot->key == NULL) { - if (map->cap <= map->size) - goto _rehash; - slot->key = key; - slot->hash = hash_full; - map->size++; - return &(slot->pointer); - } else { - for (;;) { - if (slot->hash == hash_full && strcmp(slot->key, key) == 0) - return &(slot->pointer); - if (slot->next == 0) { - break; - } - slot = &map->slot[slot->next-1]; - } - if (map->cap <= map->size) - goto _rehash; - - int empty = (hash + 1) & (map->cap-1); - while(map->slot[empty].key != NULL) { - empty = (empty + 1) & (map->cap-1); - } - struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; - empty_slot->next = slot->next; - slot->next = empty + 1; - empty_slot->key = key; - empty_slot->hash = hash_full; - - map->size++; - - return &(empty_slot->pointer); - } -_rehash: - _pbcM_sp_rehash(map); - return _pbcM_sp_query_insert_hash(map, key, hash_full); -} - -void -_pbcM_sp_insert(struct map_sp *map, const char *key, void * value) -{ - _pbcM_sp_insert_hash(map,key,calc_hash(key),value); -} - -void ** -_pbcM_sp_query_insert(struct map_sp *map, const char *key) -{ - return _pbcM_sp_query_insert_hash(map,key,calc_hash(key)); -} - -void * -_pbcM_sp_query(struct map_sp *map, const char *key) -{ - if (map == NULL) - return NULL; - size_t hash_full = calc_hash(key); - size_t hash = hash_full & (map->cap -1); - - struct _pbcM_sp_slot * slot = &map->slot[hash]; - for (;;) { - if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { - return slot->pointer; - } - if (slot->next == 0) { - return NULL; - } - slot = &map->slot[slot->next-1]; - } -} - -void -_pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)) -{ - size_t i; - for (i=0;icap;i++) { - if (map->slot[i].pointer) { - func(map->slot[i].pointer); - } - } -} - -void -_pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud) -{ - size_t i; - for (i=0;icap;i++) { - if (map->slot[i].pointer) { - func(map->slot[i].pointer,ud); - } - } -} - -static int -_find_first(struct map_sp *map) -{ - size_t i; - for (i=0;icap;i++) { - if (map->slot[i].pointer) { - return i; - } - } - return -1; -} - -static int -_find_next(struct map_sp *map, const char *key) -{ - size_t hash_full = calc_hash(key); - size_t hash = hash_full & (map->cap -1); - - struct _pbcM_sp_slot * slot = &map->slot[hash]; - for (;;) { - if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { - int i = slot - map->slot + 1; - while(icap) { - if (map->slot[i].pointer) { - return i; - } - ++i; - } - return -1; - } - if (slot->next == 0) { - return -1; - } - slot = &map->slot[slot->next-1]; - } -} - -void * -_pbcM_sp_next(struct map_sp *map, const char ** key) -{ - if (map == NULL) { - *key = NULL; - return NULL; - } - int idx; - if (*key == NULL) { - idx = _find_first(map); - } else { - idx = _find_next(map, *key); - } - if (idx < 0) { - *key = NULL; - return NULL; - } - *key = map->slot[idx].key; - return map->slot[idx].pointer; -} - - - diff --git a/lua-protobuf/map.h b/lua-protobuf/map.h deleted file mode 100644 index d0fc6a94..00000000 --- a/lua-protobuf/map.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PROTOBUF_C_MAP_H -#define PROTOBUF_C_MAP_H - -#include "alloc.h" - -struct map_ip; -struct map_si; -struct map_sp; - -struct map_kv { - int id; - void *pointer; -}; - -struct map_si * _pbcM_si_new(struct map_kv * table, int size); -int _pbcM_si_query(struct map_si *map, const char *key, int *result); -void _pbcM_si_delete(struct map_si *map); - -struct map_ip * _pbcM_ip_new(struct map_kv * table, int size); -struct map_ip * _pbcM_ip_combine(struct map_ip * a, struct map_ip * b); -void * _pbcM_ip_query(struct map_ip * map, int id); -void _pbcM_ip_delete(struct map_ip *map); - -struct map_sp * _pbcM_sp_new(int max, struct heap *h); -void _pbcM_sp_insert(struct map_sp *map, const char *key, void * value); -void * _pbcM_sp_query(struct map_sp *map, const char *key); -void ** _pbcM_sp_query_insert(struct map_sp *map, const char *key); -void _pbcM_sp_delete(struct map_sp *map); -void _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)); -void _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud); -void * _pbcM_sp_next(struct map_sp *map, const char ** key); - -#endif diff --git a/lua-protobuf/pattern.c b/lua-protobuf/pattern.c deleted file mode 100644 index 00a17ded..00000000 --- a/lua-protobuf/pattern.c +++ /dev/null @@ -1,1131 +0,0 @@ -#include "pbc.h" -#include "alloc.h" -#include "context.h" -#include "varint.h" -#include "pattern.h" -#include "array.h" -#include "proto.h" -#include "map.h" - -#include -#include -#include -#include -#include -#include - -static void -set_default_v(void * output, int ctype, pbc_var defv) { - switch (ctype) { - case CTYPE_INT32: - *(uint32_t *)output = defv->integer.low; - break; - case CTYPE_INT64: - *(uint64_t *)output = (uint64_t)defv->integer.low | (uint64_t)defv->integer.hi << 32; - break; - case CTYPE_DOUBLE: - *(double *)output = defv->real; - break; - case CTYPE_FLOAT: - *(float *)output = (float)defv->real; - break; - case CTYPE_BOOL: - *(bool *)output = (defv->integer.low != 0); - break; - case CTYPE_INT8: - *(uint8_t *)output = (uint8_t)defv->integer.low; - break; - case CTYPE_INT16: - *(uint16_t *)output = (uint16_t)defv->integer.low; - break; - case CTYPE_VAR: - *(union _pbc_var *)output = *defv; - break; - } -} - -static void -_pattern_set_default(struct _pattern_field *field, char *output) { - if (field->ctype == CTYPE_ARRAY || field->ctype == CTYPE_PACKED) { - struct _pbc_array *array = (struct _pbc_array *)(output + field->offset); - _pbcA_open(array); - } else if (field->ptype == PTYPE_ENUM) { - pbc_var defv; - defv->integer.low = field->defv->e.id; - defv->integer.hi = 0; - set_default_v(output + field->offset, field->ctype, defv); - } - set_default_v(output + field->offset, field->ctype, field->defv); -} - -void -pbc_pattern_set_default(struct pbc_pattern *pat, void *output) { - int i; - for (i=0;icount;i++) { - _pattern_set_default(&pat->f[i], output); - } -} - -// pattern unpack - -static struct _pattern_field * -bsearch_pattern(struct pbc_pattern *pat, int id) -{ - int begin = 0; - int end = pat->count; - while (begin < end) { - int mid = (begin + end)/2; - struct _pattern_field * f = &pat->f[mid]; - if (id == f->id) { - return f; - } - if (id < f->id) { - end = mid; - } else { - begin = mid + 1; - } - } - return NULL; -} - -static inline int -write_real(int ctype, double v, void *out) { - switch(ctype) { - case CTYPE_DOUBLE: - *(double *)out = v; - return 0; - case CTYPE_FLOAT: - *(float *)out = (float)v; - return 0; - case CTYPE_VAR: - ((union _pbc_var *)out)->real = v; - return 0; - } - return -1; -} - -static inline int -write_longlong(int ctype, struct longlong *i, void *out) { - switch(ctype) { - case CTYPE_INT32: - *(uint32_t *)out = i->low; - return 0; - case CTYPE_INT64: - *(uint64_t *)out = (uint64_t)i->low | (uint64_t)i->hi << 32; - return 0; - case CTYPE_BOOL: - *(bool *)out = (i->low !=0) ; - return 0; - case CTYPE_INT8: - *(uint8_t *)out = (uint8_t)i->low; - return 0; - case CTYPE_INT16: - *(uint8_t *)out = (uint16_t)i->low; - return 0; - case CTYPE_VAR: - ((union _pbc_var *)out)->integer = *i; - return 0; - } - return -1; -} - -static inline int -write_integer(int ctype, struct atom *a, void *out) { - return write_longlong(ctype, &(a->v.i), out); -} - -static int unpack_array(int ptype, char *buffer, struct atom *, pbc_array _array); - -int -_pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array) { - pbc_var var; - var->integer.hi = 0; - int i; - switch(ptype) { - case PTYPE_DOUBLE: - if (size % 8 != 0) - return -1; - for (i=0;ireal = u.d; - _pbcA_push(array, var); - } - return size/8; - case PTYPE_FLOAT: - if (size % 4 != 0) - return -1; - for (i=0;ireal = (double)u.f; - _pbcA_push(array, var); - } - return size/4; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - if (size % 4 != 0) - return -1; - for (i=0;iinteger.low = (uint32_t)buffer[i] | - (uint32_t)buffer[i+1] << 8 | - (uint32_t)buffer[i+2] << 16 | - (uint32_t)buffer[i+3] << 24; - _pbcA_push(array, var); - } - return size/4; - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - if (size % 8 != 0) - return -1; - for (i=0;iinteger.low = (uint32_t)buffer[i] | - (uint32_t)buffer[i+1] << 8 | - (uint32_t)buffer[i+2] << 16 | - (uint32_t)buffer[i+3] << 24; - var->integer.hi = (uint32_t)buffer[i+4] | - (uint32_t)buffer[i+5] << 8 | - (uint32_t)buffer[i+6] << 16 | - (uint32_t)buffer[i+7] << 24; - _pbcA_push(array, var); - } - return size/8; - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_ENUM: // enum must be integer type in pattern mode - case PTYPE_BOOL: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, &(var->integer)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, &(var->integer)); - if (len > size) - return -1; - } - _pbcA_push(array, var); - buffer += len; - size -= len; - ++n; - } - return n; - } - case PTYPE_SINT32: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, &(var->integer)); - _pbcV_dezigzag32(&(var->integer)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, &(var->integer)); - if (len > size) - return -1; - _pbcV_dezigzag32(&(var->integer)); - } - _pbcA_push(array, var); - buffer += len; - size -= len; - ++n; - } - return n; - } - case PTYPE_SINT64: { - int n = 0; - while (size > 0) { - int len; - if (size >= 10) { - len = _pbcV_decode(buffer, &(var->integer)); - _pbcV_dezigzag64(&(var->integer)); - } else { - uint8_t temp[10]; - memcpy(temp, buffer, size); - len = _pbcV_decode(buffer, &(var->integer)); - if (len > size) - return -1; - _pbcV_dezigzag64(&(var->integer)); - } - _pbcA_push(array, var); - buffer += len; - size -= len; - ++n; - } - return n; - } - } - return -1; -} - -static int -unpack_field(int ctype, int ptype, char * buffer, struct atom * a, void *out) { - if (ctype == CTYPE_ARRAY) { - return unpack_array(ptype, buffer, a , out); - } - if (ctype == CTYPE_PACKED) { - return _pbcP_unpack_packed((uint8_t *)buffer + a->v.s.start, a->v.s.end - a->v.s.start, ptype, out); - } - switch(ptype) { - case PTYPE_DOUBLE: - CHECK_BIT64(a, -1); - return write_real(ctype, read_double(a), out); - case PTYPE_FLOAT: - CHECK_BIT32(a, -1); - return write_real(ctype, read_float(a), out); - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_ENUM: // enum must be integer type in pattern mode - case PTYPE_BOOL: - CHECK_VARINT(a, -1); - return write_integer(ctype, a , out); - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - CHECK_BIT32(a, -1); - return write_integer(ctype, a , out); - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - CHECK_BIT64(a, -1); - return write_integer(ctype, a , out); - case PTYPE_SINT32: { - CHECK_VARINT(a, -1); - struct longlong temp = a->v.i; - _pbcV_dezigzag32(&temp); - return write_longlong(ctype, &temp , out); - } - case PTYPE_SINT64: { - CHECK_LEND(a, -1); - struct longlong temp = a->v.i; - _pbcV_dezigzag64(&temp); - return write_longlong(ctype, &temp , out); - } - case PTYPE_MESSAGE: - CHECK_LEND(a, -1); - ((union _pbc_var *)out)->m.buffer = buffer + a->v.s.start; - ((union _pbc_var *)out)->m.len = a->v.s.end - a->v.s.start; - return 0; - case PTYPE_STRING: - case PTYPE_BYTES: - CHECK_LEND(a, -1); - ((struct pbc_slice *)out)->buffer = buffer + a->v.s.start; - ((struct pbc_slice *)out)->len = a->v.s.end - a->v.s.start; - return 0; - } - return -1; -} - -static int -unpack_array(int ptype, char *buffer, struct atom * a, pbc_array _array) { - pbc_var var; - int r = unpack_field(CTYPE_VAR, ptype, buffer, a , var); - if (r !=0 ) - return r; - _pbcA_push(_array , var); - - return 0; -} - -void -pbc_pattern_close_arrays(struct pbc_pattern *pat, void * data) { - int i; - for (i=0;icount;i++) { - if (pat->f[i].ctype == CTYPE_ARRAY || pat->f[i].ctype == CTYPE_PACKED) { - void *array = (char *)data + pat->f[i].offset; - _pbcA_close(array); - } - } -} - -static inline int -_pack_wiretype(uint32_t wt, struct pbc_slice *s) { - int len; - if (s->len < 10) { - uint8_t temp[10]; - len = _pbcV_encode32(wt, temp); - if (len > s->len) - return -1; - memcpy(s->buffer, temp, len); - } else { - len = _pbcV_encode32(wt, s->buffer); - } - s->buffer = (char *)s->buffer + len; - s->len -= len; - return len; -} - -static inline int -_pack_varint64(uint64_t i64, struct pbc_slice *s) { - int len; - if (s->len < 10) { - uint8_t temp[10]; - len = _pbcV_encode(i64, temp); - if (len > s->len) - return -1; - memcpy(s->buffer, temp, len); - } else { - len = _pbcV_encode(i64, s->buffer); - } - s->buffer = (char *)s->buffer + len; - s->len -= len; - return len; -} - -static inline int -_pack_sint32(uint32_t v, struct pbc_slice *s) { - int len; - if (s->len < 10) { - uint8_t temp[10]; - len = _pbcV_zigzag32(v, temp); - if (len > s->len) - return -1; - memcpy(s->buffer, temp, len); - } else { - len = _pbcV_zigzag32(v, s->buffer); - } - s->buffer = (char *)s->buffer + len; - s->len -= len; - return len; -} - -static inline int -_pack_sint64(uint64_t v, struct pbc_slice *s) { - int len; - if (s->len < 10) { - uint8_t temp[10]; - len = _pbcV_zigzag(v, temp); - if (len > s->len) - return -1; - memcpy(s->buffer, temp, len); - } else { - len = _pbcV_zigzag(v, s->buffer); - } - s->buffer = (char *)s->buffer + len; - s->len -= len; - return len; -} - -static inline void -_fix32_encode(uint32_t v , uint8_t *buffer) { - buffer[0] = (uint8_t) v; - buffer[1] = (uint8_t) (v >> 8); - buffer[2] = (uint8_t) (v >> 16); - buffer[3] = (uint8_t) (v >> 24); -} - -static inline void -_fix64_encode(struct longlong *v , uint8_t *buffer) { - _fix32_encode(v->low , buffer); - _fix32_encode(v->hi, buffer + 4); -} - -static int -_pack_number(int ptype , int ctype , struct pbc_slice *s, void *input) { - pbc_var var; - if (ctype == CTYPE_VAR) { - memcpy(var, input, sizeof(var)); - } else { - switch (ctype) { - case CTYPE_INT32: - var->integer.low = *(uint32_t *)input; - var->integer.hi = 0; - break; - case CTYPE_INT64: { - uint64_t v = *(uint64_t *)input; - var->integer.low = (uint32_t) (v & 0xffffffff); - var->integer.hi = (uint32_t) (v >> 32); - break; - } - case CTYPE_INT16: - var->integer.low = *(uint16_t *)input; - var->integer.hi = 0; - break; - case CTYPE_INT8: - var->integer.low = *(uint8_t *)input; - var->integer.hi = 0; - break; - case CTYPE_BOOL: - var->integer.low = *(bool *)input; - var->integer.hi = 0; - break; - case CTYPE_DOUBLE: - var->real = *(double *)input; - break; - case CTYPE_FLOAT: - var->real = *(float *)input; - break; - } - } - - switch(ptype) { - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - if (s->len < 8) - return -1; - _fix64_encode(&(var->integer), s->buffer); - s->buffer = (char *)s->buffer + 8; - s->len -= 8; - return 8; - case PTYPE_DOUBLE: - if (s->len < 8) - return -1; - double_encode(var->real , s->buffer); - s->buffer = (char *)s->buffer + 8; - s->len -= 8; - return 8; - case PTYPE_FLOAT: - if (s->len < 4) - return -1; - float_encode((float)var->real , s->buffer); - s->buffer = (char *)s->buffer + 4; - s->len -= 4; - return 4; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - if (s->len < 4) - return -1; - _fix32_encode(var->integer.low, s->buffer); - s->buffer = (char *)s->buffer + 4; - s->len -= 4; - return 4; - case PTYPE_UINT64: - case PTYPE_INT64: - case PTYPE_INT32: - return _pack_varint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32, s); - case PTYPE_UINT32: - case PTYPE_BOOL: - case PTYPE_ENUM: - return _pack_wiretype(var->integer.low , s); - case PTYPE_SINT32: - return _pack_sint32(var->integer.low , s); - case PTYPE_SINT64: - return _pack_sint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , s); - default: - return -1; - } -} - -static int -_pack_field(struct _pattern_field *pf , int ctype, struct pbc_slice *s, void *input) { - int wiretype; - int ret = 0; - int len; - struct pbc_slice * input_slice; - struct pbc_slice string_slice; - - switch(pf->ptype) { - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - case PTYPE_DOUBLE: - wiretype = WT_BIT64; - goto _number; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - case PTYPE_FLOAT: - wiretype = WT_BIT32; - goto _number; - case PTYPE_UINT64: - case PTYPE_INT64: - case PTYPE_INT32: - case PTYPE_BOOL: - case PTYPE_UINT32: - case PTYPE_ENUM: - case PTYPE_SINT32: - case PTYPE_SINT64: - wiretype = WT_VARINT; - goto _number; - case PTYPE_STRING: - wiretype = WT_LEND; - input_slice = input; - if (input_slice->len > 0) - goto _string; - string_slice.buffer = input_slice->buffer; - string_slice.len = strlen((const char *)string_slice.buffer) - input_slice->len; - input_slice = &string_slice; - - goto _string; - case PTYPE_MESSAGE: - case PTYPE_BYTES: - wiretype = WT_LEND; - goto _bytes; - default: - break; - } - - return 0; -_bytes: - input_slice = input; -_string: - len = _pack_wiretype(pf->id << 3 | WT_LEND , s); - if (len < 0) { - return len; - } - ret += len; - len = _pack_wiretype(input_slice->len , s); - if (len < 0) { - return len; - } - ret += len; - if (input_slice->len > s->len) - return -1; - memcpy(s->buffer , input_slice->buffer, input_slice->len); - ret += input_slice->len; - s->buffer = (char *)s->buffer + input_slice->len; - s->len -= input_slice->len; - - return ret; -_number: - len = _pack_wiretype(pf->id << 3 | wiretype , s); - if (len < 0) { - return len; - } - ret += len; - len = _pack_number(pf->ptype, ctype , s, input); - if (len < 0) { - return len; - } - ret += len; - - return ret; -} - -static int -_pack_repeated(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { - int n = pbc_array_size(array); - int ret = 0; - if (n>0) { - int i; - for (i=0;ilen - len < n * width) - return -1; - int i; - for (i=0;iptype, CTYPE_VAR , s, _pbcA_index_p(array, i)); - } - - return len + n * width; -} - -static int -_pack_packed_varint(struct _pattern_field *pf , struct pbc_slice *slice, pbc_array array) { - struct pbc_slice s = * slice; - int n = pbc_array_size(array); - int estimate = n; - int estimate_len = _pack_wiretype(estimate , &s); - if (estimate_len < 0) { - return -1; - } - int i; - int packed_len = 0; - for (i=0;iptype, CTYPE_VAR , &s, _pbcA_index_p(array, i)); - if (len < 0) - return -1; - packed_len += len; - } - if (packed_len == estimate) { - *slice = s; - return packed_len + estimate_len; - } - uint8_t temp[10]; - struct pbc_slice header_slice = { temp , 10 }; - int header_len = _pack_wiretype(packed_len , &header_slice); - if (header_len == estimate_len) { - memcpy(slice->buffer , temp , header_len); - *slice = s; - return packed_len + estimate_len; - } - if (header_len + packed_len > slice->len) - return -1; - memmove((char *)slice->buffer + header_len , (char *)slice->buffer + estimate_len, packed_len); - memcpy(slice->buffer , temp , header_len); - slice->buffer = (char *)slice->buffer + packed_len + header_len; - slice->len -= packed_len + header_len; - return packed_len + header_len; -} - -static int -_pack_packed(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { - int n = pbc_array_size(array); - if (n == 0) - return 0; - - int ret = 0; - int len; - len = _pack_wiretype(pf->id << 3 | WT_LEND , s); - if (len < 0) { - return len; - } - ret += len; - - switch (pf->ptype) { - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - case PTYPE_DOUBLE: - len = _pack_packed_fixed(pf, 8, s , array); - if (len < 0) - return len; - break; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - case PTYPE_FLOAT: - len = _pack_packed_fixed(pf, 4, s , array); - if (len < 0) - return len; - break; - case PTYPE_UINT64: - case PTYPE_INT64: - case PTYPE_INT32: - case PTYPE_BOOL: - case PTYPE_UINT32: - case PTYPE_ENUM: - case PTYPE_SINT32: - case PTYPE_SINT64: - len = _pack_packed_varint(pf, s, array); - if (len < 0) - return len; - break; - } - ret += len; - - return ret; -} - -static bool -_is_default(struct _pattern_field * pf, void * in) { - switch (pf->ctype) { - case CTYPE_INT64: { - struct longlong * d64 = &pf->defv->integer; - return ((uint64_t)d64->low | (uint64_t)d64->hi << 32) == *(uint64_t *)in; - } - case CTYPE_DOUBLE: - return pf->defv->real == *(double *)in; - case CTYPE_FLOAT: - return (float)(pf->defv->real) == *(float *)in; - case CTYPE_INT32: - return pf->defv->integer.low == *(uint32_t *)in; - case CTYPE_INT16: - return (uint16_t)(pf->defv->integer.low) == *(uint16_t *)in; - case CTYPE_INT8: - return (uint8_t)(pf->defv->integer.low) == *(uint8_t *)in; - case CTYPE_BOOL: - if (pf->defv->integer.low) - return *(bool *)in == true; - else - return *(bool *)in == false; - } - if (pf->ptype == PTYPE_STRING) { - struct pbc_slice *slice = in; - if (slice->buffer == NULL) { - return pf->defv->s.str[0] == '\0'; - } - int len = slice->len; - if (len <= 0) { - return strcmp(pf->defv->s.str, slice->buffer) == 0; - } - return len == pf->defv->s.len && memcmp(pf->defv->s.str, slice->buffer, len)==0; - } - - return false; -} - -int -pbc_pattern_pack(struct pbc_pattern *pat, void *input, struct pbc_slice * s) -{ - struct pbc_slice slice = *s; - int i; - for (i=0;icount;i++) { - struct _pattern_field * pf = &pat->f[i]; - void * in = (char *)input + pf->offset; - int len = 0; - switch(pf->label) { - case LABEL_OPTIONAL: - if (_is_default(pf , in)) { - break; - } - case LABEL_REQUIRED: - len = _pack_field(pf, pf->ctype, &slice, in); - break; - case LABEL_REPEATED: - len = _pack_repeated(pf, &slice , in); - break; - case LABEL_PACKED: - len = _pack_packed(pf, &slice , in); - break; - } - if (len < 0) { - return len; - } - } - int len = (char *)slice.buffer - (char *)s->buffer; - int ret = s->len - len; - s->len = len; - return ret; -} - -int -pbc_pattern_unpack(struct pbc_pattern *pat, struct pbc_slice *s, void * output) { - if (s->len == 0) { - pbc_pattern_set_default(pat, output); - return 0; - } - pbc_ctx _ctx; - int r = _pbcC_open(_ctx, s->buffer, s->len); - if (r <= 0) { - pat->env->lasterror = "Pattern unpack open context error"; - _pbcC_close(_ctx); - return r-1; - } - - struct context * ctx = (struct context *)_ctx; - bool field[pat->count]; - memset(field, 0, sizeof(field)); - - int i; - int fc = 0; - - for (i=0;inumber;i++) { - struct _pattern_field * f = bsearch_pattern(pat, ctx->a[i].wire_id >> 3); - if (f) { - int index = f - pat->f; - if (field[index] == false) { - field[index] = true; - ++fc; - if ((f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED)) { - struct _pbc_array *array = (struct _pbc_array *)(output + f->offset); - _pbcA_open(array); - } - } - char * out = (char *)output + f->offset; - if (unpack_field(f->ctype , f->ptype , ctx->buffer , &ctx->a[i], out) < 0) { - int j; - for (j=0;jcount;j++) { - if (field[j] == true && (pat->f[j].ctype == CTYPE_ARRAY || pat->f[j].ctype == CTYPE_PACKED)) { - void *array = (char *)output + pat->f[j].offset; - _pbcA_close(array); - } - } - _pbcC_close(_ctx); - pat->env->lasterror = "Pattern unpack field error"; - return -i-1; - } - } - } - _pbcC_close(_ctx); - if (fc != pat->count) { - for (i=0;icount;i++) { - if (field[i] == false) { - _pattern_set_default(&pat->f[i], output); - } - } - } - return 0; -} - -/* - format : key %type - %f float - %F double - %d int32 - %D int64 - %b bool - %h int16 - %c int8 - %s slice - %a array -*/ - -static int -_ctype(const char * ctype) { - if (ctype[0]!='%') - return -1; - switch (ctype[1]) { - case 'f': - return CTYPE_FLOAT; - case 'F': - return CTYPE_DOUBLE; - case 'd': - return CTYPE_INT32; - case 'D': - return CTYPE_INT64; - case 'b': - return CTYPE_BOOL; - case 'h': - return CTYPE_INT16; - case 'c': - return CTYPE_INT8; - case 's': - return CTYPE_VAR; - case 'a': - return CTYPE_ARRAY; - default: - return -1; - } -} - -static int -_ctype_size(const char *ctype) { - switch (ctype[1]) { - case 'f': - return sizeof(float); - case 'F': - return sizeof(double); - case 'd': - return sizeof(int32_t); - case 'D': - return sizeof(int64_t); - case 'b': - return sizeof(bool); - case 'h': - return sizeof(int16_t); - case 'c': - return sizeof(int8_t); - case 's': - return sizeof(struct pbc_slice); - case 'a': - return sizeof(pbc_array); - default: - return 0; - } -} - -static const char * -_copy_string(const char *format , char ** temp) { - char * output = *temp; - while (*format == ' ' || *format == '\t' || *format == '\n' || *format == '\r') { - ++format; - } - while (*format != '\0' && - *format != ' ' && - *format != '\t' && - *format != '\n' && - *format != '\r') { - *output = *format; - ++output; - ++format; - } - *output = '\0'; - ++output; - *temp = output; - - return format; -} - -static int -_scan_pattern(const char * format , char * temp) { - int n = 0; - for(;;) { - format = _copy_string(format , &temp); - if (format[0] == '\0') - return 0; - ++n; - format = _copy_string(format , &temp); - if (format[0] == '\0') - return n; - } -} - -static int -_comp_field(const void * a, const void * b) { - const struct _pattern_field * fa = a; - const struct _pattern_field * fb = b; - - return fa->id - fb->id; -} - -struct pbc_pattern * -_pbcP_new(struct pbc_env * env, int n) { - size_t sz = sizeof(struct pbc_pattern) + (sizeof(struct _pattern_field)) * (n-1); - struct pbc_pattern * ret = malloc(sz); - memset(ret, 0 , sz); - ret->count = n; - ret->env = env; - return ret; -} - -static int -_check_ctype(struct _field * field, struct _pattern_field *f) { - if (field->label == LABEL_REPEATED) { - return f->ctype != CTYPE_ARRAY; - } - if (field->label == LABEL_PACKED) { - return f->ctype != CTYPE_PACKED; - } - if (field->type == PTYPE_STRING || field->type == PTYPE_MESSAGE || field->type == PTYPE_BYTES) { - return f->ctype != CTYPE_VAR; - } - if (field->type == PTYPE_FLOAT || field->type == PTYPE_DOUBLE) { - return !(f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT); - } - if (field->type == PTYPE_ENUM) { - return !(f->ctype == CTYPE_INT8 || - f->ctype == CTYPE_INT8 || - f->ctype == CTYPE_INT16 || - f->ctype == CTYPE_INT32 || - f->ctype == CTYPE_INT64); - } - - return f->ctype == CTYPE_VAR || f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED || - f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT; -} - -struct pbc_pattern * -_pattern_new(struct _message *m, const char *format) { - int len = strlen(format); - char temp[len+1]; - int n = _scan_pattern(format, temp); - struct pbc_pattern * pat = _pbcP_new(m->env, n); - int i; - - const char *ptr = temp; - - int offset = 0; - - for (i=0;if[i]); - struct _field * field = _pbcM_sp_query(m->name, ptr); - if (field == NULL) { - m->env->lasterror = "Pattern @new query none exist field"; - goto _error; - } - f->id = field->id; - f->ptype = field->type; - *f->defv = *field->default_v; - f->offset = offset; - f->label = field->label; - ptr += strlen(ptr) + 1; - f->ctype = _ctype(ptr); - if (f->ctype < 0) { - m->env->lasterror = "Pattern @new use an invalid ctype"; - goto _error; - } - - if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { - f->ctype = CTYPE_PACKED; - } - if (_check_ctype(field, f)) { - m->env->lasterror = "Pattern @new ctype check error"; - goto _error; - } - - offset += _ctype_size(ptr); - ptr += strlen(ptr) + 1; - } - - pat->count = n; - - qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); - - return pat; -_error: - free(pat); - return NULL; -} - -struct pbc_pattern * -pbc_pattern_new(struct pbc_env * env , const char * message, const char * format, ... ) { - struct _message *m = _pbcP_get_message(env, message); - if (m==NULL) { - env->lasterror = "Pattern new can't find proto"; - return NULL; - } - if (format[0]=='@') { - return _pattern_new(m , format+1); - } - - int len = strlen(format); - char temp[len+1]; - int n = _scan_pattern(format, temp); - struct pbc_pattern * pat = _pbcP_new(env, n); - int i; - va_list ap; - va_start(ap , format); - - const char *ptr = temp; - - for (i=0;if[i]); - struct _field * field = _pbcM_sp_query(m->name, ptr); - if (field == NULL) { - env->lasterror = "Pattern new query none exist field"; - goto _error; - } - f->id = field->id; - f->ptype = field->type; - *f->defv = *field->default_v; - f->offset = va_arg(ap, int); - f->label = field->label; - - ptr += strlen(ptr) + 1; - - f->ctype = _ctype(ptr); - if (f->ctype < 0) { - env->lasterror = "Pattern new use an invalid ctype"; - goto _error; - } - if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { - f->ctype = CTYPE_PACKED; - } - if (_check_ctype(field, f)) { - env->lasterror = "Pattern new ctype check error"; - goto _error; - } - - ptr += strlen(ptr) + 1; - } - - va_end(ap); - - pat->count = n; - - qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); - - return pat; -_error: - free(pat); - return NULL; -} - -void -pbc_pattern_delete(struct pbc_pattern * pat) { - free(pat); -} diff --git a/lua-protobuf/pattern.h b/lua-protobuf/pattern.h deleted file mode 100644 index 880d3d5d..00000000 --- a/lua-protobuf/pattern.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PROTOBUF_C_PATTERN_H -#define PROTOBUF_C_PATTERN_H - -#include "pbc.h" -#include "context.h" -#include "array.h" - -struct _pattern_field { - int id; - int offset; - int ptype; - int ctype; - int label; - pbc_var defv; -}; - -struct pbc_pattern { - struct pbc_env * env; - int count; - struct _pattern_field f[1]; -}; - -struct pbc_pattern * _pbcP_new(struct pbc_env * env, int n); -int _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array); - -#endif diff --git a/lua-protobuf/pbc-lua.c b/lua-protobuf/pbc-lua.c deleted file mode 100644 index d55c5507..00000000 --- a/lua-protobuf/pbc-lua.c +++ /dev/null @@ -1,1005 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "pbc.h" - -#if LUA_VERSION_NUM == 501 - -#define lua_rawlen lua_objlen -#define luaL_newlib(L ,reg) luaL_register(L,"protobuf.c",reg) -#define luaL_buffinit(L , _ ) -#define luaL_prepbuffsize( b , cap ) malloc(cap) -#define _Free(p) free(p) -#undef luaL_addsize -#define luaL_addsize(b , len) lua_pushlstring(L, temp , len) ; free(temp) -#define luaL_pushresult(b) -#define luaL_checkversion(L) - -#else - -#define _Free(p) - -#endif - -static inline void * -checkuserdata(lua_State *L, int index) { - void * ud = lua_touserdata(L,index); - if (ud == NULL) { - luaL_error(L, "userdata %d is nil",index); - } - return ud; -} - -static int -_env_new(lua_State *L) { - struct pbc_env * env = pbc_new(); - lua_pushlightuserdata(L, env); - return 1; -} - -static int -_env_delete(lua_State *L) { - struct pbc_env * env = lua_touserdata(L,1); - pbc_delete(env); - - return 0; -} - -static int -_env_register(lua_State *L) { - struct pbc_env * env = checkuserdata(L,1); - size_t sz = 0; - const char * buffer = luaL_checklstring(L, 2 , &sz); - struct pbc_slice slice; - slice.buffer = (void *)buffer; - slice.len = (int)sz; - int ret = pbc_register(env, &slice); - - if (ret) { - return luaL_error(L, "register fail"); - } - return 0; -} - -static int -_rmessage_new(lua_State *L) { - struct pbc_env * env = checkuserdata(L,1); - const char * typename = luaL_checkstring(L,2); - struct pbc_slice slice; - if (lua_isstring(L,3)) { - size_t sz = 0; - slice.buffer = (void *)lua_tolstring(L,3,&sz); - slice.len = (int)sz; - } else { - slice.buffer = lua_touserdata(L,3); - slice.len = luaL_checkinteger(L,4); - } - struct pbc_rmessage * m = pbc_rmessage_new(env, typename, &slice); - if (m==NULL) - return 0; - lua_pushlightuserdata(L,m); - return 1; -} - -static int -_rmessage_delete(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - pbc_rmessage_delete(m); - - return 0; -} - -static int -_rmessage_integer(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - int32_t v = (int32_t)pbc_rmessage_integer(m, key, index, NULL); - - lua_pushinteger(L,v); - - return 1; -} - -static int -_rmessage_int32(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - uint32_t v = pbc_rmessage_integer(m, key, index, NULL); - lua_pushlightuserdata(L,(void *)(intptr_t)v); - - return 1; -} - -static int -_rmessage_int64_ia64(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - uint32_t v[2]; - v[0] = pbc_rmessage_integer(m, key, index, &v[1]); - uint64_t u64 = (uint64_t)v[0] | (uint64_t)v[1] << 32; - - lua_pushlightuserdata(L,(void *)u64); - - return 1; -} - -static int -_rmessage_int52(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - uint32_t hi,low; - low = pbc_rmessage_integer(m, key, index, &hi); - int64_t v = (int64_t)((uint64_t)hi << 32 | (uint64_t)low); - lua_pushnumber(L,(lua_Number)v); - - return 1; -} - -static int -_rmessage_uint52(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - uint32_t hi,low; - low = pbc_rmessage_integer(m, key, index, &hi); - uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; - lua_pushnumber(L,(lua_Number)v); - - return 1; -} - -static int -_rmessage_real(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = luaL_checkinteger(L,3); - double v = pbc_rmessage_real(m, key, index); - - lua_pushnumber(L,v); - - return 1; -} - -static int -_rmessage_string(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = lua_tointeger(L,3); - int sz = 0; - const char * v = pbc_rmessage_string(m,key,index,&sz); - lua_pushlstring(L,v,sz); - return 1; -} - -static int -_rmessage_message(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int index = lua_tointeger(L,3); - struct pbc_rmessage * v = pbc_rmessage_message(m,key,index); - lua_pushlightuserdata(L,v); - return 1; -} - -static int -_rmessage_size(lua_State *L) { - struct pbc_rmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - - int sz = pbc_rmessage_size(m, key); - - lua_pushinteger(L, sz); - - return 1; -} - -static int -_env_type(lua_State *L) { - lua_settop(L,3); - struct pbc_env * env = checkuserdata(L,1); - const char * typename = luaL_checkstring(L,2); - if (lua_isnil(L,3)) { - int ret = pbc_type(env, typename, NULL, NULL); - lua_pushboolean(L,ret); - return 1; - } - const char * key = luaL_checkstring(L,3); - const char * type = NULL; - int ret = pbc_type(env, typename, key, &type); - lua_pushinteger(L,ret); - if (type == NULL) { - return 1; - } { - lua_pushstring(L, type); - return 2; - } -} - -static int -_wmessage_new(lua_State *L) { - struct pbc_env * env = checkuserdata(L,1); - const char * typename = luaL_checkstring(L,2); - struct pbc_wmessage * ret = pbc_wmessage_new(env, typename); - lua_pushlightuserdata(L,ret); - return 1; -} - -static int -_wmessage_delete(lua_State *L) { - struct pbc_wmessage * m = lua_touserdata(L,1); - pbc_wmessage_delete(m); - - return 0; -} - - -static int -_wmessage_integer(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int number = luaL_checkinteger(L,3); - uint32_t hi = 0; - if (number < 0) - hi = ~0; - pbc_wmessage_integer(m, key, number, hi); - - return 0; -} - -static int -_wmessage_real(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - double number = luaL_checknumber(L,3); - pbc_wmessage_real(m, key, number); - - return 0; -} - -static int -_wmessage_string(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - size_t len = 0; - const char * v = luaL_checklstring(L,3,&len); - int err = pbc_wmessage_string(m, key, v, (int)len); - if (err) { - return luaL_error(L, "Invalid enum %s", v); - } - - return 0; -} - -static int -_wmessage_message(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - struct pbc_wmessage * ret = pbc_wmessage_message(m, key); - lua_pushlightuserdata(L, ret); - - return 1; -} - -static int -_wmessage_int32(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - if (!lua_islightuserdata(L,3)) { - return luaL_error(L,"Need a lightuserdata for int32"); - } - void *number = lua_touserdata(L,3); - pbc_wmessage_integer(m, key, (uint32_t)(intptr_t)number , 0); - return 0; -} - -static int -_wmessage_int64_ia64(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - luaL_checktype(L, 3, LUA_TLIGHTUSERDATA); - void * v = lua_touserdata(L,3); - uint64_t v64 = (uintptr_t)v; - pbc_wmessage_integer(m, key, (uint32_t)v64 , (uint32_t)(v64>>32)); - return 0; -} - -static int -_wmessage_int52(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - int64_t number = (int64_t)(luaL_checknumber(L,3)); - uint32_t hi = (uint32_t)(number >> 32); - pbc_wmessage_integer(m, key, (uint32_t)number, hi); - - return 0; -} - -static int -_wmessage_uint52(lua_State *L) { - struct pbc_wmessage * m = checkuserdata(L,1); - const char * key = luaL_checkstring(L,2); - lua_Number v = (luaL_checknumber(L,3)); - if (v < 0) { - return luaL_error(L, "negative number : %f passed to unsigned field",v); - } - uint64_t number = (uint64_t)v; - uint32_t hi = (uint32_t)(number >> 32); - pbc_wmessage_integer(m, key, (uint32_t)number, hi); - - return 0; -} - -static int -_wmessage_buffer(lua_State *L) { - struct pbc_slice slice; - struct pbc_wmessage * m = checkuserdata(L,1); - pbc_wmessage_buffer(m , &slice); - lua_pushlightuserdata(L, slice.buffer); - lua_pushinteger(L, slice.len); - return 2; -} - -static int -_wmessage_buffer_string(lua_State *L) { - struct pbc_slice slice; - struct pbc_wmessage * m = checkuserdata(L,1); - pbc_wmessage_buffer(m , &slice); - lua_pushlstring(L, (const char *)slice.buffer, slice.len); - return 1; -} - -/* - lightuserdata env - */ -static int -_last_error(lua_State *L) { - struct pbc_env * env = checkuserdata(L, 1); - const char * err = pbc_error(env); - lua_pushstring(L,err); - return 1; -} - -/* - lightuserdata env - string message - string format - */ -static int -_pattern_new(lua_State *L) { - struct pbc_env * env = checkuserdata(L, 1); - const char * message = luaL_checkstring(L,2); - const char * format = luaL_checkstring(L,3); - struct pbc_pattern * pat = pbc_pattern_new(env, message, format); - if (pat == NULL) { - return luaL_error(L, "create patten %s (%s) failed", message , format); - } - lua_pushlightuserdata(L,pat); - - return 1; -} - -static int -_pattern_delete(lua_State *L) { - struct pbc_pattern * pat = lua_touserdata(L,1); - pbc_pattern_delete(pat); - - return 0; -} - -static void * -_push_value(lua_State *L, char * ptr, char type) { - switch(type) { - case 'u': { - uint64_t v = *(uint64_t*)ptr; - ptr += 8; - lua_pushnumber(L,(lua_Number)v); - break; - } - case 'i': { - int32_t v = *(int32_t*)ptr; - ptr += 4; - lua_pushinteger(L,v); - break; - } - case 'b': { - int32_t v = *(int32_t*)ptr; - ptr += 4; - lua_pushboolean(L,v); - break; - } - case 'p': { - uint32_t v = *(uint32_t*)ptr; - ptr += 4; - lua_pushlightuserdata(L,(void *)(intptr_t)v); - break; - } - case 'x': { - void * v; - memcpy(&v, ptr, 8); - lua_pushlightuserdata(L,v); - ptr += 8; - break; - } - case 'd': { - int64_t v = *(int64_t*)ptr; - ptr += 8; - lua_pushnumber(L,(lua_Number)v); - break; - } - case 'r': { - double v = *(double *)ptr; - ptr += 8; - lua_pushnumber(L,v); - break; - } - case 's': { - struct pbc_slice * slice = (struct pbc_slice *)ptr; - lua_pushlstring(L,slice->buffer, slice->len); - ptr += sizeof(struct pbc_slice); - break; - } - case 'm': { - struct pbc_slice * slice = (struct pbc_slice *)ptr; - lua_createtable(L,2,0); - lua_pushlightuserdata(L, slice->buffer); - lua_rawseti(L,-2,1); - lua_pushinteger(L,slice->len); - lua_rawseti(L,-2,2); - ptr += sizeof(struct pbc_slice); - break; - } - } - return ptr; -} - -static void -_push_array(lua_State *L, pbc_array array, char type, int index) { - switch (type) { - case 'I': { - int v = pbc_array_integer(array, index, NULL); - lua_pushinteger(L, v); - break; - } - case 'U': { - uint32_t hi = 0; - uint32_t low = pbc_array_integer(array, index, &hi); - uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; - lua_pushnumber(L, (lua_Number)v); - break; - } - case 'D': { - uint32_t hi = 0; - uint32_t low = pbc_array_integer(array, index, &hi); - uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; - lua_pushnumber(L, (lua_Number)((int64_t)v)); - break; - } - case 'B': { - int v = pbc_array_integer(array, index, NULL); - lua_pushboolean(L, v); - break; - } - case 'P': { - uint32_t v = pbc_array_integer(array, index, NULL); - lua_pushlightuserdata(L,(void *)(intptr_t)v); - break; - } - case 'X': { - uint32_t hi = 0; - uint32_t low = pbc_array_integer(array, index, &hi); - uint64_t v = (uint64_t)low | (uint64_t)hi << 32; - lua_pushlightuserdata(L, (void *)v); - break; - } - case 'R': { - double v = pbc_array_real(array, index); - lua_pushnumber(L, v); - break; - } - case 'S': { - struct pbc_slice * slice = pbc_array_slice(array, index); - lua_pushlstring(L, (const char *)slice->buffer,slice->len); - break; - } - case 'M': { - struct pbc_slice * slice = pbc_array_slice(array, index); - lua_createtable(L,2,0); - lua_pushlightuserdata(L,slice->buffer); - lua_rawseti(L,-2,1); - lua_pushinteger(L,slice->len); - lua_rawseti(L,-2,2); - break; - } - } - lua_rawseti(L,-2,index+1); -} - -/* - lightuserdata pattern - string format "ixrsmb" - integer size - lightuserdata buffer - integer buffer_len - */ -static int -_pattern_unpack(lua_State *L) { - struct pbc_pattern * pat = checkuserdata(L, 1); - if (pat == NULL) { - return luaL_error(L, "unpack pattern is NULL"); - } - size_t format_sz = 0; - const char * format = lua_tolstring(L,2,&format_sz); - int size = lua_tointeger(L,3); - struct pbc_slice slice; - if (lua_isstring(L,4)) { - size_t buffer_len = 0; - const char *buffer = luaL_checklstring(L,4,&buffer_len); - slice.buffer = (void *)buffer; - slice.len = buffer_len; - } else { - if (!lua_isuserdata(L,4)) { - return luaL_error(L, "Need a userdata"); - } - slice.buffer = lua_touserdata(L,4); - slice.len = luaL_checkinteger(L,5); - } - - char temp[size]; - int ret = pbc_pattern_unpack(pat, &slice, temp); - if (ret < 0) - return 0; - lua_checkstack(L, format_sz + 3); - int i; - char * ptr = temp; - bool array = false; - for (i=0;i= 'a' && type <='z') { - ptr = _push_value(L,ptr,type); - } else { - array = true; - int n = pbc_array_size((void *)ptr); - lua_createtable(L,n,0); - int j; - for (j=0;jbuffer = (void*)str; - slice->len = sz; - return ptr + sizeof(struct pbc_slice); - } - case 'm': { - struct pbc_slice * slice = (struct pbc_slice *)ptr; - if (lua_istable(L,index)) { - lua_rawgeti(L,index,1); - slice->buffer = lua_touserdata(L,-1); - lua_rawgeti(L,index,2); - slice->len = lua_tointeger(L,-1); - lua_pop(L,2); - } else { - size_t sz = 0; - const char * buffer = luaL_checklstring(L, index, &sz); - slice->buffer = (void *)buffer; - slice->len = sz; - } - return ptr + sizeof(struct pbc_slice); - } - default: - luaL_error(L,"unknown format %c", type); - return ptr; - } -} - -static void -_get_array_value(lua_State *L, pbc_array array, char type) { - switch(type) { - case 'I': { - int32_t v = luaL_checkinteger(L, -1); - uint32_t hi = 0; - if (v<0) { - hi = ~0; - } - pbc_array_push_integer(array, v, hi); - break; - } - case 'U' : { - uint64_t v = (uint64_t)luaL_checknumber(L, -1); - pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); - break; - } - case 'D' : { - int64_t v = (int64_t)luaL_checknumber(L, -1); - pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); - break; - } - case 'B': { - int32_t v = lua_toboolean(L, -1); - pbc_array_push_integer(array, v ? 1: 0, 0); - break; - } - case 'P': { - void *p = lua_touserdata(L, -1); - uint32_t v = (uint32_t)(intptr_t)p; - pbc_array_push_integer(array, v, 0); - break; - } - case 'X': { - luaL_checktype(L,-1,LUA_TLIGHTUSERDATA); - void * i64 = lua_touserdata(L,-1); - uint64_t v = (uintptr_t)i64; - pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); - break; - } - case 'R': { - double v = luaL_checknumber(L, -1); - pbc_array_push_real(array, v); - break; - } - case 'S': { - size_t sz = 0; - const char * str = luaL_checklstring(L, -1, &sz); - struct pbc_slice slice; - slice.buffer = (void*)str; - slice.len = sz; - pbc_array_push_slice(array, &slice); - break; - } - case 'M': { - struct pbc_slice slice; - if (lua_istable(L,-1)) { - lua_rawgeti(L,-1,1); - slice.buffer = lua_touserdata(L,-1); - lua_rawgeti(L,-2,2); - slice.len = lua_tointeger(L,-1); - lua_pop(L,2); - } else { - size_t sz = 0; - const char * buffer = luaL_checklstring(L, -1, &sz); - slice.buffer = (void *)buffer; - slice.len = sz; - } - pbc_array_push_slice(array, &slice); - break; - } - } -} - -/* - lightuserdata pattern - string format "ixrsmbp" - integer size - */ -static int -_pattern_pack(lua_State *L) { - struct pbc_pattern * pat = checkuserdata(L,1); - if (pat == NULL) { - return luaL_error(L, "pack pattern is NULL"); - } - size_t format_sz = 0; - const char * format = lua_tolstring(L,2,&format_sz); - int size = lua_tointeger(L,3); - - char data[size]; -// A trick , we don't need default value. zero buffer for array and message field. -// pbc_pattern_set_default(pat, data); - memset(data, 0 , size); - - char * ptr = data; - - int i; - - for (i=0;i= 'a' && format[i] <='z') { - ptr = _get_value(L, 4+i, ptr, format[i]); - } else { - if (!lua_istable(L,4+i)) { - luaL_error(L,"need table for array type"); - } - int j; - int n = lua_rawlen(L,4+i); - for (j=0;ji.low); - break; - case PBC_REAL: - lua_pushnumber(L, v->f); - break; - case PBC_BOOL: - lua_pushboolean(L, v->i.low); - break; - case PBC_ENUM: - lua_pushstring(L, v->e.name); - break; - case PBC_BYTES: - case PBC_STRING: - lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); - break; - case PBC_MESSAGE: - lua_pushvalue(L, -3); - lua_pushstring(L, typename); - lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); - lua_call(L, 2 , 1); - break; - case PBC_FIXED64: - // in 64 bit arch, push pointer - lua_pushlightuserdata(L,(void *)(uintptr_t)((uint64_t)v->i.low | (uint64_t)v->i.hi << 32)); - break; - case PBC_FIXED32: - lua_pushlightuserdata(L,(void *)(intptr_t)v->i.low); - break; - case PBC_INT64: { - uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low); - lua_pushnumber(L,(lua_Number)(int64_t)v64); - break; - } - case PBC_UINT: { - uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low); - lua_pushnumber(L,(lua_Number)v64); - break; - } - default: - luaL_error(L, "Unknown type %s", typename); - break; - } -} - -/* - -3: function decode - -2: table key - -1: table id - */ -static void -decode_cb(void *ud, int type, const char * typename, union pbc_value *v, int id, const char *key) { - lua_State *L = ud; - if (type & PBC_REPEATED) { - push_value(L, type & ~PBC_REPEATED, typename, v); - new_array(L, id , key); // func.decode table.key table.id value array - int n = lua_rawlen(L,-1); - lua_insert(L, -2); // func.decode table.key table.id array value - lua_rawseti(L, -2 , n+1); // func.decode table.key table.id array - lua_pop(L,1); - } else { - push_value(L, type, typename, v); - lua_setfield(L, -3 , key); - } -} - -/* - :1 lightuserdata env - :2 function decode_message - :3 table target - :4 string type - :5 string data - :5 lightuserdata pointer - :6 integer len - - table - */ -static int -_decode(lua_State *L) { - struct pbc_env * env = checkuserdata(L,1); - luaL_checktype(L, 2 , LUA_TFUNCTION); - luaL_checktype(L, 3 , LUA_TTABLE); - const char * type = luaL_checkstring(L,4); - struct pbc_slice slice; - if (lua_type(L,5) == LUA_TSTRING) { - size_t len; - slice.buffer = (void *)luaL_checklstring(L,5,&len); - slice.len = (int)len; - } else { - slice.buffer = checkuserdata(L,5); - slice.len = luaL_checkinteger(L,6); - } - lua_pushvalue(L, 2); - lua_pushvalue(L, 3); - lua_newtable(L); - - int n = pbc_decode(env, type, &slice, decode_cb, L); - if (n<0) { - lua_pushboolean(L,0); - } else { - lua_pushboolean(L,1); - } - return 1; -} - -int -luaopen_protobuf_c(lua_State *L) { - luaL_Reg reg[] = { - {"_env_new" , _env_new }, - {"_env_delete" , _env_delete }, - {"_env_register" , _env_register }, - {"_env_type", _env_type }, - {"_rmessage_new" , _rmessage_new }, - {"_rmessage_delete" , _rmessage_delete }, - {"_rmessage_integer" , _rmessage_integer }, - {"_rmessage_int32", _rmessage_int32 }, - {"_rmessage_int64", _rmessage_int64_ia64 }, - {"_rmessage_int52", _rmessage_int52 }, - {"_rmessage_uint52", _rmessage_uint52 }, - {"_rmessage_real" , _rmessage_real }, - {"_rmessage_string" , _rmessage_string }, - {"_rmessage_message" , _rmessage_message }, - {"_rmessage_size" , _rmessage_size }, - {"_wmessage_new", _wmessage_new }, - {"_wmessage_delete", _wmessage_delete }, - {"_wmessage_integer", _wmessage_integer }, - {"_wmessage_real", _wmessage_real }, - {"_wmessage_string", _wmessage_string }, - {"_wmessage_message", _wmessage_message }, - {"_wmessage_int32", _wmessage_int32 }, - {"_wmessage_int64", _wmessage_int64_ia64 }, - {"_wmessage_int52", _wmessage_int52 }, - {"_wmessage_uint52", _wmessage_uint52 }, - {"_wmessage_buffer", _wmessage_buffer }, - {"_wmessage_buffer_string", _wmessage_buffer_string }, - {"_pattern_new", _pattern_new }, - {"_pattern_delete", _pattern_delete }, - {"_pattern_size", _pattern_size }, - {"_pattern_unpack", _pattern_unpack }, - {"_pattern_pack", _pattern_pack }, - {"_last_error", _last_error }, - {"_decode", _decode }, - {NULL,NULL}, - }; - - if (sizeof(void *) != sizeof(uint64_t)) { - luaL_error(L, "Skynet need ia64"); - } - - luaL_checkversion(L); - luaL_newlib(L, reg); - - return 1; -} diff --git a/lua-protobuf/pbc.h b/lua-protobuf/pbc.h deleted file mode 100644 index dbc956c0..00000000 --- a/lua-protobuf/pbc.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef PROTOBUF_C_H -#define PROTOBUF_C_H - -#include -#include - -#define PBC_ARRAY_CAP 64 - -#define PBC_NOEXIST -1 -#define PBC_INT 1 -#define PBC_REAL 2 -#define PBC_BOOL 3 -#define PBC_ENUM 4 -#define PBC_STRING 5 -#define PBC_MESSAGE 6 -#define PBC_FIXED64 7 -#define PBC_FIXED32 8 -#define PBC_BYTES 9 -#define PBC_INT64 10 -#define PBC_UINT 11 -#define PBC_UNKNOWN 12 -#define PBC_REPEATED 128 - -typedef struct _pbc_array { char _data[PBC_ARRAY_CAP]; } pbc_array[1]; - -struct pbc_slice { - void *buffer; - int len; -}; - -struct pbc_pattern; -struct pbc_env; -struct pbc_rmessage; -struct pbc_wmessage; - -struct pbc_env * pbc_new(void); -void pbc_delete(struct pbc_env *); -int pbc_register(struct pbc_env *, struct pbc_slice * slice); -int pbc_type(struct pbc_env *, const char * typename , const char * key , const char ** type); -const char * pbc_error(struct pbc_env *); - -// callback api -union pbc_value { - struct { - uint32_t low; - uint32_t hi; - } i; - double f; - struct pbc_slice s; - struct { - int id; - const char * name; - } e; -}; - -typedef void (*pbc_decoder)(void *ud, int type, const char * typename, union pbc_value *v, int id, const char *key); -int pbc_decode(struct pbc_env * env, const char * typename , struct pbc_slice * slice, pbc_decoder f, void *ud); - -// message api - -struct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * typename , struct pbc_slice * slice); -void pbc_rmessage_delete(struct pbc_rmessage *); - -uint32_t pbc_rmessage_integer(struct pbc_rmessage * , const char *key , int index, uint32_t *hi); -double pbc_rmessage_real(struct pbc_rmessage * , const char *key , int index); -const char * pbc_rmessage_string(struct pbc_rmessage * , const char *key , int index, int *sz); -struct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage *, const char *key, int index); -int pbc_rmessage_size(struct pbc_rmessage *, const char *key); -int pbc_rmessage_next(struct pbc_rmessage *, const char **key); - -struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *typename); -void pbc_wmessage_delete(struct pbc_wmessage *); - -// for negative integer, pass -1 to hi -int pbc_wmessage_integer(struct pbc_wmessage *, const char *key, uint32_t low, uint32_t hi); -int pbc_wmessage_real(struct pbc_wmessage *, const char *key, double v); -int pbc_wmessage_string(struct pbc_wmessage *, const char *key, const char * v, int len); -struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *, const char *key); -void * pbc_wmessage_buffer(struct pbc_wmessage *, struct pbc_slice * slice); - -// array api - -int pbc_array_size(pbc_array); -uint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi); -double pbc_array_real(pbc_array array, int index); -struct pbc_slice * pbc_array_slice(pbc_array array, int index); - -void pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi); -void pbc_array_push_slice(pbc_array array, struct pbc_slice *); -void pbc_array_push_real(pbc_array array, double v); - -struct pbc_pattern * pbc_pattern_new(struct pbc_env * , const char * message, const char *format, ...); -void pbc_pattern_delete(struct pbc_pattern *); - -// return unused bytes , -1 for error -int pbc_pattern_pack(struct pbc_pattern *, void *input, struct pbc_slice * s); - -// <0 for error -int pbc_pattern_unpack(struct pbc_pattern *, struct pbc_slice * s , void * output); - -void pbc_pattern_set_default(struct pbc_pattern * , void *data); -void pbc_pattern_close_arrays(struct pbc_pattern *, void *data); - -#endif diff --git a/lua-protobuf/proto.c b/lua-protobuf/proto.c deleted file mode 100644 index fc8c59bd..00000000 --- a/lua-protobuf/proto.c +++ /dev/null @@ -1,252 +0,0 @@ -#include "pbc.h" -#include "proto.h" -#include "pattern.h" -#include "map.h" -#include "alloc.h" -#include "stringpool.h" -#include "bootstrap.h" - -#include -#include - -const char * -pbc_error(struct pbc_env * p) { - const char *err = p->lasterror; - p->lasterror = ""; - return err; -} - -struct _message * -_pbcP_get_message(struct pbc_env * p , const char *name) { - return _pbcM_sp_query(p->msgs, name); -} - -struct pbc_env * -pbc_new(void) { - struct pbc_env * p = malloc(sizeof(*p)); - p->files = _pbcM_sp_new(0 , NULL); - p->enums = _pbcM_sp_new(0 , NULL); - p->msgs = _pbcM_sp_new(0 , NULL); - p->lasterror = ""; - - _pbcB_init(p); - - return p; -} - -static void -free_enum(void *p) { - struct _enum * e = p; - _pbcM_ip_delete(e->id); - _pbcM_si_delete(e->name); - - free(p); -} - -static void -free_stringpool(void *p) { - _pbcS_delete(p); -} - -static void -free_msg(void *p) { - struct _message * m = p; - if (m->id) - _pbcM_ip_delete(m->id); - free(m->def); - _pbcM_sp_foreach(m->name, free); - _pbcM_sp_delete(m->name); - free(p); -} - -void -pbc_delete(struct pbc_env *p) { - _pbcM_sp_foreach(p->enums, free_enum); - _pbcM_sp_delete(p->enums); - - _pbcM_sp_foreach(p->msgs, free_msg); - _pbcM_sp_delete(p->msgs); - - _pbcM_sp_foreach(p->files, free_stringpool); - _pbcM_sp_delete(p->files); - - free(p); -} - -struct _enum * -_pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) { - void * check = _pbcM_sp_query(p->enums, name); - if (check) - return NULL; - struct _enum * v = malloc(sizeof(*v)); - v->key = name; - v->id = _pbcM_ip_new(table,sz); - v->name = _pbcM_si_new(table,sz); - v->default_v->e.id = table[0].id; - v->default_v->e.name = table[0].pointer; - - _pbcM_sp_insert(p->enums, name , v); - return v; -} - -void -_pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) { - struct _message * m = _pbcM_sp_query(p->msgs, name); - if (m==NULL) { - m = malloc(sizeof(*m)); - m->def = NULL; - m->key = name; - m->id = NULL; - m->name = _pbcM_sp_new(0 , NULL); - m->env = p; - _pbcM_sp_insert(p->msgs, name, m); - } - struct _field * field = malloc(sizeof(*field)); - memcpy(field,f,sizeof(*f)); - _pbcM_sp_insert(m->name, field->name, field); - pbc_var atom; - atom->m.buffer = field; - if (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) { - _pbcA_push(queue, atom); - } -} - -struct _iter { - int count; - struct map_kv * table; -}; - -static void -_count(void *p, void *ud) { - struct _iter *iter = ud; - iter->count ++; -} - -static void -_set_table(void *p, void *ud) { - struct _field * field = p; - struct _iter *iter = ud; - iter->table[iter->count].id = field->id; - iter->table[iter->count].pointer = field; - ++iter->count; -} - -struct _message * -_pbcP_init_message(struct pbc_env * p, const char *name) { - struct _message * m = _pbcM_sp_query(p->msgs, name); - if (m == NULL) { - m = malloc(sizeof(*m)); - m->def = NULL; - m->key = name; - m->id = NULL; - m->name = _pbcM_sp_new(0 , NULL); - m->env = p; - _pbcM_sp_insert(p->msgs, name, m); - - return m; - } - if (m->id) { - // extend message, delete old id map. - _pbcM_ip_delete(m->id); - } - struct _iter iter = { 0, NULL }; - _pbcM_sp_foreach_ud(m->name, _count, &iter); - iter.table = malloc(iter.count * sizeof(struct map_kv)); - iter.count = 0; - _pbcM_sp_foreach_ud(m->name, _set_table, &iter); - - m->id = _pbcM_ip_new(iter.table , iter.count); - - free(iter.table); - - return m; -} - -int -_pbcP_message_default(struct _message * m, const char * name, pbc_var defv) { - struct _field * f= _pbcM_sp_query(m->name, name); - if (f==NULL) { - // invalid key - defv->p[0] = NULL; - defv->p[1] = NULL; - return -1; - } - *defv = *(f->default_v); - return f->type; -} - -int -_pbcP_type(struct _field * field, const char ** type) { - if (field == NULL) { - return 0; - } - int ret = 0; - switch (field->type) { - case PTYPE_DOUBLE: - case PTYPE_FLOAT: - ret = PBC_REAL; - break; - case PTYPE_INT64: - case PTYPE_SINT64: - ret = PBC_INT64; - break; - case PTYPE_INT32: - case PTYPE_SINT32: - ret = PBC_INT; - break; - case PTYPE_UINT32: - case PTYPE_UINT64: - ret = PBC_UINT; - break; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - ret = PBC_FIXED32; - break; - case PTYPE_SFIXED64: - case PTYPE_FIXED64: - ret = PBC_FIXED64; - break; - case PTYPE_BOOL: - ret = PBC_BOOL; - break; - case PTYPE_STRING: - ret = PBC_STRING; - break; - case PTYPE_BYTES: - ret = PBC_BYTES; - break; - case PTYPE_ENUM: - ret = PBC_ENUM; - if (type) { - *type = field->type_name.e->key; - } - break; - case PTYPE_MESSAGE: - ret = PBC_MESSAGE; - if (type) { - *type = field->type_name.m->key; - } - break; - default: - return 0; - } - if (field->label == LABEL_REPEATED || - field->label == LABEL_PACKED) { - ret |= PBC_REPEATED; - } - - return ret; -} - -int -pbc_type(struct pbc_env * p, const char * typename , const char * key , const char ** type) { - struct _message *m = _pbcP_get_message(p, typename); - if (m==NULL) { - return 0; - } - if (key == NULL) { - return PBC_NOEXIST; - } - struct _field * field = _pbcM_sp_query(m->name, key); - return _pbcP_type(field, type); -} diff --git a/lua-protobuf/proto.h b/lua-protobuf/proto.h deleted file mode 100644 index c5b93673..00000000 --- a/lua-protobuf/proto.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef PROTOBUFC_PROTO_H -#define PROTOBUFC_PROTO_H - -#include "pbc.h" -#include "map.h" -#include "array.h" - -#include -#include - -struct map_ip; -struct map_si; -struct map_sp; -struct _message; -struct _enum; - -#define LABEL_OPTIONAL 0 -#define LABEL_REQUIRED 1 -#define LABEL_REPEATED 2 -#define LABEL_PACKED 3 - -struct _field { - int id; - const char *name; - int type; - int label; - pbc_var default_v; - union { - const char * n; - struct _message * m; - struct _enum * e; - } type_name; -}; - -struct _message { - const char * key; - struct map_ip * id; // id -> _field - struct map_sp * name; // string -> _field - struct pbc_rmessage * def; // default message - struct pbc_env * env; -}; - -struct _enum { - const char * key; - struct map_ip * id; - struct map_si * name; - pbc_var default_v; -}; - -struct pbc_env { - struct map_sp * files; // string -> void * - struct map_sp * enums; // string -> _enum - struct map_sp * msgs; // string -> _message - const char * lasterror; -}; - -struct _message * _pbcP_init_message(struct pbc_env * p, const char *name); -void _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue); -struct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz ); -int _pbcP_message_default(struct _message * m, const char * name, pbc_var defv); -struct _message * _pbcP_get_message(struct pbc_env * p, const char *name); -int _pbcP_type(struct _field * field, const char **type); - -#endif diff --git a/lua-protobuf/register.c b/lua-protobuf/register.c deleted file mode 100644 index c0f9f17e..00000000 --- a/lua-protobuf/register.c +++ /dev/null @@ -1,335 +0,0 @@ -#include "pbc.h" -#include "proto.h" -#include "alloc.h" -#include "map.h" -#include "bootstrap.h" -#include "context.h" -#include "stringpool.h" - -#include -#include - -static const char * -_concat_name(struct _stringpool *p , const char *prefix , int prefix_sz , const char *name , int name_sz, int *sz) { - if (prefix_sz == 0) { - if (sz) { - *sz = name_sz; - } - return _pbcS_build(p , name, name_sz); - } - char temp[name_sz + prefix_sz + 2]; - memcpy(temp,prefix,prefix_sz); - temp[prefix_sz] = '.'; - memcpy(temp+prefix_sz+1,name,name_sz); - temp[name_sz + prefix_sz + 1] = '\0'; - if (sz) { - *sz = name_sz + prefix_sz + 1; - } - return _pbcS_build(p , temp, name_sz + prefix_sz + 1); -} - -static void -_register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) { - int field_count = pbc_rmessage_size(enum_type, "value"); - struct map_kv *table = malloc(field_count * sizeof(struct map_kv)); - int i; - for (i=0;itype == PTYPE_STRING || f->type == PTYPE_BYTES) { - f->default_v->s.str = ""; - f->default_v->s.len = 0; - } else { - f->default_v->integer.low = 0; - f->default_v->integer.hi = 0; - } - return; - } - - switch (f->type) { - case PTYPE_DOUBLE: - case PTYPE_FLOAT: - f->default_v->real = strtod(value,NULL); - break; - case PTYPE_STRING: - f->default_v->s.str = _pbcS_build(pool, value , sz); - f->default_v->s.len = sz; - break; - case PTYPE_ENUM: - // enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one() - f->default_v->s.str = value; - f->default_v->s.len = sz; - break; - case PTYPE_BOOL: - if (strcmp(value,"true") == 0) { - f->default_v->integer.low = 1; - } else { - f->default_v->integer.low = 0; - } - f->default_v->integer.hi = 0; - break; - case PTYPE_UINT64: - case PTYPE_INT64: - case PTYPE_SFIXED64: - case PTYPE_SINT64: { - long long v = strtoll(value, NULL, 10); - f->default_v->integer.low = (long) v; - f->default_v->integer.hi = (long)(v >> 32); - break; - } - case PTYPE_INT32: - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - case PTYPE_SINT32: - f->default_v->integer.low = strtol(value, NULL, 10); - if (f->default_v->integer.low < 0) { - f->default_v->integer.hi = -1; - } else { - f->default_v->integer.hi = 0; - } - break; - case PTYPE_UINT32: - f->default_v->integer.low = strtoul(value, NULL, 10); - f->default_v->integer.hi = 0; - break; - case PTYPE_BYTES: - case PTYPE_MESSAGE: - // bytes and message types have no default value - f->default_v->m.buffer = 0; - f->default_v->m.len = 0; - break; - default: - f->default_v->integer.low = 0; - f->default_v->integer.hi = 0; - break; - } -} - -static void -_register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) { - f->id = pbc_rmessage_integer(field, "number", 0 , 0); - f->type = pbc_rmessage_integer(field, "type", 0 , 0); // enum - f->label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0 - if (pbc_rmessage_size(field , "options") > 0) { - struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0); - int packed = pbc_rmessage_integer(options , "packed" , 0 , NULL); - if (packed) { - f->label = LABEL_PACKED; - } - } - f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1; // abandon prefix '.' - int vsz; - const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz); - _set_default(pool , f , f->type, default_value , vsz); -} - -static void -_register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) { - int extension_count = pbc_rmessage_size(msg , "extension"); - if (extension_count <= 0) - return; - int i; - - const char * last = NULL; - - for (i=0;ifiles, filename)) { - return CHECK_FILE_EXIST; - } - int sz = pbc_rmessage_size(file, "dependency"); - int i; - for (i=0;ifiles, dname) == NULL) { - return CHECK_FILE_DEPENDENCY; - } - } - - *fname = filename; - - return CHECK_FILE_OK; -} - -static int -_register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) { - int r = 0; - int i; - for (i=0;ifiles , filename, pool); - _register(p,files[i],pool); - files[i] = NULL; - } - break; - } - } - return r; -} - -int -pbc_register(struct pbc_env * p, struct pbc_slice *slice) { - struct pbc_rmessage * message = pbc_rmessage_new(p, "google.protobuf.FileDescriptorSet", slice); - if (message == NULL) { - p->lasterror = "register open google.protobuf.FileDescriptorSet fail"; - return 1; - } - int n = pbc_rmessage_size(message, "file"); - struct pbc_rmessage * files[n]; - int i; - if (n == 0) { - p->lasterror = "register empty"; - goto _error; - } - for (i=0;ilasterror = "register open fail"; - goto _error; - } - } - - int r = n; - do { - int rr = _register_no_dependency(p,files , n); - if (rr == r) { - p->lasterror = "register dependency error"; - goto _error; - } - r = rr; - } while (r>0); - - pbc_rmessage_delete(message); - return 0; -_error: - pbc_rmessage_delete(message); - return 1; -} diff --git a/lua-protobuf/rmessage.c b/lua-protobuf/rmessage.c deleted file mode 100644 index a93146da..00000000 --- a/lua-protobuf/rmessage.c +++ /dev/null @@ -1,455 +0,0 @@ -#include "pbc.h" -#include "alloc.h" -#include "map.h" -#include "context.h" -#include "proto.h" -#include "pattern.h" -#include "varint.h" - -#include -#include - -struct pbc_rmessage { - struct _message * msg; - struct map_sp * index; // key -> struct value * - struct heap * heap; -}; - -union _var { - pbc_var var; - pbc_array array; - struct pbc_rmessage message; -} ; - -struct value { - struct _field * type; - union _var v; -}; - -int -pbc_rmessage_next(struct pbc_rmessage *m, const char **key) { - struct value * v = _pbcM_sp_next(m->index, key); - if (*key == NULL) { - return 0; - } - return _pbcP_type(v->type, NULL); -} - -#define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var)) -#define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array)) -#define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage)) - -static struct value * -read_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) { - const char * temp = (const char *) (buffer + a->v.s.start); - int len = a->v.s.end - a->v.s.start; - - if (len > 0 && temp[len-1] == '\0') { - struct value * v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->s.str = temp; - v->v.var->s.len = len; - return v; - } else { - struct value * v = _pbcH_alloc(h, SIZE_VAR + len + 1); - memcpy(((char *)v) + SIZE_VAR , temp, len); - *(((char *)v) + SIZE_VAR + len) = '\0'; - v->v.var->s.str = ((char *)v) + SIZE_VAR; - v->v.var->s.len = len; - return v; - } -} - -static void -read_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) { - const char * temp = (const char *) (buffer + a->v.s.start); - int len = a->v.s.end - a->v.s.start; - if (len == 0) { - var->s.str = ""; - var->s.len = 0; - } - else if (temp[len-1] == '\0') { - var->s.str = temp; - var->s.len = len; - } else { - char * temp2 = _pbcH_alloc(h, len + 1); - memcpy(temp2, temp, len); - temp2[len]='\0'; - var->s.str = temp2; - var->s.len = -len; - } -} - -static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size, struct heap *h); - -static struct value * -read_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) { - struct value * v; - - switch (f->type) { - case PTYPE_DOUBLE: - CHECK_BIT64(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->real = read_double(a); - break; - case PTYPE_FLOAT: - CHECK_BIT32(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->real = (double) read_float(a); - break; - case PTYPE_ENUM: - CHECK_VARINT(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->e.id = a->v.i.low; - v->v.var->e.name = _pbcM_ip_query(f->type_name.e->id , a->v.i.low); - break; - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_BOOL: - CHECK_VARINT(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->integer = a->v.i; - break; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - CHECK_BIT32(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->integer = a->v.i; - break; - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - CHECK_BIT64(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->integer = a->v.i; - break; - case PTYPE_SINT32: - CHECK_VARINT(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->integer = a->v.i; - _pbcV_dezigzag32(&(v->v.var->integer)); - break; - case PTYPE_SINT64: - CHECK_VARINT(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->integer = a->v.i; - _pbcV_dezigzag64(&(v->v.var->integer)); - break; - case PTYPE_STRING: - CHECK_LEND(a,NULL); - v = read_string(h,a,f,buffer); - break; - case PTYPE_BYTES: - CHECK_LEND(a,NULL); - v = _pbcH_alloc(h, SIZE_VAR); - v->v.var->s.str = (const char *)(buffer + a->v.s.start); - v->v.var->s.len = a->v.s.end - a->v.s.start; - break; - case PTYPE_MESSAGE: - CHECK_LEND(a,NULL); - v = _pbcH_alloc(h, SIZE_MESSAGE); - _pbc_rmessage_new(&(v->v.message), f->type_name.m , - buffer + a->v.s.start , - a->v.s.end - a->v.s.start,h); - break; - default: - return NULL; - } - v->type = f; - return v; -} - -static void -push_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) { - int n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start, - f->type , array); - if (n<=0) { - // todo : error - type->env->lasterror = "Unpack packed field error"; - return; - } - if (f->type == PTYPE_ENUM) { - int i; - for (i=0;iinteger.low; - v->e.id = id; - v->e.name = _pbcM_ip_query(f->type_name.e->id , id); - } - } -} - -static void -push_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) { - pbc_var v; - - switch (f->type) { - case PTYPE_DOUBLE: - v->real = read_double(a); - break; - case PTYPE_FLOAT: - v->real = (double) read_float(a); - break; - case PTYPE_ENUM: - v->e.id = a->v.i.low; - v->e.name = _pbcM_ip_query(f->type_name.e->id , a->v.i.low); - break; - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - case PTYPE_UINT32: - case PTYPE_FIXED32: - case PTYPE_FIXED64: - case PTYPE_SFIXED32: - case PTYPE_SFIXED64: - case PTYPE_BOOL: - v->integer = a->v.i; - break; - case PTYPE_SINT32: - v->integer = a->v.i; - _pbcV_dezigzag32(&(v->integer)); - break; - case PTYPE_SINT64: - v->integer = a->v.i; - _pbcV_dezigzag64(&(v->integer)); - break; - case PTYPE_STRING: - CHECK_LEND(a, ); - read_string_var(h,v,a,f,buffer); - break; - case PTYPE_BYTES: - CHECK_LEND(a, ); - v->s.str = (const char *)(buffer + a->v.s.start); - v->s.len = a->v.s.end - a->v.s.start; - break; - case PTYPE_MESSAGE: { - CHECK_LEND(a, ); - struct pbc_rmessage message; - _pbc_rmessage_new(&message, f->type_name.m , - buffer + a->v.s.start , - a->v.s.end - a->v.s.start,h); - if (message.msg == NULL) { - return; - } - v->p[0] = message.msg; - v->p[1] = message.index; - break; - } - default: - return; - } - - _pbcA_push(array,v); -} - -static void -_pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) { - if (size == 0) { - ret->msg = type; - ret->index = _pbcM_sp_new(0 , h); - ret->heap = h; - return; - } - pbc_ctx _ctx; - int count = _pbcC_open(_ctx,buffer,size); - if (count <= 0) { - type->env->lasterror = "rmessage decode context error"; - memset(ret , 0, sizeof(*ret)); - return; - } - struct context * ctx = (struct context *)_ctx; - - ret->msg = type; - ret->index = _pbcM_sp_new(count, h); - ret->heap = h; - - int i; - - for (i=0;inumber;i++) { - int id = ctx->a[i].wire_id >> 3; - struct _field * f = _pbcM_ip_query(type->id , id); - if (f) { - if (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) { - struct value * v; - void ** vv = _pbcM_sp_query_insert(ret->index, f->name); - if (*vv == NULL) { - v = _pbcH_alloc(h, SIZE_ARRAY); - v->type = f; - _pbcA_open_heap(v->v.array,ret->heap); - *vv = v; - } else { - v= *vv; - } - if (f->label == LABEL_PACKED) { - push_value_packed(type, v->v.array , f , &(ctx->a[i]), buffer); - if (pbc_array_size(v->v.array) == 0) { - type->env->lasterror = "rmessage decode packed data error"; - *vv = NULL; - } - } else { - push_value_array(h,v->v.array , f, &(ctx->a[i]), buffer); - if (pbc_array_size(v->v.array) == 0) { - type->env->lasterror = "rmessage decode repeated data error"; - *vv = NULL; - } - } - } else { - struct value * v = read_value(h, f, &(ctx->a[i]), buffer); - if (v) { - _pbcM_sp_insert(ret->index, f->name, v); - } else { - type->env->lasterror = "rmessage decode data error"; - } - } - } - } - - _pbcC_close(_ctx); -} - -struct pbc_rmessage * -pbc_rmessage_new(struct pbc_env * env, const char * typename , struct pbc_slice * slice) { - struct _message * msg = _pbcP_get_message(env, typename); - if (msg == NULL) { - env->lasterror = "Proto not found"; - return NULL; - } - struct pbc_rmessage temp; - struct heap * h = _pbcH_new(slice->len); - _pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h); - if (temp.msg == NULL) { - _pbcH_delete(h); - return NULL; - } - - struct pbc_rmessage *m = _pbcH_alloc(temp.heap, sizeof(*m)); - *m = temp; - return m; -} - -void -pbc_rmessage_delete(struct pbc_rmessage * m) { - if (m) { - _pbcH_delete(m->heap); - } -} - -const char * -pbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) { - struct value * v = _pbcM_sp_query(m->index,key); - int type = 0; - pbc_var var; - if (v == NULL) { - type = _pbcP_message_default(m->msg, key, var); - } else { - if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { - _pbcA_index(v->v.array, index, var); - } else { - var[0] = v->v.var[0]; - } - type = v->type->type; - } - - if (type == PTYPE_ENUM) { - if (sz) { - *sz = strlen(var->e.name); - } - return var->e.name; - } - - if (sz) { - int len = var->s.len; - if (len<0) { - len = - len; - } - *sz = len; - } - return var->s.str; -} - -uint32_t -pbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) { - struct value * v = _pbcM_sp_query(m->index,key); - pbc_var var; - int type = 0; - if (v == NULL) { - type = _pbcP_message_default(m->msg, key, var); - } else { - if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { - _pbcA_index(v->v.array, index, var); - } else { - var[0] = v->v.var[0]; - } - type = v->type->type; - } - - if (type == PTYPE_ENUM) { - if (hi) { - *hi = 0; - } - return var->e.id; - } - - if (hi) { - *hi = var->integer.hi; - } - return var->integer.low; -} - -double -pbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) { - struct value * v = _pbcM_sp_query(m->index,key); - pbc_var var; - if (v == NULL) { - _pbcP_message_default(m->msg, key, var); - } else { - if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { - _pbcA_index(v->v.array, index, var); - } else { - return v->v.var->real; - } - } - return var->real; -} - - -struct pbc_rmessage * -pbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) { - struct value * v = _pbcM_sp_query(rm->index,key); - if (v == NULL) { - struct _field * f = _pbcM_sp_query(rm->msg->name, key); - if (f == NULL) { - rm->msg->env->lasterror = "Invalid key for sub-message"; - // invalid key - return NULL; - } - struct _message * m = f->type_name.m; - - if (m->def == NULL) { - // m->def will be free at the end (pbc_delete). - m->def = malloc(sizeof(struct pbc_rmessage)); - m->def->msg = m; - m->def->index = NULL; - } - return m->def; - } else { - if (v->type->label == LABEL_REPEATED) { - return _pbcA_index_p(v->v.array,index); - } else { - return &(v->v.message); - } - } -} - -int -pbc_rmessage_size(struct pbc_rmessage *m, const char *key) { - struct value * v = _pbcM_sp_query(m->index,key); - if (v == NULL) { - return 0; - } - if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { - return pbc_array_size(v->v.array); - } else { - return 1; - } -} \ No newline at end of file diff --git a/lua-protobuf/stringpool.c b/lua-protobuf/stringpool.c deleted file mode 100644 index 9e644585..00000000 --- a/lua-protobuf/stringpool.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "alloc.h" - -#include -#include - -#define PAGE_SIZE 256 - -struct _stringpool { - char * buffer; - size_t len; - struct _stringpool *next; -}; - -struct _stringpool * -_pbcS_new(void) { - struct _stringpool * ret = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); - ret->buffer = (char *)(ret + 1); - ret->len = 0; - ret->next = NULL; - return ret; -} - -void -_pbcS_delete(struct _stringpool *pool) { - while(pool) { - struct _stringpool *next = pool->next; - free(pool); - pool = next; - } -} - -const char * -_pbcS_build(struct _stringpool *pool, const char * str , int sz) { - size_t s = sz + 1; - if (s < PAGE_SIZE - pool->len) { - char * ret = pool->buffer + pool->len; - memcpy(pool->buffer + pool->len, str, s); - pool->len += s; - return ret; - } - if (s > PAGE_SIZE) { - struct _stringpool * next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + s); - next->buffer = (char *)(next + 1); - memcpy(next->buffer, str, s); - next->len = s; - next->next = pool->next; - pool->next = next; - return next->buffer; - } - struct _stringpool *next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); - next->buffer = pool->buffer; - next->next = pool->next; - next->len = pool->len; - - pool->next = next; - pool->buffer = (char *)(next + 1); - memcpy(pool->buffer, str, s); - pool->len = s; - return pool->buffer; -} diff --git a/lua-protobuf/stringpool.h b/lua-protobuf/stringpool.h deleted file mode 100644 index 394423da..00000000 --- a/lua-protobuf/stringpool.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef PROTOBUF_C_STRINGPOOL_H -#define PROTOBUF_C_STRINGPOOL_H - -struct _stringpool; - -struct _stringpool * _pbcS_new(void); -void _pbcS_delete(struct _stringpool *pool); -const char * _pbcS_build(struct _stringpool *pool, const char * str , int sz); - -#endif diff --git a/lua-protobuf/test.lua b/lua-protobuf/test.lua deleted file mode 100644 index 3855e0e6..00000000 --- a/lua-protobuf/test.lua +++ /dev/null @@ -1,30 +0,0 @@ -require "protobuf" - -addr = io.open("addressbook.pb","rb") -buffer = addr:read "*a" -addr:close() - -protobuf.register(buffer) - -addressbook = { - name = "Alice", - id = 12345, - phone = { - { number = "1301234567" }, - { number = "87654321", type = "WORK" }, - } -} - -code = protobuf.encode("tutorial.Person", addressbook) - -decode = protobuf.decode("tutorial.Person" , code) - -print(decode.name) -print(decode.id) -for _,v in ipairs(decode.phone) do - print("\t"..v.number, v.type) -end - -phonebuf = protobuf.pack("tutorial.Person.PhoneNumber number","87654321") -buffer = protobuf.pack("tutorial.Person name id phone", "Alice", 123, { phonebuf }) -print(protobuf.unpack("tutorial.Person name id phone", buffer)) diff --git a/lua-protobuf/varint.c b/lua-protobuf/varint.c deleted file mode 100644 index b80a7172..00000000 --- a/lua-protobuf/varint.c +++ /dev/null @@ -1,110 +0,0 @@ -#include "varint.h" - -#include "pbc.h" - -#include - -inline int -_pbcV_encode32(uint32_t number, uint8_t buffer[10]) -{ - if (number < 0x80) { - buffer[0] = (uint8_t) number ; - return 1; - } - buffer[0] = (uint8_t) (number | 0x80 ); - if (number < 0x4000) { - buffer[1] = (uint8_t) (number >> 7 ); - return 2; - } - buffer[1] = (uint8_t) ((number >> 7) | 0x80 ); - if (number < 0x200000) { - buffer[2] = (uint8_t) (number >> 14); - return 3; - } - buffer[2] = (uint8_t) ((number >> 14) | 0x80 ); - if (number < 0x10000000) { - buffer[3] = (uint8_t) (number >> 21); - return 4; - } - buffer[3] = (uint8_t) ((number >> 21) | 0x80 ); - buffer[4] = (uint8_t) (number >> 28); - return 5; -} - -int -_pbcV_encode(uint64_t number, uint8_t buffer[10]) -{ - if ((number & 0xffffffff) == number) { - return _pbcV_encode32((uint32_t)number , buffer); - } - int i = 0; - do { - buffer[i] = (uint8_t)(number | 0x80); - number >>= 7; - ++i; - } while (number >= 0x80); - buffer[i] = (uint8_t)number; - return i+1; -} - -int -_pbcV_decode(uint8_t buffer[10], struct longlong *result) { - if (!(buffer[0] & 0x80)) { - result->low = buffer[0]; - result->hi = 0; - return 1; - } - uint32_t r = buffer[0] & 0x7f; - int i; - for (i=1;i<4;i++) { - r |= ((buffer[i]&0x7f) << (7*i)); - if (!(buffer[i] & 0x80)) { - result->low = r; - result->hi = 0; - return i+1; - } - } - uint64_t lr = 0; - for (i=4;i<10;i++) { - lr |= ((buffer[i] & 0x7f) << (7*(i-4))); - if (!(buffer[i] & 0x80)) { - result->hi = (uint32_t)(lr >> 4); - result->low = r | (((uint32_t)lr & 0xf) << 28); - return i+1; - } - } - - result->low = 0; - result->hi = 0; - return 10; -} - -int -_pbcV_zigzag32(int32_t n, uint8_t buffer[10]) -{ - n = (n << 1) ^ (n >> 31); - return _pbcV_encode32(n,buffer); -} - -int -_pbcV_zigzag(int64_t n, uint8_t buffer[10]) -{ - n = (n << 1) ^ (n >> 63); - return _pbcV_encode(n,buffer); -} - -void -_pbcV_dezigzag64(struct longlong *r) -{ - uint32_t low = r->low; - r->low = ((low >> 1) | ((r->hi & 1) << 31)) ^ - (low & 1); - r->hi = (r->hi >> 1) ^ - (low & 1); -} - -void -_pbcV_dezigzag32(struct longlong *r) -{ - uint32_t low = r->low; - r->low = (low >> 1) ^ - (low & 1); - r->hi = -(low >> 31); -} diff --git a/lua-protobuf/varint.h b/lua-protobuf/varint.h deleted file mode 100644 index 000882ec..00000000 --- a/lua-protobuf/varint.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef PROTOBUF_C_VARINT_H -#define PROTOBUF_C_VARINT_H - -#include - -struct longlong { - uint32_t low; - uint32_t hi; -}; - -int _pbcV_encode32(uint32_t number, uint8_t buffer[10]); -int _pbcV_encode(uint64_t number, uint8_t buffer[10]); -int _pbcV_zigzag32(int32_t number, uint8_t buffer[10]); -int _pbcV_zigzag(int64_t number, uint8_t buffer[10]); - -int _pbcV_decode(uint8_t buffer[10], struct longlong *result); -void _pbcV_dezigzag64(struct longlong *r); -void _pbcV_dezigzag32(struct longlong *r); - -#endif diff --git a/lua-protobuf/wmessage.c b/lua-protobuf/wmessage.c deleted file mode 100644 index bf81f69f..00000000 --- a/lua-protobuf/wmessage.c +++ /dev/null @@ -1,509 +0,0 @@ -#include "pbc.h" -#include "context.h" -#include "alloc.h" -#include "varint.h" -#include "map.h" -#include "proto.h" - -#include -#include -#include -#include - -#define WMESSAGE_SIZE 64 - -struct pbc_wmessage { - struct _message *type; - uint8_t * buffer; - uint8_t * ptr; - uint8_t * endptr; - pbc_array sub; - struct map_sp *packed; - struct heap * heap; -}; - -struct _packed { - int id; - int ptype; - pbc_array data; -}; - -static struct pbc_wmessage * -_wmessage_new(struct heap *h, struct _message *msg) { - struct pbc_wmessage * m = _pbcH_alloc(h, sizeof(*m)); - m->type = msg; - m->buffer = _pbcH_alloc(h, WMESSAGE_SIZE); - m->ptr = m->buffer; - m->endptr = m->buffer + WMESSAGE_SIZE; - _pbcA_open_heap(m->sub, h); - m->packed = NULL; - m->heap = h; - - return m; -} - -struct pbc_wmessage * -pbc_wmessage_new(struct pbc_env * env, const char *typename) { - struct _message * msg = _pbcP_get_message(env, typename); - if (msg == NULL) - return NULL; - struct heap *h = _pbcH_new(0); - return _wmessage_new(h, msg); -} - -void -pbc_wmessage_delete(struct pbc_wmessage *m) { - if (m) { - _pbcH_delete(m->heap); - } -} - -static void -_expand(struct pbc_wmessage *m, int sz) { - if (m->ptr + sz > m->endptr) { - int cap = m->endptr - m->buffer; - sz = m->ptr + sz - m->buffer; - do { - cap = cap * 2; - } while ( sz > cap ) ; - int old_size = m->ptr - m->buffer; - uint8_t * buffer = _pbcH_alloc(m->heap, cap); - memcpy(buffer, m->buffer, old_size); - m->ptr = buffer + (m->ptr - m->buffer); - m->endptr = buffer + cap; - m->buffer = buffer; - } -} - -static struct _packed * -_get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) { - if (m->packed == NULL) { - m->packed = _pbcM_sp_new(4, m->heap); - } - void ** v = _pbcM_sp_query_insert(m->packed , key); - if (*v == NULL) { - *v = _pbcH_alloc(m->heap, sizeof(struct _packed)); - struct _packed *p = *v; - p->id = f->id; - p->ptype = f->type; - _pbcA_open_heap(p->data, m->heap); - return p; - } - return *v; -} - -static void -_packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) { - struct _packed * packed = _get_packed(m,f,key); - pbc_var var; - var->integer.low = low; - var->integer.hi = hi; - _pbcA_push(packed->data , var); -} - -static void -_packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) { - struct _packed * packed = _get_packed(m,f,key); - pbc_var var; - var->real = v; - _pbcA_push(packed->data , var); -} - -static inline void -int64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) { - buffer[0] = (uint8_t)(low & 0xff); - buffer[1] = (uint8_t)(low >> 8 & 0xff); - buffer[2] = (uint8_t)(low >> 16 & 0xff); - buffer[3] = (uint8_t)(low >> 24 & 0xff); - buffer[4] = (uint8_t)(hi & 0xff); - buffer[5] = (uint8_t)(hi >> 8 & 0xff); - buffer[6] = (uint8_t)(hi >> 16 & 0xff); - buffer[7] = (uint8_t)(hi >> 24 & 0xff); -} - -static inline void -int32_encode(uint32_t low, uint8_t * buffer) { - buffer[0] = (uint8_t)(low & 0xff); - buffer[1] = (uint8_t)(low >> 8 & 0xff); - buffer[2] = (uint8_t)(low >> 16 & 0xff); - buffer[3] = (uint8_t)(low >> 24 & 0xff); -} - -int -pbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) { - struct _field * f = _pbcM_sp_query(m->type->name,key); - if (f==NULL) { - // todo : error - m->type->env->lasterror = "wmessage_interger query key error"; - return -1; - } - if (f->label == LABEL_PACKED) { - _packed_integer(m , f, key , low, hi); - return 0; - } - if (f->label == LABEL_OPTIONAL) { - if (f->type == PTYPE_ENUM) { - if (low == f->default_v->e.id) - return 0; - } else { - if (low == f->default_v->integer.low && - hi == f->default_v->integer.hi) { - return 0; - } - } - } - int id = f->id << 3; - - _expand(m,20); - switch (f->type) { - case PTYPE_INT64: - case PTYPE_UINT64: - case PTYPE_INT32: - id |= WT_VARINT; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr); - break; - case PTYPE_UINT32: - case PTYPE_ENUM: - case PTYPE_BOOL: - id |= WT_VARINT; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_encode32(low, m->ptr); - break; - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - id |= WT_BIT64; - m->ptr += _pbcV_encode32(id, m->ptr); - int64_encode(low,hi,m->ptr); - m->ptr += 8; - break; - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - id |= WT_BIT32; - m->ptr += _pbcV_encode32(id, m->ptr); - int32_encode(low,m->ptr); - m->ptr += 4; - break; - case PTYPE_SINT32: - id |= WT_VARINT; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_zigzag32(low, m->ptr); - break; - case PTYPE_SINT64: - id |= WT_VARINT; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr); - break; - } - - return 0; -} - -int -pbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) { - struct _field * f = _pbcM_sp_query(m->type->name,key); - if (f == NULL) { - // todo : error - m->type->env->lasterror = "wmessage_real query key error"; - return -1; - } - if (f->label == LABEL_PACKED) { - _packed_real(m , f, key , v); - return 0; - } - - if (f->label == LABEL_OPTIONAL) { - if (v == f->default_v->real) - return 0; - } - int id = f->id << 3; - _expand(m,18); - switch (f->type) { - case PTYPE_FLOAT: { - id |= WT_BIT32; - m->ptr += _pbcV_encode32(id, m->ptr); - float_encode(v , m->ptr); - m->ptr += 4; - break; - } - case PTYPE_DOUBLE: - id |= WT_BIT64; - m->ptr += _pbcV_encode32(id, m->ptr); - double_encode(v , m->ptr); - m->ptr += 8; - break; - } - - return 0; -} - -int -pbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) { - struct _field * f = _pbcM_sp_query(m->type->name,key); - if (f == NULL) { - // todo : error - m->type->env->lasterror = "wmessage_string query key error"; - return -1; - } - - bool varlen = false; - - if (len <=0) { - varlen = true; - // -1 for add '\0' - len = strlen(v) - len; - } - if (f->label == LABEL_PACKED) { - if (f->type == PTYPE_ENUM) { - char temp[len+1]; - if (!varlen || v[len] != '\0') { - memcpy(temp,v,len); - temp[len]='\0'; - v = temp; - } - int enum_id = 0; - int err = _pbcM_si_query(f->type_name.e->name, v , &enum_id); - if (err) { - // todo : error , invalid enum - m->type->env->lasterror = "wmessage_string packed invalid enum"; - return -1; - } - _packed_integer(m , f, key , enum_id , 0); - } - return 0; - } - - if (f->label == LABEL_OPTIONAL) { - if (f->type == PTYPE_ENUM) { - if (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\0') { - return 0; - } - } else if (f->type == PTYPE_STRING) { - if (len == f->default_v->s.len && - strcmp(v, f->default_v->s.str) == 0) { - return 0; - } - } - } - int id = f->id << 3; - _expand(m,20); - switch (f->type) { - case PTYPE_ENUM : { - char temp[len+1]; - if (!varlen || v[len] != '\0') { - memcpy(temp,v,len); - temp[len]='\0'; - v = temp; - } - int enum_id = 0; - int err = _pbcM_si_query(f->type_name.e->name, v, &enum_id); - if (err) { - // todo : error , enum invalid - m->type->env->lasterror = "wmessage_string invalid enum"; - return -1; - } - id |= WT_VARINT; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_encode32(enum_id, m->ptr); - break; - } - case PTYPE_STRING: - case PTYPE_BYTES: - id |= WT_LEND; - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_encode32(len, m->ptr); - _expand(m,len); - memcpy(m->ptr , v , len); - m->ptr += len; - break; - } - - return 0; -} - -struct pbc_wmessage * -pbc_wmessage_message(struct pbc_wmessage *m, const char *key) { - struct _field * f = _pbcM_sp_query(m->type->name,key); - if (f == NULL) { - // todo : error - m->type->env->lasterror = "wmessage_message query key error"; - return NULL; - } - pbc_var var; - var->p[0] = _wmessage_new(m->heap, f->type_name.m); - var->p[1] = f; - _pbcA_push(m->sub , var); - return var->p[0]; -} - -static void -_pack_packed_64(struct _packed *p,struct pbc_wmessage *m) { - int n = pbc_array_size(p->data); - int len = n * 8; - int i; - pbc_var var; - _expand(m,10 + len); - m->ptr += _pbcV_encode32(len, m->ptr); - switch (p->ptype) { - case PTYPE_DOUBLE: - for (i=0;idata, i, var); - double_encode(var->real , m->ptr + i * 8); - } - break; - default: - for (i=0;idata, i, var); - int64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8); - } - break; - } - m->ptr += len; -} - -static void -_pack_packed_32(struct _packed *p,struct pbc_wmessage *m) { - int n = pbc_array_size(p->data); - int len = n * 4; - int i; - pbc_var var; - _expand(m,10 + len); - m->ptr += _pbcV_encode32(len, m->ptr); - switch (p->ptype) { - case PTYPE_FLOAT: - for (i=0;idata, i, var); - float_encode(var->real , m->ptr + i * 8); - } - break; - default: - for (i=0;idata, i, var); - int32_encode(var->integer.low , m->ptr + i * 8); - } - break; - } - m->ptr += len; -} - -static void -_pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) { - int n = pbc_array_size(p->data); - int offset = m->ptr - m->buffer; - int len = n * 2; - if (p->ptype == PTYPE_BOOL) { - len = n; - } - int i; - pbc_var var; - _expand(m,10 + len); - int len_len = _pbcV_encode32(len, m->ptr); - m->ptr += len_len; - - switch (p->ptype) { - case PTYPE_INT64: - case PTYPE_UINT64: - for (i=0;idata, i, var); - _expand(m,10); - m->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); - } - break; - case PTYPE_INT32: - case PTYPE_BOOL: - case PTYPE_UINT32: - case PTYPE_ENUM: - for (i=0;idata, i, var); - _expand(m,10); - m->ptr += _pbcV_encode32(var->integer.low , m->ptr); - } - break; - case PTYPE_SINT32: - for (i=0;idata, i, var); - _expand(m,10); - m->ptr += _pbcV_zigzag32(var->integer.low, m->ptr); - } - break; - case PTYPE_SINT64: - for (i=0;idata, i, var); - _expand(m,10); - m->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); - } - break; - default: - // error - memset(m->ptr , 0 , n); - m->ptr += n; - m->type->env->lasterror = "wmessage type error when pack packed"; - break; - } - int end_offset = m->ptr - m->buffer; - int end_len = end_offset - (offset + len_len); - if (end_len != len) { - uint8_t temp[10]; - int end_len_len = _pbcV_encode32(end_len, temp); - if (end_len_len != len_len) { - _expand(m, end_len_len); - memmove(m->buffer + offset + end_len_len , - m->buffer + offset + len_len , - end_len); - } - memcpy(m->buffer + offset , temp, end_len_len); - } -} - -static void -_pack_packed(void *p, void *ud) { - struct _packed *packed = p; - struct pbc_wmessage * m = ud; - int id = packed->id << 3 | WT_LEND; - _expand(m,10); - m->ptr += _pbcV_encode32(id, m->ptr); - switch(packed->ptype) { - case PTYPE_DOUBLE: - case PTYPE_FIXED64: - case PTYPE_SFIXED64: - _pack_packed_64(packed,m); - break; - case PTYPE_FLOAT: - case PTYPE_FIXED32: - case PTYPE_SFIXED32: - _pack_packed_32(packed,m); - break; - default: - _pack_packed_varint(packed,m); - break; - } -} - -void * -pbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) { - if (m->packed) { - _pbcM_sp_foreach_ud(m->packed , _pack_packed, m); - } - int i; - int n = pbc_array_size(m->sub); - for (i=0;isub, i , var); - struct pbc_slice s; - pbc_wmessage_buffer(var->p[0] , &s); - if (s.buffer) { - struct _field * f = var->p[1]; - int id = f->id << 3 | WT_LEND; - _expand(m,20+s.len); - m->ptr += _pbcV_encode32(id, m->ptr); - m->ptr += _pbcV_encode32(s.len, m->ptr); - memcpy(m->ptr, s.buffer, s.len); - m->ptr += s.len; - } - } - slice->buffer = m->buffer; - slice->len = m->ptr - m->buffer; - - return m->buffer; -} - diff --git a/lualib/protobuf.lua b/lualib/protobuf.lua deleted file mode 100644 index cb741b60..00000000 --- a/lualib/protobuf.lua +++ /dev/null @@ -1,592 +0,0 @@ -local c = require "protobuf.c" -local setmetatable = setmetatable -local type = type -local table = table -local assert = assert -local pairs = pairs -local ipairs = ipairs -local string = string -local print = print -local io = io -local tinsert = table.insert -local rawget = rawget - -module "protobuf" - -local _pattern_cache = {} - -local function clear_pat() - for _,v in pairs(_pattern_cache) do - c._pattern_delete(v.CObj) - end -end - -local P = c._env_new() -setmetatable(_M , { - __gc = function(t) - clear_pat() - c._env_delete(P) - end }) - -function lasterror() - return c._last_error(P) -end - -local decode_type_cache = {} -local _R_meta = {} - -function _R_meta:__index(key) - local v = decode_type_cache[self._CType][key](self, key) - self[key] = v - return v -end - -local function link_parent(self, parent) - local link = rawget(parent, _Children) - if link == nil then - link = {} - rawset(parent, "_Children" , link) - end - tinsert(link, self) -end - -local function remove_cobj(self) - self._CObj = nil - setmetatable(self, nil) - local children = self._Children - if children then - for _,v in ipairs(children) do - remove_cobj(v) - end - end -end - -local function delete_all(self) - c._rmessage_delete(self._CObj) - remove_cobj(self) -end - -local _reader = {} - -function _reader:int(key) - return c._rmessage_integer(self._CObj , key , 0) -end - -function _reader:real(key) - return c._rmessage_real(self._CObj , key , 0) -end - -function _reader:string(key) - return c._rmessage_string(self._CObj , key , 0) -end - -function _reader:bool(key) - return c._rmessage_integer(self._CObj , key , 0) ~= 0 -end - -function _reader:message(key, message_type) - local rmessage = c._rmessage_message(self._CObj , key , 0) - if rmessage then - local v = { - _CObj = rmessage, - _CType = message_type, - _Parent = self, - } - return setmetatable( v , _R_meta ) - end -end - -function _reader:int32(key) - return c._rmessage_int32(self._CObj , key , 0) -end - -function _reader:int64(key) - return c._rmessage_int64(self._CObj , key , 0) -end - -function _reader:int52(key) - return c._rmessage_int52(self._CObj , key , 0) -end - -function _reader:uint52(key) - return c._rmessage_uint52(self._CObj , key , 0) -end - -function _reader:int_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_integer(cobj , key , i)) - end - return ret -end - -function _reader:real_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_real(cobj , key , i)) - end - return ret -end - -function _reader:string_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_string(cobj , key , i)) - end - return ret -end - -function _reader:bool_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_integer(cobj , key , i) ~= 0) - end - return ret -end - -function _reader:message_repeated(key, message_type) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - local m = { - _CObj = c._rmessage_message(cobj , key , i), - _CType = message_type, - _Parent = self, - } - tinsert(ret, setmetatable( m , _R_meta )) - end - return ret -end - -function _reader:int32_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_int32(cobj , key , i)) - end - return ret -end - -function _reader:int64_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_int64(cobj , key , i)) - end - return ret -end - -function _reader:int52_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_int52(cobj , key , i)) - end - return ret -end - -function _reader:uint52_repeated(key) - local cobj = self._CObj - local n = c._rmessage_size(cobj , key) - local ret = {} - for i=0,n-1 do - tinsert(ret, c._rmessage_uint52(cobj , key , i)) - end - return ret -end - -_reader[1] = function(msg) return _reader.int end -_reader[2] = function(msg) return _reader.real end -_reader[3] = function(msg) return _reader.bool end -_reader[4] = function(msg) return _reader.string end -_reader[5] = function(msg) return _reader.string end -_reader[6] = function(msg) - local message = _reader.message - return function(self,key) - return message(self, key, msg) - end -end -_reader[7] = function(msg) return _reader.int64 end -_reader[8] = function(msg) return _reader.int32 end -_reader[9] = _reader[5] -_reader[10] = function(msg) return _reader.int52 end -_reader[11] = function(msg) return _reader.uint52 end - -_reader[128+1] = function(msg) return _reader.int_repeated end -_reader[128+2] = function(msg) return _reader.real_repeated end -_reader[128+3] = function(msg) return _reader.bool_repeated end -_reader[128+4] = function(msg) return _reader.string_repeated end -_reader[128+5] = function(msg) return _reader.string_repeated end -_reader[128+6] = function(msg) - local message = _reader.message_repeated - return function(self,key) - return message(self, key, msg) - end -end -_reader[128+7] = function(msg) return _reader.int64_repeated end -_reader[128+8] = function(msg) return _reader.int32_repeated end -_reader[128+9] = _reader[128+5] -_reader[128+10] = function(msg) return _reader.int52_repeated end -_reader[128+11] = function(msg) return _reader.uint52_repeated end - -local _decode_type_meta = {} - -function _decode_type_meta:__index(key) - local t, msg = c._env_type(P, self._CType, key) - local func = assert(_reader[t],key)(msg) - self[key] = func - return func -end - -setmetatable(decode_type_cache , { - __index = function(self, key) - local v = setmetatable({ _CType = key } , _decode_type_meta) - self[key] = v - return v - end -}) - -local _R_metagc = { - __index = _R_meta.__index -} - -_R_metagc.__gc = assert(delete_all) - -local function decode_message( message , buffer, length) - local rmessage = c._rmessage_new(P, message, buffer, length) - if rmessage then - local self = { - _CObj = rmessage, - _CType = message, - } - return setmetatable( self , _R_metagc ) - end -end - ---close_decoder = assert(delete_all) - -function register( buffer) - c._env_register(P, buffer) -end - -function register_file(filename) - local f = assert(io.open(filename , "rb")) - local buffer = f:read "*a" - c._env_register(P, buffer) - f:close() -end - ------------ encode ---------------- - -local encode_type_cache = {} - -local function encode_message(CObj, message_type, t) - local type = encode_type_cache[message_type] - for k,v in pairs(t) do - local func = type[k] - func(CObj, k , v) - end -end - -local _writer = { - int = c._wmessage_integer, - real = c._wmessage_real, - enum = c._wmessage_string, - string = c._wmessage_string, - int64 = c._wmessage_int64, - int32 = c._wmessage_int32, - int52 = c._wmessage_int52, - uint52 = c._wmessage_uint52, -} - -function _writer:bool(k,v) - c._wmessage_integer(self, k, v and 1 or 0) -end - -function _writer:message(k, v , message_type) - local submessage = c._wmessage_message(self, k) - encode_message(submessage, message_type, v) -end - -function _writer:int_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_integer(self,k,v) - end -end - -function _writer:real_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_real(self,k,v) - end -end - -function _writer:bool_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_integer(self, k, v and 1 or 0) - end -end - -function _writer:string_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_string(self,k,v) - end -end - -function _writer:message_repeated(k,v, message_type) - for _,v in ipairs(v) do - local submessage = c._wmessage_message(self, k) - encode_message(submessage, message_type, v) - end -end - -function _writer:int32_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_int32(self,k,v) - end -end - -function _writer:int64_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_int64(self,k,v) - end -end - -function _writer:int52_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_int52(self,k,v) - end -end - -function _writer:uint52_repeated(k,v) - for _,v in ipairs(v) do - c._wmessage_uint52(self,k,v) - end -end - -_writer[1] = function(msg) return _writer.int end -_writer[2] = function(msg) return _writer.real end -_writer[3] = function(msg) return _writer.bool end -_writer[4] = function(msg) return _writer.string end -_writer[5] = function(msg) return _writer.string end -_writer[6] = function(msg) - local message = _writer.message - return function(self,key , v) - return message(self, key, v, msg) - end -end -_writer[7] = function(msg) return _writer.int64 end -_writer[8] = function(msg) return _writer.int32 end -_writer[9] = _writer[5] -_writer[10] = function(msg) return _writer.int52 end -_writer[11] = function(msg) return _writer.uint52 end - -_writer[128+1] = function(msg) return _writer.int_repeated end -_writer[128+2] = function(msg) return _writer.real_repeated end -_writer[128+3] = function(msg) return _writer.bool_repeated end -_writer[128+4] = function(msg) return _writer.string_repeated end -_writer[128+5] = function(msg) return _writer.string_repeated end -_writer[128+6] = function(msg) - local message = _writer.message_repeated - return function(self,key, v) - return message(self, key, v, msg) - end -end -_writer[128+7] = function(msg) return _writer.int64_repeated end -_writer[128+8] = function(msg) return _writer.int32_repeated end -_writer[128+9] = _writer[128+5] -_writer[128+10] = function(msg) return _writer.int52_repeated end -_writer[128+11] = function(msg) return _writer.uint52_repeated end - -local _encode_type_meta = {} - -function _encode_type_meta:__index(key) - local t, msg = c._env_type(P, self._CType, key) - local func = assert(_writer[t],key)(msg) - self[key] = func - return func -end - -setmetatable(encode_type_cache , { - __index = function(self, key) - local v = setmetatable({ _CType = key } , _encode_type_meta) - self[key] = v - return v - end -}) - -function encode( message, t , func) - local encoder = c._wmessage_new(P, message) - assert(encoder , message) - encode_message(encoder, message, t) - if func then - local buffer, len = c._wmessage_buffer(encoder) - func(buffer, len) - c._wmessage_delete(encoder) - else - local s = c._wmessage_buffer_string(encoder) - c._wmessage_delete(encoder) - return s - end -end - ---------- unpack ---------- - -local _pattern_type = { - [1] = {"%d","i"}, - [2] = {"%F","r"}, - [3] = {"%d","b"}, - [4] = {"%d","i"}, - [5] = {"%s","s"}, - [6] = {"%s","m"}, - [7] = {"%D","x"}, - [8] = {"%d","p"}, - [10] = {"%D","d"}, - [11] = {"%D","u"}, - [128+1] = {"%a","I"}, - [128+2] = {"%a","R"}, - [128+3] = {"%a","B"}, - [128+4] = {"%a","I"}, - [128+5] = {"%a","S"}, - [128+6] = {"%a","M"}, - [128+7] = {"%a","X"}, - [128+8] = {"%a","P"}, - [128+10] = {"%a", "D" }, - [128+11] = {"%a", "U" }, -} - -_pattern_type[9] = _pattern_type[5] -_pattern_type[128+9] = _pattern_type[128+5] - - -local function _pattern_create(pattern) - local iter = string.gmatch(pattern,"[^ ]+") - local message = iter() - local cpat = {} - local lua = {} - for v in iter do - local tidx = c._env_type(P, message, v) - local t = _pattern_type[tidx] - assert(t,tidx) - tinsert(cpat,v .. " " .. t[1]) - tinsert(lua,t[2]) - end - local cobj = c._pattern_new(P, message , "@" .. table.concat(cpat," ")) - if cobj == nil then - return - end - local pat = { - CObj = cobj, - format = table.concat(lua), - size = 0 - } - pat.size = c._pattern_size(pat.format) - - return pat -end - -setmetatable(_pattern_cache, { - __index = function(t, key) - local v = _pattern_create(key) - t[key] = v - return v - end -}) - -function unpack(pattern, buffer, length) - local pat = _pattern_cache[pattern] - return c._pattern_unpack(pat.CObj , pat.format, pat.size, buffer, length) -end - -function pack(pattern, ...) - local pat = _pattern_cache[pattern] - return c._pattern_pack(pat.CObj, pat.format, pat.size , ...) -end - -function check(typename , field) - if field == nil then - return c._env_type(P,typename) - else - return c._env_type(P,typename,field) ~=0 - end -end - --------------- - -local default_cache = setmetatable({} , {__mode = "kv"}) - -local function default_table(typename) - local v = default_cache[typename] - if v then - return v - end - - v = { __index = assert(decode_message(typename , "")) } - - default_cache[typename] = v - return v -end - -local decode_message_mt = {} - -local function decode_message_cb(typename, buffer) - return setmetatable ( { typename, buffer } , decode_message_mt) -end - -function decode(typename, buffer, length) - local ret = {} - local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length) - if ok then - return setmetatable(ret , default_table(typename)) - else - return false , c._last_error(P) - end -end - -local function expand(tbl) - local typename = rawget(tbl , 1) - local buffer = rawget(tbl , 2) - tbl[1] , tbl[2] = nil , nil - assert(c._decode(P, decode_message_cb , tbl , typename, buffer), typename) - setmetatable(tbl , default_table(typename)) -end - -function decode_message_mt.__index(tbl, key) - expand(tbl) - return tbl[key] -end - -function decode_message_mt.__pairs(tbl) - expand(tbl) - return pairs(tbl) -end - -local function set_default(typename, tbl) - for k,v in pairs(tbl) do - if type(v) == "table" then - local t, msg = c._env_type(P, typename, k) - if t == 6 then - set_default(msg, v) - elseif t == 128+6 then - for _,v in ipairs(v) do - set_default(msg, v) - end - end - end - end - return setmetatable(tbl , default_table(typename)) -end - - -default=set_default diff --git a/lualib/protobuf/parser.lua b/lualib/protobuf/parser.lua deleted file mode 100644 index dbe74b6a..00000000 --- a/lualib/protobuf/parser.lua +++ /dev/null @@ -1,397 +0,0 @@ ------------------------ --- simple proto parser ------------------------ - -local lpeg = require "lpeg" -local P = lpeg.P -local S = lpeg.S -local R = lpeg.R -local C = lpeg.C -local Ct = lpeg.Ct -local Cg = lpeg.Cg -local Cc = lpeg.Cc -local V = lpeg.V - -local next = next -local error = error -local tonumber = tonumber -local pairs = pairs -local ipairs = ipairs -local rawset = rawset -local tinsert = table.insert -local smatch = string.match -local sbyte = string.byte - -local internal_type = { - double = "TYPE_DOUBLE", - float = "TYPE_FLOAT", - uint64 = "TYPE_UINT64", - int = "TYPE_INT32", - int32 = "TYPE_INT32", - int64 = "TYPE_INT64", - fixed64 = "TYPE_FIXED64", - fixed32 = "TYPE_FIXED32", - bool = "TYPE_BOOL", - string = "TYPE_STRING", - bytes = "TYPE_BYTES", - uint32 = "TYPE_UINT32", - sfixed32 = "TYPE_SFIXED32", - sfixed64 = "TYPE_SFIXED64", - sint32 = "TYPE_SINT32", - sint64 = "TYPE_SINT64", -} - -local function count_lines(_,pos, parser_state) - if parser_state.pos < pos then - parser_state.line = parser_state.line + 1 - parser_state.pos = pos - end - return pos -end - -local exception = lpeg.Cmt( lpeg.Carg(1) , function ( _ , pos, parser_state) - error( "syntax error at [" .. (parser_state.file or "") .."] (" .. parser_state.line ..")" ) - return pos -end) - -local eof = P(-1) -local newline = lpeg.Cmt((P"\n" + "\r\n") * lpeg.Carg(1) ,count_lines) -local line_comment = "//" * (1 - newline) ^0 * (newline + eof) -local blank = S" \t" + newline + line_comment -local blank0 = blank ^ 0 -local blanks = blank ^ 1 -local alpha = R"az" + R"AZ" + "_" -local alnum = alpha + R"09" -local str_c = (1 - S("\\\"")) + P("\\") * 1 -local str = P"\"" * C(str_c^0) * "\"" -local dotname = ("." * alpha * alnum ^ 0) ^ 0 -local typename = C(alpha * alnum ^ 0 * dotname) -local name = C(alpha * alnum ^ 0) -local filename = C((alnum + "/" + "." + "-")^1) -local id = R"09" ^ 1 / tonumber + "max" * Cc(-1) -local bool = "true" * Cc(true) + "false" * Cc(false) -local value = str + bool + name + id -local patterns = {} - -local enum_item = Cg(name * blank0 * "=" * blank0 * id * blank0 * ";" * blank0) - -local function insert(tbl, k,v) - tinsert(tbl, { name = k , number = v }) - return tbl -end - -patterns.ENUM = Ct(Cg("enum","type") * blanks * Cg(typename,"name") * blank0 * - "{" * blank0 * - Cg(lpeg.Cf(Ct"" * enum_item^1 , insert),"value") - * "}" * blank0) - -local prefix_field = P"required" * Cc"LABEL_REQUIRED" + - P"optional" * Cc"LABEL_OPTIONAL" + - P"repeated" * Cc"LABEL_REPEATED" -local postfix_pair = blank0 * Cg(name * blank0 * "=" * blank0 * value * blank0) -local postfix_pair_2 = blank0 * "," * postfix_pair -local postfix_field = "[" * postfix_pair * postfix_pair_2^0 * blank0 * "]" -local options = lpeg.Cf(Ct"" * postfix_field , rawset) ^ -1 - -local function setoption(t, options) - if next(options) then - t.options = options - end - return t -end - -local message_field = lpeg.Cf ( - Ct( Cg(prefix_field,"label") * blanks * - Cg(typename,"type_name") * blanks * - Cg(name,"name") * blank0 * "=" * blank0 * - Cg(id,"number") - ) * blank0 * options , - setoption) * blank0 * ";" * blank0 - -local extensions = Ct( - Cg("extensions" , "type") * blanks * - Cg(id,"start") * blanks * "to" * blanks * - Cg(id,"end") * blank0 * ";" * blank0 - ) - -patterns.EXTEND = Ct( - Cg("extend", "type") * blanks * - Cg(typename, "name") * blank0 * "{" * blank0 * - Cg(Ct((message_field) ^ 1),"extension") * "}" * blank0 - ) - -patterns.MESSAGE = P { Ct( - Cg("message","type") * blanks * - Cg(typename,"name") * blank0 * "{" * blank0 * - Cg(Ct((message_field + patterns.ENUM + extensions + patterns.EXTEND + V(1)) ^ 1),"items") * "}" * blank0 - ) } - -patterns.OPTION = Ct( - Cg("option" , "type") * blanks * - Cg(name, "name") * blank0 * "=" * blank0 * - Cg(value, "value") - ) * blank0 * ";" * blank0 - -patterns.IMPORT = Ct( Cg("import" , "type") * blanks * Cg(filename, "name") ) * blank0 - -patterns.PACKAGE = Ct( Cg("package", "type") * blanks * Cg(typename, "name") ) * blank0 * ";" * blank0 - -local proto_tbl = { "PROTO" } - -do - local k, v = next(patterns) - local p = V(k) - proto_tbl[k] = v - for k,v in next , patterns , k do - proto_tbl[k] = v - p = p + V(k) - end - proto_tbl.PROTO = Ct(blank0 * p ^ 1) -end - -local proto = P(proto_tbl) - -local deal = {} - -function deal:import(v) - self.dependency = self.dependency or {} - tinsert(self.dependency , v.name) -end - -function deal:package(v) - self.package = v.name -end - -function deal:enum(v) - self.enum_type = self.enum_type or {} - tinsert(self.enum_type , v) -end - -function deal:option(v) - self.options = self.options or {} - self.options[v.name] = v.value -end - -function deal:extend(v) - self.extension = self.extension or {} - local extendee = v.name - for _,v in ipairs(v.extension) do - v.extendee = extendee - v.type = internal_type[v.type_name] - if v.type then - v.type_name = nil - end - tinsert(self.extension , v) - end -end - -function deal:extensions(v) - self.extension_range = self.extension_range or {} - tinsert(self.extension_range, v) -end - -local function _add_nested_message(self, item) - if item.type == nil then - item.type = internal_type[item.type_name] - if item.type then - item.type_name = nil - end - self.field = self.field or {} - tinsert(self.field, item) - else - local f = deal[item.type] - item.type = nil - f(self , item) - end -end - -function deal:message(v) - self.nested_type = self.nested_type or {} - local m = { name = v.name } - tinsert(self.nested_type , m) - for _,v in ipairs(v.items) do - _add_nested_message(m, v) - end -end - -local function fix(r) - local p = {} - for _,v in ipairs(r) do - local f = deal[v.type] - v.type = nil - f(p , v) - end - - p.message_type = p.nested_type - p.nested_type = nil - - return p -end - ---- fix message name - -local NULL = {} - -local function _match_name(namespace , n , all) - if sbyte(n) == 46 then - return n - end - - repeat - local name = namespace .. "." .. n - if all[name] then - return name - end - namespace = smatch(namespace,"(.*)%.[%w_]+$") - until namespace == nil -end - -local function _fix_field(namespace , field, all) - local type_name = field.type_name - if type_name == "" then - field.type_name = nil - return - elseif type_name == nil then - return - end - - local full_name = assert(_match_name(namespace, field.type_name, all) , field.type_name , all) - - field.type_name = full_name - field.type = all[full_name] - - local options = field.options - if options then - if options.default then - field.default_value = tostring(options.default) - options.default = nil - end - if next(options) == nil then - field.options = nil - end - end -end - -local function _fix_extension(namespace, ext, all) - for _,field in ipairs(ext or NULL) do - field.extendee = assert(_match_name(namespace, field.extendee,all),field.extendee) - _fix_field(namespace , field , all) - end -end - -local function _fix_message(msg , all) - for _,field in ipairs(msg.field or NULL) do - _fix_field(assert(all[msg],msg.name) , field , all) - end - for _,nest in ipairs(msg.nested_type or NULL) do - _fix_message(nest , all) - end - _fix_extension(all[msg] , msg.extension , all) -end - -local function _fix_typename(file , all) - for _,message in ipairs(file.message_type or NULL) do - _fix_message(message , all) - end - _fix_extension(file.package , file.extension , all) -end - ---- merge messages - -local function _enum_fullname(prefix, enum , all) - local fullname - if sbyte(enum.name) == 46 then - fullname = enum.name - else - fullname = prefix .. "." .. enum.name - end - all[fullname] = "TYPE_ENUM" - all[enum] = fullname -end - -local function _message_fullname(prefix , msg , all) - local fullname - if sbyte(msg.name) == 46 then - fullname = msg.name - else - fullname = prefix .. "." .. msg.name - end - all[fullname] = "TYPE_MESSAGE" - all[msg] = fullname - for _,nest in ipairs(msg.nested_type or NULL) do - _message_fullname(fullname , nest , all) - end - for _,enum in ipairs(msg.enum_type or NULL) do - _enum_fullname(fullname , enum , all) - end -end - -local function _gen_fullname(file , all) - local prefix = "" - if file.package then - prefix = "." .. file.package - end - for _,message in ipairs(file.message_type or NULL) do - _message_fullname(prefix , message , all) - end - for _,enum in ipairs(file.enum_type or NULL) do - _enum_fullname(prefix , enum , all) - end -end - ---- parser - -local parser = {} - -local function parser_one(text,filename) - local state = { file = filename, pos = 0, line = 1 } - local r = lpeg.match(proto * -1 + exception , text , 1, state ) - local t = fix(r) - return t -end - -function parser.parser(text,filename) - local t = parser_one(text,filename) - local all = {} - _gen_fullname(t,all) - _fix_typename(t , all) - return t -end - -local pb = require "protobuf" - -function parser.register(fileset , path) - local all = {} - local files = {} - if type(fileset) == "string" then - fileset = { fileset } - end - for _, filename in ipairs(fileset) do - local fullname - if path then - fullname = path .. "/" .. filename - else - fullname = filename - end - local f = assert(io.open(fullname , "r")) - local buffer = f:read "*a" - f:close() - local t = parser_one(buffer,filename) - _gen_fullname(t,all) - t.name = filename - tinsert(files , t) - end - for _,file in ipairs(files) do - _fix_typename(file,all) - end - - local pbencode = pb.encode("google.protobuf.FileDescriptorSet" , { file = files }) - - if pbencode == nil then - error(pb.lasterror()) - end - pb.register(pbencode) - return files -end - -return parser \ No newline at end of file