RPA Toolkit
Start reusing orphan records, instead of just generating waste of space.
[rpatk.git] / rpa2 / rpastat.c
1 #include "rmem.h"
2 #include "rarray.h"
3 #include "rpastat.h"
4 #include "rpaerror.h"
5 #include "rvmcodegen.h"
6 #include "rvmcpu.h"
7 #include "rutf.h"
8 #include "rcharconv.h"
9
10
11 #define RPA_STAT_SETERROR_CODE(__s__, __e__) do { (__s__)->error = __e__; } while (0)
12
13
14 rpastat_t *rpa_stat_create(rpadbex_t *dbex, rulong stacksize)
15 {
16         rpastat_t *stat = (rpastat_t *) r_zmalloc(sizeof(*stat));
17         if (stacksize == 0)
18                 stacksize = RPA_DEFAULT_STACKSIZE;
19         stat->cpu = rpavm_cpu_create(stacksize);
20         stat->cache = rpa_cache_create();
21         if (!stat->cpu) {
22                 r_free(stat);
23                 return NULL;
24         }
25         stat->dbex = dbex;
26         stat->records = r_array_create(sizeof(rparecord_t));
27         stat->emitstack = r_array_create(sizeof(rlong));
28         stat->orphans = r_array_create(sizeof(rlong));
29         stat->cpu->userdata1 = stat;
30
31         return stat;
32 }
33
34
35 void rpa_stat_destroy(rpastat_t *stat)
36 {
37         if (stat) {
38                 if (stat->instack)
39                         r_free(stat->instackbuffer);
40                 r_array_destroy(stat->records);
41                 r_array_destroy(stat->emitstack);
42                 r_array_destroy(stat->orphans);
43                 rpavm_cpu_destroy(stat->cpu);
44                 rpa_cache_destroy(stat->cache);
45                 r_free(stat);
46         }
47 }
48
49
50 void rpa_stat_cachedisable(rpastat_t *stat, ruint disable)
51 {
52         rpa_cache_disable(stat->cache, disable);
53 }
54
55
56 rint rpa_stat_init(rpastat_t *stat, const rchar *input, const rchar *start, const rchar *end)
57 {
58         rulong size;
59
60         if (!stat) {
61                 return -1;
62         }
63         if (start > end) {
64                 return -1;
65         }
66         if (input < start || input > end) {
67                 return -1;
68         }
69         size = end - start;
70         stat->start = start;
71         stat->end = end;
72         stat->input = input;
73         stat->error = 0;
74         r_array_setlength(stat->orphans, 0);
75         r_array_setlength(stat->emitstack, 0);
76         stat->cache->hit = 0;
77         if (stat->instacksize < size) {
78                 stat->instackbuffer = r_realloc(stat->instackbuffer, (size + 2) * sizeof(rpainput_t));
79                 stat->instacksize = size + 1;
80                 stat->instack = &stat->instackbuffer[1];
81                 r_memset(stat->instackbuffer, 0, sizeof(rpainput_t) * 2);
82         }
83         stat->ip.input = input;
84         stat->ip.serial = 0;
85         return 0;
86 }
87
88
89 void rpa_stat_cacheinvalidate(rpastat_t *stat)
90 {
91         rpa_cache_invalidate(stat->cache);
92 }
93
94
95 rint rpa_stat_encodingset(rpastat_t *stat, ruint encoding)
96 {
97         if (!stat) {
98                 return -1;
99         }
100
101         stat->encoding = encoding;
102         return 0;
103 }
104
105
106 static rparecord_t *rpa_stat_nextrecord(rpastat_t *stat, rparecord_t *cur)
107 {
108         if (r_array_empty(stat->records))
109                 return NULL;
110         if (cur == NULL) {
111                 return (rparecord_t *)r_array_slot(stat->records, 0);
112         }
113         if (cur >= (rparecord_t *)r_array_lastslot(stat->records) || cur < (rparecord_t *)r_array_slot(stat->records, 0))
114                 return NULL;
115         cur = (rparecord_t *)r_array_slot(stat->records, cur->next);
116         if (cur->type == RPA_RECORD_TAIL)
117                 return NULL;
118         return cur;
119 }
120
121
122 static void rpa_stat_fixrecords(rpastat_t *stat)
123 {
124         rarray_t *records;
125         rparecord_t *cur = (rparecord_t *)r_array_slot(stat->records, 0);
126
127         cur = rpa_stat_nextrecord(stat, cur);
128         if (!cur) {
129                 /*
130                  * There are no records
131                  */
132                 r_array_setlength(stat->records, 0);
133                 return;
134         }
135         records = (rarray_t *)r_array_create(sizeof(rparecord_t));
136         while (cur) {
137                 r_array_add(records, cur);
138                 cur = rpa_stat_nextrecord(stat, cur);
139         }
140         r_array_destroy(stat->records);
141         stat->records = records;
142 }
143
144
145
146 rlong rpa_stat_exec(rpastat_t *stat, rvm_asmins_t *prog, rword off)
147 {
148         rlong ret;
149
150         if (!stat) {
151                 return -1;
152         }
153         rpa_stat_cacheinvalidate(stat);
154         r_array_setlength(stat->records, 0);
155         RVM_CPUREG_SETU(stat->cpu, SP, 0);
156         RVM_CPUREG_SETU(stat->cpu, FP, 0);
157         RVM_CPUREG_SETL(stat->cpu, R_REC, -1);
158         RVM_CPUREG_SETU(stat->cpu, R_LOO, 0);
159         RVM_CPUREG_SETU(stat->cpu, R_TOP, -1);
160         if (stat->debug) {
161                 ret = rvm_cpu_exec_debug(stat->cpu, prog, off);
162         } else {
163                 ret = rvm_cpu_exec(stat->cpu, prog, off);
164         }
165         if (ret < 0) {
166                 if (stat->cpu->error == RVM_E_USERABORT)
167                         RPA_STAT_SETERROR_CODE(stat, RPA_E_USERABORT);
168                 else
169                         RPA_STAT_SETERROR_CODE(stat, stat->cpu->error);
170                 r_array_setlength(stat->records, 0);
171                 return -1;
172         }
173         rpa_stat_fixrecords(stat);
174         ret = (rlong)RVM_CPUREG_GETL(stat->cpu, R0);
175         if (ret < 0) {
176                 r_array_setlength(stat->records, 0);
177                 return 0;
178         }
179         return ret;
180 }
181
182
183 static rlong rpa_stat_exec_noinit(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end)
184 {
185         rlong topsiz = 0;
186         rpainput_t *ptp;
187
188         rpa_stat_init(stat, input, start, end);
189         if ((topsiz = rpa_stat_exec(stat, rvm_dbex_getexecutable(stat->dbex), rvm_dbex_executableoffset(stat->dbex, rid))) < 0) {
190                 return -1;
191         }
192         if (topsiz <= 0)
193                 return 0;
194         ptp = &stat->instack[topsiz];
195         return (ptp->input - input);
196 }
197
198
199 rlong rpa_stat_scan(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end, const rchar **where)
200 {
201         rlong ret;
202
203         if (!stat) {
204                 return -1;
205         }
206         while (input < end) {
207                 ret = rpa_stat_exec_noinit(stat, rid, input, start, end);
208                 if (ret < 0)
209                         return -1;
210                 if (ret > 0) {
211                         *where = input;
212                         return ret;
213                 }
214                 input += 1;
215         }
216         return ret;
217 }
218
219
220 rlong rpa_stat_match(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end)
221 {
222         if (!stat) {
223                 return -1;
224         }
225
226         return rpa_stat_exec_noinit(stat, rid, input, start, end);
227 }
228
229
230 rlong rpa_stat_parse(rpastat_t *stat, rparule_t rid, const rchar *input, const rchar *start, const rchar *end, rarray_t **records)
231 {
232         rint res = 0;
233
234         if (!stat) {
235                 return -1;
236         }
237
238         res = rpa_stat_exec_noinit(stat, rid, input, start, end);
239         if (res > 0 && !r_array_empty(stat->records) && records) {
240                 *records = stat->records;
241                 stat->records = r_array_create(sizeof(rparecord_t));
242         }
243         return res;
244 }
245
246
247 rint rpa_stat_abort(rpastat_t *stat)
248 {
249         if (!stat) {
250                 return -1;
251         }
252
253         rvm_cpu_abort(stat->cpu);
254         return 0;
255 }
256
257
258 rint rpa_stat_matchchr(rpastat_t *stat, rssize_t top, rulong wc)
259 {
260         rint ret = 0;
261         rpainput_t *in = &stat->instack[top];
262
263         if (in->eof)
264                 return 0;
265         if (stat->encoding & RPA_ENCODING_ICASE) {
266                 ret = (in->wc == wc || in->iwc == wc) ? 1 : 0;
267         } else {
268                 ret = (in->wc == wc) ? 1 : 0;
269         }
270         return ret;
271 }
272
273
274 rint rpa_stat_matchspchr(rpastat_t *stat, rssize_t top, rulong wc)
275 {
276         rint ret = 0;
277         rpainput_t *in = &stat->instack[top];
278
279         if (in->eof)
280                 return 0;
281
282         switch (wc) {
283                 case '.':
284                         return 1;
285                         break;
286                 case 't':
287                         wc = '\t';
288                         break;
289                 case 'r':
290                         wc = '\r';
291                         break;
292                 case 'n':
293                         wc = '\n';
294                         break;
295                 default:
296                         break;
297         };
298
299         ret = (in->wc == wc) ? 1 : 0;
300         return ret;
301 }
302
303
304 rint rpa_stat_matchrng(rpastat_t *stat, rssize_t top, rulong wc1, rulong wc2)
305 {
306         rint ret = 0;
307         rpainput_t *in = &stat->instack[top];
308
309         if (in->eof)
310                 return 0;
311         if (stat->encoding & RPA_ENCODING_ICASE) {
312                 ret = ((in->wc >= wc1 && in->wc <= wc2) || (in->iwc >= wc1 && in->iwc <= wc2)) ? 1 : 0;
313         } else {
314                 ret = ((in->wc >= wc1 && in->wc <= wc2)) ? 1 : 0;
315         }
316         return ret;
317 }
318
319
320 static rint rpa_stat_utf8_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
321 {
322         return r_utf8_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
323 }
324
325
326 static rint rpa_stat_byte_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
327 {
328         if (input >= stat->end) {
329                 *pwc = (unsigned int)0;
330                 return 0;
331         }
332         *pwc = *((const ruchar*)input);
333         return 1;
334 }
335
336
337 static int rpa_stat_utf16_getchar(ruint32 *pwc, rpastat_t *stat, const rchar *input)
338 {
339         return r_utf16_mbtowc(pwc, (const ruchar*)input, (const ruchar*)stat->end);
340 }
341
342
343 rlong rpa_stat_shift(rpastat_t *stat, rssize_t top)
344 {
345         rpainput_t * ptp = &stat->instack[top];
346
347         if (ptp->eof)
348                 return -1;
349         ptp++;
350         top++;
351         if (top >= (rlong)stat->ip.serial) {
352                 rint inc = 0;
353                 ptp->input = stat->ip.input;
354                 if (ptp->input < stat->end) {
355                         switch (stat->encoding & RPA_ENCODING_MASK) {
356                         default:
357                         case RPA_ENCODING_UTF8:
358                                 inc = rpa_stat_utf8_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
359                                 break;
360                         case RPA_ENCODING_UTF16LE:
361                                 inc = rpa_stat_utf16_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
362                                 break;
363                         case RPA_ENCODING_BYTE:
364                                 inc = rpa_stat_byte_getchar(&ptp->wc, stat, (const rchar*)stat->ip.input);
365                                 break;
366                         };
367                         if (stat->encoding & RPA_ENCODING_ICASE)
368                                 ptp->iwc = r_charicase(ptp->wc);
369                         stat->ip.input += inc;
370                         stat->ip.serial += 1;
371                         ptp->eof = 0;
372                 } else {
373                         ptp->wc = (ruint32)-1;
374                         ptp->eof = 1;
375                 }
376         }
377
378         return top;
379 }