1#include "jsi.h"
2#include "jsparse.h"
3#include "jscompile.h"
4#include "jsvalue.h"
5#include "jsrun.h"
6#include "jsbuiltin.h"
7
8#include <assert.h>
9
10static void *js_defaultalloc(void *actx, void *ptr, int size)
11{
12 if (size == 0) {
13 free(ptr);
14 return NULL;
15 }
16 return realloc(ptr, (size_t)size);
17}
18
19static void js_defaultreport(js_State *J, const char *message)
20{
21 fputs(message, stderr);
22 fputc('\n', stderr);
23}
24
25static void js_defaultpanic(js_State *J)
26{
27 js_report(J, "uncaught exception");
28 /* return to javascript to abort */
29}
30
31int js_ploadstring(js_State *J, const char *filename, const char *source)
32{
33 if (js_try(J))
34 return 1;
35 js_loadstring(J, filename, source);
36 js_endtry(J);
37 return 0;
38}
39
40int js_ploadfile(js_State *J, const char *filename)
41{
42 if (js_try(J))
43 return 1;
44 js_loadfile(J, filename);
45 js_endtry(J);
46 return 0;
47}
48
49const char *js_trystring(js_State *J, int idx, const char *error)
50{
51 const char *s;
52 if (js_try(J)) {
53 js_pop(J, 1);
54 return error;
55 }
56 s = js_tostring(J, idx);
57 js_endtry(J);
58 return s;
59}
60
61double js_trynumber(js_State *J, int idx, double error)
62{
63 double v;
64 if (js_try(J)) {
65 js_pop(J, 1);
66 return error;
67 }
68 v = js_tonumber(J, idx);
69 js_endtry(J);
70 return v;
71}
72
73int js_tryinteger(js_State *J, int idx, int error)
74{
75 int v;
76 if (js_try(J)) {
77 js_pop(J, 1);
78 return error;
79 }
80 v = js_tointeger(J, idx);
81 js_endtry(J);
82 return v;
83}
84
85int js_tryboolean(js_State *J, int idx, int error)
86{
87 int v;
88 if (js_try(J)) {
89 js_pop(J, 1);
90 return error;
91 }
92 v = js_toboolean(J, idx);
93 js_endtry(J);
94 return v;
95}
96
97static void js_loadstringx(js_State *J, const char *filename, const char *source, int iseval)
98{
99 js_Ast *P;
100 js_Function *F;
101
102 if (js_try(J)) {
103 jsP_freeparse(J);
104 js_throw(J);
105 }
106
107 P = jsP_parse(J, filename, source);
108 F = jsC_compilescript(J, P, iseval ? J->strict : J->default_strict);
109 jsP_freeparse(J);
110 js_newscript(J, F, iseval ? (J->strict ? J->E : NULL) : J->GE);
111
112 js_endtry(J);
113}
114
115void js_loadeval(js_State *J, const char *filename, const char *source)
116{
117 js_loadstringx(J, filename, source, 1);
118}
119
120void js_loadstring(js_State *J, const char *filename, const char *source)
121{
122 js_loadstringx(J, filename, source, 0);
123}
124
125void js_loadfile(js_State *J, const char *filename)
126{
127 FILE *f;
128 char *s;
129 int n, t;
130
131 f = fopen(filename, "rb");
132 if (!f) {
133 js_error(J, "cannot open file '%s': %s", filename, strerror(errno));
134 }
135
136 if (fseek(f, 0, SEEK_END) < 0) {
137 fclose(f);
138 js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
139 }
140
141 n = ftell(f);
142 if (n < 0) {
143 fclose(f);
144 js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno));
145 }
146
147 if (fseek(f, 0, SEEK_SET) < 0) {
148 fclose(f);
149 js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
150 }
151
152 if (js_try(J)) {
153 fclose(f);
154 js_throw(J);
155 }
156 s = js_malloc(J, n + 1); /* add space for string terminator */
157 js_endtry(J);
158
159 t = fread(s, 1, (size_t)n, f);
160 if (t != n) {
161 js_free(J, s);
162 fclose(f);
163 js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
164 }
165
166 s[n] = 0; /* zero-terminate string containing file data */
167
168 if (js_try(J)) {
169 js_free(J, s);
170 fclose(f);
171 js_throw(J);
172 }
173
174 js_loadstring(J, filename, s);
175
176 js_free(J, s);
177 fclose(f);
178 js_endtry(J);
179}
180
181int js_dostring(js_State *J, const char *source)
182{
183 if (js_try(J)) {
184 js_report(J, js_trystring(J, -1, "Error"));
185 js_pop(J, 1);
186 return 1;
187 }
188 js_loadstring(J, "[string]", source);
189 js_pushundefined(J);
190 js_call(J, 0);
191 js_pop(J, 1);
192 js_endtry(J);
193 return 0;
194}
195
196int js_dofile(js_State *J, const char *filename)
197{
198 if (js_try(J)) {
199 js_report(J, js_trystring(J, -1, "Error"));
200 js_pop(J, 1);
201 return 1;
202 }
203 js_loadfile(J, filename);
204 js_pushundefined(J);
205 js_call(J, 0);
206 js_pop(J, 1);
207 js_endtry(J);
208 return 0;
209}
210
211js_Panic js_atpanic(js_State *J, js_Panic panic)
212{
213 js_Panic old = J->panic;
214 J->panic = panic;
215 return old;
216}
217
218void js_report(js_State *J, const char *message)
219{
220 if (J->report)
221 J->report(J, message);
222}
223
224void js_setreport(js_State *J, js_Report report)
225{
226 J->report = report;
227}
228
229void js_setcontext(js_State *J, void *uctx)
230{
231 J->uctx = uctx;
232}
233
234void *js_getcontext(js_State *J)
235{
236 return J->uctx;
237}
238
239js_State *js_newstate(js_Alloc alloc, void *actx, int flags)
240{
241 js_State *J;
242
243 assert(sizeof(js_Value) == 16);
244 assert(soffsetof(js_Value, type) == 15);
245
246 if (!alloc)
247 alloc = js_defaultalloc;
248
249 J = alloc(actx, NULL, sizeof *J);
250 if (!J)
251 return NULL;
252 memset(J, 0, sizeof(*J));
253 J->actx = actx;
254 J->alloc = alloc;
255
256 if (flags & JS_STRICT)
257 J->strict = J->default_strict = 1;
258
259 J->trace[0].name = "-top-";
260 J->trace[0].file = "native";
261 J->trace[0].line = 0;
262
263 J->report = js_defaultreport;
264 J->panic = js_defaultpanic;
265
266 J->stack = alloc(actx, NULL, JS_STACKSIZE * sizeof *J->stack);
267 if (!J->stack) {
268 alloc(actx, NULL, 0);
269 return NULL;
270 }
271
272 J->gcmark = 1;
273 J->nextref = 0;
274
275 J->R = jsV_newobject(J, JS_COBJECT, NULL);
276 J->G = jsV_newobject(J, JS_COBJECT, NULL);
277 J->E = jsR_newenvironment(J, J->G, NULL);
278 J->GE = J->E;
279
280 jsB_init(J);
281
282 return J;
283}
284