RPA Toolkit
Refined the rpastat_t public interface. Added more API documentation.
[rpatk.git] / rjs / rjsparser.c
1 #include "rmem.h"
2 #include "rjsrules.h"
3 #include "rjsparser.h"
4 #include "rjserror.h"
5
6
7 void rjs_parser_dbex_error(rjs_parser_t *parser)
8 {
9         rpa_errinfo_t err;
10         r_memset(&err, 0, sizeof(err));
11         rpa_dbex_lasterrorinfo(parser->dbex, &err);
12         r_printf("Failed to load RPA rules");
13         if (err.mask & RPA_ERRINFO_CODE) {
14                 r_printf(", Error Code: %ld", err.code);
15         }
16         if (err.mask & RPA_ERRINFO_OFFSET) {
17                 rlong line = 1, i;
18                 const rchar *ptr = rjs_rules_get();
19                 for (i = 0; i < err.offset; i++) {
20                         if (ptr[i] == '\n')
21                                 line += 1;
22                 }
23                 r_printf(", Offset: %ld, Line: %ld", err.offset, line);
24         }
25         if (err.mask & RPA_ERRINFO_NAME) {
26                 r_printf(", Rule Name: %s", err.name);
27         }
28         r_printf("\n");
29 }
30
31
32 rjs_parser_t *rjs_parser_create()
33 {
34         rjs_parser_t *parser = (rjs_parser_t *) r_zmalloc(sizeof(*parser));
35
36         parser->dbex = rpa_dbex_create();
37         if (!parser) {
38                 rjs_parser_destroy(parser);
39                 return NULL;
40         }
41         rpa_dbex_open(parser->dbex);
42         if (rpa_dbex_load(parser->dbex, rjs_rules_get(), rjs_rules_size()) < 0) {
43                 rjs_parser_dbex_error(parser);
44                 rjs_parser_destroy(parser);
45                 return NULL;
46         }
47         rpa_dbex_close(parser->dbex);
48         if (rpa_dbex_compile(parser->dbex) < 0) {
49                 rjs_parser_dbex_error(parser);
50                 rjs_parser_destroy(parser);
51                 return NULL;
52         }
53         return parser;
54 }
55
56
57 void rjs_parser_destroy(rjs_parser_t *parser)
58 {
59         if (parser) {
60                 rpa_dbex_destroy(parser->dbex);
61                 r_free(parser);
62         }
63 }
64
65
66 rlong rjs_parser_offset2line(const rchar *script, rlong offset)
67 {
68         rlong line = 1;
69         const rchar *ptr;
70
71         for (line = 1, ptr = script + offset; ptr >= script; --ptr) {
72                 if (*ptr == '\n' && ptr != script + offset)
73                         line += 1;
74         }
75
76         return line;
77 }
78
79
80 rlong rjs_parser_offset2lineoffset(const rchar *script, rlong offset)
81 {
82         rlong lineoffset = 0;
83         const rchar *ptr;
84
85         for (lineoffset = 0, ptr = script + offset; ptr > script; --ptr) {
86                 if (*ptr == '\n' && ptr != script + offset)
87                         break;
88                 lineoffset += 1;
89         }
90         return offset - lineoffset;
91 }
92
93
94 rlong rjs_parser_exec(rjs_parser_t *parser, const rchar *script, rsize_t size, rarray_t *ast, rjs_error_t *error)
95 {
96         rlong res = 0;
97         rpastat_t *stat = rpa_stat_create(parser->dbex, 4096);
98         res = rpa_stat_parse(stat, rpa_dbex_last(parser->dbex), RPA_ENCODING_UTF8, script, script, script + size, ast);
99         if (res < 0 && error) {
100                 rpa_errinfo_t rpaerror;
101                 rpa_stat_lasterrorinfo(stat, &rpaerror);
102                 if (rpaerror.code == RPA_E_RULEABORT) {
103                         error->type = RJS_ERRORTYPE_SYNTAX;
104                         error->error = RJS_ERROR_SYNTAX;
105                         error->offset = rpaerror.offset;
106                         error->line = rjs_parser_offset2line(script, error->offset);
107                         error->lineoffset = rjs_parser_offset2lineoffset(script, error->offset);
108                 }
109         }
110         rpa_stat_destroy(stat);
111         return res;
112 }