immunio 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +234 -0
  3. data/README.md +147 -0
  4. data/bin/immunio +5 -0
  5. data/lib/immunio.rb +29 -0
  6. data/lib/immunio/agent.rb +260 -0
  7. data/lib/immunio/authentication.rb +96 -0
  8. data/lib/immunio/blocked_app.rb +38 -0
  9. data/lib/immunio/channel.rb +432 -0
  10. data/lib/immunio/cli.rb +39 -0
  11. data/lib/immunio/context.rb +114 -0
  12. data/lib/immunio/errors.rb +43 -0
  13. data/lib/immunio/immunio_ca.crt +45 -0
  14. data/lib/immunio/logger.rb +87 -0
  15. data/lib/immunio/plugins/action_dispatch.rb +45 -0
  16. data/lib/immunio/plugins/action_view.rb +431 -0
  17. data/lib/immunio/plugins/active_record.rb +707 -0
  18. data/lib/immunio/plugins/active_record_relation.rb +370 -0
  19. data/lib/immunio/plugins/authlogic.rb +80 -0
  20. data/lib/immunio/plugins/csrf.rb +24 -0
  21. data/lib/immunio/plugins/devise.rb +40 -0
  22. data/lib/immunio/plugins/environment_reporter.rb +69 -0
  23. data/lib/immunio/plugins/eval.rb +51 -0
  24. data/lib/immunio/plugins/exception_handler.rb +55 -0
  25. data/lib/immunio/plugins/gems_tracker.rb +5 -0
  26. data/lib/immunio/plugins/haml.rb +36 -0
  27. data/lib/immunio/plugins/http_finisher.rb +50 -0
  28. data/lib/immunio/plugins/http_tracker.rb +203 -0
  29. data/lib/immunio/plugins/io.rb +96 -0
  30. data/lib/immunio/plugins/redirect.rb +42 -0
  31. data/lib/immunio/plugins/warden.rb +66 -0
  32. data/lib/immunio/processor.rb +234 -0
  33. data/lib/immunio/rails.rb +26 -0
  34. data/lib/immunio/request.rb +139 -0
  35. data/lib/immunio/rufus_lua_ext/ref.rb +27 -0
  36. data/lib/immunio/rufus_lua_ext/state.rb +157 -0
  37. data/lib/immunio/rufus_lua_ext/table.rb +137 -0
  38. data/lib/immunio/rufus_lua_ext/utils.rb +13 -0
  39. data/lib/immunio/version.rb +5 -0
  40. data/lib/immunio/vm.rb +291 -0
  41. data/lua-hooks/ext/all.c +78 -0
  42. data/lua-hooks/ext/bitop/README +22 -0
  43. data/lua-hooks/ext/bitop/bit.c +189 -0
  44. data/lua-hooks/ext/extconf.rb +38 -0
  45. data/lua-hooks/ext/libinjection/COPYING +37 -0
  46. data/lua-hooks/ext/libinjection/libinjection.h +65 -0
  47. data/lua-hooks/ext/libinjection/libinjection_html5.c +847 -0
  48. data/lua-hooks/ext/libinjection/libinjection_html5.h +54 -0
  49. data/lua-hooks/ext/libinjection/libinjection_sqli.c +2301 -0
  50. data/lua-hooks/ext/libinjection/libinjection_sqli.h +295 -0
  51. data/lua-hooks/ext/libinjection/libinjection_sqli_data.h +9349 -0
  52. data/lua-hooks/ext/libinjection/libinjection_xss.c +531 -0
  53. data/lua-hooks/ext/libinjection/libinjection_xss.h +21 -0
  54. data/lua-hooks/ext/libinjection/lualib.c +109 -0
  55. data/lua-hooks/ext/lpeg/HISTORY +90 -0
  56. data/lua-hooks/ext/lpeg/lpcap.c +537 -0
  57. data/lua-hooks/ext/lpeg/lpcap.h +43 -0
  58. data/lua-hooks/ext/lpeg/lpcode.c +986 -0
  59. data/lua-hooks/ext/lpeg/lpcode.h +34 -0
  60. data/lua-hooks/ext/lpeg/lpeg-128.gif +0 -0
  61. data/lua-hooks/ext/lpeg/lpeg.html +1429 -0
  62. data/lua-hooks/ext/lpeg/lpprint.c +244 -0
  63. data/lua-hooks/ext/lpeg/lpprint.h +35 -0
  64. data/lua-hooks/ext/lpeg/lptree.c +1238 -0
  65. data/lua-hooks/ext/lpeg/lptree.h +77 -0
  66. data/lua-hooks/ext/lpeg/lptypes.h +149 -0
  67. data/lua-hooks/ext/lpeg/lpvm.c +355 -0
  68. data/lua-hooks/ext/lpeg/lpvm.h +58 -0
  69. data/lua-hooks/ext/lpeg/makefile +55 -0
  70. data/lua-hooks/ext/lpeg/re.html +498 -0
  71. data/lua-hooks/ext/lpeg/test.lua +1409 -0
  72. data/lua-hooks/ext/lua-cmsgpack/CMakeLists.txt +45 -0
  73. data/lua-hooks/ext/lua-cmsgpack/README.md +115 -0
  74. data/lua-hooks/ext/lua-cmsgpack/lua_cmsgpack.c +957 -0
  75. data/lua-hooks/ext/lua-cmsgpack/test.lua +570 -0
  76. data/lua-hooks/ext/lua-snapshot/LICENSE +7 -0
  77. data/lua-hooks/ext/lua-snapshot/Makefile +12 -0
  78. data/lua-hooks/ext/lua-snapshot/README.md +18 -0
  79. data/lua-hooks/ext/lua-snapshot/dump.lua +15 -0
  80. data/lua-hooks/ext/lua-snapshot/snapshot.c +455 -0
  81. data/lua-hooks/ext/lua/COPYRIGHT +34 -0
  82. data/lua-hooks/ext/lua/lapi.c +1087 -0
  83. data/lua-hooks/ext/lua/lapi.h +16 -0
  84. data/lua-hooks/ext/lua/lauxlib.c +652 -0
  85. data/lua-hooks/ext/lua/lauxlib.h +174 -0
  86. data/lua-hooks/ext/lua/lbaselib.c +659 -0
  87. data/lua-hooks/ext/lua/lcode.c +831 -0
  88. data/lua-hooks/ext/lua/lcode.h +76 -0
  89. data/lua-hooks/ext/lua/ldblib.c +398 -0
  90. data/lua-hooks/ext/lua/ldebug.c +638 -0
  91. data/lua-hooks/ext/lua/ldebug.h +33 -0
  92. data/lua-hooks/ext/lua/ldo.c +519 -0
  93. data/lua-hooks/ext/lua/ldo.h +57 -0
  94. data/lua-hooks/ext/lua/ldump.c +164 -0
  95. data/lua-hooks/ext/lua/lfunc.c +174 -0
  96. data/lua-hooks/ext/lua/lfunc.h +34 -0
  97. data/lua-hooks/ext/lua/lgc.c +710 -0
  98. data/lua-hooks/ext/lua/lgc.h +110 -0
  99. data/lua-hooks/ext/lua/linit.c +38 -0
  100. data/lua-hooks/ext/lua/liolib.c +556 -0
  101. data/lua-hooks/ext/lua/llex.c +463 -0
  102. data/lua-hooks/ext/lua/llex.h +81 -0
  103. data/lua-hooks/ext/lua/llimits.h +128 -0
  104. data/lua-hooks/ext/lua/lmathlib.c +263 -0
  105. data/lua-hooks/ext/lua/lmem.c +86 -0
  106. data/lua-hooks/ext/lua/lmem.h +49 -0
  107. data/lua-hooks/ext/lua/loadlib.c +705 -0
  108. data/lua-hooks/ext/lua/loadlib_rel.c +760 -0
  109. data/lua-hooks/ext/lua/lobject.c +214 -0
  110. data/lua-hooks/ext/lua/lobject.h +381 -0
  111. data/lua-hooks/ext/lua/lopcodes.c +102 -0
  112. data/lua-hooks/ext/lua/lopcodes.h +268 -0
  113. data/lua-hooks/ext/lua/loslib.c +243 -0
  114. data/lua-hooks/ext/lua/lparser.c +1339 -0
  115. data/lua-hooks/ext/lua/lparser.h +82 -0
  116. data/lua-hooks/ext/lua/lstate.c +214 -0
  117. data/lua-hooks/ext/lua/lstate.h +169 -0
  118. data/lua-hooks/ext/lua/lstring.c +111 -0
  119. data/lua-hooks/ext/lua/lstring.h +31 -0
  120. data/lua-hooks/ext/lua/lstrlib.c +871 -0
  121. data/lua-hooks/ext/lua/ltable.c +588 -0
  122. data/lua-hooks/ext/lua/ltable.h +40 -0
  123. data/lua-hooks/ext/lua/ltablib.c +287 -0
  124. data/lua-hooks/ext/lua/ltm.c +75 -0
  125. data/lua-hooks/ext/lua/ltm.h +54 -0
  126. data/lua-hooks/ext/lua/lua.c +392 -0
  127. data/lua-hooks/ext/lua/lua.def +131 -0
  128. data/lua-hooks/ext/lua/lua.h +388 -0
  129. data/lua-hooks/ext/lua/lua.rc +28 -0
  130. data/lua-hooks/ext/lua/lua_dll.rc +26 -0
  131. data/lua-hooks/ext/lua/luac.c +200 -0
  132. data/lua-hooks/ext/lua/luac.rc +1 -0
  133. data/lua-hooks/ext/lua/luaconf.h +763 -0
  134. data/lua-hooks/ext/lua/luaconf.h.in +724 -0
  135. data/lua-hooks/ext/lua/luaconf.h.orig +763 -0
  136. data/lua-hooks/ext/lua/lualib.h +53 -0
  137. data/lua-hooks/ext/lua/lundump.c +227 -0
  138. data/lua-hooks/ext/lua/lundump.h +36 -0
  139. data/lua-hooks/ext/lua/lvm.c +767 -0
  140. data/lua-hooks/ext/lua/lvm.h +36 -0
  141. data/lua-hooks/ext/lua/lzio.c +82 -0
  142. data/lua-hooks/ext/lua/lzio.h +67 -0
  143. data/lua-hooks/ext/lua/print.c +227 -0
  144. data/lua-hooks/ext/luautf8/README.md +152 -0
  145. data/lua-hooks/ext/luautf8/lutf8lib.c +1274 -0
  146. data/lua-hooks/ext/luautf8/unidata.h +3064 -0
  147. data/lua-hooks/lib/boot.lua +254 -0
  148. data/lua-hooks/lib/encode.lua +4 -0
  149. data/lua-hooks/lib/lexers/LICENSE +21 -0
  150. data/lua-hooks/lib/lexers/bash.lua +134 -0
  151. data/lua-hooks/lib/lexers/bash_dqstr.lua +62 -0
  152. data/lua-hooks/lib/lexers/css.lua +216 -0
  153. data/lua-hooks/lib/lexers/html.lua +106 -0
  154. data/lua-hooks/lib/lexers/javascript.lua +68 -0
  155. data/lua-hooks/lib/lexers/lexer.lua +1575 -0
  156. data/lua-hooks/lib/lexers/markers.lua +33 -0
  157. metadata +308 -0
