RPA Toolkit
Implemented the PHP extension for RPA.
[rpatk.git] / rpa / rpadbex.c
1 /**
2  *\file rpadbex.c
3  */
4
5 #include "rpacompiler.h"
6 #include "rpadbex.h"
7 #include "rpastatpriv.h"
8 #include "rpaparser.h"
9 #include "rpaoptimization.h"
10 #include "rmem.h"
11 #include "rutf.h"
12
13 typedef rinteger (*rpa_dbex_recordhandler)(rpadbex_t *dbex, rlong rec);
14
15 #define RPA_RULEINFO_NONE 0
16 #define RPA_RULEINFO_NAMEDRULE 1
17 #define RPA_RULEINFO_ANONYMOUSRULE 2
18 #define RPA_RULEINFO_DIRECTIVE 3
19
20 #define RPA_DBEX_SETERRINFO_CODE(__d__, __e__) do { (__d__)->err.code = __e__; (__d__)->err.mask |= RPA_ERRINFO_CODE; } while (0)
21 #define RPA_DBEX_SETERRINFO_OFFSET(__d__, __o__) do { (__d__)->err.offset = __o__; (__d__)->err.mask |= RPA_ERRINFO_OFFSET; } while (0)
22 #define RPA_DBEX_SETERRINFO_LINE(__d__, __l__) do { (__d__)->err.line = __l__; (__d__)->err.mask |= RPA_ERRINFO_LINE; } while (0)
23 #define RPA_DBEX_SETERRINFO_RULEID(__d__, __r__) do { (__d__)->err.ruleid = __r__; (__d__)->err.mask |= RPA_ERRINFO_RULEID; } while (0)
24 #define RPA_DBEX_SETERRINFO_NAME(__d__, __n__, __s__) do { \
25         (__d__)->err.mask |= RPA_ERRINFO_NAME; \
26         r_memset((__d__)->err.name, 0, sizeof((__d__)->err.name)); \
27         r_strncpy((__d__)->err.name, __n__, R_MIN(__s__, (sizeof((__d__)->err.name) - 1)));  } while (0)
28
29
30 typedef struct rpa_ruleinfo_s {
31         rlong startrec;
32         rlong sizerecs;
33         rlong codeoff;
34         rlong codesiz;
35         rulong type;
36 } rpa_ruleinfo_t;
37
38
39 struct rpadbex_s {
40         rpa_compiler_t *co;
41         rpa_parser_t *pa;
42         rarray_t *records;
43         rarray_t *temprecords;
44         rharray_t *rules;
45         rarray_t *recstack;
46         rarray_t *inlinestack;
47         rarray_t *text;
48         rpa_dbex_recordhandler *handlers;
49         rpa_errinfo_t err;
50         rulong headoff;
51         rulong optimizations:1;
52         rulong debug:1;
53         rulong compiled:1;
54 };
55
56 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid);
57 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, rlong rec);
58 static rinteger rpa_dbex_rulename(rpadbex_t *dbex, rlong rec, const rchar **name, rsize_t *namesize);
59 static rinteger rpa_parseinfo_loopdetect(rpadbex_t *dbex, rlong parent, rlong loopto);
60 static rlong rpa_dbex_firstinlined(rpadbex_t *dbex);
61 static rinteger rpa_dbex_findinlined(rpadbex_t *dbex, rlong startrec);
62 static rinteger rpa_dbex_playchildrecords(rpadbex_t *dbex, rlong rec);
63 static rinteger rpa_dbex_playreversechildrecords(rpadbex_t *dbex, rlong rec);
64 static rinteger rpa_dbex_playrecord(rpadbex_t *dbex, rlong rec);
65 static rinteger rpa_dbex_rh_default(rpadbex_t *dbex, rlong rec);
66
67
68 void rpa_dbex_debug_recordhead(rpadbex_t *dbex, rlong rec)
69 {
70         if (dbex->debug) {
71                 rarray_t *records = dbex->records;
72                 rparecord_t *prec = (rparecord_t *) r_array_slot(records, rec);
73                 dbex->headoff = rvm_codegen_getcodesize(dbex->co->cg);
74                 if (prec->type & RPA_RECORD_START) {
75                         rpa_record_dump(records, rec);
76                 }
77         }
78
79 }
80
81
82 void rpa_dbex_debug_recordtail(rpadbex_t *dbex, rlong rec)
83 {
84         if (dbex->debug) {
85                 rarray_t *records = dbex->records;
86                 rparecord_t *prec = (rparecord_t *) r_array_slot(records, rec);
87                 rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, dbex->headoff), rvm_codegen_getcodesize(dbex->co->cg) - dbex->headoff);
88                 if (prec->type & RPA_RECORD_END) {
89                         rpa_record_dump(records, rec);
90                 }
91         }
92 }
93
94
95 static rinteger rpa_dbex_rh_default(rpadbex_t *dbex, rlong rec)
96 {
97         rarray_t *records = dbex->records;
98         rparecord_t *prec;
99
100         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
101         prec = rpa_dbex_record(dbex, rec);
102         R_ASSERT(prec);
103         rpa_dbex_debug_recordhead(dbex, rec);
104         rpa_dbex_debug_recordtail(dbex, rec);
105         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
106                 return -1;
107         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
108         prec = rpa_dbex_record(dbex, rec);
109         R_ASSERT(prec);
110         rpa_dbex_debug_recordhead(dbex, rec);
111         rpa_dbex_debug_recordtail(dbex, rec);
112         return 0;
113 }
114
115
116
117 static rinteger rpa_dbex_playrecord(rpadbex_t *dbex, rlong rec)
118 {
119         rarray_t *records = dbex->records;
120         rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
121
122         if (prec->ruleuid >= 0 && prec->ruleuid < RPA_PRODUCTION_COUNT && dbex->handlers[prec->ruleuid]) {
123                 return dbex->handlers[prec->ruleuid](dbex, rec);
124         }
125         return rpa_dbex_rh_default(dbex, rec);
126 }
127
128
129 static rinteger rpa_dbex_playchildrecords(rpadbex_t *dbex, rlong rec)
130 {
131         rlong child;
132         rarray_t *records = dbex->records;
133
134         for (child = rpa_recordtree_firstchild(records, rec, RPA_RECORD_START); child >= 0; child = rpa_recordtree_next(records, child, RPA_RECORD_START)) {
135                 if (rpa_dbex_playrecord(dbex, child) < 0)
136                         return -1;
137         }
138         return 0;
139 }
140
141
142 static rinteger rpa_dbex_playreversechildrecords(rpadbex_t *dbex, rlong rec)
143 {
144         rlong child;
145         rarray_t *records = dbex->records;
146
147         for (child = rpa_recordtree_lastchild(records, rec, RPA_RECORD_START); child >= 0; child = rpa_recordtree_prev(records, child, RPA_RECORD_START)) {
148                 if (rpa_dbex_playrecord(dbex, child) < 0)
149                         return -1;
150         }
151
152         return 0;
153 }
154
155
156 static rlong rpa_dbex_getmatchchr(rulong matchtype)
157 {
158         switch (matchtype & RPA_MATCH_MASK) {
159         default:
160         case RPA_MATCH_NONE:
161                 return RPA_MATCHCHR_NAN;
162                 break;
163         case RPA_MATCH_MULTIPLE:
164                 return RPA_MATCHCHR_MUL;
165                 break;
166         case RPA_MATCH_OPTIONAL:
167                 return RPA_MATCHCHR_OPT;
168                 break;
169         case RPA_MATCH_MULTIOPT:
170                 return RPA_MATCHCHR_MOP;
171                 break;
172         };
173         return RPA_MATCHCHR_NAN;
174 }
175
176
177 static rlong rpa_dbex_getmatchspecialchr(rulong matchtype)
178 {
179         switch (matchtype & RPA_MATCH_MASK) {
180         default:
181         case RPA_MATCH_NONE:
182                 return RPA_MATCHSPCHR_NAN;
183                 break;
184         case RPA_MATCH_MULTIPLE:
185                 return RPA_MATCHSPCHR_MUL;
186                 break;
187         case RPA_MATCH_OPTIONAL:
188                 return RPA_MATCHSPCHR_OPT;
189                 break;
190         case RPA_MATCH_MULTIOPT:
191                 return RPA_MATCHSPCHR_MOP;
192                 break;
193         };
194         return RPA_MATCHSPCHR_NAN;
195 }
196
197
198 static rinteger rpa_record2long(rparecord_t *prec, ruint32 *num)
199 {
200         rchar *endptr = NULL;
201         rchar buffer[64];
202
203         if (!prec || !num || prec->inputsiz == 0 || prec->inputsiz >= sizeof(buffer))
204                 return -1;
205         r_memset(buffer, 0, sizeof(buffer));
206         r_memcpy(buffer, prec->input, prec->inputsiz);
207         if (prec->ruleuid == RPA_PRODUCTION_HEX) {
208                 *num = (ruint32)r_strtoul(prec->input, &endptr, 16);
209         } else if (prec->ruleuid == RPA_PRODUCTION_DEC) {
210                 *num = (ruint32)r_strtoul(prec->input, &endptr, 10);
211         } else {
212                 return -1;
213         }
214         return 0;
215 }
216
217
218 static rinteger rpa_dbex_rh_uid(rpadbex_t *dbex, rlong rec)
219 {
220 /*
221         const rchar *name = NULL;
222         rsize_t namesize;
223         ruint32 uid = 0;
224         rparecord_t *pnumrec;
225         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
226
227         if (prec->type & RPA_RECORD_START) {
228                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
229                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
230                         return -1;
231                 }
232                 pnumrec = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
233                 if (!pnumrec) {
234                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
235                         return -1;
236                 }
237                 if (rpa_record2long(pnumrec, &uid) < 0) {
238                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
239                         return -1;
240                 }
241                 rpa_compiler_rulepref_set_ruleuid(dbex->co, name, namesize, uid);
242                 rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
243         } else if (prec->type & RPA_RECORD_END) {
244
245         }
246         return 0;
247 */
248
249         const rchar *name = NULL;
250         rsize_t namesize;
251         ruint32 uid = 0;
252         rparecord_t *pnumrec;
253         rarray_t *records = dbex->records;
254         rparecord_t *prec;
255
256         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
257         prec = rpa_dbex_record(dbex, rec);
258         R_ASSERT(prec);
259         rpa_dbex_debug_recordhead(dbex, rec);
260         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
261                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
262                 return -1;
263         }
264         pnumrec = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
265         if (!pnumrec) {
266                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
267                 return -1;
268         }
269         if (rpa_record2long(pnumrec, &uid) < 0) {
270                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
271                 return -1;
272         }
273         rpa_compiler_rulepref_set_ruleuid(dbex->co, name, namesize, uid);
274         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
275         rpa_dbex_debug_recordtail(dbex, rec);
276         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
277                 return -1;
278         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
279         prec = rpa_dbex_record(dbex, rec);
280         R_ASSERT(prec);
281         rpa_dbex_debug_recordhead(dbex, rec);
282         rpa_dbex_debug_recordtail(dbex, rec);
283         return 0;
284 }
285
286
287 static rinteger rpa_dbex_rh_abort(rpadbex_t *dbex, rlong rec)
288 {
289         const rchar *name = NULL;
290         rsize_t namesize;
291         rarray_t *records = dbex->records;
292         rparecord_t *prec;
293
294         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
295         prec = rpa_dbex_record(dbex, rec);
296         R_ASSERT(prec);
297         rpa_dbex_debug_recordhead(dbex, rec);
298         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
299                 return -1;
300         }
301         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_ABORTONFAIL);
302         rpa_dbex_debug_recordtail(dbex, rec);
303         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
304                 return -1;
305         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
306         prec = rpa_dbex_record(dbex, rec);
307         R_ASSERT(prec);
308         rpa_dbex_debug_recordhead(dbex, rec);
309         rpa_dbex_debug_recordtail(dbex, rec);
310         return 0;
311 }
312
313
314 static rinteger rpa_dbex_rh_emit(rpadbex_t *dbex, rlong rec)
315 {
316         const rchar *name = NULL;
317         rsize_t namesize;
318         rarray_t *records = dbex->records;
319         rparecord_t *prec;
320
321         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
322         prec = rpa_dbex_record(dbex, rec);
323         R_ASSERT(prec);
324         rpa_dbex_debug_recordhead(dbex, rec);
325         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
326                 return -1;
327         }
328         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
329         rpa_dbex_debug_recordtail(dbex, rec);
330         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
331                 return -1;
332         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
333         prec = rpa_dbex_record(dbex, rec);
334         R_ASSERT(prec);
335         rpa_dbex_debug_recordhead(dbex, rec);
336         rpa_dbex_debug_recordtail(dbex, rec);
337         return 0;
338
339         /*
340         const rchar *name = NULL;
341         rsize_t namesize;
342         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
343
344         if (prec->type & RPA_RECORD_START) {
345                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
346                         return -1;
347                 }
348                 rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
349         } else if (prec->type & RPA_RECORD_END) {
350
351         }
352         return 0;
353         */
354 }
355
356
357 static rinteger rpa_dbex_rh_noemit(rpadbex_t *dbex, rlong rec)
358 {
359         const rchar *name = NULL;
360         rsize_t namesize;
361         rarray_t *records = dbex->records;
362         rparecord_t *prec;
363
364         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
365         prec = rpa_dbex_record(dbex, rec);
366         R_ASSERT(prec);
367         rpa_dbex_debug_recordhead(dbex, rec);
368         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
369                 return -1;
370         }
371         rpa_compiler_rulepref_clear_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
372         rpa_dbex_debug_recordtail(dbex, rec);
373         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
374                 return -1;
375         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
376         prec = rpa_dbex_record(dbex, rec);
377         R_ASSERT(prec);
378         rpa_dbex_debug_recordhead(dbex, rec);
379         rpa_dbex_debug_recordtail(dbex, rec);
380         return 0;
381
382 /*
383         const rchar *name = NULL;
384         rsize_t namesize;
385         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
386
387         if (prec->type & RPA_RECORD_START) {
388                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
389                         return -1;
390                 }
391                 rpa_compiler_rulepref_clear_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
392         } else if (prec->type & RPA_RECORD_END) {
393
394         }
395         return 0;
396 */
397 }
398
399
400 static rinteger rpa_dbex_setemit(rpadbex_t *dbex, rboolean emit)
401 {
402         rlong i;
403         rpa_ruleinfo_t *info;
404
405         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
406                 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
407                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
408                 if (info->type == RPA_RULEINFO_NAMEDRULE) {
409                         if (emit) {
410                                 rpa_compiler_rulepref_set_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
411                         } else {
412                                 rpa_compiler_rulepref_clear_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
413                         }
414                 }
415         }
416         return 0;
417 }
418
419
420 static rinteger rpa_dbex_rh_emitall(rpadbex_t *dbex, rlong rec)
421 {
422         rarray_t *records = dbex->records;
423         rparecord_t *prec;
424
425         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
426         prec = rpa_dbex_record(dbex, rec);
427         R_ASSERT(prec);
428         rpa_dbex_debug_recordhead(dbex, rec);
429         rpa_dbex_setemit(dbex, TRUE);
430         rpa_dbex_debug_recordtail(dbex, rec);
431         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
432                 return -1;
433         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
434         prec = rpa_dbex_record(dbex, rec);
435         R_ASSERT(prec);
436         rpa_dbex_debug_recordhead(dbex, rec);
437         rpa_dbex_debug_recordtail(dbex, rec);
438         return 0;
439
440 /*
441         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
442
443         if (prec->type & RPA_RECORD_START) {
444                 rpa_dbex_setemit(dbex, TRUE);
445         } else if (prec->type & RPA_RECORD_END) {
446
447         }
448         return 0;
449 */
450 }
451
452
453 static rinteger rpa_dbex_rh_emitnone(rpadbex_t *dbex, rlong rec)
454 {
455         rarray_t *records = dbex->records;
456         rparecord_t *prec;
457
458         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
459         prec = rpa_dbex_record(dbex, rec);
460         R_ASSERT(prec);
461         rpa_dbex_debug_recordhead(dbex, rec);
462         rpa_dbex_setemit(dbex, FALSE);
463         rpa_dbex_debug_recordtail(dbex, rec);
464         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
465                 return -1;
466         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
467         prec = rpa_dbex_record(dbex, rec);
468         R_ASSERT(prec);
469         rpa_dbex_debug_recordhead(dbex, rec);
470         rpa_dbex_debug_recordtail(dbex, rec);
471         return 0;
472 /*
473         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
474
475         if (prec->type & RPA_RECORD_START) {
476                 rpa_dbex_setemit(dbex, FALSE);
477         } else if (prec->type & RPA_RECORD_END) {
478
479         }
480         return 0;
481 */
482 }
483
484
485 static rinteger rpa_dbex_rh_namedrule(rpadbex_t *dbex, rlong rec)
486 {
487         const rchar *name = NULL;
488         rsize_t namesize;
489         rarray_t *records = dbex->records;
490         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
491
492         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
493         prec = rpa_dbex_record(dbex, rec);
494         R_ASSERT(prec);
495         rpa_dbex_debug_recordhead(dbex, rec);
496         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
497
498                 return -1;
499         }
500         if (!r_array_empty(dbex->inlinestack)) {
501                 rpa_compiler_inlinerule_begin(dbex->co, name, namesize, 0);
502         } else {
503                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
504                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BL, DA, XX, XX, 3));
505                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
506                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
507
508                 if ((prec->usertype & RPA_LOOP_PATH)) {
509                         rpa_compiler_loop_begin(dbex->co, name, namesize);
510                 } else {
511                         rpa_compiler_rule_begin(dbex->co, name, namesize);
512                 }
513         }
514         r_array_add(dbex->inlinestack, &rec);
515         rpa_dbex_debug_recordtail(dbex, rec);
516         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
517                 return -1;
518         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
519         prec = rpa_dbex_record(dbex, rec);
520         R_ASSERT(prec);
521         rpa_dbex_debug_recordhead(dbex, rec);
522         r_array_removelast(dbex->inlinestack);
523         if (!r_array_empty(dbex->inlinestack)) {
524                 rpa_compiler_inlinerule_end(dbex->co);
525         } else {
526                 if ((prec->usertype & RPA_LOOP_PATH)) {
527                         rpa_compiler_loop_end(dbex->co);
528                 } else {
529                         rpa_compiler_rule_end(dbex->co);
530                 }
531         }
532         rpa_dbex_debug_recordtail(dbex, rec);
533         return 0;
534 }
535
536
537 static rinteger rpa_dbex_rh_anonymousrule(rpadbex_t *dbex, rlong rec)
538 {
539         rarray_t *records = dbex->records;
540         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
541
542         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
543         prec = rpa_dbex_record(dbex, rec);
544         R_ASSERT(prec);
545         rpa_dbex_debug_recordhead(dbex, rec);
546         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
547         rpa_compiler_exp_begin(dbex->co, RPA_MATCH_NONE);
548         rpa_dbex_debug_recordtail(dbex, rec);
549         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
550                 return -1;
551         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
552         prec = rpa_dbex_record(dbex, rec);
553         R_ASSERT(prec);
554         rpa_dbex_debug_recordhead(dbex, rec);
555         rpa_compiler_exp_end(dbex->co);
556         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
557         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
558         rpa_dbex_debug_recordtail(dbex, rec);
559
560         return 0;
561 }
562
563
564 static rinteger rpa_dbex_rh_char(rpadbex_t *dbex, rlong rec)
565 {
566         rparecord_t *prec;
567         rarray_t *records = dbex->records;
568         ruint32 wc = 0;
569
570         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
571         prec = rpa_dbex_record(dbex, rec);
572         R_ASSERT(prec);
573         rpa_dbex_debug_recordhead(dbex, rec);
574         rpa_dbex_debug_recordtail(dbex, rec);
575         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
576                 return -1;
577         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
578         prec = rpa_dbex_record(dbex, rec);
579         R_ASSERT(prec);
580         rpa_dbex_debug_recordhead(dbex, rec);
581         if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
582
583                 return -1;
584         }
585         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
586         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
587         rpa_dbex_debug_recordtail(dbex, rec);
588         return 0;
589 }
590
591
592 static rinteger rpa_dbex_rh_specialchar(rpadbex_t *dbex, rlong rec)
593 {
594         ruint32 wc = 0;
595         rarray_t *records = dbex->records;
596         rparecord_t *prec;
597
598         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
599         prec = rpa_dbex_record(dbex, rec);
600         R_ASSERT(prec);
601         rpa_dbex_debug_recordhead(dbex, rec);
602         rpa_dbex_debug_recordtail(dbex, rec);
603         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
604                 return -1;
605         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
606         prec = rpa_dbex_record(dbex, rec);
607         R_ASSERT(prec);
608         rpa_dbex_debug_recordhead(dbex, rec);
609         if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
610
611                 return -1;
612         }
613         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchspecialchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
614         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
615         rpa_dbex_debug_recordtail(dbex, rec);
616         return 0;
617
618
619 /*
620         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
621
622         if (prec->type & RPA_RECORD_END) {
623                 ruint32 wc = 0;
624                 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
625
626                         return -1;
627                 }
628                 rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchspecialchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
629                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
630         }
631
632         return 0;
633 */
634 }
635
636
637 static rinteger rpa_dbex_rh_cls(rpadbex_t *dbex, rlong rec)
638 {
639         rarray_t *records = dbex->records;
640         rparecord_t *prec;
641
642         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
643         prec = rpa_dbex_record(dbex, rec);
644         R_ASSERT(prec);
645         rpa_dbex_debug_recordhead(dbex, rec);
646         rpa_compiler_class_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
647         rpa_dbex_debug_recordtail(dbex, rec);
648         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
649                 return -1;
650         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
651         prec = rpa_dbex_record(dbex, rec);
652         R_ASSERT(prec);
653         rpa_dbex_debug_recordhead(dbex, rec);
654         rpa_compiler_class_end(dbex->co);
655         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
656         rpa_dbex_debug_recordtail(dbex, rec);
657         return 0;
658
659 /*
660         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
661
662         if (prec->type & RPA_RECORD_START) {
663                 rpa_compiler_class_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
664
665         } else if (prec->type & RPA_RECORD_END) {
666                 rpa_compiler_class_end(dbex->co);
667                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
668         }
669
670         return 0;
671 */
672 }
673
674
675 static rinteger rpa_dbex_rh_clschar(rpadbex_t *dbex, rlong rec)
676 {
677         ruint32 wc = 0;
678         rarray_t *records = dbex->records;
679         rparecord_t *prec;
680
681         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
682         prec = rpa_dbex_record(dbex, rec);
683         R_ASSERT(prec);
684         rpa_dbex_debug_recordhead(dbex, rec);
685         rpa_dbex_debug_recordtail(dbex, rec);
686         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
687                 return -1;
688         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
689         prec = rpa_dbex_record(dbex, rec);
690         R_ASSERT(prec);
691         rpa_dbex_debug_recordhead(dbex, rec);
692         if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
693
694                 return -1;
695         }
696         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, wc));
697         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
698         rpa_dbex_debug_recordtail(dbex, rec);
699         return 0;
700
701
702 /*
703         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
704
705         if (prec->type & RPA_RECORD_END) {
706                 ruint32 wc = 0;
707                 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
708
709                         return -1;
710                 }
711                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, wc));
712                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
713         }
714
715         return 0;
716 */
717 }
718
719
720 static rinteger rpa_dbex_rh_minexp(rpadbex_t *dbex, rlong rec)
721 {
722         rarray_t *records = dbex->records;
723         rparecord_t *prec;
724
725         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
726         prec = rpa_dbex_record(dbex, rec);
727         R_ASSERT(prec);
728         rpa_dbex_debug_recordhead(dbex, rec);
729         rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
730         rpa_dbex_debug_recordtail(dbex, rec);
731         if (rpa_dbex_playreversechildrecords(dbex, rec) < 0)
732                 return -1;
733         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
734         prec = rpa_dbex_record(dbex, rec);
735         R_ASSERT(prec);
736         rpa_dbex_debug_recordhead(dbex, rec);
737         rpa_compiler_exp_end(dbex->co);
738         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
739         rpa_dbex_debug_recordtail(dbex, rec);
740         return 0;
741 }
742
743 static rinteger rpa_dbex_rh_exp(rpadbex_t *dbex, rlong rec)
744 {
745         rarray_t *records = dbex->records;
746         rparecord_t *prec;
747
748         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
749         prec = rpa_dbex_record(dbex, rec);
750         R_ASSERT(prec);
751         rpa_dbex_debug_recordhead(dbex, rec);
752         rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
753         rpa_dbex_debug_recordtail(dbex, rec);
754         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
755                 return -1;
756         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
757         prec = rpa_dbex_record(dbex, rec);
758         R_ASSERT(prec);
759         rpa_dbex_debug_recordhead(dbex, rec);
760         rpa_compiler_exp_end(dbex->co);
761         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
762         rpa_dbex_debug_recordtail(dbex, rec);
763         return 0;
764
765
766 /*
767         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
768
769         if (prec->type & RPA_RECORD_START) {
770                 rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
771
772         } else if (prec->type & RPA_RECORD_END) {
773                 rpa_compiler_exp_end(dbex->co);
774                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
775         }
776
777         return 0;
778 */
779 }
780
781
782 static rinteger rpa_dbex_rh_orop(rpadbex_t *dbex, rlong rec)
783 {
784         rarray_t *records = dbex->records;
785         rparecord_t *prec;
786
787         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
788         prec = rpa_dbex_record(dbex, rec);
789         R_ASSERT(prec);
790         rpa_dbex_debug_recordhead(dbex, rec);
791         rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
792         rpa_dbex_debug_recordtail(dbex, rec);
793         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
794                 return -1;
795         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
796         prec = rpa_dbex_record(dbex, rec);
797         R_ASSERT(prec);
798         rpa_dbex_debug_recordhead(dbex, rec);
799         rpa_compiler_altexp_end(dbex->co);
800         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
801         rpa_dbex_debug_recordtail(dbex, rec);
802         return 0;
803
804
805 /*
806         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
807
808         if (prec->type & RPA_RECORD_START) {
809                 rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
810
811         } else if (prec->type & RPA_RECORD_END) {
812                 rpa_compiler_altexp_end(dbex->co);
813                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
814         }
815
816         return 0;
817 */
818 }
819
820
821 static rinteger rpa_dbex_rh_norop(rpadbex_t *dbex, rlong rec)
822 {
823         rarray_t *records = dbex->records;
824         rparecord_t *prec;
825
826         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
827         prec = rpa_dbex_record(dbex, rec);
828         R_ASSERT(prec);
829         rpa_dbex_debug_recordhead(dbex, rec);
830         rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
831         rpa_dbex_debug_recordtail(dbex, rec);
832         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
833                 return -1;
834         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
835         prec = rpa_dbex_record(dbex, rec);
836         R_ASSERT(prec);
837         rpa_dbex_debug_recordhead(dbex, rec);
838         rpa_compiler_altexp_end(dbex->co);
839         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
840         rpa_dbex_debug_recordtail(dbex, rec);
841         return 0;
842
843
844 /*
845         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
846
847         if (prec->type & RPA_RECORD_START) {
848                 rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
849
850         } else if (prec->type & RPA_RECORD_END) {
851                 rpa_compiler_altexp_end(dbex->co);
852                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
853         }
854
855         return 0;
856 */
857 }
858
859
860 static rinteger rpa_dbex_rh_notop(rpadbex_t *dbex, rlong rec)
861 {
862         rarray_t *records = dbex->records;
863         rparecord_t *prec;
864
865         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
866         prec = rpa_dbex_record(dbex, rec);
867         R_ASSERT(prec);
868         rpa_dbex_debug_recordhead(dbex, rec);
869         rpa_compiler_notexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
870         rpa_dbex_debug_recordtail(dbex, rec);
871         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
872                 return -1;
873         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
874         prec = rpa_dbex_record(dbex, rec);
875         R_ASSERT(prec);
876         rpa_dbex_debug_recordhead(dbex, rec);
877         rpa_compiler_notexp_end(dbex->co);
878         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
879         rpa_dbex_debug_recordtail(dbex, rec);
880         return 0;
881
882
883 /*
884         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
885
886         if (prec->type & RPA_RECORD_START) {
887                 rpa_compiler_notexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
888
889         } else if (prec->type & RPA_RECORD_END) {
890                 rpa_compiler_notexp_end(dbex->co);
891                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
892         }
893
894         return 0;
895 */
896 }
897
898
899 static rinteger rpa_dbex_rh_range(rpadbex_t *dbex, rlong rec)
900 {
901         rarray_t *records = dbex->records;
902         rparecord_t *prec;
903
904         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
905         prec = rpa_dbex_record(dbex, rec);
906         R_ASSERT(prec);
907         rpa_dbex_debug_recordhead(dbex, rec);
908         dbex->co->currange.p1 = 0;
909         dbex->co->currange.p2 = 0;
910         rpa_dbex_debug_recordtail(dbex, rec);
911         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
912                 return -1;
913         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
914         prec = rpa_dbex_record(dbex, rec);
915         R_ASSERT(prec);
916         rpa_dbex_debug_recordhead(dbex, rec);
917         if (dbex->co->currange.p1 < dbex->co->currange.p2)
918                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
919         else
920                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
921         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
922         rpa_dbex_debug_recordtail(dbex, rec);
923         return 0;
924
925
926 /*
927         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
928
929         if (prec->type & RPA_RECORD_START) {
930                 dbex->co->currange.p1 = 0;
931                 dbex->co->currange.p2 = 0;
932         } else if (prec->type & RPA_RECORD_END) {
933                 if (dbex->co->currange.p1 < dbex->co->currange.p2)
934                         rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
935                 else
936                         rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
937                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
938         }
939
940         return 0;
941 */
942 }
943
944
945 static rinteger rpa_dbex_rh_numrange(rpadbex_t *dbex, rlong rec)
946 {
947         rarray_t *records = dbex->records;
948         rparecord_t *prec;
949         rparecord_t *child;
950         /*
951          * Fix me: probably we don't need to access the children from here. There should be a way just to
952          * play them a regular records!
953          */
954
955         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
956         prec = rpa_dbex_record(dbex, rec);
957         R_ASSERT(prec);
958         rpa_dbex_debug_recordhead(dbex, rec);
959         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
960         if (rpa_record2long(child, &dbex->co->currange.p1) < 0)
961                 return -1;
962         child = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
963         if (rpa_record2long(child, &dbex->co->currange.p2) < 0)
964                 return -1;
965         rpa_dbex_debug_recordtail(dbex, rec);
966         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
967                 return -1;
968         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
969         prec = rpa_dbex_record(dbex, rec);
970         R_ASSERT(prec);
971         rpa_dbex_debug_recordhead(dbex, rec);
972         if (dbex->co->currange.p1 < dbex->co->currange.p2)
973                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
974         else
975                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
976         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
977         rpa_dbex_debug_recordtail(dbex, rec);
978         return 0;
979
980
981 /*
982         rparecord_t *prec = (rparecord_t *) rpa_dbex_record(dbex, rec);
983
984         if (!prec)
985                 return -1;
986
987         if (prec->type & RPA_RECORD_START) {
988                 rparecord_t *child;
989                 child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
990                 if (rpa_record2long(child, &dbex->co->currange.p1) < 0)
991                         return -1;
992                 child = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
993                 if (rpa_record2long(child, &dbex->co->currange.p2) < 0)
994                         return -1;
995         } else if (prec->type & RPA_RECORD_END) {
996                 if (dbex->co->currange.p1 < dbex->co->currange.p2)
997                         rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
998                 else
999                         rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
1000                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
1001         }
1002
1003         return 0;
1004 */
1005 }
1006
1007
1008 static rinteger rpa_dbex_rh_clsnum(rpadbex_t *dbex, rlong rec)
1009 {
1010         rarray_t *records = dbex->records;
1011         rparecord_t *prec;
1012         rparecord_t *child;
1013         ruint32 wc;
1014
1015         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
1016         prec = rpa_dbex_record(dbex, rec);
1017         R_ASSERT(prec);
1018         rpa_dbex_debug_recordhead(dbex, rec);
1019         rpa_dbex_debug_recordtail(dbex, rec);
1020         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
1021                 return -1;
1022         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
1023         prec = rpa_dbex_record(dbex, rec);
1024         R_ASSERT(prec);
1025         rpa_dbex_debug_recordhead(dbex, rec);
1026         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
1027         if (rpa_record2long(child, &wc) < 0)
1028                 return -1;
1029         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
1030         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
1031         rpa_dbex_debug_recordtail(dbex, rec);
1032         return 0;
1033
1034 /*
1035         rparecord_t *prec = (rparecord_t *) rpa_dbex_record(dbex, rec);
1036
1037         if (!prec)
1038                 return -1;
1039         if (prec->type & RPA_RECORD_START) {
1040
1041         } else if (prec->type & RPA_RECORD_END) {
1042                 ruint32 wc;
1043                 rparecord_t *child;
1044                 child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
1045                 if (rpa_record2long(child, &wc) < 0)
1046                         return -1;
1047                 rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
1048                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
1049         }
1050
1051         return 0;
1052 */
1053 }
1054
1055
1056 static rinteger rpa_dbex_rh_beginchar(rpadbex_t *dbex, rlong rec)
1057 {
1058         rarray_t *records = dbex->records;
1059         rparecord_t *prec;
1060         ruint32 wc = 0;
1061
1062         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
1063         prec = rpa_dbex_record(dbex, rec);
1064         R_ASSERT(prec);
1065         rpa_dbex_debug_recordhead(dbex, rec);
1066         rpa_dbex_debug_recordtail(dbex, rec);
1067         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
1068                 return -1;
1069         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
1070         prec = rpa_dbex_record(dbex, rec);
1071         R_ASSERT(prec);
1072         rpa_dbex_debug_recordhead(dbex, rec);
1073         if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
1074
1075                 return -1;
1076         }
1077         dbex->co->currange.p1 = wc;
1078         rpa_dbex_debug_recordtail(dbex, rec);
1079         return 0;
1080
1081 /*
1082         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
1083
1084         if (prec->type & RPA_RECORD_START) {
1085
1086         } else if (prec->type & RPA_RECORD_END) {
1087                 ruint32 wc = 0;
1088                 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
1089
1090                         return -1;
1091                 }
1092                 dbex->co->currange.p1 = wc;
1093         }
1094
1095         return 0;
1096 */
1097 }
1098
1099
1100 static rinteger rpa_dbex_rh_endchar(rpadbex_t *dbex, rlong rec)
1101 {
1102         rarray_t *records = dbex->records;
1103         rparecord_t *prec;
1104         ruint32 wc = 0;
1105
1106         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
1107         prec = rpa_dbex_record(dbex, rec);
1108         R_ASSERT(prec);
1109         rpa_dbex_debug_recordhead(dbex, rec);
1110         rpa_dbex_debug_recordtail(dbex, rec);
1111         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
1112                 return -1;
1113         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
1114         prec = rpa_dbex_record(dbex, rec);
1115         R_ASSERT(prec);
1116         rpa_dbex_debug_recordhead(dbex, rec);
1117         if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
1118
1119                 return -1;
1120         }
1121         dbex->co->currange.p2 = wc;
1122         rpa_dbex_debug_recordtail(dbex, rec);
1123         return 0;
1124
1125 /*
1126         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
1127
1128         if (prec->type & RPA_RECORD_START) {
1129
1130         } else if (prec->type & RPA_RECORD_END) {
1131                 ruint32 wc = 0;
1132                 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
1133
1134                         return -1;
1135                 }
1136                 dbex->co->currange.p2 = wc;
1137         }
1138         return 0;
1139 */
1140 }
1141
1142
1143 static rinteger rpa_dbex_rh_branch(rpadbex_t *dbex, rlong rec)
1144 {
1145         rarray_t *records = dbex->records;
1146         rparecord_t *prec;
1147
1148         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
1149         prec = rpa_dbex_record(dbex, rec);
1150         R_ASSERT(prec);
1151         rpa_dbex_debug_recordhead(dbex, rec);
1152         if (prec->usertype & RPA_NONLOOP_PATH) {
1153                 rpa_compiler_nonloopybranch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
1154         } else {
1155                 rpa_compiler_branch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
1156         }
1157         rpa_dbex_debug_recordtail(dbex, rec);
1158         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
1159                 return -1;
1160         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
1161         prec = rpa_dbex_record(dbex, rec);
1162         R_ASSERT(prec);
1163         rpa_dbex_debug_recordhead(dbex, rec);
1164         if (prec->usertype & RPA_NONLOOP_PATH) {
1165                 rpa_compiler_nonloopybranch_end(dbex->co);
1166         } else {
1167                 rpa_compiler_branch_end(dbex->co);
1168         }
1169         rpa_dbex_debug_recordtail(dbex, rec);
1170         return 0;
1171
1172 /*
1173         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
1174
1175         if (prec->type & RPA_RECORD_START) {
1176                 if (prec->usertype & RPA_NONLOOP_PATH) {
1177                         rpa_compiler_nonloopybranch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
1178                 } else {
1179                         rpa_compiler_branch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
1180                 }
1181         } else if (prec->type & RPA_RECORD_END) {
1182
1183                 if (prec->usertype & RPA_NONLOOP_PATH) {
1184                         rpa_compiler_nonloopybranch_end(dbex->co);
1185                 } else {
1186                         rpa_compiler_branch_end(dbex->co);
1187                 }
1188
1189         }
1190         return 0;
1191 */
1192 }
1193
1194
1195 static void rpa_dbex_rh_loopref(rpadbex_t *dbex, rparecord_t *prec)
1196 {
1197         /*
1198          * We ignore, it doesn't make sense for loops:
1199          * RPA_MATCH_MULTIPLE
1200          */
1201         rpa_compiler_exp_begin(dbex->co, (prec->usertype & RPA_MATCH_OPTIONAL));
1202         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
1203         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 3));
1204         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
1205         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1206         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_ADD, R_TOP, R_TOP, R_LOO, 0));
1207         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, R_LOO, XX, 0));
1208         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1209         rpa_compiler_exp_end(dbex->co);
1210 //      rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1211
1212 }
1213
1214
1215 static rinteger rpa_dbex_rh_aref(rpadbex_t *dbex, rlong rec)
1216 {
1217         const rchar *name = NULL;
1218         rsize_t namesize;
1219         rpa_ruleinfo_t *info;
1220         rarray_t *records = dbex->records;
1221         rparecord_t *prec;
1222
1223         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
1224         prec = rpa_dbex_record(dbex, rec);
1225         R_ASSERT(prec);
1226         rpa_dbex_debug_recordhead(dbex, rec);
1227         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
1228
1229                 return -1;
1230         }
1231
1232         if ((prec->usertype & RPA_LOOP_PATH) && rpa_parseinfo_loopdetect(dbex, rec, rpa_dbex_firstinlined(dbex))) {
1233                 info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1234                 if (!info) {
1235                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVED_SYMBOL);
1236                         RPA_DBEX_SETERRINFO_NAME(dbex, name, namesize);
1237                         return -1;
1238                 }
1239                 if (rpa_dbex_findinlined(dbex, info->startrec)) {
1240                         rpa_dbex_rh_loopref(dbex, prec);
1241                 } else {
1242                         if (prec->usertype & RPA_MATCH_OPTIONAL) {
1243                                 /*
1244                                  * Most probably this is useless case - loop refs shouldn't have quantitative modifiers
1245                                  * but in case they do we wrap the inlined production rule in quantitative expression.
1246                                  * The inlined named rule can take the quantitative argument, but I just don't have
1247                                  * a clean way to pass it from here - so, lets play the records inside an expression that
1248                                  * has the right quantitative argument.
1249                                  * We ignore, it doesn't make sense for loops:
1250                                  * RPA_MATCH_MULTIPLE
1251                                  */
1252                                 rpa_compiler_exp_begin(dbex->co, RPA_MATCH_OPTIONAL);
1253                                 rpa_dbex_playrecord(dbex, info->startrec);
1254                                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1255                                 rpa_compiler_exp_end(dbex->co);
1256                         } else {
1257                                 rpa_dbex_playrecord(dbex, info->startrec);
1258                         }
1259                 }
1260         } else {
1261                 rpa_compiler_reference(dbex->co, name, namesize, (prec->usertype & RPA_MATCH_MASK));
1262         }
1263         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1264         rpa_dbex_debug_recordtail(dbex, rec);
1265         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
1266                 return -1;
1267         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
1268         prec = rpa_dbex_record(dbex, rec);
1269         R_ASSERT(prec);
1270         rpa_dbex_debug_recordhead(dbex, rec);
1271         rpa_dbex_debug_recordtail(dbex, rec);
1272         return 0;
1273
1274
1275 #if 0
1276         const rchar *name = NULL;
1277         rsize_t namesize;
1278         rpa_ruleinfo_t *info;
1279         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
1280
1281         if (prec->type & RPA_RECORD_START) {
1282                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
1283
1284                         return -1;
1285                 }
1286
1287                 if ((prec->usertype & RPA_LOOP_PATH) && rpa_parseinfo_loopdetect(dbex, rec, rpa_dbex_firstinlined(dbex))) {
1288                         info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1289                         if (!info) {
1290                                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVED_SYMBOL);
1291                                 RPA_DBEX_SETERRINFO_NAME(dbex, name, namesize);
1292                                 return -1;
1293                         }
1294                         if (rpa_dbex_findinlined(dbex, info->startrec)) {
1295                                 rpa_dbex_rh_loopref(dbex, prec);
1296                         } else {
1297                                 if (prec->usertype & RPA_MATCH_OPTIONAL) {
1298                                         /*
1299                                          * Most probably this is useless case - loop refs shouldn't have quantitative modifiers
1300                                          * but in case they do we wrap the inlined production rule in quantitative expression.
1301                                          * The inlined named rule can take the quantitative argument, but I just don't have
1302                                          * a clean way to pass it from here - so, lets play the records inside an expression that
1303                                          * has the right quantitative argument.
1304                                          * We ignore, it doesn't make sense for loops:
1305                                          * RPA_MATCH_MULTIPLE
1306                                          */
1307                                         rpa_compiler_exp_begin(dbex->co, RPA_MATCH_OPTIONAL);
1308                                         rpa_dbex_play_recordhandlers(dbex, info->startrec, info->sizerecs);
1309                                         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1310                                         rpa_compiler_exp_end(dbex->co);
1311                                 } else {
1312                                         rpa_dbex_play_recordhandlers(dbex, info->startrec, info->sizerecs);
1313                                 }
1314                         }
1315                 } else {
1316                         rpa_compiler_reference(dbex->co, name, namesize, (prec->usertype & RPA_MATCH_MASK));
1317                 }
1318                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
1319
1320         } else if (prec->type & RPA_RECORD_END) {
1321
1322         }
1323         return 0;
1324 #endif
1325 }
1326
1327
1328 rpadbex_t *rpa_dbex_create(void)
1329 {
1330         rpadbex_t *dbex = (rpadbex_t *) r_zmalloc(sizeof(*dbex));
1331
1332         dbex->co = rpa_compiler_create();
1333         dbex->pa = rpa_parser_create();
1334         dbex->text = r_array_create(sizeof(rchar *));
1335         dbex->records = r_array_create(sizeof(rparecord_t));
1336         dbex->temprecords = r_array_create(sizeof(rparecord_t));
1337         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
1338         dbex->recstack = r_array_create(sizeof(rulong));
1339         dbex->inlinestack = r_array_create(sizeof(rulong));
1340         dbex->handlers = r_zmalloc(sizeof(rpa_dbex_recordhandler) * RPA_PRODUCTION_COUNT);
1341         rpa_dbex_cfgset(dbex, RPA_DBEXCFG_OPTIMIZATIONS, 1);
1342
1343         dbex->handlers[RPA_PRODUCTION_NONE] = rpa_dbex_rh_default;
1344         dbex->handlers[RPA_PRODUCTION_NAMEDRULE] = rpa_dbex_rh_namedrule;
1345         dbex->handlers[RPA_PRODUCTION_ANONYMOUSRULE] = rpa_dbex_rh_anonymousrule;
1346         dbex->handlers[RPA_PRODUCTION_CLS] = rpa_dbex_rh_cls;
1347         dbex->handlers[RPA_PRODUCTION_CHAR] = rpa_dbex_rh_char;
1348         dbex->handlers[RPA_PRODUCTION_SPECIALCHAR] = rpa_dbex_rh_specialchar;
1349         dbex->handlers[RPA_PRODUCTION_CLSCHAR] = rpa_dbex_rh_clschar;
1350         dbex->handlers[RPA_PRODUCTION_AREF] = rpa_dbex_rh_aref;
1351         dbex->handlers[RPA_PRODUCTION_CREF] = rpa_dbex_rh_aref;
1352         dbex->handlers[RPA_PRODUCTION_BRACKETEXP] = rpa_dbex_rh_exp;
1353         dbex->handlers[RPA_PRODUCTION_OROP] = rpa_dbex_rh_orop;
1354         dbex->handlers[RPA_PRODUCTION_NOTOP] = rpa_dbex_rh_notop;
1355         dbex->handlers[RPA_PRODUCTION_ALTBRANCH] = rpa_dbex_rh_branch;
1356         dbex->handlers[RPA_PRODUCTION_NEGBRANCH] = rpa_dbex_rh_branch;
1357         dbex->handlers[RPA_PRODUCTION_CHARRNG] = rpa_dbex_rh_range;
1358         dbex->handlers[RPA_PRODUCTION_NUMRNG] = rpa_dbex_rh_numrange;
1359         dbex->handlers[RPA_PRODUCTION_CLSNUM] = rpa_dbex_rh_clsnum;
1360         dbex->handlers[RPA_PRODUCTION_BEGINCHAR] = rpa_dbex_rh_beginchar;
1361         dbex->handlers[RPA_PRODUCTION_ENDCHAR] = rpa_dbex_rh_endchar;
1362         dbex->handlers[RPA_PRODUCTION_NOROP] = rpa_dbex_rh_norop;
1363         dbex->handlers[RPA_PRODUCTION_REQOP] = rpa_dbex_rh_exp;
1364         dbex->handlers[RPA_PRODUCTION_MINOP] = rpa_dbex_rh_minexp;
1365         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMIT] = rpa_dbex_rh_emit;
1366         dbex->handlers[RPA_PRODUCTION_DIRECTIVEABORT] = rpa_dbex_rh_abort;
1367         dbex->handlers[RPA_PRODUCTION_DIRECTIVENOEMIT] = rpa_dbex_rh_noemit;
1368         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITALL] = rpa_dbex_rh_emitall;
1369         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITNONE] = rpa_dbex_rh_emitnone;
1370         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITID] = rpa_dbex_rh_uid;
1371
1372         return dbex;
1373 }
1374
1375
1376 void rpa_dbex_destroy(rpadbex_t *dbex)
1377 {
1378         int i;
1379         if (dbex) {
1380                 for (i = 0; i < r_array_length(dbex->text); i++)
1381                         r_free(r_array_index(dbex->text, i, rchar*));
1382                 rpa_compiler_destroy(dbex->co);
1383                 rpa_parser_destroy(dbex->pa);
1384                 r_harray_destroy(dbex->rules);
1385                 r_array_destroy(dbex->records);
1386                 r_array_destroy(dbex->temprecords);
1387                 r_array_destroy(dbex->recstack);
1388                 r_array_destroy(dbex->inlinestack);
1389                 r_array_destroy(dbex->text);
1390                 r_free(dbex->handlers);
1391                 r_free(dbex);
1392         }
1393 }
1394
1395
1396 static rinteger rpa_parseinfo_loopdetect_do(rpadbex_t *dbex, rlong parent, rlong loopto, rinteger inderction)
1397 {
1398         rsize_t namesiz;
1399         const rchar *name;
1400         rlong i;
1401         rinteger ret = 0;
1402         rparecord_t *prec;
1403
1404         if (parent == loopto && inderction > 0)
1405                 return 1;
1406         for (i = 0; i < r_array_length(dbex->recstack); i++) {
1407                 if (parent == r_array_index(dbex->recstack, i, rlong))
1408                         return 0;
1409         }
1410         r_array_add(dbex->recstack, &parent);
1411
1412         if (!(prec = (rparecord_t *)r_array_slot(dbex->records, parent)))
1413                 return 0;
1414         if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)
1415                 i = parent;
1416         else
1417                 i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START);
1418         for (; i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1419                 prec = (rparecord_t *)r_array_slot(dbex->records, i);
1420                 if (prec->ruleuid == RPA_PRODUCTION_RULENAME)
1421                         continue;
1422                 if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF) {
1423                         rpa_ruleinfo_t *info;
1424                         if ((inderction > 0 || i != parent) && i == loopto) {
1425                                 /*
1426                                  * We found what we are looking for
1427                                  */
1428                                 ret = 1;
1429                                 break;
1430                         }
1431                         if (rpa_dbex_rulename(dbex, i, &name, &namesiz) < 0)
1432                                 R_ASSERT(0);
1433                         info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesiz));
1434                         if (!info)
1435                                 continue;
1436                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, info->startrec, loopto, inderction + 1)) > 0)
1437                                 break;
1438                 } else {
1439                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, i, loopto, inderction + 1)) > 0)
1440                                 break;
1441                 }
1442
1443                 if ((prec->usertype & RPA_MATCH_OPTIONAL) == 0 && (prec->ruleuid == RPA_PRODUCTION_CREF || prec->ruleuid == RPA_PRODUCTION_AREF ||
1444                                 prec->ruleuid == RPA_PRODUCTION_CHAR || prec->ruleuid == RPA_PRODUCTION_CLS || prec->ruleuid == RPA_PRODUCTION_SPECIALCHAR))
1445                         break;
1446
1447         }
1448
1449         r_array_removelast(dbex->recstack);
1450         return ret;
1451 }
1452
1453
1454 static rinteger rpa_parseinfo_loopdetect(rpadbex_t *dbex, rlong parent, rlong loopto)
1455 {
1456         if (parent != loopto) {
1457                 /*
1458                  * Make sure we are dealing with a loop first
1459                  */
1460                 if (!rpa_parseinfo_loopdetect_do(dbex, loopto, parent, 0))
1461                         return 0;
1462         }
1463
1464         return (rpa_parseinfo_loopdetect_do(dbex, parent, loopto, 0)) ? 1 : 0;
1465 }
1466
1467
1468 static void rpa_parseinfo_marklooppath(rpadbex_t *dbex, rlong parent)
1469 {
1470         rlong i;
1471
1472         if (rpa_parseinfo_loopdetect(dbex, parent, parent) > 0) {
1473                 rpa_record_setusertype(dbex->records, parent, RPA_LOOP_PATH, RVALSET_OR);
1474                 for (i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1475                         rpa_parseinfo_marklooppath(dbex, i);
1476                 }
1477         }
1478 }
1479
1480
1481 static rinteger rpa_parseinfo_rule_checkforloop(rpadbex_t *dbex, const char *name, rsize_t namesize, rlong loopto)
1482 {
1483         rpa_ruleinfo_t *info = info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1484
1485         if (!info)
1486                 return 0;
1487         return rpa_parseinfo_loopdetect(dbex, info->startrec, loopto);
1488 }
1489
1490
1491 static void rpa_dbex_buildloopinfo(rpadbex_t *dbex)
1492 {
1493         ruinteger i, p;
1494         rharray_t *rules = dbex->rules;
1495         rpa_ruleinfo_t *info;
1496
1497         for (i = 0; i < r_array_length(rules->members); i++) {
1498                 if ((info = (rpa_ruleinfo_t *)r_harray_get(rules, i)) != NULL)
1499                         rpa_parseinfo_marklooppath(dbex, info->startrec);
1500         }
1501
1502         /*
1503          * Mark the non-loop branches.
1504          */
1505         for (i = 0; i < r_array_length(dbex->records); i++) {
1506                 rparecord_t *prec = (rparecord_t *)r_array_slot(dbex->records, i);
1507                 if (prec->type == RPA_RECORD_START &&
1508                         (prec->ruleuid == RPA_PRODUCTION_ALTBRANCH) &&
1509                         (prec->usertype & RPA_LOOP_PATH) == 0) {
1510                         p = rpa_recordtree_parent(dbex->records, i, RPA_RECORD_START);
1511                         if (p >= 0) {
1512                                 prec = (rparecord_t *)r_array_slot(dbex->records, p);
1513                                 if (prec && (prec->usertype & RPA_LOOP_PATH))
1514                                         rpa_record_setusertype(dbex->records, i, RPA_NONLOOP_PATH, RVALSET_OR);
1515                         }
1516                 }
1517         }
1518 }
1519
1520
1521 static void rpa_dbex_buildruleinfo(rpadbex_t *dbex)
1522 {
1523         rparecord_t *rec;
1524         rpa_ruleinfo_t info;
1525         ruinteger nrecords;
1526         rlong i;
1527         const rchar *name = NULL;
1528         rsize_t namesize = 0;
1529
1530         if (dbex->rules) {
1531                 r_object_destroy((robject_t *)dbex->rules);
1532                 dbex->rules = NULL;
1533         }
1534         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
1535
1536         for (i = 0, nrecords = r_array_length(dbex->records); i < nrecords; i++) {
1537                 if (!(rec = rpa_dbex_record(dbex, i)))
1538                         continue;
1539                 if ((rec->ruleuid == RPA_PRODUCTION_NAMEDRULE) && (rec->type & RPA_RECORD_START)) {
1540                         r_memset(&info, 0, sizeof(info));
1541                         info.type = RPA_RULEINFO_NAMEDRULE;
1542                         info.startrec = i;
1543                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1544                         if (info.sizerecs < 0)
1545                                 continue;
1546                         if (rpa_dbex_rulename(dbex, i, &name, &namesize) < 0) {
1547                                 continue;
1548                         }
1549                         r_harray_add(dbex->rules, name, namesize, &info);
1550                         i += info.sizerecs - 1;
1551                 } else if ((rec->ruleuid == RPA_PRODUCTION_ANONYMOUSRULE) && (rec->type & RPA_RECORD_START)) {
1552                         r_memset(&info, 0, sizeof(info));
1553                         info.type = RPA_RULEINFO_ANONYMOUSRULE;
1554                         info.startrec = i;
1555                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1556                         if (info.sizerecs < 0)
1557                                 continue;
1558                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1559                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1560                         i += info.sizerecs - 1;
1561                 } else if ((rec->type & RPA_RECORD_START) && (rec->ruleuid >= RPA_PRODUCTION_DIRECTIVEEMIT) && (rec->ruleuid <= RPA_PRODUCTION_DIRECTIVEEMITID)) {
1562                         r_memset(&info, 0, sizeof(info));
1563                         info.type = RPA_RULEINFO_DIRECTIVE;
1564                         info.startrec = i;
1565                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1566                         if (info.sizerecs < 0)
1567                                 continue;
1568                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1569                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1570                         i += info.sizerecs - 1;
1571                 }
1572
1573         }
1574 }
1575
1576
1577 static rlong rpa_dbex_copy_handler(rarray_t *records, rlong rec, rpointer userdata)
1578 {
1579         rpadbex_t *dbex = (rpadbex_t *)userdata;
1580         rlong index;
1581
1582         rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
1583         if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & RPA_RECORD_START)) {
1584                 /*
1585                  * Ignore it
1586                  */
1587         } else if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & (RPA_RECORD_END))) {
1588                 ruint32 usertype = RPA_MATCH_NONE;
1589                 rlong lastrec = 0;
1590                 /*
1591                  * Don't copy it but set the usertype of the previous record accordingly.
1592                  */
1593                 switch (*prec->input) {
1594                 case '?':
1595                         usertype = RPA_MATCH_OPTIONAL;
1596                         break;
1597                 case '+':
1598                         usertype = RPA_MATCH_MULTIPLE;
1599                         break;
1600                 case '*':
1601                         usertype = RPA_MATCH_MULTIOPT;
1602                         break;
1603                 default:
1604                         usertype = RPA_MATCH_NONE;
1605                 };
1606                 lastrec = r_array_length(dbex->records) - 1;
1607                 if (lastrec >= 0)
1608                         rpa_record_setusertype(dbex->records, lastrec, usertype, RVALSET_OR);
1609         } else if (prec->ruleuid != RPA_RECORD_INVALID_UID) {
1610                 index = r_array_add(dbex->records, prec);
1611                 /*
1612                  * Optimizations. Lets apply the optimizations while we copy the records.
1613                  * This is probably not the most clean way to apply optimizations, in the future
1614                  * we should probably think of optimization pass right before compiling.
1615                  */
1616                 if (dbex->optimizations) {
1617                         if (prec->ruleuid == RPA_PRODUCTION_OROP && (prec->type & RPA_RECORD_END)) {
1618                                 rpa_optimiztion_orop(dbex->records, rpa_recordtree_get(dbex->records, index, RPA_RECORD_START));
1619                         }
1620                 }
1621         }
1622
1623         return 0;
1624 }
1625
1626
1627 static void rpa_dbex_copyrecords(rpadbex_t *dbex)
1628 {
1629         rinteger i;
1630         rarray_t *records = dbex->temprecords;
1631
1632         for (i = rpa_recordtree_get(records, 0, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(records, i, RPA_RECORD_START))
1633                 rpa_recordtree_walk(records, i, 0, rpa_dbex_copy_handler, dbex);
1634 }
1635
1636
1637 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, rlong rec)
1638 {
1639         rparecord_t *prec;
1640
1641         if (!dbex || !dbex->rules)
1642                 return NULL;
1643         if (rec < 0 || rec >= r_array_length(dbex->records))
1644                 return NULL;
1645         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1646         return prec;
1647
1648 }
1649
1650
1651 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid)
1652 {
1653         rparecord_t *prec;
1654         rpa_ruleinfo_t *info;
1655         rlong rec;
1656
1657         if (!dbex || !dbex->rules)
1658                 return NULL;
1659         info = r_harray_get(dbex->rules, rid);
1660         if (!info)
1661                 return NULL;
1662         rec = info->startrec + info->sizerecs - 1;
1663         if (rec < 0 || rec >= r_array_length(dbex->records))
1664                 return NULL;
1665         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1666         return prec;
1667 }
1668
1669
1670 static rinteger rpa_dbex_rulename(rpadbex_t *dbex, rlong rec, const rchar **name, rsize_t *namesize)
1671 {
1672         rparecord_t *pnamerec = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_START), RPA_RECORD_END));
1673         if (!pnamerec || !(pnamerec->ruleuid & RPA_PRODUCTION_RULENAME))
1674                 return -1;
1675         *name = pnamerec->input;
1676         *namesize = pnamerec->inputsiz;
1677         return 0;
1678 }
1679
1680
1681 rinteger rpa_dbex_open(rpadbex_t *dbex)
1682 {
1683         if (!dbex)
1684                 return -1;
1685         if (dbex->rules) {
1686                 r_object_destroy((robject_t *)dbex->rules);
1687                 dbex->rules = NULL;
1688         }
1689         dbex->compiled = 0;
1690         return 0;
1691 }
1692
1693
1694 void rpa_dbex_close(rpadbex_t *dbex)
1695 {
1696         if (!dbex)
1697                 return;
1698         rpa_dbex_buildruleinfo(dbex);
1699         rpa_dbex_buildloopinfo(dbex);
1700 }
1701
1702
1703 rlong rpa_dbex_load(rpadbex_t *dbex, const rchar *rules, rsize_t size)
1704 {
1705         rlong ret;
1706         rchar *text;
1707
1708         if (!dbex)
1709                 return -1;
1710         if (dbex->rules) {
1711                 /*
1712                  * Dbex is not open
1713                  */
1714                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTOPEN);
1715                 return -1;
1716         }
1717
1718         text = r_strndup(rules, size);
1719         R_ASSERT(text);
1720         r_array_add(dbex->text, &text);
1721         r_array_setlength(dbex->temprecords, 0);
1722         if ((ret = rpa_parser_load(dbex->pa, text, size, dbex->temprecords)) < 0) {
1723
1724                 return -1;
1725         }
1726         if (ret != size) {
1727                 rlong line = 1;
1728                 rchar *ptext = text;
1729                 ptext += ret;
1730                 for (line = 1; ptext >= text; --ptext) {
1731                         if (*ptext == '\n')
1732                                 line += 1;
1733                 }
1734                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
1735                 RPA_DBEX_SETERRINFO_OFFSET(dbex, ret);
1736                 RPA_DBEX_SETERRINFO_LINE(dbex, line);
1737                 return -1;
1738         }
1739         rpa_dbex_copyrecords(dbex);
1740         return ret;
1741 }
1742
1743
1744 rlong rpa_dbex_load_s(rpadbex_t *dbex, const rchar *rules)
1745 {
1746         return rpa_dbex_load(dbex, rules, r_strlen(rules));
1747 }
1748
1749
1750 void rpa_dbex_dumpindented(rpadbex_t *dbex, rlong rec, rinteger level, const rchar *rulelabel)
1751 {
1752         rchar buffer[1024];
1753         rinteger i, size;
1754         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1755
1756         if (!prec)
1757                 return;
1758         r_memset(buffer, 0, sizeof(buffer));
1759         for (i = 0; i < level + 1; i++)
1760                 r_printf("   ");
1761         r_printf("(");
1762         r_printf("%s, %c, %c", rulelabel, rpa_record_optchar(prec, 'x'), rpa_record_loopchar(prec, 'x'));
1763         r_printf(")");
1764         size = R_MIN(prec->inputsiz, sizeof(buffer) - 1);
1765         r_strncpy(buffer, prec->input, size);
1766
1767         if (size == (sizeof(buffer) - 1))
1768                 r_printf(" %s ...\n", buffer);
1769         else
1770                 r_printf(" %s\n", buffer);
1771         return;
1772 }
1773
1774
1775 static rlong rpa_dbex_firstinlined(rpadbex_t *dbex)
1776 {
1777         rlong ret = r_array_empty(dbex->inlinestack) ? -1 : r_array_index(dbex->inlinestack, 0, rlong);
1778         return ret;
1779 }
1780
1781
1782 static rinteger rpa_dbex_findinlined(rpadbex_t *dbex, rlong startrec)
1783 {
1784         rlong i;
1785         for (i = 0; i < r_array_length(dbex->inlinestack); i++) {
1786                 if (r_array_index(dbex->inlinestack, i, rlong) == startrec)
1787                         return 1;
1788         }
1789         return 0;
1790 }
1791
1792
1793 static void rpa_dbex_dumptree_do(rpadbex_t *dbex, rlong rec, rinteger level)
1794 {
1795         rparecord_t *prec = rpa_dbex_record(dbex, rec);
1796         if (prec && prec->ruleuid == RPA_PRODUCTION_RULENAME)
1797                 return;
1798         if (prec && (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)) {
1799                 const rchar *name = NULL;
1800                 rsize_t namesize = 0;
1801                 rinteger loop = 0;
1802                 rpa_ruleinfo_t *info;
1803
1804                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) >= 0) {
1805                         loop = rpa_parseinfo_rule_checkforloop(dbex, name, namesize, rpa_dbex_firstinlined(dbex));
1806                         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1807                         if (loop && info){
1808                                 if (!rpa_dbex_findinlined(dbex, info->startrec)) {
1809                                         /*
1810                                          * Temporary set the quantitative flags for the inlined rule to the parent
1811                                          * reference, so they are printed correctly. After the printing is done
1812                                          * restore the original flags.
1813                                          */
1814                                         rparecord_t *prulestart = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_START));
1815                                         rparecord_t *pruleend = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1816                                         rulong optional = (prulestart->usertype & RPA_MATCH_OPTIONAL);
1817                                         prulestart->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1818                                         pruleend->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1819                                         r_array_add(dbex->inlinestack, &info->startrec);
1820                                         rpa_dbex_dumptree_do(dbex, info->startrec, level);
1821                                         r_array_removelast(dbex->inlinestack);
1822                                         if (!optional) {
1823                                                 prulestart->usertype &= ~RPA_MATCH_OPTIONAL;
1824                                                 pruleend->usertype &= ~RPA_MATCH_OPTIONAL;
1825                                         }
1826                                 } else {
1827                                         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, "loopref");
1828                                 }
1829                                 return;
1830                         }
1831                 }
1832         }
1833         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, prec->rule);
1834         for (rec = rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_START); rec >= 0; rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START)) {
1835                 rpa_dbex_dumptree_do(dbex, rec, level + 1);
1836         }
1837 }
1838
1839
1840 rinteger rpa_dbex_dumptree(rpadbex_t *dbex, rparule_t rid)
1841 {
1842         rpa_ruleinfo_t *info;
1843
1844         if (!dbex)
1845                 return -1;
1846         if (rid < 0) {
1847                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1848                 return -1;
1849         }
1850         if (!dbex->rules) {
1851                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1852                 return -1;
1853         }
1854         if (!(info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid))) {
1855                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1856                 return -1;
1857         }
1858         r_array_add(dbex->inlinestack, &info->startrec);
1859         rpa_dbex_dumptree_do(dbex, info->startrec, 0);
1860         r_array_removelast(dbex->inlinestack);
1861         return 0;
1862 }
1863
1864
1865 rinteger rpa_dbex_dumpproductions(rpadbex_t *dbex)
1866 {
1867         rinteger ret = 0;
1868         rparule_t rid;
1869         rchar buffer[512];
1870
1871         if (!dbex)
1872                 return -1;
1873         if (!dbex->rules) {
1874                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1875                 return -1;
1876         }
1877         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1878                 ret = rpa_dbex_strncpy(dbex, buffer, rid, sizeof(buffer));
1879                 if ( ret >= 0) {
1880                         if (ret == sizeof(buffer))
1881                                 r_printf("   %s ...\n", buffer);
1882                         else
1883                                 r_printf("   %s\n", buffer);
1884                 }
1885
1886         }
1887         return ret;
1888 }
1889
1890
1891 rinteger rpa_dbex_dumprecords(rpadbex_t *dbex)
1892 {
1893         rlong i;
1894
1895         if (!dbex)
1896                 return -1;
1897         if (!dbex->rules) {
1898                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1899                 return -1;
1900         }
1901         for (i = 0; i < r_array_length(dbex->records); i++) {
1902                 rpa_record_dump(dbex->records, i);
1903         }
1904         return 0;
1905 }
1906
1907
1908 rinteger rpa_dbex_dumpinfo(rpadbex_t *dbex)
1909 {
1910         rlong i;
1911         rpa_ruleinfo_t *info;
1912
1913         if (!dbex)
1914                 return -1;
1915         if (!dbex->rules) {
1916                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1917                 return -1;
1918         }
1919         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1920                 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
1921                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1922                 switch (info->type) {
1923                 case RPA_RULEINFO_NAMEDRULE:
1924                         r_printf("N ");
1925                         break;
1926                 case RPA_RULEINFO_ANONYMOUSRULE:
1927                         r_printf("A ");
1928                         break;
1929                 case RPA_RULEINFO_DIRECTIVE:
1930                         r_printf("D ");
1931                         break;
1932                 default:
1933                         r_printf("  ");
1934                         break;
1935                 };
1936                 r_printf("(%7d, %4d, code: %7ld, %5ld) : %s\n", info->startrec, info->sizerecs, info->codeoff, info->codesiz, name->str);
1937         }
1938         return 0;
1939 }
1940
1941
1942 rinteger rpa_dbex_dumpuids(rpadbex_t *dbex)
1943 {
1944         rlong i;
1945         rlong rec;
1946         rpa_ruleinfo_t *info;
1947         rchar *buffer = r_zmalloc(32 * sizeof(rchar));
1948
1949         if (!dbex)
1950                 return -1;
1951         if (!dbex->rules) {
1952                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1953                 return -1;
1954         }
1955         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1956                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1957                 if (info->type == RPA_RULEINFO_DIRECTIVE) {
1958                         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1959                         if (prec->ruleuid == RPA_PRODUCTION_DIRECTIVEEMITID && prec->inputsiz) {
1960                                 rec = rpa_recordtree_firstchild(dbex->records, info->startrec, RPA_RECORD_START);
1961                                 while (rec >= 0) {
1962                                         prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1963                                         if (prec->ruleuid == RPA_PRODUCTION_ALIASNAME) {
1964                                                 ruint32 dec;
1965                                                 if (rpa_record2long(rpa_dbex_record(dbex, rpa_recordtree_next(dbex->records, rec, RPA_RECORD_END)), &dec) < 0)
1966                                                         break;
1967                                                 buffer = r_realloc(buffer, prec->inputsiz + 1);
1968                                                 r_memset(buffer, 0, prec->inputsiz + 1);
1969                                                 r_memcpy(buffer, prec->input, prec->inputsiz);
1970                                                 r_printf("#define %s %d\n", buffer, dec);
1971                                                 break;
1972                                         }
1973                                         rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START);
1974                                 }
1975                         }
1976                 }
1977         }
1978         r_free(buffer);
1979         return 0;
1980 }
1981
1982
1983 rinteger rpa_dbex_dumpcode(rpadbex_t* dbex, rparule_t rid)
1984 {
1985         rpa_ruleinfo_t *info;
1986         if (!dbex)
1987                 return -1;
1988         if (rid < 0) {
1989                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1990                 return -1;
1991         }
1992         if (!dbex->rules) {
1993                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1994                 return -1;
1995         }
1996         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1997         if (!info)
1998                 return -1;
1999         rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, info->codeoff), info->codesiz);
2000         return 0;
2001 }
2002
2003
2004 rsize_t rpa_dbex_strlen(rpadbex_t *dbex, rparule_t rid)
2005 {
2006         rparecord_t *prec;
2007         rsize_t size;
2008
2009         if (!dbex)
2010                 return -1;
2011         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
2012                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2013                 return -1;
2014         }
2015         size = prec->inputsiz;
2016         return size;
2017 }
2018
2019
2020 rsize_t rpa_dbex_strncpy(rpadbex_t *dbex, rchar *dst, rparule_t rid, rsize_t n)
2021 {
2022         rparecord_t *prec;
2023         rsize_t size;
2024
2025         if (!dbex)
2026                 return -1;
2027         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
2028                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2029                 return -1;
2030         }
2031         size = prec->inputsiz;
2032         if (n <= size)
2033                 size = n - 1;
2034         r_memset(dst, 0, n);
2035         r_strncpy(dst, prec->input, size);
2036         return size + 1;
2037 }
2038
2039
2040 rparule_t rpa_dbex_first(rpadbex_t *dbex)
2041 {
2042         if (!dbex)
2043                 return -1;
2044         if (!dbex->rules) {
2045                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2046                 return -1;
2047         }
2048
2049         if (r_array_length(dbex->rules->members) <= 0) {
2050                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2051                 return -1;
2052         }
2053         return 0;
2054 }
2055
2056
2057 rparule_t rpa_dbex_last(rpadbex_t *dbex)
2058 {
2059         if (!dbex)
2060                 return -1;
2061         if (!dbex->rules) {
2062                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2063                 return -1;
2064         }
2065
2066         if (r_array_length(dbex->rules->members) <= 0) {
2067                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2068                 return -1;
2069         }
2070         return r_array_length(dbex->rules->members) - 1;
2071 }
2072
2073
2074 rparule_t rpa_dbex_lookup(rpadbex_t *dbex, const rchar *name, rsize_t namesize)
2075 {
2076         rparule_t ret;
2077
2078         if (!dbex) {
2079                 return -1;
2080         }
2081         if (!dbex->rules) {
2082                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2083                 return -1;
2084         }
2085
2086         ret = (rparule_t) r_harray_taillookup(dbex->rules, name, namesize);
2087         if (ret < 0) {
2088                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2089         }
2090         return ret;
2091 }
2092
2093
2094 rparule_t rpa_dbex_lookup_s(rpadbex_t *dbex, const rchar *name)
2095 {
2096         return rpa_dbex_lookup(dbex, name, r_strlen(name));
2097 }
2098
2099
2100 rparule_t rpa_dbex_next(rpadbex_t *dbex, rparule_t rid)
2101 {
2102         if (!dbex)
2103                 return -1;
2104         if (!dbex->rules) {
2105                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2106                 return -1;
2107         }
2108
2109         ++rid;
2110         if (rid < r_array_length(dbex->rules->members))
2111                 return rid;
2112         return -1;
2113 }
2114
2115
2116 rparule_t rpa_dbex_prev(rpadbex_t *dbex, rparule_t rid)
2117 {
2118         if (!dbex)
2119                 return -1;
2120         if (!dbex->rules) {
2121                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2122                 return -1;
2123         }
2124         --rid;
2125         if (rid >= 0)
2126                 return rid;
2127         return -1;
2128 }
2129
2130
2131 rlong rpa_dbex_lasterror(rpadbex_t *dbex)
2132 {
2133         if (!dbex)
2134                 return -1;
2135         return dbex->err.code;
2136 }
2137
2138
2139 rlong rpa_dbex_lasterrorinfo(rpadbex_t *dbex, rpa_errinfo_t *errinfo)
2140 {
2141         if (!dbex || !errinfo)
2142                 return -1;
2143         r_memcpy(errinfo, &dbex->err, sizeof(rpa_errinfo_t));
2144         return 0;
2145 }
2146
2147
2148 const rchar *rpa_dbex_version()
2149 {
2150         return "2.0";
2151 }
2152
2153
2154 static rinteger rpa_dbex_compile_rule(rpadbex_t *dbex, rparule_t rid)
2155 {
2156         rlong codeoff;
2157         rpa_ruleinfo_t *info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
2158
2159         if (!info)
2160                 return -1;
2161         codeoff = rvm_codegen_getcodesize(dbex->co->cg);
2162         if (rpa_dbex_playrecord(dbex, info->startrec) < 0)
2163                 return -1;
2164         info->codeoff = codeoff;
2165         info->codesiz = rvm_codegen_getcodesize(dbex->co->cg) - codeoff;
2166         return 0;
2167 }
2168
2169
2170 rinteger rpa_dbex_compile(rpadbex_t *dbex)
2171 {
2172         rparule_t rid;
2173         rvm_codelabel_t *labelerr;
2174
2175         if (!dbex)
2176                 return -1;
2177         if (!dbex->rules) {
2178                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2179                 return -1;
2180         }
2181         /*
2182          * By default all production rules emit
2183          */
2184         if (dbex->co)
2185                 rpa_compiler_destroy(dbex->co);
2186         dbex->co = rpa_compiler_create();
2187         rpa_dbex_setemit(dbex, TRUE);
2188
2189         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
2190                 if (rpa_dbex_compile_rule(dbex, rid) < 0) {
2191                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_COMPILE);
2192                         return -1;
2193                 }
2194         }
2195
2196         if (rvm_codegen_relocate(dbex->co->cg, &labelerr) < 0) {
2197                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVED_SYMBOL);
2198                 RPA_DBEX_SETERRINFO_NAME(dbex, labelerr->name->str, labelerr->name->size);
2199                 return -1;
2200         }
2201         dbex->compiled = 1;
2202         return 0;
2203 }
2204
2205
2206 rvm_asmins_t *rpa_dbex_executable(rpadbex_t *dbex)
2207 {
2208         if (!dbex)
2209                 return NULL;
2210         if (!dbex->rules) {
2211                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2212                 return NULL;
2213         }
2214         if (!dbex->compiled || rvm_codegen_getcodesize(dbex->co->cg) == 0) {
2215                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
2216                 return NULL;
2217         }
2218         return rvm_codegen_getcode(dbex->co->cg, 0);
2219 }
2220
2221
2222 rlong rpa_dbex_executableoffset(rpadbex_t *dbex, rparule_t rid)
2223 {
2224         rpa_ruleinfo_t *info;
2225
2226         if (!dbex)
2227                 return -1;
2228         if (!dbex->rules) {
2229                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
2230                 return -1;
2231         }
2232         if (!dbex->compiled) {
2233                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
2234                 return -1;
2235         }
2236         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
2237         if (!info) {
2238                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
2239                 return -1;
2240         }
2241         return info->codeoff;
2242 }
2243
2244
2245 rlong rpa_dbex_cfgset(rpadbex_t *dbex, rulong cfg, rulong val)
2246 {
2247         if (!dbex)
2248                 return -1;
2249         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
2250                 dbex->optimizations = val;
2251                 return 0;
2252         } else if(cfg == RPA_DBEXCFG_DEBUG) {
2253                 dbex->debug = val;
2254                 return 0;
2255         }
2256         return -1;
2257 }
2258
2259
2260 rlong rpa_dbex_cfgget(rpadbex_t *dbex, rulong cfg)
2261 {
2262         if (!dbex)
2263                 return -1;
2264         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
2265                 return dbex->optimizations;
2266         } else if(cfg == RPA_DBEXCFG_DEBUG) {
2267                 return dbex->debug;
2268         }
2269         return -1;
2270 }
2271