diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-09-11 22:53:53 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-09-11 22:55:38 +0200 |
commit | 280a7c191bd5bda0d1d885c1c24ec4674d8a880e (patch) | |
tree | b18b6fb7337302edcda77f769c0fe508bea5ba5f | |
parent | 974eafbb07578742ac6aa965c73b62792865ebd7 (diff) |
syntax: introduce !== and === operators
Also treat "in" as relational operator.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | eval.c | 66 | ||||
-rw-r--r-- | lexer.c | 4 | ||||
-rw-r--r-- | lexer.h | 2 | ||||
-rw-r--r-- | parser.y | 15 |
4 files changed, 78 insertions, 9 deletions
@@ -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); @@ -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'", @@ -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) @@ -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); } |