RPA Toolkit
2908593e8ef0645efe5664ead43ef7769514b625
[rpatk.git] / rjs / rjsexec.c
1 /*
2  *  Regular Pattern Analyzer (RPA)
3  *  Copyright (c) 2009-2010 Martin Stoilov
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  *  Martin Stoilov <martin@rpasearch.com>
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include "rlib/rmem.h"
25 #include "rjs/rjs.h"
26 #include "rjs/rjsfile.h"
27 #include "rpa/rparecord.h"
28
29
30 static int debuginfo = 0;
31 static int parseinfo = 0;
32 static int compileonly = 0;
33 static int debugcompileonly = 0;
34 static int statinfo = 0;
35
36
37 static char *errormsg[] = {
38         "OK",
39         "Undefined identifier",
40         "Syntax error",
41         "Not a function",
42         "Not a function call",
43         "Not a loop",
44         "Not a if statement",
45         "Unknown",
46         "Unknown",
47         "Unknown",
48         "Unknown",
49         "Unknown",
50         "Unknown",
51         "Unknown",
52         "Unknown",
53         "Unknown",
54         "Unknown",
55 };
56
57
58 static void rjs_exec_ltrim(rvmcpu_t *cpu, rvm_asmins_t *ins)
59 {
60         const char *ptr, *list;
61         unsigned long size;
62         rvmreg_t *r = NULL, *l = NULL;
63         rstring_t *src, *dest;
64
65         if (RJS_SWI_PARAMS(cpu) == 0)
66                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
67         r = (rvmreg_t *) RJS_SWI_PARAM(cpu, 1);
68         if (RJS_SWI_PARAMS(cpu) > 1) {
69                 l = (rvmreg_t *) RJS_SWI_PARAM(cpu, 2);
70                 if (rvm_reg_gettype(l) != RVM_DTYPE_STRING)
71                         RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
72         }
73         if (rvm_reg_gettype(r) != RVM_DTYPE_STRING)
74                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
75         if (l)
76                 list = ((rstring_t *)RVM_REG_GETP(l))->s.str;
77         else
78                 list = " \t\n\r\0";
79         src = (rstring_t *)RVM_REG_GETP(r);
80         ptr = src->s.str;
81         size = src->s.size;
82         while (size > 0) {
83                 if (!r_strchr(list, *ptr))
84                         break;
85                 size--;
86                 ptr++;
87         }
88         dest = r_string_create_strsize(ptr, size);
89         r_gc_add(cpu->gc, (robject_t*)dest);
90         rvm_reg_setstring(RVM_CPUREG_PTR(cpu, R0), dest);
91 }
92
93
94 static void rjs_exec_rtrim(rvmcpu_t *cpu, rvm_asmins_t *ins)
95 {
96         const char *ptr, *list;
97         unsigned long size;
98         rvmreg_t *r = NULL, *l = NULL;
99         rstring_t *src, *dest;
100
101         if (RJS_SWI_PARAMS(cpu) == 0)
102                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
103         r = (rvmreg_t *) RJS_SWI_PARAM(cpu, 1);
104         if (RJS_SWI_PARAMS(cpu) > 1) {
105                 l = (rvmreg_t *) RJS_SWI_PARAM(cpu, 2);
106                 if (rvm_reg_gettype(l) != RVM_DTYPE_STRING)
107                         RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
108         }
109         if (rvm_reg_gettype(r) != RVM_DTYPE_STRING)
110                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
111         if (l)
112                 list = ((rstring_t *)RVM_REG_GETP(l))->s.str;
113         else
114                 list = " \t\n\r\0";
115         src = (rstring_t *)RVM_REG_GETP(r);
116         size = src->s.size;
117         ptr = src->s.str + size - 1;
118         while (size > 0) {
119                 if (!r_strchr(list, *ptr))
120                         break;
121                 size--;
122                 ptr--;
123         }
124         dest = r_string_create_strsize(src->s.str, size);
125         r_gc_add(cpu->gc, (robject_t*)dest);
126         rvm_reg_setstring(RVM_CPUREG_PTR(cpu, R0), dest);
127 }
128
129
130 static void rjs_exec_trim(rvmcpu_t *cpu, rvm_asmins_t *ins)
131 {
132         const char *start, *ptr, *list;
133         unsigned long size;
134         rvmreg_t *r = NULL, *l = NULL;
135         rstring_t *src, *dest;
136
137         if (RJS_SWI_PARAMS(cpu) == 0)
138                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
139
140         r = (rvmreg_t *) RJS_SWI_PARAM(cpu, 1);
141         if (RJS_SWI_PARAMS(cpu) > 1) {
142                 l = (rvmreg_t *) RJS_SWI_PARAM(cpu, 2);
143                 if (rvm_reg_gettype(l) != RVM_DTYPE_STRING)
144                         RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
145         }
146         if (rvm_reg_gettype(r) != RVM_DTYPE_STRING)
147                 RJS_SWI_ABORT(rjs_engine_get(cpu), NULL);
148         if (l)
149                 list = ((rstring_t *)RVM_REG_GETP(l))->s.str;
150         else
151                 list = " \t\n\r\0";
152         src = (rstring_t *)RVM_REG_GETP(r);
153         ptr = src->s.str;
154         size = src->s.size;
155         while (size > 0) {
156                 if (!r_strchr(list, *ptr))
157                         break;
158                 size--;
159                 ptr++;
160         }
161         start = ptr;
162         ptr = start + size - 1;
163         while (size > 0) {
164                 if (!r_strchr(list, *ptr))
165                         break;
166                 size--;
167                 ptr--;
168         }
169         dest = r_string_create_strsize(start, size);
170         r_gc_add(cpu->gc, (robject_t*)dest);
171         rvm_reg_setstring(RVM_CPUREG_PTR(cpu, R0), dest);
172 }
173
174
175 static rvm_switable_t swistring[] = {
176                 {"ltrim", rjs_exec_ltrim},
177                 {"rtrim", rjs_exec_rtrim},
178                 {"trim", rjs_exec_trim},
179                 {NULL, NULL},
180 };
181
182
183 int rjs_exec_script(rjs_engine_t *jse, rstr_t  *script)
184 {
185         if (!script)
186                 return -1;
187         if (parseinfo) {
188                 rjs_engine_dumpast(jse, script->str, script->size);
189         } else if (debugcompileonly) {
190                 int res = 0;
191                 jse->debugcompile = 1;
192                 res = rjs_engine_compile(jse, script->str, script->size);
193                 jse->debugcompile = 0;
194                 if (res < 0)
195                         return -1;
196         } else if (compileonly) {
197                 if (rjs_engine_compile(jse, script->str, script->size) < 0)
198                         return -1;
199         } else {
200                 if (rjs_engine_compile(jse, script->str, script->size) < 0)
201                         return -1;
202                 if (rjs_engine_run(jse) < 0)
203                         return -1;
204         }
205
206         return 0;
207 }
208
209
210 long jrs_offset2line(const char *script, long offset)
211 {
212         long line = 0;
213         const char *ptr;
214
215         for (line = 1, ptr = script + offset; ptr >= script; --ptr) {
216                 if (*ptr == '\n')
217                         line += 1;
218         }
219
220         return line;
221 }
222
223
224 void rjs_display_errors(rjs_engine_t *jse, rstr_t *script)
225 {
226         unsigned long i;
227         rjs_error_t *err;
228
229         for (i = 0; i < r_array_length(jse->errors); i++) {
230                 err = (rjs_error_t *)r_array_slot(jse->errors, i);
231                 fprintf(stdout, "Line: %ld (%ld, %ld), Error Code: %ld, ", (long)err->line, err->offset, err->lineoffset, err->error);
232                 fprintf(stdout, "%s: ", errormsg[err->error]);
233                 if (err->size) {
234                         fwrite(script->str + err->offset, sizeof(char), err->size, stdout);
235                 } else {
236                         fwrite(script->str + err->lineoffset, sizeof(char), err->offset - err->lineoffset, stdout);
237                 }
238                 fprintf(stdout, "\n");
239         }
240 }
241
242
243 int usage(int argc, char *argv[])
244 {
245             fprintf(stderr, "RJS with RPA Engine: %s \n", rpa_dbex_version());
246                 fprintf(stderr, "Copyright (C) 2010 Martin Stoilov\n\n");
247
248                 fprintf(stderr, "\t-e <script_expression>   Run the script supplied on the command line.\n");
249                 fprintf(stderr, "\t-f <script_file>         Run the script file.\n");
250                 fprintf(stderr, "\t-p                       Display rules parsing records.\n");
251                 fprintf(stderr, "\t-d                       Execute in debug mode.\n");
252                 fprintf(stderr, "\t-c                       Compile the script, without running it.\n");
253                 fprintf(stderr, "\t-C                       Compile the script, showing the compile info, without running it.\n");
254                 fprintf(stderr, "\t-h, --help               Display this help.\n");
255                 return 0;
256 }
257
258
259 int main(int argc, char *argv[])
260 {
261         int i;
262         rstr_t *script = NULL, *unmapscript = NULL;
263         rstr_t line;
264         rjs_engine_t *jse;
265
266         for (i = 1; i < argc; i++) {
267                 if (r_strcmp(argv[i], "--help") == 0 || r_strcmp(argv[i], "-help") == 0 || r_strcmp(argv[i], "/?") == 0 || r_strcmp(argv[i], "-h") == 0) {
268                         usage(argc, argv);
269                         return 1;
270                 }
271         }
272
273         jse = rjs_engine_create();
274         if (!jse)
275                 return 1;
276         if (rjs_engine_addswitable(jse, "string", swistring) < 0) {
277                 return 2;
278         }
279         for (i = 1; i < argc; i++) {
280                 if (r_strcmp(argv[i], "-L") == 0) {
281
282                 } else if (r_strcmp(argv[i], "-d") == 0) {
283                         debuginfo = 1;
284                         jse->debugexec = 1;
285                 } else if (r_strcmp(argv[i], "-p") == 0) {
286                         parseinfo = 1;
287                 } else if (r_strcmp(argv[i], "-C") == 0) {
288                         debugcompileonly = 1;
289                 } else if (r_strcmp(argv[i], "-c") == 0) {
290                         compileonly = 1;
291                 } else if (r_strcmp(argv[i], "-t") == 0) {
292                         statinfo = 1;
293                 }
294         }
295
296         for (i = 1; i < argc; i++) {
297                 if (r_strcmp(argv[i], "-e") == 0) {
298                         if (++i < argc) {
299                                 line.str = argv[i];
300                                 line.size = r_strlen(argv[i]);
301                                 script = &line;
302                         }
303                         if (rjs_exec_script(jse, script) < 0)
304                                 goto end;
305                 }
306         }
307
308         for (i = 1; i < argc; i++) {
309                 if (r_strcmp(argv[i], "-f") == 0) {
310                         if (++i < argc) {
311                                 script = rjs_file_map(argv[i]);
312                                 r_printf("%s\n", script->str);
313                                 if (script) {
314                                         unmapscript = script;
315                                 }
316                         }
317                         if (rjs_exec_script(jse, script) < 0)
318                                 goto end;
319                 }
320         }
321
322 end:
323         if (jse && r_array_length(jse->errors))
324                 rjs_display_errors(jse, script);
325         rjs_engine_destroy(jse);
326         if (unmapscript)
327                 rjs_file_unmap(unmapscript);
328         if (statinfo)
329                 fprintf(stdout, "\nRJS Version: %s, memory: %ld Bytes (leaked %ld Bytes)\n", rjs_version(), (long)r_debug_get_maxmem(), (long)r_debug_get_allocmem());
330         return 0;
331 }