diff options
author | wszqkzqk <wszqkzqk@qq.com> | 2022-12-13 21:56:53 +0800 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2022-12-22 17:13:52 +0100 |
commit | c5679d09cdc8b49c9b886fc6617db901350c301d (patch) | |
tree | a75445dfdeaef656e8c03140f793028c3e746369 | |
parent | a67d19f51082944e3751760d6c0ae09efc35b860 (diff) | |
download | vala-c5679d09cdc8b49c9b886fc6617db901350c301d.tar.gz |
parser: Properly handle chained equality expressions
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1385
-rw-r--r-- | codegen/valaccodebasemodule.vala | 13 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/parser/chained-equality-type-invalid.test | 8 | ||||
-rw-r--r-- | tests/parser/chained-equality.c-expected | 212 | ||||
-rw-r--r-- | tests/parser/chained-equality.vala | 70 | ||||
-rw-r--r-- | vala/valabinaryexpression.vala | 44 | ||||
-rw-r--r-- | vala/valaparser.vala | 27 |
7 files changed, 342 insertions, 34 deletions
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 2969679c9..c8301c821 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -5842,8 +5842,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { } } - bool is_string_comparison = !(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type) - && !(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type); + bool is_string_comparison = false; + if (!(expr.right.value_type is NullType) && expr.right.value_type.compatible (string_type)) { + if (!(expr.left.value_type is NullType) && expr.left.value_type.compatible (string_type)) { + is_string_comparison = true; + } else if (expr.is_chained) { + unowned BinaryExpression lbe = (BinaryExpression) expr.left; + if (!(lbe.right.value_type is NullType) && lbe.right.value_type.compatible (string_type)) { + is_string_comparison = true; + } + } + } bool has_string_literal = (expr.left is StringLiteral || expr.right is StringLiteral); if (is_string_comparison || (has_string_literal && expr.operator != BinaryOperator.PLUS)) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 94346acf3..407bffc5b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -931,6 +931,8 @@ TESTS = \ parser/attribute-missing-literal.test \ parser/attribute-wrong-number.test \ parser/block-delimiter-missing.test \ + parser/chained-equality-type-invalid.test \ + parser/chained-equality.vala \ parser/constant-owned.test \ parser/constant-local-owned.test \ parser/constructor-class-exists.test \ diff --git a/tests/parser/chained-equality-type-invalid.test b/tests/parser/chained-equality-type-invalid.test new file mode 100644 index 000000000..e280245ed --- /dev/null +++ b/tests/parser/chained-equality-type-invalid.test @@ -0,0 +1,8 @@ +Invalid Code + +void main () { + var foo = "world"; + var bar = 0; + if (foo == "world" != 0) { + } +} diff --git a/tests/parser/chained-equality.c-expected b/tests/parser/chained-equality.c-expected new file mode 100644 index 000000000..3e59b5d34 --- /dev/null +++ b/tests/parser/chained-equality.c-expected @@ -0,0 +1,212 @@ +/* parser_chained_equality.c generated by valac, the Vala compiler + * generated from parser_chained_equality.vala, do not modify */ + +#include <glib.h> +#include <stdlib.h> +#include <string.h> + +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg); +#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; } +#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; } +#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg); + +static void _vala_main (void); + +static void +_vala_main (void) +{ + { + gint foo = 0; + gint bar = 0; + gint _tmp0_; + foo = 123; + bar = 123; + _tmp0_ = bar; + _vala_assert ((foo == _tmp0_) && (_tmp0_ == 123), "foo == bar == 123"); + } + { + gint foo = 0; + gint bar = 0; + gint _tmp1_; + foo = 111; + bar = 222; + _tmp1_ = bar; + _vala_assert ((foo != _tmp1_) && (_tmp1_ == 222), "foo != bar == 222"); + } + { + gint foo = 0; + gint bar = 0; + gint _tmp2_; + foo = 111; + bar = 111; + _tmp2_ = bar; + _vala_assert ((foo == _tmp2_) && (_tmp2_ != 222), "foo == bar != 222"); + } + { + gint foo = 0; + gint bar = 0; + gint _tmp3_; + gint _tmp4_; + foo = 111; + bar = 111; + _tmp3_ = foo; + _tmp4_ = bar; + _vala_assert (((0 < _tmp3_) && (_tmp3_ == _tmp4_)) && (_tmp4_ < 222), "0 < foo == bar < 222"); + } + { + gint a = 0; + gint b = 0; + gint c = 0; + gint _tmp5_; + gint _tmp6_; + a = 111; + b = 111; + c = 111; + _tmp5_ = b; + _tmp6_ = c; + _vala_assert (((a == _tmp5_) && (_tmp5_ == _tmp6_)) && (_tmp6_ == 111), "a == b == c == 111"); + } + { + gint a = 0; + gint b = 0; + gint c = 0; + gint _tmp7_; + gint _tmp8_; + a = 111; + b = 222; + c = 333; + _tmp7_ = b; + _tmp8_ = c; + _vala_assert (((a != _tmp7_) && (_tmp7_ != _tmp8_)) && (_tmp8_ != 123), "a != b != c != 123"); + } + { + gchar* foo = NULL; + gchar* _tmp9_; + gchar* bar = NULL; + gchar* _tmp10_; + gchar* _tmp11_; + _tmp9_ = g_strdup ("world"); + foo = _tmp9_; + _tmp10_ = g_strdup ("hello"); + bar = _tmp10_; + _tmp11_ = bar; + _vala_assert ((g_strcmp0 (foo, _tmp11_) > 0) && (g_strcmp0 (_tmp11_, "hello") == 0), "foo > bar == \"hello\""); + _g_free0 (bar); + _g_free0 (foo); + } + { + gchar* a = NULL; + gchar* _tmp12_; + gchar* b = NULL; + gchar* _tmp13_; + gchar* c = NULL; + gchar* _tmp14_; + gchar* _tmp15_; + gchar* _tmp16_; + gchar* _tmp17_; + gchar* _tmp18_; + _tmp12_ = g_strdup ("hello"); + a = _tmp12_; + _tmp13_ = g_strdup ("hello"); + b = _tmp13_; + _tmp14_ = g_strdup ("hello"); + c = _tmp14_; + _tmp15_ = a; + _tmp16_ = b; + _tmp17_ = c; + _tmp18_ = "hello"; + _vala_assert (((((g_strcmp0 ("hello", _tmp15_) == 0) && (g_strcmp0 (_tmp15_, _tmp16_) <= 0)) && (g_strcmp0 (_tmp16_, _tmp17_) == 0)) && (g_strcmp0 (_tmp17_, _tmp18_) == 0)) && (g_strcmp0 (_tmp18_, "hello") <= 0), "\"hello\" == a <= b == c == \"hello\" <= \"hello\""); + _g_free0 (c); + _g_free0 (b); + _g_free0 (a); + } + { + gchar* foo = NULL; + gchar* _tmp19_; + gchar* bar = NULL; + gchar* _tmp20_; + gchar* _tmp21_; + _tmp19_ = g_strdup ("h"); + foo = _tmp19_; + _tmp20_ = g_strdup ("h"); + bar = _tmp20_; + _tmp21_ = bar; + _vala_assert ((g_strcmp0 (foo, _tmp21_) == 0) && (g_strcmp0 (_tmp21_, "hello") < 0), "foo == bar < \"hello\""); + _g_free0 (bar); + _g_free0 (foo); + } + { + gchar* foo = NULL; + gchar* _tmp22_; + gchar* bar = NULL; + gchar* _tmp23_; + gchar* _tmp24_; + _tmp22_ = g_strdup ("hello"); + foo = _tmp22_; + _tmp23_ = g_strdup ("world"); + bar = _tmp23_; + _tmp24_ = bar; + _vala_assert ((g_strcmp0 (foo, _tmp24_) != 0) && (g_strcmp0 (_tmp24_, "world") == 0), "foo != bar == \"world\""); + _g_free0 (bar); + _g_free0 (foo); + } + { + gchar* foo = NULL; + gchar* _tmp25_; + gchar* bar = NULL; + gchar* _tmp26_; + gchar* _tmp27_; + _tmp25_ = g_strdup ("world"); + foo = _tmp25_; + _tmp26_ = g_strdup ("world"); + bar = _tmp26_; + _tmp27_ = bar; + _vala_assert ((g_strcmp0 (foo, _tmp27_) == 0) && (g_strcmp0 (_tmp27_, "hello") != 0), "foo == bar != \"hello\""); + _g_free0 (bar); + _g_free0 (foo); + } + { + gchar* foo = NULL; + gchar* _tmp28_; + gchar* bar = NULL; + gchar* _tmp29_; + gchar* _tmp30_; + gint _tmp31_; + _tmp28_ = g_strdup ("world"); + foo = _tmp28_; + _tmp29_ = g_strdup ("world"); + bar = _tmp29_; + _tmp30_ = bar; + _tmp31_ = 0; + _vala_assert (((g_strcmp0 (foo, _tmp30_) == 0) && (g_strcmp0 (_tmp30_, "hello") != 0)) == ((0 == _tmp31_) && (_tmp31_ <= 1)), "(foo == bar != \"hello\") == (0 == 0 <= 1)"); + _g_free0 (bar); + _g_free0 (foo); + } + { + gchar* foo = NULL; + gchar* _tmp32_; + gchar* bar = NULL; + gchar* _tmp33_; + gchar* _tmp34_; + gint _tmp35_; + _tmp32_ = g_strdup ("world"); + foo = _tmp32_; + _tmp33_ = g_strdup ("world"); + bar = _tmp33_; + _tmp34_ = bar; + _tmp35_ = 1; + _vala_assert (((g_strcmp0 (foo, _tmp34_) == 0) && (g_strcmp0 (_tmp34_, "hello") == 0)) == ((1 == _tmp35_) && (_tmp35_ <= 0)), "(foo == bar == \"hello\") == (1 == 1 <= 0)"); + _g_free0 (bar); + _g_free0 (foo); + } +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/parser/chained-equality.vala b/tests/parser/chained-equality.vala new file mode 100644 index 000000000..ce734af64 --- /dev/null +++ b/tests/parser/chained-equality.vala @@ -0,0 +1,70 @@ +void main () { + { + var foo = 123; + var bar = 123; + assert (foo == bar == 123); + } + { + var foo = 111; + var bar = 222; + assert (foo != bar == 222); + } + { + var foo = 111; + var bar = 111; + assert (foo == bar != 222); + } + { + var foo = 111; + var bar = 111; + assert (0 < foo == bar < 222); + } + { + var a = 111; + var b = 111; + var c = 111; + assert (a == b == c == 111); + } + { + var a = 111; + var b = 222; + var c = 333; + assert (a != b != c != 123); + } + { + var foo = "world"; + var bar = "hello"; + assert (foo > bar == "hello"); + } + { + var a = "hello"; + var b = "hello"; + var c = "hello"; + assert ("hello" == a <= b == c == "hello" <= "hello"); + } + { + var foo = "h"; + var bar = "h"; + assert (foo == bar < "hello"); + } + { + var foo = "hello"; + var bar = "world"; + assert (foo != bar == "world"); + } + { + var foo = "world"; + var bar = "world"; + assert (foo == bar != "hello"); + } + { + var foo = "world"; + var bar = "world"; + assert ((foo == bar != "hello") == (0 == 0 <= 1)); // true == true + } + { + var foo = "world"; + var bar = "world"; + assert ((foo == bar == "hello") == (1 == 1 <= 0)); // false == false + } +} diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 6545e1cff..d627e2942 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -467,7 +467,12 @@ public class Vala.BinaryExpression : Expression { DataType resulting_type; if (is_chained) { - var lbe = (BinaryExpression) left; + unowned BinaryExpression lbe = (BinaryExpression) left; + if (lbe.right.value_type.compatible (context.analyzer.string_type) + && right.value_type.compatible (context.analyzer.string_type)) { + value_type = context.analyzer.bool_type; + break; + } resulting_type = context.analyzer.get_arithmetic_result_type (lbe.right.target_type, right.target_type); } else { resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type); @@ -475,7 +480,14 @@ public class Vala.BinaryExpression : Expression { if (resulting_type == null) { error = true; - Report.error (source_reference, "Relational operation not supported for types `%s' and `%s'", left.value_type.to_string (), right.value_type.to_string ()); + unowned DataType left_type; + if (is_chained) { + unowned BinaryExpression lbe = (BinaryExpression) left; + left_type = lbe.right.value_type; + } else { + left_type = left.value_type; + } + Report.error (source_reference, "Relational operation not supported for types `%s' and `%s'", left_type.to_string (), right.value_type.to_string ()); return false; } @@ -515,17 +527,31 @@ public class Vala.BinaryExpression : Expression { } } - if (!right.value_type.compatible (left.value_type) - && !left.value_type.compatible (right.value_type)) { - Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), left.value_type.to_string ()); - error = true; - return false; + DataType resulting_type; + if (is_chained) { + unowned BinaryExpression lbe = (BinaryExpression) left; + resulting_type = context.analyzer.get_arithmetic_result_type (lbe.right.target_type, right.target_type); + if (!right.value_type.compatible (lbe.right.value_type) + && !lbe.right.value_type.compatible (right.value_type)) { + Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), lbe.right.value_type.to_string ()); + error = true; + return false; + } + } else { + resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type); + if (!right.value_type.compatible (left.value_type) + && !left.value_type.compatible (right.value_type)) { + Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible", right.value_type.to_string (), left.value_type.to_string ()); + error = true; + return false; + } } - var resulting_type = context.analyzer.get_arithmetic_result_type (left.target_type, right.target_type); if (resulting_type != null) { // numeric operation - left.target_type = resulting_type.copy (); + if (!is_chained) { + left.target_type = resulting_type.copy (); + } right.target_type = resulting_type.copy (); } diff --git a/vala/valaparser.vala b/vala/valaparser.vala index d932b8b2d..25769ec54 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -1452,6 +1452,8 @@ public class Vala.Parser : CodeVisitor { case BinaryOperator.LESS_THAN: case BinaryOperator.LESS_THAN_OR_EQUAL: case BinaryOperator.GREATER_THAN_OR_EQUAL: + case BinaryOperator.EQUALITY: + case BinaryOperator.INEQUALITY: next (); var right = parse_type_check_expression (); if (first) { @@ -1485,32 +1487,11 @@ public class Vala.Parser : CodeVisitor { return left; } - Expression parse_equality_expression () throws ParseError { - var begin = get_location (); - var left = parse_relational_expression (); - bool found = true; - while (found) { - var operator = get_binary_operator (current ()); - switch (operator) { - case BinaryOperator.EQUALITY: - case BinaryOperator.INEQUALITY: - next (); - var right = parse_relational_expression (); - left = new BinaryExpression (operator, left, right, get_src (begin)); - break; - default: - found = false; - break; - } - } - return left; - } - Expression parse_and_expression () throws ParseError { var begin = get_location (); - var left = parse_equality_expression (); + var left = parse_relational_expression (); while (accept (TokenType.BITWISE_AND)) { - var right = parse_equality_expression (); + var right = parse_relational_expression (); left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin)); } return left; |