@@ -0,0 +1,244 @@
1
+ /*
2
+ ** $Id: lpprint.c,v 1.7 2013/04/12 16:29:49 roberto Exp $
3
+ ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
4
+ */
5
+
6
+ #include <ctype.h>
7
+ #include <limits.h>
8
+ #include <stdio.h>
9
+
10
+
11
+ #include "lptypes.h"
12
+ #include "lpprint.h"
13
+ #include "lpcode.h"
14
+
15
+
16
+ #if defined(LPEG_DEBUG)
17
+
18
+ /*
19
+ ** {======================================================
20
+ ** Printing patterns (for debugging)
21
+ ** =======================================================
22
+ */
23
+
24
+
25
+ void printcharset (const byte *st) {
26
+ int i;
27
+ printf("[");
28
+ for (i = 0; i <= UCHAR_MAX; i++) {
29
+ int first = i;
30
+ while (testchar(st, i) && i <= UCHAR_MAX) i++;
31
+ if (i - 1 == first) /* unary range? */
32
+ printf("(%02x)", first);
33
+ else if (i - 1 > first) /* non-empty range? */
34
+ printf("(%02x-%02x)", first, i - 1);
35
+ }
36
+ printf("]");
37
+ }
38
+
39
+
40
+ static void printcapkind (int kind) {
41
+ const char *const modes[] = {
42
+ "close", "position", "constant", "backref",
43
+ "argument", "simple", "table", "function",
44
+ "query", "string", "num", "substitution", "fold",
45
+ "runtime", "group"};
46
+ printf("%s", modes[kind]);
47
+ }
48
+
49
+
50
+ static void printjmp (const LpegInstruction *op, const LpegInstruction *p) {
51
+ printf("-> %d", (int)(p + (p + 1)->offset - op));
52
+ }
53
+
54
+
55
+ static void printinst (const LpegInstruction *op, const LpegInstruction *p) {
56
+ const char *const names[] = {
57
+ "any", "char", "set",
58
+ "testany", "testchar", "testset",
59
+ "span", "behind",
60
+ "ret", "end",
61
+ "choice", "jmp", "call", "open_call",
62
+ "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup",
63
+ "fullcapture", "opencapture", "closecapture", "closeruntime"
64
+ };
65
+ printf("%02ld: %s ", (long)(p - op), names[p->i.code]);
66
+ switch ((Opcode)p->i.code) {
67
+ case IChar: {
68
+ printf("'%c'", p->i.aux);
69
+ break;
70
+ }
71
+ case ITestChar: {
72
+ printf("'%c'", p->i.aux); printjmp(op, p);
73
+ break;
74
+ }
75
+ case IFullCapture: {
76
+ printcapkind(getkind(p));
77
+ printf(" (size = %d) (idx = %d)", getoff(p), p->i.key);
78
+ break;
79
+ }
80
+ case IOpenCapture: {
81
+ printcapkind(getkind(p));
82
+ printf(" (idx = %d)", p->i.key);
83
+ break;
84
+ }
85
+ case ISet: {
86
+ printcharset((p+1)->buff);
87
+ break;
88
+ }
89
+ case ITestSet: {
90
+ printcharset((p+2)->buff); printjmp(op, p);
91
+ break;
92
+ }
93
+ case ISpan: {
94
+ printcharset((p+1)->buff);
95
+ break;
96
+ }
97
+ case IOpenCall: {
98
+ printf("-> %d", (p + 1)->offset);
99
+ break;
100
+ }
101
+ case IBehind: {
102
+ printf("%d", p->i.aux);
103
+ break;
104
+ }
105
+ case IJmp: case ICall: case ICommit: case IChoice:
106
+ case IPartialCommit: case IBackCommit: case ITestAny: {
107
+ printjmp(op, p);
108
+ break;
109
+ }
110
+ default: break;
111
+ }
112
+ printf("\n");
113
+ }
114
+
115
+
116
+ void printpatt (LpegInstruction *p, int n) {
117
+ LpegInstruction *op = p;
118
+ while (p < op + n) {
119
+ printinst(op, p);
120
+ p += sizei(p);
121
+ }
122
+ }
123
+
124
+
125
+ #if defined(LPEG_DEBUG)
126
+ static void printcap (Capture *cap) {
127
+ printcapkind(cap->kind);
128
+ printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s);
129
+ }
130
+
131
+
132
+ void printcaplist (Capture *cap, Capture *limit) {
133
+ printf(">======\n");
134
+ for (; cap->s && (limit == NULL || cap < limit); cap++)
135
+ printcap(cap);
136
+ printf("=======\n");
137
+ }
138
+ #endif
139
+
140
+ /* }====================================================== */
141
+
142
+
143
+ /*
144
+ ** {======================================================
145
+ ** Printing trees (for debugging)
146
+ ** =======================================================
147
+ */
148
+
149
+ static const char *tagnames[] = {
150
+ "char", "set", "any",
151
+ "true", "false",
152
+ "rep",
153
+ "seq", "choice",
154
+ "not", "and",
155
+ "call", "opencall", "rule", "grammar",
156
+ "behind",
157
+ "capture", "run-time"
158
+ };
159
+
160
+
161
+ void printtree (TTree *tree, int ident) {
162
+ int i;
163
+ for (i = 0; i < ident; i++) printf(" ");
164
+ printf("%s", tagnames[tree->tag]);
165
+ switch (tree->tag) {
166
+ case TChar: {
167
+ int c = tree->u.n;
168
+ if (isprint(c))
169
+ printf(" '%c'\n", c);
170
+ else
171
+ printf(" (%02X)\n", c);
172
+ break;
173
+ }
174
+ case TSet: {
175
+ printcharset(treebuffer(tree));
176
+ printf("\n");
177
+ break;
178
+ }
179
+ case TOpenCall: case TCall: {
180
+ printf(" key: %d\n", tree->key);
181
+ break;
182
+ }
183
+ case TBehind: {
184
+ printf(" %d\n", tree->u.n);
185
+ printtree(sib1(tree), ident + 2);
186
+ break;
187
+ }
188
+ case TCapture: {
189
+ printf(" cap: %d key: %d n: %d\n", tree->cap, tree->key, tree->u.n);
190
+ printtree(sib1(tree), ident + 2);
191
+ break;
192
+ }
193
+ case TRule: {
194
+ printf(" n: %d key: %d\n", tree->cap, tree->key);
195
+ printtree(sib1(tree), ident + 2);
196
+ break; /* do not print next rule as a sibling */
197
+ }
198
+ case TGrammar: {
199
+ TTree *rule = sib1(tree);
200
+ printf(" %d\n", tree->u.n); /* number of rules */
201
+ for (i = 0; i < tree->u.n; i++) {
202
+ printtree(rule, ident + 2);
203
+ rule = sib2(rule);
204
+ }
205
+ assert(rule->tag == TTrue); /* sentinel */
206
+ break;
207
+ }
208
+ default: {
209
+ int sibs = numsiblings[tree->tag];
210
+ printf("\n");
211
+ if (sibs >= 1) {
212
+ printtree(sib1(tree), ident + 2);
213
+ if (sibs >= 2)
214
+ printtree(sib2(tree), ident + 2);
215
+ }
216
+ break;
217
+ }
218
+ }
219
+ }
220
+
221
+
222
+ void printktable (lua_State *L, int idx) {
223
+ int n, i;
224
+ lua_getfenv(L, idx);
225
+ if (lua_isnil(L, -1)) /* no ktable? */
226
+ return;
227
+ n = lua_objlen(L, -1);
228
+ printf("[");
229
+ for (i = 1; i <= n; i++) {
230
+ printf("%d = ", i);
231
+ lua_rawgeti(L, -1, i);
232
+ if (lua_isstring(L, -1))
233
+ printf("%s ", lua_tostring(L, -1));
234
+ else
235
+ printf("%s ", lua_typename(L, lua_type(L, -1)));
236
+ lua_pop(L, 1);
237
+ }
238
+ printf("]\n");
239
+ /* leave ktable at the stack */
240
+ }
241
+
242
+ /* }====================================================== */
243
+
244
+ #endif
@@ -0,0 +1,35 @@
1
+ /*
2
+ ** $Id: lpprint.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
3
+ */
4
+
5
+
6
+ #if !defined(lpprint_h)
7
+ #define lpprint_h
8
+
9
+
10
+ #include "lptree.h"
11
+ #include "lpvm.h"
12
+
13
+
14
+ #if defined(LPEG_DEBUG)
15
+
16
+ void printpatt (LpegInstruction *p, int n);
17
+ void printtree (TTree *tree, int ident);
18
+ void printktable (lua_State *L, int idx);
19
+ void printcharset (const byte *st);
20
+ void printcaplist (Capture *cap, Capture *limit);
21
+
22
+ #else
23
+
24
+ #define printktable(L,idx) \
25
+ luaL_error(L, "function only implemented in debug mode")
26
+ #define printtree(tree,i) \
27
+ luaL_error(L, "function only implemented in debug mode")
28
+ #define printpatt(p,n) \
29
+ luaL_error(L, "function only implemented in debug mode")
30
+
31
+ #endif
32
+
33
+
34
+ #endif
35
+
@@ -0,0 +1,1238 @@
1
+ /*
2
+ ** $Id: lptree.c,v 1.13 2014/12/12 16:59:10 roberto Exp $
3
+ ** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
4
+ */
5
+
6
+ #include <ctype.h>
7
+ #include <limits.h>
8
+ #include <string.h>
9
+
10
+
11
+ #include "../lua/lua.h"
12
+ #include "../lua/lauxlib.h"
13
+
14
+ #include "lptypes.h"
15
+ #include "lpcap.h"
16
+ #include "lpcode.h"
17
+ #include "lpprint.h"
18
+ #include "lptree.h"
19
+
20
+
21
+ /* number of siblings for each tree */
22
+ const byte numsiblings[] = {
23
+ 0, 0, 0, /* char, set, any */
24
+ 0, 0, /* true, false */
25
+ 1, /* rep */
26
+ 2, 2, /* seq, choice */
27
+ 1, 1, /* not, and */
28
+ 0, 0, 2, 1, /* call, opencall, rule, grammar */
29
+ 1, /* behind */
30
+ 1, 1 /* capture, runtime capture */
31
+ };
32
+
33
+
34
+ static TTree *newgrammar (lua_State *L, int arg);
35
+
36
+
37
+ /*
38
+ ** returns a reasonable name for value at index 'idx' on the stack
39
+ */
40
+ static const char *val2str (lua_State *L, int idx) {
41
+ const char *k = lua_tostring(L, idx);
42
+ if (k != NULL)
43
+ return lua_pushfstring(L, "%s", k);
44
+ else
45
+ return lua_pushfstring(L, "(a %s)", luaL_typename(L, idx));
46
+ }
47
+
48
+
49
+ /*
50
+ ** Fix a TOpenCall into a TCall node, using table 'postable' to
51
+ ** translate a key to its rule address in the tree. Raises an
52
+ ** error if key does not exist.
53
+ */
54
+ static void fixonecall (lua_State *L, int postable, TTree *g, TTree *t) {
55
+ int n;
56
+ lua_rawgeti(L, -1, t->key); /* get rule's name */
57
+ lua_gettable(L, postable); /* query name in position table */
58
+ n = lua_tonumber(L, -1); /* get (absolute) position */
59
+ lua_pop(L, 1); /* remove position */
60
+ if (n == 0) { /* no position? */
61
+ lua_rawgeti(L, -1, t->key); /* get rule's name again */
62
+ luaL_error(L, "rule '%s' undefined in given grammar", val2str(L, -1));
63
+ }
64
+ t->tag = TCall;
65
+ t->u.ps = n - (t - g); /* position relative to node */
66
+ assert(sib2(t)->tag == TRule);
67
+ sib2(t)->key = t->key;
68
+ }
69
+
70
+
71
+ /*
72
+ ** Transform left associative constructions into right
73
+ ** associative ones, for sequence and choice; that is:
74
+ ** (t11 + t12) + t2 => t11 + (t12 + t2)
75
+ ** (t11 * t12) * t2 => t11 * (t12 * t2)
76
+ ** (that is, Op (Op t11 t12) t2 => Op t11 (Op t12 t2))
77
+ */
78
+ static void correctassociativity (TTree *tree) {
79
+ TTree *t1 = sib1(tree);
80
+ assert(tree->tag == TChoice || tree->tag == TSeq);
81
+ while (t1->tag == tree->tag) {
82
+ int n1size = tree->u.ps - 1; /* t1 == Op t11 t12 */
83
+ int n11size = t1->u.ps - 1;
84
+ int n12size = n1size - n11size - 1;
85
+ memmove(sib1(tree), sib1(t1), n11size * sizeof(TTree)); /* move t11 */
86
+ tree->u.ps = n11size + 1;
87
+ sib2(tree)->tag = tree->tag;
88
+ sib2(tree)->u.ps = n12size + 1;
89
+ }
90
+ }
91
+
92
+
93
+ /*
94
+ ** Make final adjustments in a tree. Fix open calls in tree 't',
95
+ ** making them refer to their respective rules or raising appropriate
96
+ ** errors (if not inside a grammar). Correct associativity of associative
97
+ ** constructions (making them right associative). Assume that tree's
98
+ ** ktable is at the top of the stack (for error messages).
99
+ */
100
+ static void finalfix (lua_State *L, int postable, TTree *g, TTree *t) {
101
+ tailcall:
102
+ switch (t->tag) {
103
+ case TGrammar: /* subgrammars were already fixed */
104
+ return;
105
+ case TOpenCall: {
106
+ if (g != NULL) /* inside a grammar? */
107
+ fixonecall(L, postable, g, t);
108
+ else { /* open call outside grammar */
109
+ lua_rawgeti(L, -1, t->key);
110
+ luaL_error(L, "rule '%s' used outside a grammar", val2str(L, -1));
111
+ }
112
+ break;
113
+ }
114
+ case TSeq: case TChoice:
115
+ correctassociativity(t);
116
+ break;
117
+ }
118
+ switch (numsiblings[t->tag]) {
119
+ case 1: /* finalfix(L, postable, g, sib1(t)); */
120
+ t = sib1(t); goto tailcall;
121
+ case 2:
122
+ finalfix(L, postable, g, sib1(t));
123
+ t = sib2(t); goto tailcall; /* finalfix(L, postable, g, sib2(t)); */
124
+ default: assert(numsiblings[t->tag] == 0); break;
125
+ }
126
+ }
127
+
128
+
129
+ /*
130
+ ** {======================================================
131
+ ** Tree generation
132
+ ** =======================================================
133
+ */
134
+
135
+ /*
136
+ ** In 5.2, could use 'luaL_testudata'...
137
+ */
138
+ static int testpattern (lua_State *L, int idx) {
139
+ if (lua_touserdata(L, idx)) { /* value is a userdata? */
140
+ if (lua_getmetatable(L, idx)) { /* does it have a metatable? */
141
+ luaL_getmetatable(L, PATTERN_T);
142
+ if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
143
+ lua_pop(L, 2); /* remove both metatables */
144
+ return 1;
145
+ }
146
+ }
147
+ }
148
+ return 0;
149
+ }
150
+
151
+
152
+ static Pattern *getpattern (lua_State *L, int idx) {
153
+ return (Pattern *)luaL_checkudata(L, idx, PATTERN_T);
154
+ }
155
+
156
+
157
+ static int getsize (lua_State *L, int idx) {
158
+ return (lua_objlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1;
159
+ }
160
+
161
+
162
+ static TTree *gettree (lua_State *L, int idx, int *len) {
163
+ Pattern *p = getpattern(L, idx);
164
+ if (len)
165
+ *len = getsize(L, idx);
166
+ return p->tree;
167
+ }
168
+
169
+
170
+ /*
171
+ ** create a pattern
172
+ */
173
+ static TTree *newtree (lua_State *L, int len) {
174
+ size_t size = (len - 1) * sizeof(TTree) + sizeof(Pattern);
175
+ Pattern *p = (Pattern *)lua_newuserdata(L, size);
176
+ luaL_getmetatable(L, PATTERN_T);
177
+ lua_setmetatable(L, -2);
178
+ p->code = NULL; p->codesize = 0;
179
+ return p->tree;
180
+ }
181
+
182
+
183
+ static TTree *newleaf (lua_State *L, int tag) {
184
+ TTree *tree = newtree(L, 1);
185
+ tree->tag = tag;
186
+ return tree;
187
+ }
188
+
189
+
190
+ static TTree *newcharset (lua_State *L) {
191
+ TTree *tree = newtree(L, bytes2slots(CHARSETSIZE) + 1);
192
+ tree->tag = TSet;
193
+ loopset(i, treebuffer(tree)[i] = 0);
194
+ return tree;
195
+ }
196
+
197
+
198
+ /*
199
+ ** add to tree a sequence where first sibling is 'sib' (with size
200
+ ** 'sibsize'); returns position for second sibling
201
+ */
202
+ static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) {
203
+ tree->tag = TSeq; tree->u.ps = sibsize + 1;
204
+ memcpy(sib1(tree), sib, sibsize * sizeof(TTree));
205
+ return sib2(tree);
206
+ }
207
+
208
+
209
+ /*
210
+ ** Add element 'idx' to 'ktable' of pattern at the top of the stack;
211
+ ** create new 'ktable' if necessary. Return index of new element.
212
+ ** If new element is nil, does not add it to table (as it would be
213
+ ** useless) and returns 0, as ktable[0] is always nil.
214
+ */
215
+ static int addtoktable (lua_State *L, int idx) {
216
+ if (idx == 0) /* no actual value to insert? */
217
+ return 0;
218
+ else {
219
+ int n;
220
+ lua_getfenv(L, -1); /* get ktable from pattern */
221
+ n = lua_objlen(L, -1);
222
+ if (n == 0) { /* is it empty/non-existent? */
223
+ lua_pop(L, 1); /* remove it */
224
+ lua_createtable(L, 1, 0); /* create a fresh table */
225
+ lua_pushvalue(L, -1); /* make a copy */
226
+ lua_setfenv(L, -3); /* set it as 'ktable' for pattern */
227
+ }
228
+ if (!lua_isnil(L, idx)) { /* non-nil value? */
229
+ lua_pushvalue(L, idx); /* element to be added */
230
+ lua_rawseti(L, -2, ++n);
231
+ }
232
+ lua_pop(L, 1); /* remove 'ktable' */
233
+ return n;
234
+ }
235
+ }
236
+
237
+
238
+ /*
239
+ ** Build a sequence of 'n' nodes, each with tag 'tag' and 'u.n' got
240
+ ** from the array 's' (or 0 if array is NULL). (TSeq is binary, so it
241
+ ** must build a sequence of sequence of sequence...)
242
+ */
243
+ static void fillseq (TTree *tree, int tag, int n, const char *s) {
244
+ int i;
245
+ for (i = 0; i < n - 1; i++) { /* initial n-1 copies of Seq tag; Seq ... */
246
+ tree->tag = TSeq; tree->u.ps = 2;
247
+ sib1(tree)->tag = tag;
248
+ sib1(tree)->u.n = s ? (byte)s[i] : 0;
249
+ tree = sib2(tree);
250
+ }
251
+ tree->tag = tag; /* last one does not need TSeq */
252
+ tree->u.n = s ? (byte)s[i] : 0;
253
+ }
254
+
255
+
256
+ /*
257
+ ** Numbers as patterns:
258
+ ** 0 == true (always match); n == TAny repeated 'n' times;
259
+ ** -n == not (TAny repeated 'n' times)
260
+ */
261
+ static TTree *numtree (lua_State *L, int n) {
262
+ if (n == 0)
263
+ return newleaf(L, TTrue);
264
+ else {
265
+ TTree *tree, *nd;
266
+ if (n > 0)
267
+ tree = nd = newtree(L, 2 * n - 1);
268
+ else { /* negative: code it as !(-n) */
269
+ n = -n;
270
+ tree = newtree(L, 2 * n);
271
+ tree->tag = TNot;
272
+ nd = sib1(tree);
273
+ }
274
+ fillseq(nd, TAny, n, NULL); /* sequence of 'n' any's */
275
+ return tree;
276
+ }
277
+ }
278
+
279
+
280
+ /*
281
+ ** Convert value at index 'idx' to a pattern
282
+ */
283
+ static TTree *getpatt (lua_State *L, int idx, int *len) {
284
+ TTree *tree;
285
+ switch (lua_type(L, idx)) {
286
+ case LUA_TSTRING: {
287
+ size_t slen;
288
+ const char *s = lua_tolstring(L, idx, &slen); /* get string */
289
+ if (slen == 0) /* empty? */
290
+ tree = newleaf(L, TTrue); /* always match */
291
+ else {
292
+ tree = newtree(L, 2 * (slen - 1) + 1);
293
+ fillseq(tree, TChar, slen, s); /* sequence of 'slen' chars */
294
+ }
295
+ break;
296
+ }
297
+ case LUA_TNUMBER: {
298
+ int n = lua_tointeger(L, idx);
299
+ tree = numtree(L, n);
300
+ break;
301
+ }
302
+ case LUA_TBOOLEAN: {
303
+ tree = (lua_toboolean(L, idx) ? newleaf(L, TTrue) : newleaf(L, TFalse));
304
+ break;
305
+ }
306
+ case LUA_TTABLE: {
307
+ tree = newgrammar(L, idx);
308
+ break;
309
+ }
310
+ case LUA_TFUNCTION: {
311
+ tree = newtree(L, 2);
312
+ tree->tag = TRunTime;
313
+ tree->key = addtoktable(L, idx);
314
+ sib1(tree)->tag = TTrue;
315
+ break;
316
+ }
317
+ default: {
318
+ return gettree(L, idx, len);
319
+ }
320
+ }
321
+ lua_replace(L, idx); /* put new tree into 'idx' slot */
322
+ if (len)
323
+ *len = getsize(L, idx);
324
+ return tree;
325
+ }
326
+
327
+
328
+ /*
329
+ ** Return the number of elements in the ktable of pattern at 'idx'.
330
+ ** In Lua 5.2, default "environment" for patterns is nil, not
331
+ ** a table. Treat it as an empty table. In Lua 5.1, assumes that
332
+ ** the environment has no numeric indices (len == 0)
333
+ */
334
+ static int ktablelen (lua_State *L, int idx) {
335
+ if (!lua_istable(L, idx)) return 0;
336
+ else return lua_objlen(L, idx);
337
+ }
338
+
339
+
340
+ /*
341
+ ** Concatentate the contents of table 'idx1' into table 'idx2'.
342
+ ** (Assume that both indices are negative.)
343
+ ** Return the original length of table 'idx2'
344
+ */
345
+ static int concattable (lua_State *L, int idx1, int idx2) {
346
+ int i;
347
+ int n1 = ktablelen(L, idx1);
348
+ int n2 = ktablelen(L, idx2);
349
+ if (n1 == 0) return 0; /* nothing to correct */
350
+ for (i = 1; i <= n1; i++) {
351
+ lua_rawgeti(L, idx1, i);
352
+ lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */
353
+ }
354
+ return n2;
355
+ }
356
+
357
+
358
+ /*
359
+ ** Make a merge of ktables from p1 and p2 the ktable for the new
360
+ ** pattern at the top of the stack.
361
+ */
362
+ static int joinktables (lua_State *L, int p1, int p2) {
363
+ int n1, n2;
364
+ lua_getfenv(L, p1); /* get ktables */
365
+ lua_getfenv(L, p2);
366
+ n1 = ktablelen(L, -2);
367
+ n2 = ktablelen(L, -1);
368
+ if (n1 == 0 && n2 == 0) { /* are both tables empty? */
369
+ lua_pop(L, 2); /* nothing to be done; pop tables */
370
+ return 0; /* nothing to correct */
371
+ }
372
+ if (n2 == 0 || lua_equal(L, -2, -1)) { /* second table is empty or equal? */
373
+ lua_pop(L, 1); /* pop 2nd table */
374
+ lua_setfenv(L, -2); /* set 1st ktable into new pattern */
375
+ return 0; /* nothing to correct */
376
+ }
377
+ if (n1 == 0) { /* first table is empty? */
378
+ lua_setfenv(L, -3); /* set 2nd table into new pattern */
379
+ lua_pop(L, 1); /* pop 1st table */
380
+ return 0; /* nothing to correct */
381
+ }
382
+ else {
383
+ lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */
384
+ /* stack: new p; ktable p1; ktable p2; new ktable */
385
+ concattable(L, -3, -1); /* from p1 into new ktable */
386
+ concattable(L, -2, -1); /* from p2 into new ktable */
387
+ lua_setfenv(L, -4); /* new ktable becomes p env */
388
+ lua_pop(L, 2); /* pop other ktables */
389
+ return n1; /* correction for indices from p2 */
390
+ }
391
+ }
392
+
393
+
394
+ static void correctkeys (TTree *tree, int n) {
395
+ if (n == 0) return; /* no correction? */
396
+ tailcall:
397
+ switch (tree->tag) {
398
+ case TOpenCall: case TCall: case TRunTime: case TRule: {
399
+ if (tree->key > 0)
400
+ tree->key += n;
401
+ break;
402
+ }
403
+ case TCapture: {
404
+ if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum)
405
+ tree->key += n;
406
+ break;
407
+ }
408
+ default: break;
409
+ }
410
+ switch (numsiblings[tree->tag]) {
411
+ case 1: /* correctkeys(sib1(tree), n); */
412
+ tree = sib1(tree); goto tailcall;
413
+ case 2:
414
+ correctkeys(sib1(tree), n);
415
+ tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */
416
+ default: assert(numsiblings[tree->tag] == 0); break;
417
+ }
418
+ }
419
+
420
+
421
+ /*
422
+ ** copy 'ktable' of element 'idx' to new tree (on top of stack)
423
+ */
424
+ static void copyktable (lua_State *L, int idx) {
425
+ lua_getfenv(L, idx);
426
+ lua_setfenv(L, -2);
427
+ }
428
+
429
+
430
+ /*
431
+ ** merge 'ktable' from rule at stack index 'idx' into 'ktable'
432
+ ** from tree at the top of the stack, and correct corresponding
433
+ ** tree.
434
+ */
435
+ static void mergektable (lua_State *L, int idx, TTree *rule) {
436
+ int n;
437
+ lua_getfenv(L, -1); /* get ktables */
438
+ lua_getfenv(L, idx);
439
+ n = concattable(L, -1, -2);
440
+ lua_pop(L, 2); /* remove both ktables */
441
+ correctkeys(rule, n);
442
+ }
443
+
444
+
445
+ /*
446
+ ** create a new tree, whith a new root and one sibling.
447
+ ** Sibling must be on the Lua stack, at index 1.
448
+ */
449
+ static TTree *newroot1sib (lua_State *L, int tag) {
450
+ int s1;
451
+ TTree *tree1 = getpatt(L, 1, &s1);
452
+ TTree *tree = newtree(L, 1 + s1); /* create new tree */
453
+ tree->tag = tag;
454
+ memcpy(sib1(tree), tree1, s1 * sizeof(TTree));
455
+ copyktable(L, 1);
456
+ return tree;
457
+ }
458
+
459
+
460
+ /*
461
+ ** create a new tree, whith a new root and 2 siblings.
462
+ ** Siblings must be on the Lua stack, first one at index 1.
463
+ */
464
+ static TTree *newroot2sib (lua_State *L, int tag) {
465
+ int s1, s2;
466
+ TTree *tree1 = getpatt(L, 1, &s1);
467
+ TTree *tree2 = getpatt(L, 2, &s2);
468
+ TTree *tree = newtree(L, 1 + s1 + s2); /* create new tree */
469
+ tree->tag = tag;
470
+ tree->u.ps = 1 + s1;
471
+ memcpy(sib1(tree), tree1, s1 * sizeof(TTree));
472
+ memcpy(sib2(tree), tree2, s2 * sizeof(TTree));
473
+ correctkeys(sib2(tree), joinktables(L, 1, 2));
474
+ return tree;
475
+ }
476
+
477
+
478
+ static int lp_P (lua_State *L) {
479
+ luaL_checkany(L, 1);
480
+ getpatt(L, 1, NULL);
481
+ lua_settop(L, 1);
482
+ return 1;
483
+ }
484
+
485
+
486
+ /*
487
+ ** sequence operator; optimizations:
488
+ ** false x => false, x true => x, true x => x
489
+ ** (cannot do x . false => false because x may have runtime captures)
490
+ */
491
+ static int lp_seq (lua_State *L) {
492
+ TTree *tree1 = getpatt(L, 1, NULL);
493
+ TTree *tree2 = getpatt(L, 2, NULL);
494
+ if (tree1->tag == TFalse || tree2->tag == TTrue)
495
+ lua_pushvalue(L, 1); /* false . x == false, x . true = x */
496
+ else if (tree1->tag == TTrue)
497
+ lua_pushvalue(L, 2); /* true . x = x */
498
+ else
499
+ newroot2sib(L, TSeq);
500
+ return 1;
501
+ }
502
+
503
+
504
+ /*
505
+ ** choice operator; optimizations:
506
+ ** charset / charset => charset
507
+ ** true / x => true, x / false => x, false / x => x
508
+ ** (x / true is not equivalent to true)
509
+ */
510
+ static int lp_choice (lua_State *L) {
511
+ Charset st1, st2;
512
+ TTree *t1 = getpatt(L, 1, NULL);
513
+ TTree *t2 = getpatt(L, 2, NULL);
514
+ if (tocharset(t1, &st1) && tocharset(t2, &st2)) {
515
+ TTree *t = newcharset(L);
516
+ loopset(i, treebuffer(t)[i] = st1.cs[i] | st2.cs[i]);
517
+ }
518
+ else if (nofail(t1) || t2->tag == TFalse)
519
+ lua_pushvalue(L, 1); /* true / x => true, x / false => x */
520
+ else if (t1->tag == TFalse)
521
+ lua_pushvalue(L, 2); /* false / x => x */
522
+ else
523
+ newroot2sib(L, TChoice);
524
+ return 1;
525
+ }
526
+
527
+
528
+ /*
529
+ ** p^n
530
+ */
531
+ static int lp_star (lua_State *L) {
532
+ int size1;
533
+ int n = (int)luaL_checkinteger(L, 2);
534
+ TTree *tree1 = getpatt(L, 1, &size1);
535
+ if (n >= 0) { /* seq tree1 (seq tree1 ... (seq tree1 (rep tree1))) */
536
+ TTree *tree = newtree(L, (n + 1) * (size1 + 1));
537
+ if (nullable(tree1))
538
+ luaL_error(L, "loop body may accept empty string");
539
+ while (n--) /* repeat 'n' times */
540
+ tree = seqaux(tree, tree1, size1);
541
+ tree->tag = TRep;
542
+ memcpy(sib1(tree), tree1, size1 * sizeof(TTree));
543
+ }
544
+ else { /* choice (seq tree1 ... choice tree1 true ...) true */
545
+ TTree *tree;
546
+ n = -n;
547
+ /* size = (choice + seq + tree1 + true) * n, but the last has no seq */
548
+ tree = newtree(L, n * (size1 + 3) - 1);
549
+ for (; n > 1; n--) { /* repeat (n - 1) times */
550
+ tree->tag = TChoice; tree->u.ps = n * (size1 + 3) - 2;
551
+ sib2(tree)->tag = TTrue;
552
+ tree = sib1(tree);
553
+ tree = seqaux(tree, tree1, size1);
554
+ }
555
+ tree->tag = TChoice; tree->u.ps = size1 + 1;
556
+ sib2(tree)->tag = TTrue;
557
+ memcpy(sib1(tree), tree1, size1 * sizeof(TTree));
558
+ }
559
+ copyktable(L, 1);
560
+ return 1;
561
+ }
562
+
563
+
564
+ /*
565
+ ** #p == &p
566
+ */
567
+ static int lp_and (lua_State *L) {
568
+ newroot1sib(L, TAnd);
569
+ return 1;
570
+ }
571
+
572
+
573
+ /*
574
+ ** -p == !p
575
+ */
576
+ static int lp_not (lua_State *L) {
577
+ newroot1sib(L, TNot);
578
+ return 1;
579
+ }
580
+
581
+
582
+ /*
583
+ ** [t1 - t2] == Seq (Not t2) t1
584
+ ** If t1 and t2 are charsets, make their difference.
585
+ */
586
+ static int lp_sub (lua_State *L) {
587
+ Charset st1, st2;
588
+ int s1, s2;
589
+ TTree *t1 = getpatt(L, 1, &s1);
590
+ TTree *t2 = getpatt(L, 2, &s2);
591
+ if (tocharset(t1, &st1) && tocharset(t2, &st2)) {
592
+ TTree *t = newcharset(L);
593
+ loopset(i, treebuffer(t)[i] = st1.cs[i] & ~st2.cs[i]);
594
+ }
595
+ else {
596
+ TTree *tree = newtree(L, 2 + s1 + s2);
597
+ tree->tag = TSeq; /* sequence of... */
598
+ tree->u.ps = 2 + s2;
599
+ sib1(tree)->tag = TNot; /* ...not... */
600
+ memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */
601
+ memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */
602
+ correctkeys(sib1(tree), joinktables(L, 1, 2));
603
+ }
604
+ return 1;
605
+ }
606
+
607
+
608
+ static int lp_set (lua_State *L) {
609
+ size_t l;
610
+ const char *s = luaL_checklstring(L, 1, &l);
611
+ TTree *tree = newcharset(L);
612
+ while (l--) {
613
+ setchar(treebuffer(tree), (byte)(*s));
614
+ s++;
615
+ }
616
+ return 1;
617
+ }
618
+
619
+
620
+ static int lp_range (lua_State *L) {
621
+ int arg;
622
+ int top = lua_gettop(L);
623
+ TTree *tree = newcharset(L);
624
+ for (arg = 1; arg <= top; arg++) {
625
+ int c;
626
+ size_t l;
627
+ const char *r = luaL_checklstring(L, arg, &l);
628
+ luaL_argcheck(L, l == 2, arg, "range must have two characters");
629
+ for (c = (byte)r[0]; c <= (byte)r[1]; c++)
630
+ setchar(treebuffer(tree), c);
631
+ }
632
+ return 1;
633
+ }
634
+
635
+
636
+ /*
637
+ ** Look-behind predicate
638
+ */
639
+ static int lp_behind (lua_State *L) {
640
+ TTree *tree;
641
+ TTree *tree1 = getpatt(L, 1, NULL);
642
+ int n = fixedlen(tree1);
643
+ luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length");
644
+ luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures");
645
+ luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind");
646
+ tree = newroot1sib(L, TBehind);
647
+ tree->u.n = n;
648
+ return 1;
649
+ }
650
+
651
+
652
+ /*
653
+ ** Create a non-terminal
654
+ */
655
+ static int lp_V (lua_State *L) {
656
+ TTree *tree = newleaf(L, TOpenCall);
657
+ luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected");
658
+ tree->key = addtoktable(L, 1);
659
+ return 1;
660
+ }
661
+
662
+
663
+ /*
664
+ ** Create a tree for a non-empty capture, with a body and
665
+ ** optionally with an associated Lua value (at index 'labelidx' in the
666
+ ** stack)
667
+ */
668
+ static int capture_aux (lua_State *L, int cap, int labelidx) {
669
+ TTree *tree = newroot1sib(L, TCapture);
670
+ tree->cap = cap;
671
+ tree->key = addtoktable(L, labelidx);
672
+ return 1;
673
+ }
674
+
675
+
676
+ /*
677
+ ** Fill a tree with an empty capture, using an empty (TTrue) sibling.
678
+ */
679
+ static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) {
680
+ tree->tag = TCapture;
681
+ tree->cap = cap;
682
+ tree->key = addtoktable(L, idx);
683
+ sib1(tree)->tag = TTrue;
684
+ return tree;
685
+ }
686
+
687
+
688
+ /*
689
+ ** Create a tree for an empty capture
690
+ */
691
+ static TTree *newemptycap (lua_State *L, int cap, int idx) {
692
+ return auxemptycap(L, newtree(L, 2), cap, idx);
693
+ }
694
+
695
+
696
+ /*
697
+ ** Captures with syntax p / v
698
+ ** (function capture, query capture, string capture, or number capture)
699
+ */
700
+ static int lp_divcapture (lua_State *L) {
701
+ switch (lua_type(L, 2)) {
702
+ case LUA_TFUNCTION: return capture_aux(L, Cfunction, 2);
703
+ case LUA_TTABLE: return capture_aux(L, Cquery, 2);
704
+ case LUA_TSTRING: return capture_aux(L, Cstring, 2);
705
+ case LUA_TNUMBER: {
706
+ int n = lua_tointeger(L, 2);
707
+ TTree *tree = newroot1sib(L, TCapture);
708
+ luaL_argcheck(L, 0 <= n && n <= SHRT_MAX, 1, "invalid number");
709
+ tree->cap = Cnum;
710
+ tree->key = n;
711
+ return 1;
712
+ }
713
+ default: return luaL_argerror(L, 2, "invalid replacement value");
714
+ }
715
+ }
716
+
717
+
718
+ static int lp_substcapture (lua_State *L) {
719
+ return capture_aux(L, Csubst, 0);
720
+ }
721
+
722
+
723
+ static int lp_tablecapture (lua_State *L) {
724
+ return capture_aux(L, Ctable, 0);
725
+ }
726
+
727
+
728
+ static int lp_groupcapture (lua_State *L) {
729
+ if (lua_isnoneornil(L, 2))
730
+ return capture_aux(L, Cgroup, 0);
731
+ else {
732
+ luaL_checkstring(L, 2);
733
+ return capture_aux(L, Cgroup, 2);
734
+ }
735
+ }
736
+
737
+
738
+ static int lp_foldcapture (lua_State *L) {
739
+ luaL_checktype(L, 2, LUA_TFUNCTION);
740
+ return capture_aux(L, Cfold, 2);
741
+ }
742
+
743
+
744
+ static int lp_simplecapture (lua_State *L) {
745
+ return capture_aux(L, Csimple, 0);
746
+ }
747
+
748
+
749
+ static int lp_poscapture (lua_State *L) {
750
+ newemptycap(L, Cposition, 0);
751
+ return 1;
752
+ }
753
+
754
+
755
+ static int lp_argcapture (lua_State *L) {
756
+ int n = (int)luaL_checkinteger(L, 1);
757
+ TTree *tree = newemptycap(L, Carg, 0);
758
+ tree->key = n;
759
+ luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index");
760
+ return 1;
761
+ }
762
+
763
+
764
+ static int lp_backref (lua_State *L) {
765
+ luaL_checkstring(L, 1);
766
+ newemptycap(L, Cbackref, 1);
767
+ return 1;
768
+ }
769
+
770
+
771
+ /*
772
+ ** Constant capture
773
+ */
774
+ static int lp_constcapture (lua_State *L) {
775
+ int i;
776
+ int n = lua_gettop(L); /* number of values */
777
+ if (n == 0) /* no values? */
778
+ newleaf(L, TTrue); /* no capture */
779
+ else if (n == 1)
780
+ newemptycap(L, Cconst, 1); /* single constant capture */
781
+ else { /* create a group capture with all values */
782
+ TTree *tree = newtree(L, 1 + 3 * (n - 1) + 2);
783
+ tree->tag = TCapture;
784
+ tree->cap = Cgroup;
785
+ tree->key = 0;
786
+ tree = sib1(tree);
787
+ for (i = 1; i <= n - 1; i++) {
788
+ tree->tag = TSeq;
789
+ tree->u.ps = 3; /* skip TCapture and its sibling */
790
+ auxemptycap(L, sib1(tree), Cconst, i);
791
+ tree = sib2(tree);
792
+ }
793
+ auxemptycap(L, tree, Cconst, i);
794
+ }
795
+ return 1;
796
+ }
797
+
798
+
799
+ static int lp_matchtime (lua_State *L) {
800
+ TTree *tree;
801
+ luaL_checktype(L, 2, LUA_TFUNCTION);
802
+ tree = newroot1sib(L, TRunTime);
803
+ tree->key = addtoktable(L, 2);
804
+ return 1;
805
+ }
806
+
807
+ /* }====================================================== */
808
+
809
+
810
+ /*
811
+ ** {======================================================
812
+ ** Grammar - Tree generation
813
+ ** =======================================================
814
+ */
815
+
816
+ /*
817
+ ** push on the stack the index and the pattern for the
818
+ ** initial rule of grammar at index 'arg' in the stack;
819
+ ** also add that index into position table.
820
+ */
821
+ static void getfirstrule (lua_State *L, int arg, int postab) {
822
+ lua_rawgeti(L, arg, 1); /* access first element */
823
+ if (lua_isstring(L, -1)) { /* is it the name of initial rule? */
824
+ lua_pushvalue(L, -1); /* duplicate it to use as key */
825
+ lua_gettable(L, arg); /* get associated rule */
826
+ }
827
+ else {
828
+ lua_pushinteger(L, 1); /* key for initial rule */
829
+ lua_insert(L, -2); /* put it before rule */
830
+ }
831
+ if (!testpattern(L, -1)) { /* initial rule not a pattern? */
832
+ if (lua_isnil(L, -1))
833
+ luaL_error(L, "grammar has no initial rule");
834
+ else
835
+ luaL_error(L, "initial rule '%s' is not a pattern", lua_tostring(L, -2));
836
+ }
837
+ lua_pushvalue(L, -2); /* push key */
838
+ lua_pushinteger(L, 1); /* push rule position (after TGrammar) */
839
+ lua_settable(L, postab); /* insert pair at position table */
840
+ }
841
+
842
+ /*
843
+ ** traverse grammar at index 'arg', pushing all its keys and patterns
844
+ ** into the stack. Create a new table (before all pairs key-pattern) to
845
+ ** collect all keys and their associated positions in the final tree
846
+ ** (the "position table").
847
+ ** Return the number of rules and (in 'totalsize') the total size
848
+ ** for the new tree.
849
+ */
850
+ static int collectrules (lua_State *L, int arg, int *totalsize) {
851
+ int n = 1; /* to count number of rules */
852
+ int postab = lua_gettop(L) + 1; /* index of position table */
853
+ int size; /* accumulator for total size */
854
+ lua_newtable(L); /* create position table */
855
+ getfirstrule(L, arg, postab);
856
+ size = 2 + getsize(L, postab + 2); /* TGrammar + TRule + rule */
857
+ lua_pushnil(L); /* prepare to traverse grammar table */
858
+ while (lua_next(L, arg) != 0) {
859
+ if (lua_tonumber(L, -2) == 1 ||
860
+ lua_equal(L, -2, postab + 1)) { /* initial rule? */
861
+ lua_pop(L, 1); /* remove value (keep key for lua_next) */
862
+ continue;
863
+ }
864
+ if (!testpattern(L, -1)) /* value is not a pattern? */
865
+ luaL_error(L, "rule '%s' is not a pattern", val2str(L, -2));
866
+ luaL_checkstack(L, LUA_MINSTACK, "grammar has too many rules");
867
+ lua_pushvalue(L, -2); /* push key (to insert into position table) */
868
+ lua_pushinteger(L, size);
869
+ lua_settable(L, postab);
870
+ size += 1 + getsize(L, -1); /* update size */
871
+ lua_pushvalue(L, -2); /* push key (for next lua_next) */
872
+ n++;
873
+ }
874
+ *totalsize = size + 1; /* TTrue to finish list of rules */
875
+ return n;
876
+ }
877
+
878
+
879
+ static void buildgrammar (lua_State *L, TTree *grammar, int frule, int n) {
880
+ int i;
881
+ TTree *nd = sib1(grammar); /* auxiliary pointer to traverse the tree */
882
+ for (i = 0; i < n; i++) { /* add each rule into new tree */
883
+ int ridx = frule + 2*i + 1; /* index of i-th rule */
884
+ int rulesize;
885
+ TTree *rn = gettree(L, ridx, &rulesize);
886
+ nd->tag = TRule;
887
+ nd->key = 0;
888
+ nd->cap = i; /* rule number */
889
+ nd->u.ps = rulesize + 1; /* point to next rule */
890
+ memcpy(sib1(nd), rn, rulesize * sizeof(TTree)); /* copy rule */
891
+ mergektable(L, ridx, sib1(nd)); /* merge its ktable into new one */
892
+ nd = sib2(nd); /* move to next rule */
893
+ }
894
+ nd->tag = TTrue; /* finish list of rules */
895
+ }
896
+
897
+
898
+ /*
899
+ ** Check whether a tree has potential infinite loops
900
+ */
901
+ static int checkloops (TTree *tree) {
902
+ tailcall:
903
+ if (tree->tag == TRep && nullable(sib1(tree)))
904
+ return 1;
905
+ else if (tree->tag == TGrammar)
906
+ return 0; /* sub-grammars already checked */
907
+ else {
908
+ switch (numsiblings[tree->tag]) {
909
+ case 1: /* return checkloops(sib1(tree)); */
910
+ tree = sib1(tree); goto tailcall;
911
+ case 2:
912
+ if (checkloops(sib1(tree))) return 1;
913
+ /* else return checkloops(sib2(tree)); */
914
+ tree = sib2(tree); goto tailcall;
915
+ default: assert(numsiblings[tree->tag] == 0); return 0;
916
+ }
917
+ }
918
+ }
919
+
920
+
921
+ static int verifyerror (lua_State *L, int *passed, int npassed) {
922
+ int i, j;
923
+ for (i = npassed - 1; i >= 0; i--) { /* search for a repetition */
924
+ for (j = i - 1; j >= 0; j--) {
925
+ if (passed[i] == passed[j]) {
926
+ lua_rawgeti(L, -1, passed[i]); /* get rule's key */
927
+ return luaL_error(L, "rule '%s' may be left recursive", val2str(L, -1));
928
+ }
929
+ }
930
+ }
931
+ return luaL_error(L, "too many left calls in grammar");
932
+ }
933
+
934
+
935
+ /*
936
+ ** Check whether a rule can be left recursive; raise an error in that
937
+ ** case; otherwise return 1 iff pattern is nullable. Assume ktable at
938
+ ** the top of the stack.
939
+ */
940
+ static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed,
941
+ int nullable) {
942
+ tailcall:
943
+ switch (tree->tag) {
944
+ case TChar: case TSet: case TAny:
945
+ case TFalse:
946
+ return nullable; /* cannot pass from here */
947
+ case TTrue:
948
+ case TBehind: /* look-behind cannot have calls */
949
+ return 1;
950
+ case TNot: case TAnd: case TRep:
951
+ /* return verifyrule(L, sib1(tree), passed, npassed, 1); */
952
+ tree = sib1(tree); nullable = 1; goto tailcall;
953
+ case TCapture: case TRunTime:
954
+ /* return verifyrule(L, sib1(tree), passed, npassed); */
955
+ tree = sib1(tree); goto tailcall;
956
+ case TCall:
957
+ /* return verifyrule(L, sib2(tree), passed, npassed); */
958
+ tree = sib2(tree); goto tailcall;
959
+ case TSeq: /* only check 2nd child if first is nullable */
960
+ if (!verifyrule(L, sib1(tree), passed, npassed, 0))
961
+ return nullable;
962
+ /* else return verifyrule(L, sib2(tree), passed, npassed); */
963
+ tree = sib2(tree); goto tailcall;
964
+ case TChoice: /* must check both children */
965
+ nullable = verifyrule(L, sib1(tree), passed, npassed, nullable);
966
+ /* return verifyrule(L, sib2(tree), passed, npassed, nullable); */
967
+ tree = sib2(tree); goto tailcall;
968
+ case TRule:
969
+ if (npassed >= MAXRULES)
970
+ return verifyerror(L, passed, npassed);
971
+ else {
972
+ passed[npassed++] = tree->key;
973
+ /* return verifyrule(L, sib1(tree), passed, npassed); */
974
+ tree = sib1(tree); goto tailcall;
975
+ }
976
+ case TGrammar:
977
+ return nullable(tree); /* sub-grammar cannot be left recursive */
978
+ default: assert(0); return 0;
979
+ }
980
+ }
981
+
982
+
983
+ static void verifygrammar (lua_State *L, TTree *grammar) {
984
+ int passed[MAXRULES];
985
+ TTree *rule;
986
+ /* check left-recursive rules */
987
+ for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) {
988
+ if (rule->key == 0) continue; /* unused rule */
989
+ verifyrule(L, sib1(rule), passed, 0, 0);
990
+ }
991
+ assert(rule->tag == TTrue);
992
+ /* check infinite loops inside rules */
993
+ for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) {
994
+ if (rule->key == 0) continue; /* unused rule */
995
+ if (checkloops(sib1(rule))) {
996
+ lua_rawgeti(L, -1, rule->key); /* get rule's key */
997
+ luaL_error(L, "empty loop in rule '%s'", val2str(L, -1));
998
+ }
999
+ }
1000
+ assert(rule->tag == TTrue);
1001
+ }
1002
+
1003
+
1004
+ /*
1005
+ ** Give a name for the initial rule if it is not referenced
1006
+ */
1007
+ static void initialrulename (lua_State *L, TTree *grammar, int frule) {
1008
+ if (sib1(grammar)->key == 0) { /* initial rule is not referenced? */
1009
+ int n = lua_objlen(L, -1) + 1; /* index for name */
1010
+ lua_pushvalue(L, frule); /* rule's name */
1011
+ lua_rawseti(L, -2, n); /* ktable was on the top of the stack */
1012
+ sib1(grammar)->key = n;
1013
+ }
1014
+ }
1015
+
1016
+
1017
+ static TTree *newgrammar (lua_State *L, int arg) {
1018
+ int treesize;
1019
+ int frule = lua_gettop(L) + 2; /* position of first rule's key */
1020
+ int n = collectrules(L, arg, &treesize);
1021
+ TTree *g = newtree(L, treesize);
1022
+ luaL_argcheck(L, n <= MAXRULES, arg, "grammar has too many rules");
1023
+ g->tag = TGrammar; g->u.n = n;
1024
+ lua_newtable(L); /* create 'ktable' */
1025
+ lua_setfenv(L, -2);
1026
+ buildgrammar(L, g, frule, n);
1027
+ lua_getfenv(L, -1); /* get 'ktable' for new tree */
1028
+ finalfix(L, frule - 1, g, sib1(g));
1029
+ initialrulename(L, g, frule);
1030
+ verifygrammar(L, g);
1031
+ lua_pop(L, 1); /* remove 'ktable' */
1032
+ lua_insert(L, -(n * 2 + 2)); /* move new table to proper position */
1033
+ lua_pop(L, n * 2 + 1); /* remove position table + rule pairs */
1034
+ return g; /* new table at the top of the stack */
1035
+ }
1036
+
1037
+ /* }====================================================== */
1038
+
1039
+
1040
+ static LpegInstruction *prepcompile (lua_State *L, Pattern *p, int idx) {
1041
+ lua_getfenv(L, idx); /* push 'ktable' (may be used by 'finalfix') */
1042
+ finalfix(L, 0, NULL, p->tree);
1043
+ lua_pop(L, 1); /* remove 'ktable' */
1044
+ return compile(L, p);
1045
+ }
1046
+
1047
+
1048
+ static int lp_printtree (lua_State *L) {
1049
+ TTree *tree = getpatt(L, 1, NULL);
1050
+ int c = lua_toboolean(L, 2);
1051
+ if (c) {
1052
+ lua_getfenv(L, 1); /* push 'ktable' (may be used by 'finalfix') */
1053
+ finalfix(L, 0, NULL, tree);
1054
+ lua_pop(L, 1); /* remove 'ktable' */
1055
+ }
1056
+ printktable(L, 1);
1057
+ printtree(tree, 0);
1058
+ return 0;
1059
+ }
1060
+
1061
+
1062
+ static int lp_printcode (lua_State *L) {
1063
+ Pattern *p = getpattern(L, 1);
1064
+ printktable(L, 1);
1065
+ if (p->code == NULL) /* not compiled yet? */
1066
+ prepcompile(L, p, 1);
1067
+ printpatt(p->code, p->codesize);
1068
+ return 0;
1069
+ }
1070
+
1071
+
1072
+ /*
1073
+ ** Get the initial position for the match, interpreting negative
1074
+ ** values from the end of the subject
1075
+ */
1076
+ static size_t initposition (lua_State *L, size_t len) {
1077
+ lua_Integer ii = luaL_optinteger(L, 3, 1);
1078
+ if (ii > 0) { /* positive index? */
1079
+ if ((size_t)ii <= len) /* inside the string? */
1080
+ return (size_t)ii - 1; /* return it (corrected to 0-base) */
1081
+ else return len; /* crop at the end */
1082
+ }
1083
+ else { /* negative index */
1084
+ if ((size_t)(-ii) <= len) /* inside the string? */
1085
+ return len - ((size_t)(-ii)); /* return position from the end */
1086
+ else return 0; /* crop at the beginning */
1087
+ }
1088
+ }
1089
+
1090
+
1091
+ /*
1092
+ ** Main match function
1093
+ */
1094
+ static int lp_match (lua_State *L) {
1095
+ Capture capture[INITCAPSIZE];
1096
+ const char *r;
1097
+ size_t l;
1098
+ Pattern *p = (getpatt(L, 1, NULL), getpattern(L, 1));
1099
+ LpegInstruction *code = (p->code != NULL) ? p->code : prepcompile(L, p, 1);
1100
+ const char *s = luaL_checklstring(L, SUBJIDX, &l);
1101
+ size_t i = initposition(L, l);
1102
+ int ptop = lua_gettop(L);
1103
+ lua_pushnil(L); /* initialize subscache */
1104
+ lua_pushlightuserdata(L, capture); /* initialize caplistidx */
1105
+ lua_getfenv(L, 1); /* initialize penvidx */
1106
+ r = lpeg_match(L, s, s + i, s + l, code, capture, ptop);
1107
+ if (r == NULL) {
1108
+ lua_pushnil(L);
1109
+ return 1;
1110
+ }
1111
+ return getcaptures(L, s, r, ptop);
1112
+ }
1113
+
1114
+
1115
+
1116
+ /*
1117
+ ** {======================================================
1118
+ ** Library creation and functions not related to matching
1119
+ ** =======================================================
1120
+ */
1121
+
1122
+ static int lp_setmax (lua_State *L) {
1123
+ luaL_optinteger(L, 1, -1);
1124
+ lua_settop(L, 1);
1125
+ lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
1126
+ return 0;
1127
+ }
1128
+
1129
+
1130
+ static int lp_version (lua_State *L) {
1131
+ lua_pushstring(L, VERSION);
1132
+ return 1;
1133
+ }
1134
+
1135
+
1136
+ static int lp_type (lua_State *L) {
1137
+ if (testpattern(L, 1))
1138
+ lua_pushliteral(L, "pattern");
1139
+ else
1140
+ lua_pushnil(L);
1141
+ return 1;
1142
+ }
1143
+
1144
+
1145
+ int lp_gc (lua_State *L) {
1146
+ Pattern *p = getpattern(L, 1);
1147
+ if (p->codesize > 0)
1148
+ realloccode(L, p, 0);
1149
+ return 0;
1150
+ }
1151
+
1152
+
1153
+ static void createcat (lua_State *L, const char *catname, int (catf) (int)) {
1154
+ TTree *t = newcharset(L);
1155
+ int i;
1156
+ for (i = 0; i <= UCHAR_MAX; i++)
1157
+ if (catf(i)) setchar(treebuffer(t), i);
1158
+ lua_setfield(L, -2, catname);
1159
+ }
1160
+
1161
+
1162
+ static int lp_locale (lua_State *L) {
1163
+ if (lua_isnoneornil(L, 1)) {
1164
+ lua_settop(L, 0);
1165
+ lua_createtable(L, 0, 12);
1166
+ }
1167
+ else {
1168
+ luaL_checktype(L, 1, LUA_TTABLE);
1169
+ lua_settop(L, 1);
1170
+ }
1171
+ createcat(L, "alnum", isalnum);
1172
+ createcat(L, "alpha", isalpha);
1173
+ createcat(L, "cntrl", iscntrl);
1174
+ createcat(L, "digit", isdigit);
1175
+ createcat(L, "graph", isgraph);
1176
+ createcat(L, "lower", islower);
1177
+ createcat(L, "print", isprint);
1178
+ createcat(L, "punct", ispunct);
1179
+ createcat(L, "space", isspace);
1180
+ createcat(L, "upper", isupper);
1181
+ createcat(L, "xdigit", isxdigit);
1182
+ return 1;
1183
+ }
1184
+
1185
+
1186
+ static struct luaL_Reg pattreg[] = {
1187
+ {"ptree", lp_printtree},
1188
+ {"pcode", lp_printcode},
1189
+ {"match", lp_match},
1190
+ {"B", lp_behind},
1191
+ {"V", lp_V},
1192
+ {"C", lp_simplecapture},
1193
+ {"Cc", lp_constcapture},
1194
+ {"Cmt", lp_matchtime},
1195
+ {"Cb", lp_backref},
1196
+ {"Carg", lp_argcapture},
1197
+ {"Cp", lp_poscapture},
1198
+ {"Cs", lp_substcapture},
1199
+ {"Ct", lp_tablecapture},
1200
+ {"Cf", lp_foldcapture},
1201
+ {"Cg", lp_groupcapture},
1202
+ {"P", lp_P},
1203
+ {"S", lp_set},
1204
+ {"R", lp_range},
1205
+ {"locale", lp_locale},
1206
+ {"version", lp_version},
1207
+ {"setmaxstack", lp_setmax},
1208
+ {"type", lp_type},
1209
+ {NULL, NULL}
1210
+ };
1211
+
1212
+
1213
+ static struct luaL_Reg metareg[] = {
1214
+ {"__mul", lp_seq},
1215
+ {"__add", lp_choice},
1216
+ {"__pow", lp_star},
1217
+ {"__gc", lp_gc},
1218
+ {"__len", lp_and},
1219
+ {"__div", lp_divcapture},
1220
+ {"__unm", lp_not},
1221
+ {"__sub", lp_sub},
1222
+ {NULL, NULL}
1223
+ };
1224
+
1225
+
1226
+ int luaopen_lpeg (lua_State *L);
1227
+ int luaopen_lpeg (lua_State *L) {
1228
+ luaL_newmetatable(L, PATTERN_T);
1229
+ lua_pushnumber(L, MAXBACK); /* initialize maximum backtracking */
1230
+ lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
1231
+ luaL_register(L, NULL, metareg);
1232
+ luaL_register(L, "lpeg", pattreg);
1233
+ lua_pushvalue(L, -1);
1234
+ lua_setfield(L, -3, "__index");
1235
+ return 1;
1236
+ }
1237
+
1238
+ /* }====================================================== */