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 
js_defaultalloc(void * actx,void * ptr,int size)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 
js_defaultreport(js_State * J,const char * message)19 static void js_defaultreport(js_State *J, const char *message)
20 {
21 	fputs(message, stderr);
22 	fputc('\n', stderr);
23 }
24 
js_defaultpanic(js_State * J)25 static void js_defaultpanic(js_State *J)
26 {
27 	js_report(J, "uncaught exception");
28 	/* return to javascript to abort */
29 }
30 
js_ploadstring(js_State * J,const char * filename,const char * source)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 
js_ploadfile(js_State * J,const char * filename)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 
js_trystring(js_State * J,int idx,const char * error)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 
js_trynumber(js_State * J,int idx,double error)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 
js_tryinteger(js_State * J,int idx,int error)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 
js_tryboolean(js_State * J,int idx,int error)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 
js_loadstringx(js_State * J,const char * filename,const char * source,int iseval)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_compile(J, P);
109 	jsP_freeparse(J);
110 	js_newscript(J, F, iseval ? (J->strict ? J->E : NULL) : J->GE);
111 
112 	js_endtry(J);
113 }
114 
js_loadeval(js_State * J,const char * filename,const char * source)115 void js_loadeval(js_State *J, const char *filename, const char *source)
116 {
117 	js_loadstringx(J, filename, source, 1);
118 }
119 
js_loadstring(js_State * J,const char * filename,const char * source)120 void js_loadstring(js_State *J, const char *filename, const char *source)
121 {
122 	js_loadstringx(J, filename, source, 0);
123 }
124 
js_loadfile(js_State * J,const char * filename)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'", filename);
134 	}
135 
136 	if (fseek(f, 0, SEEK_END) < 0) {
137 		fclose(f);
138 		js_error(J, "cannot seek in file: '%s'", filename);
139 	}
140 
141 	n = ftell(f);
142 	if (n < 0) {
143 		fclose(f);
144 		js_error(J, "cannot tell in file: '%s'", filename);
145 	}
146 
147 	if (fseek(f, 0, SEEK_SET) < 0) {
148 		fclose(f);
149 		js_error(J, "cannot seek in file: '%s'", filename);
150 	}
151 
152 	s = js_malloc(J, n + 1); /* add space for string terminator */
153 	if (!s) {
154 		fclose(f);
155 		js_error(J, "cannot allocate storage for file contents: '%s'", filename);
156 	}
157 
158 	t = fread(s, 1, (size_t)n, f);
159 	if (t != n) {
160 		js_free(J, s);
161 		fclose(f);
162 		js_error(J, "cannot read data from file: '%s'", filename);
163 	}
164 
165 	s[n] = 0; /* zero-terminate string containing file data */
166 
167 	if (js_try(J)) {
168 		js_free(J, s);
169 		fclose(f);
170 		js_throw(J);
171 	}
172 
173 	js_loadstring(J, filename, s);
174 
175 	js_free(J, s);
176 	fclose(f);
177 	js_endtry(J);
178 }
179 
js_dostring(js_State * J,const char * source)180 int js_dostring(js_State *J, const char *source)
181 {
182 	if (js_try(J)) {
183 		js_report(J, js_trystring(J, -1, "Error"));
184 		js_pop(J, 1);
185 		return 1;
186 	}
187 	js_loadstring(J, "[string]", source);
188 	js_pushundefined(J);
189 	js_call(J, 0);
190 	js_pop(J, 1);
191 	js_endtry(J);
192 	return 0;
193 }
194 
js_dofile(js_State * J,const char * filename)195 int js_dofile(js_State *J, const char *filename)
196 {
197 	if (js_try(J)) {
198 		js_report(J, js_trystring(J, -1, "Error"));
199 		js_pop(J, 1);
200 		return 1;
201 	}
202 	js_loadfile(J, filename);
203 	js_pushundefined(J);
204 	js_call(J, 0);
205 	js_pop(J, 1);
206 	js_endtry(J);
207 	return 0;
208 }
209 
js_atpanic(js_State * J,js_Panic panic)210 js_Panic js_atpanic(js_State *J, js_Panic panic)
211 {
212 	js_Panic old = J->panic;
213 	J->panic = panic;
214 	return old;
215 }
216 
js_report(js_State * J,const char * message)217 void js_report(js_State *J, const char *message)
218 {
219 	if (J->report)
220 		J->report(J, message);
221 }
222 
js_setreport(js_State * J,js_Report report)223 void js_setreport(js_State *J, js_Report report)
224 {
225 	J->report = report;
226 }
227 
js_setcontext(js_State * J,void * uctx)228 void js_setcontext(js_State *J, void *uctx)
229 {
230 	J->uctx = uctx;
231 }
232 
js_getcontext(js_State * J)233 void *js_getcontext(js_State *J)
234 {
235 	return J->uctx;
236 }
237 
js_newstate(js_Alloc alloc,void * actx,int flags)238 js_State *js_newstate(js_Alloc alloc, void *actx, int flags)
239 {
240 	js_State *J;
241 
242 	assert(sizeof(js_Value) == 16);
243 	assert(soffsetof(js_Value, type) == 15);
244 
245 	if (!alloc)
246 		alloc = js_defaultalloc;
247 
248 	J = alloc(actx, NULL, sizeof *J);
249 	if (!J)
250 		return NULL;
251 	memset(J, 0, sizeof(*J));
252 	J->actx = actx;
253 	J->alloc = alloc;
254 
255 	if (flags & JS_STRICT)
256 		J->strict = J->default_strict = 1;
257 
258 	J->trace[0].name = "-top-";
259 	J->trace[0].file = "native";
260 	J->trace[0].line = 0;
261 
262 	J->report = js_defaultreport;
263 	J->panic = js_defaultpanic;
264 
265 	J->stack = alloc(actx, NULL, JS_STACKSIZE * sizeof *J->stack);
266 	if (!J->stack) {
267 		alloc(actx, NULL, 0);
268 		return NULL;
269 	}
270 
271 	J->gcmark = 1;
272 	J->nextref = 0;
273 
274 	J->R = jsV_newobject(J, JS_COBJECT, NULL);
275 	J->G = jsV_newobject(J, JS_COBJECT, NULL);
276 	J->E = jsR_newenvironment(J, J->G, NULL);
277 	J->GE = J->E;
278 
279 	jsB_init(J);
280 
281 	return J;
282 }
283