kolibrios/programs/develop/kosjs/libmujs/jsobject.c
maxcodehack 91ae0dee0b kosjs: replace libmujs.a with sources; if argc = 0, see "usage"
git-svn-id: svn://kolibrios.org@8456 a494cfbc-eb01-0410-851d-a64ba20cac60
2020-12-20 08:45:42 +00:00

522 lines
12 KiB
C
Executable File

#include "jsi.h"
#include "jsvalue.h"
#include "jsbuiltin.h"
static void jsB_new_Object(js_State *J)
{
if (js_isundefined(J, 1) || js_isnull(J, 1))
js_newobject(J);
else
js_pushobject(J, js_toobject(J, 1));
}
static void jsB_Object(js_State *J)
{
if (js_isundefined(J, 1) || js_isnull(J, 1))
js_newobject(J);
else
js_pushobject(J, js_toobject(J, 1));
}
static void Op_toString(js_State *J)
{
if (js_isundefined(J, 0))
js_pushliteral(J, "[object Undefined]");
else if (js_isnull(J, 0))
js_pushliteral(J, "[object Null]");
else {
js_Object *self = js_toobject(J, 0);
switch (self->type) {
case JS_COBJECT: js_pushliteral(J, "[object Object]"); break;
case JS_CARRAY: js_pushliteral(J, "[object Array]"); break;
case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break;
case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break;
case JS_CEVAL: js_pushliteral(J, "[object Function]"); break;
case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break;
case JS_CERROR: js_pushliteral(J, "[object Error]"); break;
case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break;
case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break;
case JS_CSTRING: js_pushliteral(J, "[object String]"); break;
case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break;
case JS_CDATE: js_pushliteral(J, "[object Date]"); break;
case JS_CMATH: js_pushliteral(J, "[object Math]"); break;
case JS_CJSON: js_pushliteral(J, "[object JSON]"); break;
case JS_CARGUMENTS: js_pushliteral(J, "[object Arguments]"); break;
case JS_CITERATOR: js_pushliteral(J, "[object Iterator]"); break;
case JS_CUSERDATA:
js_pushliteral(J, "[object ");
js_pushliteral(J, self->u.user.tag);
js_concat(J);
js_pushliteral(J, "]");
js_concat(J);
break;
}
}
}
static void Op_valueOf(js_State *J)
{
js_copy(J, 0);
}
static void Op_hasOwnProperty(js_State *J)
{
js_Object *self = js_toobject(J, 0);
const char *name = js_tostring(J, 1);
js_Property *ref = jsV_getownproperty(J, self, name);
js_pushboolean(J, ref != NULL);
}
static void Op_isPrototypeOf(js_State *J)
{
js_Object *self = js_toobject(J, 0);
if (js_isobject(J, 1)) {
js_Object *V = js_toobject(J, 1);
do {
V = V->prototype;
if (V == self) {
js_pushboolean(J, 1);
return;
}
} while (V);
}
js_pushboolean(J, 0);
}
static void Op_propertyIsEnumerable(js_State *J)
{
js_Object *self = js_toobject(J, 0);
const char *name = js_tostring(J, 1);
js_Property *ref = jsV_getownproperty(J, self, name);
js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM));
}
static void O_getPrototypeOf(js_State *J)
{
js_Object *obj;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
if (obj->prototype)
js_pushobject(J, obj->prototype);
else
js_pushnull(J);
}
static void O_getOwnPropertyDescriptor(js_State *J)
{
js_Object *obj;
js_Property *ref;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
ref = jsV_getproperty(J, obj, js_tostring(J, 2));
if (!ref)
js_pushundefined(J);
else {
js_newobject(J);
if (!ref->getter && !ref->setter) {
js_pushvalue(J, ref->value);
js_setproperty(J, -2, "value");
js_pushboolean(J, !(ref->atts & JS_READONLY));
js_setproperty(J, -2, "writable");
} else {
if (ref->getter)
js_pushobject(J, ref->getter);
else
js_pushundefined(J);
js_setproperty(J, -2, "get");
if (ref->setter)
js_pushobject(J, ref->setter);
else
js_pushundefined(J);
js_setproperty(J, -2, "set");
}
js_pushboolean(J, !(ref->atts & JS_DONTENUM));
js_setproperty(J, -2, "enumerable");
js_pushboolean(J, !(ref->atts & JS_DONTCONF));
js_setproperty(J, -2, "configurable");
}
}
static int O_getOwnPropertyNames_walk(js_State *J, js_Property *ref, int i)
{
if (ref->left->level)
i = O_getOwnPropertyNames_walk(J, ref->left, i);
js_pushliteral(J, ref->name);
js_setindex(J, -2, i++);
if (ref->right->level)
i = O_getOwnPropertyNames_walk(J, ref->right, i);
return i;
}
static void O_getOwnPropertyNames(js_State *J)
{
js_Object *obj;
int k;
int i;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
js_newarray(J);
if (obj->properties->level)
i = O_getOwnPropertyNames_walk(J, obj->properties, 0);
else
i = 0;
if (obj->type == JS_CARRAY) {
js_pushliteral(J, "length");
js_setindex(J, -2, i++);
}
if (obj->type == JS_CSTRING) {
js_pushliteral(J, "length");
js_setindex(J, -2, i++);
for (k = 0; k < obj->u.s.length; ++k) {
js_pushnumber(J, k);
js_setindex(J, -2, i++);
}
}
if (obj->type == JS_CREGEXP) {
js_pushliteral(J, "source");
js_setindex(J, -2, i++);
js_pushliteral(J, "global");
js_setindex(J, -2, i++);
js_pushliteral(J, "ignoreCase");
js_setindex(J, -2, i++);
js_pushliteral(J, "multiline");
js_setindex(J, -2, i++);
js_pushliteral(J, "lastIndex");
js_setindex(J, -2, i++);
}
}
static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name, js_Object *desc)
{
int haswritable = 0;
int hasvalue = 0;
int enumerable = 0;
int configurable = 0;
int writable = 0;
int atts = 0;
js_pushobject(J, obj);
js_pushobject(J, desc);
if (js_hasproperty(J, -1, "writable")) {
haswritable = 1;
writable = js_toboolean(J, -1);
js_pop(J, 1);
}
if (js_hasproperty(J, -1, "enumerable")) {
enumerable = js_toboolean(J, -1);
js_pop(J, 1);
}
if (js_hasproperty(J, -1, "configurable")) {
configurable = js_toboolean(J, -1);
js_pop(J, 1);
}
if (js_hasproperty(J, -1, "value")) {
hasvalue = 1;
js_setproperty(J, -3, name);
}
if (!writable) atts |= JS_READONLY;
if (!enumerable) atts |= JS_DONTENUM;
if (!configurable) atts |= JS_DONTCONF;
if (js_hasproperty(J, -1, "get")) {
if (haswritable || hasvalue)
js_typeerror(J, "value/writable and get/set attributes are exclusive");
} else {
js_pushundefined(J);
}
if (js_hasproperty(J, -2, "set")) {
if (haswritable || hasvalue)
js_typeerror(J, "value/writable and get/set attributes are exclusive");
} else {
js_pushundefined(J);
}
js_defaccessor(J, -4, name, atts);
js_pop(J, 2);
}
static void O_defineProperty(js_State *J)
{
if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
if (!js_isobject(J, 3)) js_typeerror(J, "not an object");
ToPropertyDescriptor(J, js_toobject(J, 1), js_tostring(J, 2), js_toobject(J, 3));
js_copy(J, 1);
}
static void O_defineProperties_walk(js_State *J, js_Property *ref)
{
if (ref->left->level)
O_defineProperties_walk(J, ref->left);
if (!(ref->atts & JS_DONTENUM)) {
js_pushvalue(J, ref->value);
ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1));
js_pop(J, 1);
}
if (ref->right->level)
O_defineProperties_walk(J, ref->right);
}
static void O_defineProperties(js_State *J)
{
js_Object *props;
if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
props = js_toobject(J, 2);
if (props->properties->level)
O_defineProperties_walk(J, props->properties);
js_copy(J, 1);
}
static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref)
{
if (ref->left->level)
O_create_walk(J, obj, ref->left);
if (!(ref->atts & JS_DONTENUM)) {
if (ref->value.type != JS_TOBJECT)
js_typeerror(J, "not an object");
ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object);
}
if (ref->right->level)
O_create_walk(J, obj, ref->right);
}
static void O_create(js_State *J)
{
js_Object *obj;
js_Object *proto;
js_Object *props;
if (js_isobject(J, 1))
proto = js_toobject(J, 1);
else if (js_isnull(J, 1))
proto = NULL;
else
js_typeerror(J, "not an object or null");
obj = jsV_newobject(J, JS_COBJECT, proto);
js_pushobject(J, obj);
if (js_isdefined(J, 2)) {
if (!js_isobject(J, 2))
js_typeerror(J, "not an object");
props = js_toobject(J, 2);
if (props->properties->level)
O_create_walk(J, obj, props->properties);
}
}
static int O_keys_walk(js_State *J, js_Property *ref, int i)
{
if (ref->left->level)
i = O_keys_walk(J, ref->left, i);
if (!(ref->atts & JS_DONTENUM)) {
js_pushliteral(J, ref->name);
js_setindex(J, -2, i++);
}
if (ref->right->level)
i = O_keys_walk(J, ref->right, i);
return i;
}
static void O_keys(js_State *J)
{
js_Object *obj;
int i, k;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
js_newarray(J);
if (obj->properties->level)
i = O_keys_walk(J, obj->properties, 0);
else
i = 0;
if (obj->type == JS_CSTRING) {
for (k = 0; k < obj->u.s.length; ++k) {
js_pushnumber(J, k);
js_setindex(J, -2, i++);
}
}
}
static void O_preventExtensions(js_State *J)
{
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
js_toobject(J, 1)->extensible = 0;
js_copy(J, 1);
}
static void O_isExtensible(js_State *J)
{
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
js_pushboolean(J, js_toobject(J, 1)->extensible);
}
static void O_seal_walk(js_State *J, js_Property *ref)
{
if (ref->left->level)
O_seal_walk(J, ref->left);
ref->atts |= JS_DONTCONF;
if (ref->right->level)
O_seal_walk(J, ref->right);
}
static void O_seal(js_State *J)
{
js_Object *obj;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
obj->extensible = 0;
if (obj->properties->level)
O_seal_walk(J, obj->properties);
js_copy(J, 1);
}
static int O_isSealed_walk(js_State *J, js_Property *ref)
{
if (ref->left->level)
if (!O_isSealed_walk(J, ref->left))
return 0;
if (!(ref->atts & JS_DONTCONF))
return 0;
if (ref->right->level)
if (!O_isSealed_walk(J, ref->right))
return 0;
return 1;
}
static void O_isSealed(js_State *J)
{
js_Object *obj;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
if (obj->extensible) {
js_pushboolean(J, 0);
return;
}
if (obj->properties->level)
js_pushboolean(J, O_isSealed_walk(J, obj->properties));
else
js_pushboolean(J, 1);
}
static void O_freeze_walk(js_State *J, js_Property *ref)
{
if (ref->left->level)
O_freeze_walk(J, ref->left);
ref->atts |= JS_READONLY | JS_DONTCONF;
if (ref->right->level)
O_freeze_walk(J, ref->right);
}
static void O_freeze(js_State *J)
{
js_Object *obj;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
obj->extensible = 0;
if (obj->properties->level)
O_freeze_walk(J, obj->properties);
js_copy(J, 1);
}
static int O_isFrozen_walk(js_State *J, js_Property *ref)
{
if (ref->left->level)
if (!O_isFrozen_walk(J, ref->left))
return 0;
if (!(ref->atts & JS_READONLY))
return 0;
if (!(ref->atts & JS_DONTCONF))
return 0;
if (ref->right->level)
if (!O_isFrozen_walk(J, ref->right))
return 0;
return 1;
}
static void O_isFrozen(js_State *J)
{
js_Object *obj;
if (!js_isobject(J, 1))
js_typeerror(J, "not an object");
obj = js_toobject(J, 1);
if (obj->properties->level) {
if (!O_isFrozen_walk(J, obj->properties)) {
js_pushboolean(J, 0);
return;
}
}
js_pushboolean(J, !obj->extensible);
}
void jsB_initobject(js_State *J)
{
js_pushobject(J, J->Object_prototype);
{
jsB_propf(J, "Object.prototype.toString", Op_toString, 0);
jsB_propf(J, "Object.prototype.toLocaleString", Op_toString, 0);
jsB_propf(J, "Object.prototype.valueOf", Op_valueOf, 0);
jsB_propf(J, "Object.prototype.hasOwnProperty", Op_hasOwnProperty, 1);
jsB_propf(J, "Object.prototype.isPrototypeOf", Op_isPrototypeOf, 1);
jsB_propf(J, "Object.prototype.propertyIsEnumerable", Op_propertyIsEnumerable, 1);
}
js_newcconstructor(J, jsB_Object, jsB_new_Object, "Object", 1);
{
/* ES5 */
jsB_propf(J, "Object.getPrototypeOf", O_getPrototypeOf, 1);
jsB_propf(J, "Object.getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2);
jsB_propf(J, "Object.getOwnPropertyNames", O_getOwnPropertyNames, 1);
jsB_propf(J, "Object.create", O_create, 2);
jsB_propf(J, "Object.defineProperty", O_defineProperty, 3);
jsB_propf(J, "Object.defineProperties", O_defineProperties, 2);
jsB_propf(J, "Object.seal", O_seal, 1);
jsB_propf(J, "Object.freeze", O_freeze, 1);
jsB_propf(J, "Object.preventExtensions", O_preventExtensions, 1);
jsB_propf(J, "Object.isSealed", O_isSealed, 1);
jsB_propf(J, "Object.isFrozen", O_isFrozen, 1);
jsB_propf(J, "Object.isExtensible", O_isExtensible, 1);
jsB_propf(J, "Object.keys", O_keys, 1);
}
js_defglobal(J, "Object", JS_DONTENUM);
}