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