Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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