From 05275e2e5de3231e0e2278e3792bb077db6a33c1 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sat, 18 Jan 2014 18:20:33 +0100 Subject: [PATCH] Implement relational and equality operators. --- jsrun.c | 49 +++++++++---------------------------------- jsrun.h | 5 +++++ jsvalue.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 39 deletions(-) diff --git a/jsrun.c b/jsrun.c index 85181f5..7b88f22 100644 --- a/jsrun.c +++ b/jsrun.c @@ -693,48 +693,19 @@ static void jsR_run(js_State *J, js_Function *F) /* 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 */ diff --git a/jsrun.h b/jsrun.h index 03459c3..0a26d6d 100644 --- a/jsrun.h +++ b/jsrun.h @@ -18,6 +18,11 @@ void jsR_error(js_State *J, const char *fmt, ...); 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 */ diff --git a/jsvalue.c b/jsvalue.c index 999daa3..01eee61 100644 --- a/jsvalue.c +++ b/jsvalue.c @@ -124,5 +124,67 @@ void jsR_concat(js_State *J) 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; }