jsobject.c 13 KB

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