shithub: libmujs

Download patch

ref: a09493e144f661927c07b53f0a6f15a632721694
parent: 8e917e8c2786c31ab1a8209f429286afcc4d1ebc
author: Tor Andersson <tor@ccxvii.net>
date: Thu Feb 6 19:44:49 EST 2014

Implement ES5 prototype descriptor and misc object functions.

--- a/js.h
+++ b/js.h
@@ -95,7 +95,7 @@
 void js_setproperty(js_State *J, int idx, const char *name);
 void js_defproperty(js_State *J, int idx, const char *name, int atts);
 void js_delproperty(js_State *J, int idx, const char *name);
-void js_defaccessor(js_State *J, int idx, const char *name);
+void js_defaccessor(js_State *J, int idx, const char *name, int atts);
 
 int js_hasindex(js_State *J, int idx, unsigned int i);
 void js_getindex(js_State *J, int idx, unsigned int i);
--- a/jsobject.c
+++ b/jsobject.c
@@ -90,6 +90,208 @@
 	return 1;
 }
 
+static int O_getPrototypeOf(js_State *J, int argc)
+{
+	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);
+	return 1;
+}
+
+static int O_getOwnPropertyDescriptor(js_State *J, int argc)
+{
+	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");
+	}
+	return 1;
+}
+
+static int O_getOwnPropertyNames(js_State *J, int argc)
+{
+	js_Object *obj;
+	js_Property *ref;
+	int i;
+
+	if (!js_isobject(J, 1))
+		js_typeerror(J, "not an object");
+	obj = js_toobject(J, 1);
+
+	js_newarray(J);
+	for (ref = obj->head; ref; ref = ref->next) {
+		js_pushliteral(J, ref->name);
+		js_setindex(J, -2, i++);
+	}
+	return 1;
+}
+
+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 int O_defineProperty(js_State *J, int argc)
+{
+	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);
+	return 1;
+}
+
+static int O_defineProperties(js_State *J, int argc)
+{
+	js_Object *props;
+	js_Property *ref;
+
+	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);
+	for (ref = props->head; ref; ref = ref->next) {
+		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);
+		}
+	}
+
+	js_copy(J, 1);
+	return 1;
+}
+
+static int O_create(js_State *J, int argc)
+{
+	js_Object *obj;
+	js_Object *proto;
+	js_Object *props;
+	js_Property *ref;
+
+	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_isundefined(J, 2)) {
+		if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
+		props = js_toobject(J, 2);
+		for (ref = props->head; ref; ref = ref->next) {
+			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);
+			}
+		}
+	}
+
+	return 1;
+}
+
+static int O_keys(js_State *J, int argc)
+{
+	js_Object *obj;
+	js_Property *ref;
+	int i;
+
+	if (!js_isobject(J, 1))
+		js_typeerror(J, "not an object");
+	obj = js_toobject(J, 1);
+
+	js_newarray(J);
+	for (ref = obj->head; ref; ref = ref->next) {
+		if (!(ref->atts & JS_DONTENUM)) {
+			js_pushliteral(J, ref->name);
+			js_setindex(J, -2, i++);
+		}
+	}
+	return 1;
+}
+
 void jsB_initobject(js_State *J)
 {
 	js_pushobject(J, J->Object_prototype);
@@ -102,5 +304,21 @@
 		jsB_propf(J, "propertyIsEnumerable", Op_propertyIsEnumerable, 1);
 	}
 	js_newcconstructor(J, jsB_Object, jsB_new_Object, 1);
+	{
+		/* ES5 */
+		jsB_propf(J, "getPrototypeOf", O_getPrototypeOf, 1);
+		jsB_propf(J, "getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2);
+		jsB_propf(J, "getOwnPropertyNames", O_getOwnPropertyNames, 1);
+		jsB_propf(J, "create", O_create, 2);
+		jsB_propf(J, "defineProperty", O_defineProperty, 3);
+		jsB_propf(J, "defineProperties", O_defineProperties, 2);
+		//jsB_propf(J, "seal", O_seal, 1);
+		//jsB_propf(J, "freeze", O_freeze, 1);
+		//jsB_propf(J, "preventExtensions", O_preventExtensions, 1);
+		//jsB_propf(J, "isSealed", O_isSealed, 1);
+		//jsB_propf(J, "isFrozen", O_isFrozen, 1);
+		//jsB_propf(J, "isExtensible", O_isExtensible, 1);
+		jsB_propf(J, "keys", O_keys, 1);
+	}
 	js_defglobal(J, "Object", JS_DONTENUM);
 }
--- a/jsrun.c
+++ b/jsrun.c
@@ -612,9 +612,9 @@
 	jsR_delproperty(J, js_toobject(J, idx), name);
 }
 
-void js_defaccessor(js_State *J, int idx, const char *name)
+void js_defaccessor(js_State *J, int idx, const char *name, int atts)
 {
-	jsR_defproperty(J, js_toobject(J, idx), name, 0, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1));
+	jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1));
 	js_pop(J, 2);
 }