shithub: libmujs

Download patch

ref: 05275e2e5de3231e0e2278e3792bb077db6a33c1
parent: d3d92291f613adb0fbdac4c271fbb43fc4c69031
author: Tor Andersson <tor@ccxvii.net>
date: Sat Jan 18 13:20:33 EST 2014

Implement relational and equality operators.

--- a/jsrun.c
+++ b/jsrun.c
@@ -693,48 +693,19 @@
 
 		/* Relational operators */
 
-		/* TODO: string comparisons */
-		case OP_LT:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x < y);
-			break;
-		case OP_GT:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x > y);
-			break;
-		case OP_LE:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x <= y);
-			break;
-		case OP_GE:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x >= y);
-			break;
+		case OP_LT: b = jsR_compare(J); js_pushboolean(J, b < 0); break;
+		case OP_GT: b = jsR_compare(J); js_pushboolean(J, b > 0); break;
+		case OP_LE: b = jsR_compare(J); js_pushboolean(J, b <= 0); break;
+		case OP_GE: b = jsR_compare(J); js_pushboolean(J, b >= 0); break;
 
+		// OP_INSTANCEOF
+
 		/* Equality */
 
-		case OP_EQ:
-		case OP_STRICTEQ:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x == y);
-			break;
-		case OP_NE:
-		case OP_STRICTNE:
-			x = js_tonumber(J, -2);
-			y = js_tonumber(J, -1);
-			js_pop(J, 2);
-			js_pushboolean(J, x != y);
-			break;
+		case OP_EQ: b = jsR_equal(J); js_pushboolean(J, b); break;
+		case OP_NE: b = jsR_equal(J); js_pushboolean(J, !b); break;
+		case OP_STRICTEQ: b = jsR_strictequal(J); js_pushboolean(J, b); break;
+		case OP_STRICTNE: b = jsR_strictequal(J); js_pushboolean(J, !b); break;
 
 		/* Binary bitwise operators */
 
--- a/jsrun.h
+++ b/jsrun.h
@@ -18,6 +18,11 @@
 void js_pushobject(js_State *J, js_Object *v);
 js_Object *js_toobject(js_State *J, int idx);
 js_Value js_toprimitive(js_State *J, int idx, int hint);
+js_Value js_tovalue(js_State *J, int idx);
+void jsR_concat(js_State *J);
+int jsR_compare(js_State *J);
+int jsR_equal(js_State *J);
+int jsR_strictequal(js_State *J);
 
 /* public */
 
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -124,5 +124,67 @@
 
 int jsR_compare(js_State *J)
 {
+	js_Value va = js_toprimitive(J, -2, JS_HNUMBER);
+	js_Value vb = js_toprimitive(J, -1, JS_HNUMBER);
+	js_pop(J, 2);
+	if (va.type == JS_TSTRING && vb.type == JS_TSTRING) {
+		return strcmp(va.u.string, va.u.string);
+	} else {
+		double x = jsR_tonumber(J, &va);
+		double y = jsR_tonumber(J, &vb);
+		return x < y ? -1 : x > y ? 1 : 0;
+	}
+}
+
+int jsR_equal(js_State *J)
+{
+	js_Value va = js_tovalue(J, -2);
+	js_Value vb = js_tovalue(J, -1);
+	js_pop(J, 2);
+
+retry:
+	if (va.type == vb.type) {
+		if (va.type == JS_TUNDEFINED) return 1;
+		if (va.type == JS_TNULL) return 1;
+		if (va.type == JS_TNUMBER) return va.u.number == vb.u.number;
+		if (va.type == JS_TBOOLEAN) return va.u.boolean == vb.u.boolean;
+		if (va.type == JS_TSTRING) return !strcmp(va.u.string, vb.u.string);
+		if (va.type == JS_TOBJECT) return va.u.object == vb.u.object;
+		return 0;
+	}
+
+	if (va.type == JS_TNULL && vb.type == JS_TUNDEFINED) return 1;
+	if (va.type == JS_TUNDEFINED && vb.type == JS_TNULL) return 1;
+
+	if (va.type == JS_TNUMBER && (vb.type == JS_TSTRING || vb.type == JS_TBOOLEAN))
+		return va.u.number == jsR_tonumber(J, &vb);
+	if ((va.type == JS_TSTRING || va.type == JS_TBOOLEAN) && vb.type == JS_TNUMBER)
+		return jsR_tonumber(J, &va) == vb.u.number;
+
+	if ((va.type == JS_TSTRING || va.type == JS_TNUMBER) && vb.type == JS_TOBJECT) {
+		vb = jsR_toprimitive(J, &vb, JS_HNONE);
+		goto retry;
+	}
+	if (va.type == JS_TOBJECT && (vb.type == JS_TSTRING || vb.type == JS_TNUMBER)) {
+		va = jsR_toprimitive(J, &va, JS_HNONE);
+		goto retry;
+	}
+
+	return 0;
+}
+
+int jsR_strictequal(js_State *J)
+{
+	js_Value va = js_tovalue(J, -2);
+	js_Value vb = js_tovalue(J, -1);
+	js_pop(J, 2);
+
+	if (va.type != vb.type) return 0;
+	if (va.type == JS_TUNDEFINED) return 1;
+	if (va.type == JS_TNULL) return 1;
+	if (va.type == JS_TNUMBER) return va.u.number == vb.u.number;
+	if (va.type == JS_TBOOLEAN) return va.u.boolean == vb.u.boolean;
+	if (va.type == JS_TSTRING) return !strcmp(va.u.string, vb.u.string);
+	if (va.type == JS_TOBJECT) return va.u.object == vb.u.object;
 	return 0;
 }