RPA Toolkit
added long, double key support for the rmap_t.
[rpatk.git] / rjs / rjs.c
1 #include <stdarg.h>
2 #include "rmem.h"
3 #include "rmap.h"
4 #include "rjs.h"
5 #include "rvmcodegen.h"
6
7
8 static void rjs_engine_print(rvmcpu_t *cpu, rvm_asmins_t *ins);
9 static void rjs_engine_dbgprint(rvmcpu_t *cpu, rvm_asmins_t *ins);
10 static void rjs_engine_object(rvmcpu_t *cpu, rvm_asmins_t *ins);
11
12 static rvm_switable_t rjsswitable[] = {
13                 {"print", rjs_engine_print},
14                 {"dbgprint", rjs_engine_dbgprint},
15                 {"Object", rjs_engine_object},
16                 {"Array", rjs_engine_object},
17                 {NULL, NULL},
18 };
19
20
21 const rchar *rjs_version()
22 {
23         return RJS_VERSION_STRING;
24 }
25
26
27 rjs_engine_t *rjs_engine_create()
28 {
29         rvmreg_t *tp;
30         rjs_engine_t *jse = (rjs_engine_t *) r_zmalloc(sizeof(*jse));
31
32         jse->pa = rjs_parser_create();
33         jse->cpu = rvm_cpu_create_default();
34         jse->co = rjs_compiler_create(jse->cpu);
35         jse->cgs = r_array_create(sizeof(rvm_codegen_t*));
36         jse->errors = r_array_create(sizeof(rjs_error_t));
37         jse->cpu->userdata1 = jse;
38         rvm_cpu_addswitable(jse->cpu, "rjsswitable", rjsswitable);
39         if (!jse->pa || !jse->cpu || !jse->co || !jse->cgs)
40                 goto error;
41         tp = rvm_cpu_alloc_global(jse->cpu);
42         rvm_reg_setjsobject(tp, (robject_t *)r_map_create(sizeof(rvmreg_t), 7));
43         rvm_gc_add(jse->cpu->gc, (robject_t*)RVM_REG_GETP(tp));
44         rvm_cpu_setreg(jse->cpu, TP, tp);
45         return jse;
46 error:
47         rjs_engine_destroy(jse);
48         return NULL;
49 }
50
51
52 void rjs_engine_destroy(rjs_engine_t *jse)
53 {
54         rlong i;
55         if (jse) {
56                 if (jse->cgs) {
57                         for (i = 0; i < r_array_length(jse->cgs); i++) {
58                                 rvm_codegen_destroy(r_array_index(jse->cgs, i, rvm_codegen_t*));
59                         }
60                 }
61                 r_array_destroy(jse->cgs);
62                 r_array_destroy(jse->errors);
63                 rjs_parser_destroy(jse->pa);
64                 rvm_cpu_destroy(jse->cpu);
65                 rjs_compiler_destroy(jse->co);
66                 r_free(jse);
67         }
68 }
69
70
71 rint rjs_engine_open(rjs_engine_t *jse)
72 {
73         return 0;
74 }
75
76
77 rint rjs_engine_addswitable(rjs_engine_t *jse, const rchar *tabname, rvm_switable_t *switalbe)
78 {
79         return rvm_cpu_addswitable(jse->cpu, tabname, switalbe);
80 }
81
82
83 static rint rjs_engine_parse(rjs_engine_t *jse, const rchar *script, rsize_t size, rarray_t *records, rjs_error_t *error)
84 {
85         rlong res = 0;
86
87         res = rjs_parser_exec(jse->pa, script, size, records, error);
88         return res;
89 }
90
91
92 rint rjs_engine_compile(rjs_engine_t *jse, const rchar *script, rsize_t size)
93 {
94         rvm_codegen_t *topcg = NULL;
95         rarray_t *records = rpa_records_create();
96         rjs_error_t error;
97         jse->co->debug = jse->debugcompile;
98
99         r_memset(&error, 0, sizeof(error));
100         if (rjs_engine_parse(jse, script, size, records, &error) < 0) {
101
102                 goto err;
103         }
104
105         topcg =  r_array_empty(jse->cgs) ? NULL : r_array_last(jse->cgs, rvm_codegen_t*);
106         if (!topcg || (topcg->userdata & RJS_COMPILER_CODEGENKEEP) == 1) {
107                 topcg = rvm_codegen_create();
108                 r_array_add(jse->cgs, &topcg);
109         } else {
110                 rvm_codegen_clear(topcg);
111         }
112         topcg->userdata = 0;
113         if (rjs_compiler_compile(jse->co, script, size, records, topcg, &error) < 0) {
114                 topcg->userdata = 0;
115                 goto err;
116         }
117
118         rpa_records_destroy(records);
119         return 0;
120
121 err:
122         r_array_add(jse->errors, &error);
123         rpa_records_destroy(records);
124         return -1;
125 }
126
127
128 rint rjs_engine_dumpast(rjs_engine_t *jse, const rchar *script, rsize_t size)
129 {
130         rjs_error_t error;
131         rarray_t *records = rpa_records_create();
132
133         if (rjs_engine_parse(jse, script, size, records, &error) < 0) {
134
135
136                 return -1;
137         }
138
139         if (records) {
140                 rlong i;
141                 for (i = 0; i < rpa_records_length(records); i++)
142                         rpa_record_dump(records, i);
143         }
144
145         rpa_records_destroy(records);
146         return 0;
147 }
148
149
150 rint rjs_engine_compile_s(rjs_engine_t *jse, const rchar *script)
151 {
152         return rjs_engine_compile(jse, script, r_strlen(script));
153 }
154
155
156 rint rjs_engine_close(rjs_engine_t *jse)
157 {
158
159         return 0;
160 }
161
162
163 rint rjs_engine_run(rjs_engine_t *jse)
164 {
165         rint res = 0;
166         rvm_codegen_t *cg = r_array_empty(jse->cgs) ? NULL : r_array_last(jse->cgs, rvm_codegen_t*);
167
168         if (!cg) {
169
170                 return -1;
171         }
172         if (jse->debugexec) {
173                 res = rvm_cpu_exec_debug(jse->cpu, rvm_codegen_getcode(cg, 0), 0);
174         } else {
175                 res = rvm_cpu_exec(jse->cpu, rvm_codegen_getcode(cg, 0), 0);
176         }
177
178         if (jse->cpu->error == RVM_E_USERABORT) {
179                 rlong idx = RVM_CPUREG_GETIP(jse->cpu, PC) - rvm_codegen_getcode(cg, 0);
180                 if (idx >= 0) {
181                         r_printf("Aborted at source index: %ld\n", rvm_codegen_getsource(cg, idx));
182                 }
183         }
184
185         return res;
186 }
187
188
189 rvmreg_t * rjs_engine_exec(rjs_engine_t *jse, const rchar *script, rsize_t size)
190 {
191         if (rjs_engine_compile(jse, script, size) < 0)
192                 return NULL;
193         RVM_CPUREG_SETU(jse->cpu, FP, 0);
194         RVM_CPUREG_SETU(jse->cpu, SP, 0);
195         if (rjs_engine_run(jse) < 0)
196                 return NULL;
197         return RVM_CPUREG_PTR(jse->cpu, R0);
198 }
199
200
201 rvmreg_t *rjs_engine_exec_s(rjs_engine_t *jse, const rchar *script)
202 {
203         return rjs_engine_exec(jse, script, r_strlen(script));
204 }
205
206
207 static rint rjs_compiler_argarray_setup(rjs_compiler_t *co)
208 {
209         rvm_varmap_t *v;
210         rvmreg_t count = rvm_reg_create_long(0);
211         rmap_t *a;
212
213         v = rvm_scope_tiplookup_s(co->scope, "ARGS");
214         if (!v) {
215                 return -1;
216         }
217         a = r_map_create(sizeof(rvmreg_t), 7);
218         rvm_gc_add(co->cpu->gc, (robject_t*)a);
219         r_map_add_s(a, "count", &count);
220         rvm_reg_setjsobject((rvmreg_t*)v->data.ptr, (robject_t*)a);
221         return 0;
222 }
223
224
225 static rint rjs_compiler_addarg(rjs_compiler_t *co, rvmreg_t *arg)
226 {
227         rvm_varmap_t *v;
228         rmap_t *a;
229         rvmreg_t *count;
230         rlong index;
231
232         v = rvm_scope_tiplookup_s(co->scope, "ARGS");
233         if (!v) {
234                 return -1;
235         }
236         a = (rmap_t*)RVM_REG_GETP((rvmreg_t*)v->data.ptr);
237         index = r_map_lookup_s(a, -1, "count");
238         R_ASSERT(index >= 0);
239         count = (rvmreg_t *)r_map_value(a, index);
240         r_map_add_l(a, RVM_REG_GETL(count), arg);
241         rvm_reg_setlong(count, RVM_REG_GETL(count) + 1);
242
243         return 0;
244 }
245
246
247 rvmreg_t *rjs_engine_vexec(rjs_engine_t *jse, const rchar *script, rsize_t size, rsize_t nargs, va_list args)
248 {
249         rvmreg_t arg;
250         rsize_t i = 0;
251
252         if (rjs_engine_compile(jse, script, size) < 0)
253                 return NULL;
254         if (nargs > 0) {
255                 rjs_compiler_argarray_setup(jse->co);
256                 for (i = 0; i < nargs; i++) {
257                         arg = va_arg(args, rvmreg_t);
258                         rjs_compiler_addarg(jse->co, &arg);
259                 }
260         }
261         RVM_CPUREG_SETU(jse->cpu, FP, 0);
262         RVM_CPUREG_SETU(jse->cpu, SP, 0);
263         if (rjs_engine_run(jse) < 0)
264                 return NULL;
265         return RVM_CPUREG_PTR(jse->cpu, R0);
266 }
267
268
269 rvmreg_t *rjs_engine_args_exec(rjs_engine_t *jse, const rchar *script, rsize_t size, rsize_t nargs, ...)
270 {
271         rvmreg_t *ret;
272         va_list args;
273         va_start(args, nargs);
274         ret = rjs_engine_vexec(jse, script, size, nargs, args);
275         va_end(args);
276         return ret;
277 }
278
279
280 rvmreg_t *rjs_engine_args_exec_s(rjs_engine_t *jse, const rchar *script, rsize_t nargs, ...)
281 {
282         rvmreg_t *ret;
283         va_list args;
284         va_start(args, nargs);
285         ret = rjs_engine_vexec(jse, script, r_strlen(script), nargs, args);
286         va_end(args);
287         return ret;
288 }
289
290
291 static void rjs_engine_print(rvmcpu_t *cpu, rvm_asmins_t *ins)
292 {
293         rvmreg_t *r = (rvmreg_t *)RVM_STACK_ADDR(cpu->stack, RVM_CPUREG_GETU(cpu, FP) + 1);
294
295         if (rvm_reg_gettype(r) == RVM_DTYPE_UNSIGNED)
296                 r_printf("%lu\n", RVM_REG_GETU(r));
297         else if (rvm_reg_gettype(r) == RVM_DTYPE_NAN)
298                 r_printf("NaN\n");
299         else if (rvm_reg_gettype(r) == RVM_DTYPE_UNDEF)
300                 r_printf("undefined\n");
301         else if (rvm_reg_gettype(r) == RVM_DTYPE_BOOLEAN)
302                 r_printf("%s\n", RVM_REG_GETU(r) ? "true" : "false");
303         else if (rvm_reg_gettype(r) == RVM_DTYPE_POINTER)
304                 r_printf("%p\n", RVM_REG_GETP(r));
305         else if (rvm_reg_gettype(r) == RVM_DTYPE_LONG)
306                 r_printf("%ld\n", RVM_REG_GETL(r));
307         else if (rvm_reg_gettype(r) == RVM_DTYPE_DOUBLE)
308                 r_printf("%f\n", RVM_REG_GETD(r));
309         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRING)
310                 r_printf("%s\n", ((rstring_t*) RVM_REG_GETP(r))->s.str);
311         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRPTR)
312                 r_printf("(STRPTR) %s\n", (RVM_REG_GETSTR(r)));
313         else if (rvm_reg_gettype(r) == RVM_DTYPE_JSOBJECT)
314                 r_printf("(object) %p\n",RVM_REG_GETP(r));
315         else if (rvm_reg_gettype(r) == RVM_DTYPE_HARRAY)
316                 r_printf("(hashed array) %p\n",RVM_REG_GETP(r));
317         else if (rvm_reg_gettype(r) == RVM_DTYPE_SWIID)
318                 r_printf("(function) %p\n",RVM_REG_GETP(r));
319         else
320                 r_printf("%p\n", RVM_REG_GETP(r));
321 }
322
323
324 static void rjs_engine_dbgprint(rvmcpu_t *cpu, rvm_asmins_t *ins)
325 {
326         rvmreg_t *r = (rvmreg_t *)RVM_STACK_ADDR(cpu->stack, RVM_CPUREG_GETU(cpu, FP) + 1);
327
328         if (rvm_reg_gettype(r) == RVM_DTYPE_UNSIGNED)
329                 r_printf("(UNSIGNED) %lu\n", RVM_REG_GETU(r));
330         else if (rvm_reg_gettype(r) == RVM_DTYPE_NAN)
331                 r_printf("(NAN) NaN\n");
332         else if (rvm_reg_gettype(r) == RVM_DTYPE_UNDEF)
333                 r_printf("(UNDEF) undefined\n");
334         else if (rvm_reg_gettype(r) == RVM_DTYPE_BOOLEAN)
335                 r_printf("(BOOLEAN) %s\n", RVM_REG_GETU(r) ? "true" : "false");
336         else if (rvm_reg_gettype(r) == RVM_DTYPE_POINTER)
337                 r_printf("(POINTER) %p\n", RVM_REG_GETP(r));
338         else if (rvm_reg_gettype(r) == RVM_DTYPE_LONG)
339                 r_printf("(LONG) %ld\n", RVM_REG_GETL(r));
340         else if (rvm_reg_gettype(r) == RVM_DTYPE_DOUBLE)
341                 r_printf("(DOUBLE) %f\n", RVM_REG_GETD(r));
342         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRING)
343                 r_printf("(STRING) %s\n", ((rstring_t*) RVM_REG_GETP(r))->s.str);
344         else if (rvm_reg_gettype(r) == RVM_DTYPE_STRPTR)
345                 r_printf("(STRPTR) %s\n", (RVM_REG_GETSTR(r)));
346         else if (rvm_reg_gettype(r) == RVM_DTYPE_JSOBJECT)
347                 r_printf("(object) %p\n",RVM_REG_GETP(r));
348         else if (rvm_reg_gettype(r) == RVM_DTYPE_HARRAY)
349                 r_printf("(hashed array) %p\n",RVM_REG_GETP(r));
350         else if (rvm_reg_gettype(r) == RVM_DTYPE_SWIID)
351                 r_printf("(swi function) %p\n",RVM_REG_GETP(r));
352         else if (rvm_reg_gettype(r) == RVM_DTYPE_FUNCTION)
353                 r_printf("(function) %p\n",RVM_REG_GETP(r));
354         else
355                 r_printf("%p\n", RVM_REG_GETP(r));
356 }
357
358
359 static void rjs_engine_object(rvmcpu_t *cpu, rvm_asmins_t *ins)
360 {
361
362 }
363
364
365 void rjs_engine_abort(rjs_engine_t *jse, rjs_error_t *error)
366 {
367         if (error) {
368                 r_array_add(jse->errors, error);
369         }
370         rvm_cpu_abort(jse->cpu);
371 }
372
373
374 rjs_engine_t *rjs_engine_get(rvmcpu_t *cpu)
375 {
376         return (rjs_engine_t *)cpu->userdata1;
377 }