From ae39d48b861a10fdae62eb96226c65c5c46bc9bd Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Mon, 18 Jan 2016 16:34:09 +0100 Subject: [PATCH 1/2] test/expressions: add checks for logical operator precedence --- test/unit/core/expressions_test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/core/expressions_test.cpp b/test/unit/core/expressions_test.cpp index 75eba6217..933117a6b 100644 --- a/test/unit/core/expressions_test.cpp +++ b/test/unit/core/expressions_test.cpp @@ -62,6 +62,9 @@ TEST_CASE("expressions") properties_type prop = {{ "foo" , tr.transcode("bar") }, { "name" , tr.transcode("Québec")}, + { "grass" , tr.transcode("grow")}, + { "wind" , tr.transcode("blow")}, + { "sky" , tr.transcode("is blue")}, { "double", mapnik::value_double(1.23456)}, { "int" , mapnik::value_integer(123)}, { "bool" , mapnik::value_bool(true)}, @@ -134,6 +137,20 @@ TEST_CASE("expressions") // logical TRY_CHECK(eval(" [int] = 123 and [double] = 1.23456 && [bool] = true and [null] = null && [foo] = 'bar' ") == true); TRY_CHECK(eval(" [int] = 456 or [foo].match('foo') || length([foo]) = 3 ") == true); + TRY_CHECK(eval(" not true and not true ") == eval(" (not true ) and (not true ) ")); + TRY_CHECK(eval(" not true or not true ") == eval(" (not true ) or (not true ) ")); + TRY_CHECK(eval(" not false and not false ") == eval(" (not false) and (not false) ")); + TRY_CHECK(eval(" not false or not false ") == eval(" (not false) or (not false) ")); + + // test not/and/or precedence using combinations of "not EQ1 OP1 not EQ2 OP2 not EQ3" + TRY_CHECK(eval(" not [grass] = 'grow' and not [wind] = 'blow' and not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' and not [wind] = 'blow' or not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' or not [wind] = 'blow' and not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' or not [wind] = 'blow' or not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grew' and not [wind] = 'blew' and not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' and not [wind] = 'blew' or not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' or not [wind] = 'blew' and not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' or not [wind] = 'blew' or not [sky] = 'was blue' ") == true); // relational TRY_CHECK(eval(" [int] > 100 and [int] gt 100.0 and [double] < 2 and [double] lt 2.0 ") == true); From 15f841213ad944c8f0c64210040f521dae803ac5 Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Mon, 8 Feb 2016 17:15:13 +0100 Subject: [PATCH 2/2] expression_grammar: restrict unquoted strings to single-atom expressions - fixes #3017 - closes #3214 --- include/mapnik/expression_grammar_impl.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/mapnik/expression_grammar_impl.hpp b/include/mapnik/expression_grammar_impl.hpp index 9c82cb8c5..fea5e0395 100644 --- a/include/mapnik/expression_grammar_impl.hpp +++ b/include/mapnik/expression_grammar_impl.hpp @@ -104,7 +104,9 @@ expression_grammar::expression_grammar(std::string const& encoding) standard_wide::no_case_type no_case; using boost::phoenix::construct; - expr = logical_expr.alias(); + expr = logical_expr [_val = _1] + | ustring [_val = unicode_(_1)] + ; logical_expr = not_expr [_val = _1] >> @@ -167,10 +169,11 @@ expression_grammar::expression_grammar(std::string const& encoding) ) ; - unary_function_expr = unary_func_type > lit('(') > expr > lit(')') + unary_function_expr = unary_func_type >> '(' > logical_expr > ')' ; - binary_function_expr = binary_func_type > lit('(') > expr > lit(',') > expr > lit(')') + binary_function_expr = binary_func_type >> '(' > logical_expr > ',' + > logical_expr > ')' ; unary_expr = primary_expr [_val = _1] @@ -188,11 +191,9 @@ expression_grammar::expression_grammar(std::string const& encoding) | lit("[mapnik::geometry_type]")[_val = construct()] | attr [_val = construct( _1 ) ] | global_attr [_val = construct( _1 )] - | lit("not") >> expr [_val = !_1] | unary_function_expr [_val = _1] | binary_function_expr [_val = _1] - | '(' >> expr [_val = _1 ] >> ')' - | ustring[_val = unicode_(_1)] // if we get here then try parsing as unquoted string + | '(' > logical_expr [_val = _1 ] > ')' ; unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n')