summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--eval.c66
-rw-r--r--lexer.c4
-rw-r--r--lexer.h2
-rw-r--r--parser.y15
4 files changed, 78 insertions, 9 deletions
diff --git a/eval.c b/eval.c
index 68b2780..1e8d9a3 100644
--- a/eval.c
+++ b/eval.c
@@ -746,6 +746,68 @@ ut_execute_rel(struct ut_state *state, uint32_t off)
}
static struct json_object *
+ut_execute_equality(struct ut_state *state, uint32_t off)
+{
+ struct ut_op *op = ut_get_op(state, off);
+ uint32_t off1 = op ? op->tree.operand[0] : 0;
+ uint32_t off2 = op ? op->tree.operand[1] : 0;
+ struct json_object *v1 = ut_execute_op(state, off1);
+ struct json_object *v2 = ut_execute_op(state, off2);
+ struct ut_op *tag1 = json_object_get_userdata(v1);
+ struct ut_op *tag2 = json_object_get_userdata(v2);
+ enum json_type t1 = json_object_get_type(v1);
+ enum json_type t2 = json_object_get_type(v2);
+ struct json_object *rv;
+ bool equal = false;
+
+ if ((tag1 ? tag1->type : 0) != (tag2 ? tag2->type : 0)) {
+ equal = false;
+ }
+ else if (t1 != t2) {
+ equal = false;
+ }
+ else {
+ switch (t1) {
+ case json_type_array:
+ case json_type_object:
+ equal = (v1 == v2);
+ break;
+
+ case json_type_boolean:
+ equal = (json_object_get_boolean(v1) == json_object_get_boolean(v2));
+ break;
+
+ case json_type_double:
+ if (isnan(json_object_get_double(v1)) || isnan(json_object_get_double(v2)))
+ equal = false;
+ else
+ equal = (json_object_get_double(v1) == json_object_get_double(v2));
+
+ break;
+
+ case json_type_int:
+ equal = (json_object_get_int64(v1) == json_object_get_int64(v2));
+ break;
+
+ case json_type_string:
+ equal = !strcmp(json_object_get_string(v1), json_object_get_string(v2));
+ break;
+
+ case json_type_null:
+ equal = true;
+ break;
+ }
+ }
+
+ rv = json_object_new_boolean((op->type == T_EQS) ? equal : !equal);
+
+ ut_putval(v1);
+ ut_putval(v2);
+
+ return rv;
+}
+
+static struct json_object *
ut_execute_in(struct ut_state *state, uint32_t off)
{
struct ut_op *op = ut_get_op(state, off);
@@ -1325,6 +1387,10 @@ ut_execute_op(struct ut_state *state, uint32_t off)
case T_NE:
return ut_execute_rel(state, off);
+ case T_EQS:
+ case T_NES:
+ return ut_execute_equality(state, off);
+
case T_IN:
return ut_execute_in(state, off);
diff --git a/lexer.c b/lexer.c
index 0ce9643..390a12e 100644
--- a/lexer.c
+++ b/lexer.c
@@ -61,6 +61,8 @@ static const struct token tokens[] = {
{ T_LSTM, "{%+", 3 },
{ T_LSTM, "{%-", 3 },
{ T_RSTM, "-%}", 3 },
+ { T_EQS, "===", 3 },
+ { T_NES, "!==", 3 },
{ T_AND, "&&", 2 },
{ T_ASADD, "+=", 2 },
{ T_ASBAND, "&=", 2 },
@@ -164,6 +166,8 @@ const char *tokennames[__T_MAX] = {
[T_INC] = "'x++'",
[T_EQ] = "'x==y'",
[T_NE] = "'x!=y'",
+ [T_EQS] = "'x===y'",
+ [T_NES] = "'x!==y'",
[T_LE] = "'x<=y'",
[T_GE] = "'x>=y'",
[T_LSHIFT] = "'x<<y'",
diff --git a/lexer.h b/lexer.h
index 4d46ad0..cb6bca9 100644
--- a/lexer.h
+++ b/lexer.h
@@ -19,7 +19,7 @@
#include "ast.h"
-#define __T_MAX 71
+#define __T_MAX 73
#define T_EXCEPTION (__T_MAX + 0)
#define T_CFUNC (__T_MAX + 1)
#define T_RESSOURCE (__T_MAX + 2)
diff --git a/parser.y b/parser.y
index 33ff24e..c2d447b 100644
--- a/parser.y
+++ b/parser.y
@@ -34,9 +34,8 @@
%left T_BOR.
%left T_BXOR.
%left T_BAND.
-%left T_IN.
-%left T_EQ T_NE.
-%left T_LT T_LE T_GT T_GE.
+%left T_EQ T_NE T_EQS T_NES.
+%left T_LT T_LE T_GT T_GE T_IN.
%left T_LSHIFT T_RSHIFT.
%left T_ADD T_SUB.
%left T_MUL T_DIV T_MOD.
@@ -217,20 +216,20 @@ bor_exp(A) ::= bxor_exp(B). { A = B; }
bxor_exp(A) ::= bxor_exp(B) T_BXOR(C) band_exp(D). { A = wrap_op(C, B, D); }
bxor_exp(A) ::= band_exp(B). { A = B; }
-band_exp(A) ::= band_exp(B) T_BAND(C) in_exp(D). { A = wrap_op(C, B, D); }
-band_exp(A) ::= in_exp(B). { A = B; }
-
-in_exp(A) ::= equal_exp(B) T_IN(C) equal_exp(D). { A = wrap_op(C, B, D); }
-in_exp(A) ::= equal_exp(B). { A = B; }
+band_exp(A) ::= band_exp(B) T_BAND(C) equal_exp(D). { A = wrap_op(C, B, D); }
+band_exp(A) ::= equal_exp(B). { A = B; }
equal_exp(A) ::= equal_exp(B) T_EQ(C) rel_exp(D). { A = wrap_op(C, B, D); }
equal_exp(A) ::= equal_exp(B) T_NE(C) rel_exp(D). { A = wrap_op(C, B, D); }
+equal_exp(A) ::= equal_exp(B) T_EQS(C) rel_exp(D). { A = wrap_op(C, B, D); }
+equal_exp(A) ::= equal_exp(B) T_NES(C) rel_exp(D). { A = wrap_op(C, B, D); }
equal_exp(A) ::= rel_exp(B). { A = B; }
rel_exp(A) ::= rel_exp(B) T_LT(C) shift_exp(D). { A = wrap_op(C, B, D); }
rel_exp(A) ::= rel_exp(B) T_LE(C) shift_exp(D). { A = wrap_op(C, B, D); }
rel_exp(A) ::= rel_exp(B) T_GT(C) shift_exp(D). { A = wrap_op(C, B, D); }
rel_exp(A) ::= rel_exp(B) T_GE(C) shift_exp(D). { A = wrap_op(C, B, D); }
+rel_exp(A) ::= rel_exp(B) T_IN(C) shift_exp(D). { A = wrap_op(C, B, D); }
rel_exp(A) ::= shift_exp(B). { A = B; }
shift_exp(A) ::= shift_exp(B) T_LSHIFT(C) add_exp(D). { A = wrap_op(C, B, D); }