1#include "jsi.h"
2#include "jsvalue.h"
3#include "jsbuiltin.h"
4
5static void jsB_new_Object(js_State *J)
6{
7 if (js_isundefined(J, 1) || js_isnull(J, 1))
8 js_newobject(J);
9 else
10 js_pushobject(J, js_toobject(J, 1));
11}
12
13static void jsB_Object(js_State *J)
14{
15 if (js_isundefined(J, 1) || js_isnull(J, 1))
16 js_newobject(J);
17 else
18 js_pushobject(J, js_toobject(J, 1));
19}
20
21static void Op_toString(js_State *J)
22{
23 if (js_isundefined(J, 0))
24 js_pushliteral(J, "[object Undefined]");
25 else if (js_isnull(J, 0))
26 js_pushliteral(J, "[object Null]");
27 else {
28 js_Object *self = js_toobject(J, 0);
29 switch (self->type) {
30 case JS_COBJECT: js_pushliteral(J, "[object Object]"); break;
31 case JS_CARRAY: js_pushliteral(J, "[object Array]"); break;
32 case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break;
33 case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break;
34 case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break;
35 case JS_CERROR: js_pushliteral(J, "[object Error]"); break;
36 case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break;
37 case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break;
38 case JS_CSTRING: js_pushliteral(J, "[object String]"); break;
39 case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break;
40 case JS_CDATE: js_pushliteral(J, "[object Date]"); break;
41 case JS_CMATH: js_pushliteral(J, "[object Math]"); break;
42 case JS_CJSON: js_pushliteral(J, "[object JSON]"); break;
43 case JS_CARGUMENTS: js_pushliteral(J, "[object Arguments]"); break;
44 case JS_CITERATOR: js_pushliteral(J, "[Iterator]"); break;
45 case JS_CUSERDATA:
46 js_pushliteral(J, "[object ");
47 js_pushliteral(J, self->u.user.tag);
48 js_concat(J);
49 js_pushliteral(J, "]");
50 js_concat(J);
51 break;
52 }
53 }
54}
55
56static void Op_valueOf(js_State *J)
57{
58 js_copy(J, 0);
59}
60
61static void Op_hasOwnProperty(js_State *J)
62{
63 js_Object *self = js_toobject(J, 0);
64 const char *name = js_tostring(J, 1);
65 js_Property *ref = jsV_getownproperty(J, self, name);
66 js_pushboolean(J, ref != NULL);
67}
68
69static void Op_isPrototypeOf(js_State *J)
70{
71 js_Object *self = js_toobject(J, 0);
72 if (js_isobject(J, 1)) {
73 js_Object *V = js_toobject(J, 1);
74 do {
75 V = V->prototype;
76 if (V == self) {
77 js_pushboolean(J, 1);
78 return;
79 }
80 } while (V);
81 }
82 js_pushboolean(J, 0);
83}
84
85static void Op_propertyIsEnumerable(js_State *J)
86{
87 js_Object *self = js_toobject(J, 0);
88 const char *name = js_tostring(J, 1);
89 js_Property *ref = jsV_getownproperty(J, self, name);
90 js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM));
91}
92
93static void O_getPrototypeOf(js_State *J)
94{
95 js_Object *obj;
96 if (!js_isobject(J, 1))
97 js_typeerror(J, "not an object");
98 obj = js_toobject(J, 1);
99 if (obj->prototype)
100 js_pushobject(J, obj->prototype);
101 else
102 js_pushnull(J);
103}
104
105static void O_getOwnPropertyDescriptor(js_State *J)
106{
107 js_Object *obj;
108 js_Property *ref;
109 if (!js_isobject(J, 1))
110 js_typeerror(J, "not an object");
111 obj = js_toobject(J, 1);
112 ref = jsV_getproperty(J, obj, js_tostring(J, 2));
113 if (!ref)
114 js_pushundefined(J);
115 else {
116 js_newobject(J);
117 if (!ref->getter && !ref->setter) {
118 js_pushvalue(J, ref->value);
119 js_setproperty(J, -2, "value");
120 js_pushboolean(J, !(ref->atts & JS_READONLY));
121 js_setproperty(J, -2, "writable");
122 } else {
123 if (ref->getter)
124 js_pushobject(J, ref->getter);
125 else
126 js_pushundefined(J);
127 js_setproperty(J, -2, "get");
128 if (ref->setter)
129 js_pushobject(J, ref->setter);
130 else
131 js_pushundefined(J);
132 js_setproperty(J, -2, "set");
133 }
134 js_pushboolean(J, !(ref->atts & JS_DONTENUM));
135 js_setproperty(J, -2, "enumerable");
136 js_pushboolean(J, !(ref->atts & JS_DONTCONF));
137 js_setproperty(J, -2, "configurable");
138 }
139}
140
141static int O_getOwnPropertyNames_walk(js_State *J, js_Property *ref, int i)
142{
143 if (ref->left->level)
144 i = O_getOwnPropertyNames_walk(J, ref->left, i);
145 js_pushliteral(J, ref->name);
146 js_setindex(J, -2, i++);
147 if (ref->right->level)
148 i = O_getOwnPropertyNames_walk(J, ref->right, i);
149 return i;
150}
151
152static void O_getOwnPropertyNames(js_State *J)
153{
154 js_Object *obj;
155 int k;
156 int i;
157
158 if (!js_isobject(J, 1))
159 js_typeerror(J, "not an object");
160 obj = js_toobject(J, 1);
161
162 js_newarray(J);
163
164 if (obj->properties->level)
165 i = O_getOwnPropertyNames_walk(J, obj->properties, 0);
166 else
167 i = 0;
168
169 if (obj->type == JS_CARRAY) {
170 js_pushliteral(J, "length");
171 js_setindex(J, -2, i++);
172 }
173
174 if (obj->type == JS_CSTRING) {
175 js_pushliteral(J, "length");
176 js_setindex(J, -2, i++);
177 for (k = 0; k < obj->u.s.length; ++k) {
178 js_pushnumber(J, k);
179 js_setindex(J, -2, i++);
180 }
181 }
182
183 if (obj->type == JS_CREGEXP) {
184 js_pushliteral(J, "source");
185 js_setindex(J, -2, i++);
186 js_pushliteral(J, "global");
187 js_setindex(J, -2, i++);
188 js_pushliteral(J, "ignoreCase");
189 js_setindex(J, -2, i++);
190 js_pushliteral(J, "multiline");
191 js_setindex(J, -2, i++);
192 js_pushliteral(J, "lastIndex");
193 js_setindex(J, -2, i++);
194 }
195}
196
197static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name, js_Object *desc)
198{
199 int haswritable = 0;
200 int hasvalue = 0;
201 int enumerable = 0;
202 int configurable = 0;
203 int writable = 0;
204 int atts = 0;
205
206 js_pushobject(J, obj);
207 js_pushobject(J, desc);
208
209 if (js_hasproperty(J, -1, "writable")) {
210 haswritable = 1;
211 writable = js_toboolean(J, -1);
212 js_pop(J, 1);
213 }
214 if (js_hasproperty(J, -1, "enumerable")) {
215 enumerable = js_toboolean(J, -1);
216 js_pop(J, 1);
217 }
218 if (js_hasproperty(J, -1, "configurable")) {
219 configurable = js_toboolean(J, -1);
220 js_pop(J, 1);
221 }
222 if (js_hasproperty(J, -1, "value")) {
223 hasvalue = 1;
224 js_setproperty(J, -3, name);
225 }
226
227 if (!writable) atts |= JS_READONLY;
228 if (!enumerable) atts |= JS_DONTENUM;
229 if (!configurable) atts |= JS_DONTCONF;
230
231 if (js_hasproperty(J, -1, "get")) {
232 if (haswritable || hasvalue)
233 js_typeerror(J, "value/writable and get/set attributes are exclusive");
234 } else {
235 js_pushundefined(J);
236 }
237
238 if (js_hasproperty(J, -2, "set")) {
239 if (haswritable || hasvalue)
240 js_typeerror(J, "value/writable and get/set attributes are exclusive");
241 } else {
242 js_pushundefined(J);
243 }
244
245 js_defaccessor(J, -4, name, atts);
246
247 js_pop(J, 2);
248}
249
250static void O_defineProperty(js_State *J)
251{
252 if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
253 if (!js_isobject(J, 3)) js_typeerror(J, "not an object");
254 ToPropertyDescriptor(J, js_toobject(J, 1), js_tostring(J, 2), js_toobject(J, 3));
255 js_copy(J, 1);
256}
257
258static void O_defineProperties_walk(js_State *J, js_Property *ref)
259{
260 if (ref->left->level)
261 O_defineProperties_walk(J, ref->left);
262 if (!(ref->atts & JS_DONTENUM)) {
263 js_pushvalue(J, ref->value);
264 ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1));
265 js_pop(J, 1);
266 }
267 if (ref->right->level)
268 O_defineProperties_walk(J, ref->right);
269}
270
271static void O_defineProperties(js_State *J)
272{
273 js_Object *props;
274
275 if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
276 if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
277
278 props = js_toobject(J, 2);
279 if (props->properties->level)
280 O_defineProperties_walk(J, props->properties);
281
282 js_copy(J, 1);
283}
284
285static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref)
286{
287 if (ref->left->level)
288 O_create_walk(J, obj, ref->left);
289 if (!(ref->atts & JS_DONTENUM)) {
290 if (ref->value.type != JS_TOBJECT)
291 js_typeerror(J, "not an object");
292 ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object);
293 }
294 if (ref->right->level)
295 O_create_walk(J, obj, ref->right);
296}
297
298static void O_create(js_State *J)
299{
300 js_Object *obj;
301 js_Object *proto;
302 js_Object *props;
303
304 if (js_isobject(J, 1))
305 proto = js_toobject(J, 1);
306 else if (js_isnull(J, 1))
307 proto = NULL;
308 else
309 js_typeerror(J, "not an object or null");
310
311 obj = jsV_newobject(J, JS_COBJECT, proto);
312 js_pushobject(J, obj);
313
314 if (js_isdefined(J, 2)) {
315 if (!js_isobject(J, 2))
316 js_typeerror(J, "not an object");
317 props = js_toobject(J, 2);
318 if (props->properties->level)
319 O_create_walk(J, obj, props->properties);
320 }
321}
322
323static int O_keys_walk(js_State *J, js_Property *ref, int i)
324{
325 if (ref->left->level)
326 i = O_keys_walk(J, ref->left, i);
327 if (!(ref->atts & JS_DONTENUM)) {
328 js_pushliteral(J, ref->name);
329 js_setindex(J, -2, i++);
330 }
331 if (ref->right->level)
332 i = O_keys_walk(J, ref->right, i);
333 return i;
334}
335
336static void O_keys(js_State *J)
337{
338 js_Object *obj;
339 int i, k;
340
341 if (!js_isobject(J, 1))
342 js_typeerror(J, "not an object");
343 obj = js_toobject(J, 1);
344
345 js_newarray(J);
346
347 if (obj->properties->level)
348 i = O_keys_walk(J, obj->properties, 0);
349 else
350 i = 0;
351
352 if (obj->type == JS_CSTRING) {
353 for (k = 0; k < obj->u.s.length; ++k) {
354 js_pushnumber(J, k);
355 js_setindex(J, -2, i++);
356 }
357 }
358}
359
360static void O_preventExtensions(js_State *J)
361{
362 if (!js_isobject(J, 1))
363 js_typeerror(J, "not an object");
364 js_toobject(J, 1)->extensible = 0;
365 js_copy(J, 1);
366}
367
368static void O_isExtensible(js_State *J)
369{
370 if (!js_isobject(J, 1))
371 js_typeerror(J, "not an object");
372 js_pushboolean(J, js_toobject(J, 1)->extensible);
373}
374
375static void O_seal_walk(js_State *J, js_Property *ref)
376{
377 if (ref->left->level)
378 O_seal_walk(J, ref->left);
379 ref->atts |= JS_DONTCONF;
380 if (ref->right->level)
381 O_seal_walk(J, ref->right);
382}
383
384static void O_seal(js_State *J)
385{
386 js_Object *obj;
387
388 if (!js_isobject(J, 1))
389 js_typeerror(J, "not an object");
390
391 obj = js_toobject(J, 1);
392 obj->extensible = 0;
393
394 if (obj->properties->level)
395 O_seal_walk(J, obj->properties);
396
397 js_copy(J, 1);
398}
399
400static int O_isSealed_walk(js_State *J, js_Property *ref)
401{
402 if (ref->left->level)
403 if (!O_isSealed_walk(J, ref->left))
404 return 0;
405 if (!(ref->atts & JS_DONTCONF))
406 return 0;
407 if (ref->right->level)
408 if (!O_isSealed_walk(J, ref->right))
409 return 0;
410 return 1;
411}
412
413static void O_isSealed(js_State *J)
414{
415 js_Object *obj;
416
417 if (!js_isobject(J, 1))
418 js_typeerror(J, "not an object");
419
420 obj = js_toobject(J, 1);
421 if (obj->extensible) {
422 js_pushboolean(J, 0);
423 return;
424 }
425
426 if (obj->properties->level)
427 js_pushboolean(J, O_isSealed_walk(J, obj->properties));
428 else
429 js_pushboolean(J, 1);
430}
431
432static void O_freeze_walk(js_State *J, js_Property *ref)
433{
434 if (ref->left->level)
435 O_freeze_walk(J, ref->left);
436 ref->atts |= JS_READONLY | JS_DONTCONF;
437 if (ref->right->level)
438 O_freeze_walk(J, ref->right);
439}
440
441static void O_freeze(js_State *J)
442{
443 js_Object *obj;
444
445 if (!js_isobject(J, 1))
446 js_typeerror(J, "not an object");
447
448 obj = js_toobject(J, 1);
449 obj->extensible = 0;
450
451 if (obj->properties->level)
452 O_freeze_walk(J, obj->properties);
453
454 js_copy(J, 1);
455}
456
457static int O_isFrozen_walk(js_State *J, js_Property *ref)
458{
459 if (ref->left->level)
460 if (!O_isFrozen_walk(J, ref->left))
461 return 0;
462 if (!(ref->atts & JS_READONLY))
463 return 0;
464 if (!(ref->atts & JS_DONTCONF))
465 return 0;
466 if (ref->right->level)
467 if (!O_isFrozen_walk(J, ref->right))
468 return 0;
469 return 1;
470}
471
472static void O_isFrozen(js_State *J)
473{
474 js_Object *obj;
475
476 if (!js_isobject(J, 1))
477 js_typeerror(J, "not an object");
478
479 obj = js_toobject(J, 1);
480
481 if (obj->properties->level) {
482 if (!O_isFrozen_walk(J, obj->properties)) {
483 js_pushboolean(J, 0);
484 return;
485 }
486 }
487
488 js_pushboolean(J, !obj->extensible);
489}
490
491void jsB_initobject(js_State *J)
492{
493 js_pushobject(J, J->Object_prototype);
494 {
495 jsB_propf(J, "Object.prototype.toString", Op_toString, 0);
496 jsB_propf(J, "Object.prototype.toLocaleString", Op_toString, 0);
497 jsB_propf(J, "Object.prototype.valueOf", Op_valueOf, 0);
498 jsB_propf(J, "Object.prototype.hasOwnProperty", Op_hasOwnProperty, 1);
499 jsB_propf(J, "Object.prototype.isPrototypeOf", Op_isPrototypeOf, 1);
500 jsB_propf(J, "Object.prototype.propertyIsEnumerable", Op_propertyIsEnumerable, 1);
501 }
502 js_newcconstructor(J, jsB_Object, jsB_new_Object, "Object", 1);
503 {
504 /* ES5 */
505 jsB_propf(J, "Object.getPrototypeOf", O_getPrototypeOf, 1);
506 jsB_propf(J, "Object.getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2);
507 jsB_propf(J, "Object.getOwnPropertyNames", O_getOwnPropertyNames, 1);
508 jsB_propf(J, "Object.create", O_create, 2);
509 jsB_propf(J, "Object.defineProperty", O_defineProperty, 3);
510 jsB_propf(J, "Object.defineProperties", O_defineProperties, 2);
511 jsB_propf(J, "Object.seal", O_seal, 1);
512 jsB_propf(J, "Object.freeze", O_freeze, 1);
513 jsB_propf(J, "Object.preventExtensions", O_preventExtensions, 1);
514 jsB_propf(J, "Object.isSealed", O_isSealed, 1);
515 jsB_propf(J, "Object.isFrozen", O_isFrozen, 1);
516 jsB_propf(J, "Object.isExtensible", O_isExtensible, 1);
517 jsB_propf(J, "Object.keys", O_keys, 1);
518 }
519 js_defglobal(J, "Object", JS_DONTENUM);
520}
521