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