shithub: libmujs

Download patch

ref: 07610bd0ac03c3c3473cb1965aed6db08d6120c5
parent: 05275e2e5de3231e0e2278e3792bb077db6a33c1
author: Tor Andersson <tor@ccxvii.net>
date: Sat Jan 18 15:16:28 EST 2014

Refactor ToString and ToNumber functions. Add ToPrimitive.

--- a/jsrun.c
+++ b/jsrun.c
@@ -119,6 +119,14 @@
 int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; }
 int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; }
 
+int js_iscallable(js_State *J, int idx)
+{
+	const js_Value *v = stackidx(J, idx);
+	if (v->type == JS_TOBJECT)
+		return v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION;
+	return 0;
+}
+
 const char *js_typeof(js_State *J, int idx)
 {
 	switch (stackidx(J, idx)->type) {
--- a/jsrun.h
+++ b/jsrun.h
@@ -24,6 +24,9 @@
 int jsR_equal(js_State *J);
 int jsR_strictequal(js_State *J);
 
+const char *jsR_numbertostring(js_State *J, double number);
+double jsR_stringtonumber(js_State *J, const char *string);
+
 /* public */
 
 void js_call(js_State *J, int n);
@@ -41,6 +44,7 @@
 void js_pushnull(js_State *J);
 void js_pushboolean(js_State *J, int v);
 void js_pushnumber(js_State *J, double v);
+void js_pushliteral(js_State *J, const char *v);
 void js_pushstring(js_State *J, const char *v);
 
 void js_newobject(js_State *J);
@@ -58,6 +62,7 @@
 int js_isstring(js_State *J, int idx);
 int js_isprimitive(js_State *J, int idx);
 int js_isobject(js_State *J, int idx);
+int js_iscallable(js_State *J, int idx);
 
 int js_toboolean(js_State *J, int idx);
 double js_tonumber(js_State *J, int idx);
@@ -67,5 +72,8 @@
 void js_pop(js_State *J, int n);
 void js_dup(js_State *J);
 void js_copy(js_State *J, int idx);
+void js_rot(js_State *J, int n);
+void js_rot2(js_State *J);
+void js_rot3(js_State *J);
 
 #endif
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -2,8 +2,57 @@
 #include "jsobject.h"
 #include "jsrun.h"
 
+const char *jsR_numbertostring(js_State *J, double n)
+{
+	char buf[32];
+	if (isnan(n)) return "NaN";
+	if (isinf(n)) return n < 0 ? "-Infinity" : "Infinity";
+	if (n == 0) return "0";
+	sprintf(buf, "%.17g", n); /* DBL_DECIMAL_DIG == 17 */
+	return js_intern(J, buf);
+}
+
+double jsR_stringtonumber(js_State *J, const char *s)
+{
+	/* TODO: use lexer to parse string grammar */
+	return strtod(s, NULL);
+}
+
+static int jsR_toString(js_State *J, js_Object *obj)
+{
+	js_pushobject(J, obj);
+	js_getproperty(J, -1, "toString");
+	if (js_iscallable(J, -1)) {
+		js_rot2(J);
+		js_call(J, 0);
+		if (js_isprimitive(J, -1))
+			return 1;
+		js_pop(J, 1);
+		return 0;
+	}
+	js_pop(J, 2);
+	return 0;
+}
+
+static int jsR_valueOf(js_State *J, js_Object *obj)
+{
+	js_pushobject(J, obj);
+	js_getproperty(J, -1, "valueOf");
+	if (js_iscallable(J, -1)) {
+		js_rot2(J);
+		js_call(J, 0);
+		if (js_isprimitive(J, -1))
+			return 1;
+		js_pop(J, 1);
+		return 0;
+	}
+	js_pop(J, 2);
+	return 0;
+}
+
 js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred)
 {
+	js_Value vv;
 	js_Object *obj;
 
 	if (v->type != JS_TOBJECT)
@@ -15,15 +64,17 @@
 		preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER;
 
 	if (preferred == JS_HSTRING) {
-		// try "toString"
-		// if result is primitive, return result
-		// try "valueOf"
-		// if result is primitive, return result
+		if (jsR_toString(J, obj) || jsR_valueOf(J, obj)) {
+			vv = js_tovalue(J, -1);
+			js_pop(J, 1);
+			return vv;
+		}
 	} else {
-		// try "toString"
-		// if result is primitive, return result
-		// try "valueOf"
-		// if result is primitive, return result
+		if (jsR_valueOf(J, obj) || jsR_toString(J, obj)) {
+			vv = js_tovalue(J, -1);
+			js_pop(J, 1);
+			return vv;
+		}
 	}
 	jsR_error(J, "TypeError (ToPrimitive)");
 }
@@ -48,11 +99,7 @@
 	case JS_TNULL: return 0;
 	case JS_TBOOLEAN: return v->u.boolean;
 	case JS_TNUMBER: return v->u.number;
-	case JS_TSTRING:
-		{
-			/* TODO: use lexer to parse string grammar */
-			return strtod(v->u.string, NULL);
-		}
+	case JS_TSTRING: return jsR_stringtonumber(J, v->u.string);
 	case JS_TOBJECT:
 		{
 			js_Value vv = jsR_toprimitive(J, v, JS_HNUMBER);
@@ -68,16 +115,7 @@
 	case JS_TUNDEFINED: return "undefined";
 	case JS_TNULL: return "null";
 	case JS_TBOOLEAN: return v->u.boolean ? "true" : "false";
-	case JS_TNUMBER:
-		{
-			char buf[32];
-			double n = v->u.number;
-			if (isnan(n)) return "NaN";
-			if (isinf(n)) return n < 0 ? "-Infinity" : "Infinity";
-			if (n == 0) return "0";
-			sprintf(buf, "%.17g", n); /* DBL_DECIMAL_DIG == 17 */
-			return js_intern(J, buf);
-		}
+	case JS_TNUMBER: return jsR_numbertostring(J, v->u.number);
 	case JS_TSTRING: return v->u.string;
 	case JS_TOBJECT:
 		{