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 | |
10 | static 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 | |
19 | static void js_defaultreport(js_State *J, const char *message) |
20 | { |
21 | fputs(message, stderr); |
22 | fputc('\n', stderr); |
23 | } |
24 | |
25 | static void js_defaultpanic(js_State *J) |
26 | { |
27 | js_report(J, "uncaught exception" ); |
28 | /* return to javascript to abort */ |
29 | } |
30 | |
31 | int 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 | |
40 | int 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 | |
49 | const 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 | |
61 | double 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 | |
73 | int 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 | |
85 | int 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 | |
97 | static 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 | |
115 | void js_loadeval(js_State *J, const char *filename, const char *source) |
116 | { |
117 | js_loadstringx(J, filename, source, 1); |
118 | } |
119 | |
120 | void js_loadstring(js_State *J, const char *filename, const char *source) |
121 | { |
122 | js_loadstringx(J, filename, source, 0); |
123 | } |
124 | |
125 | void 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 | |
181 | int 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 | |
196 | int 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 | |
211 | js_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 | |
218 | void js_report(js_State *J, const char *message) |
219 | { |
220 | if (J->report) |
221 | J->report(J, message); |
222 | } |
223 | |
224 | void js_setreport(js_State *J, js_Report report) |
225 | { |
226 | J->report = report; |
227 | } |
228 | |
229 | void js_setcontext(js_State *J, void *uctx) |
230 | { |
231 | J->uctx = uctx; |
232 | } |
233 | |
234 | void *js_getcontext(js_State *J) |
235 | { |
236 | return J->uctx; |
237 | } |
238 | |
239 | js_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 | |