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;
}