Bladeren bron

LibSQL: Properly parse ESCAPE expressions

The evaluation order of method parameters is unspecified in C++, and
so we couldn't rely on parse_statement() being called before
parse_escape() when building a MatchExpression.

With this patch, we explicitly parse what we need in the right order,
before building the MatchExpression object.
Guilherme Gonçalves 3 jaren geleden
bovenliggende
commit
e957c078d5
2 gewijzigde bestanden met toevoegingen van 32 en 12 verwijderingen
  1. 10 3
      Tests/LibSQL/TestSqlExpressionParser.cpp
  2. 22 9
      Userland/Libraries/LibSQL/AST/Parser.cpp

+ 10 - 3
Tests/LibSQL/TestSqlExpressionParser.cpp

@@ -463,7 +463,7 @@ TEST_CASE(match_expression)
         EXPECT(parse(builder.build()).is_error());
     }
 
-    auto validate = [](StringView sql, SQL::AST::MatchOperator expected_operator, bool expected_invert_expression) {
+    auto validate = [](StringView sql, SQL::AST::MatchOperator expected_operator, bool expected_invert_expression, bool expect_escape) {
         auto result = parse(sql);
         EXPECT(!result.is_error());
 
@@ -475,6 +475,7 @@ TEST_CASE(match_expression)
         EXPECT(!is<SQL::AST::ErrorExpression>(*match.rhs()));
         EXPECT_EQ(match.type(), expected_operator);
         EXPECT_EQ(match.invert_expression(), expected_invert_expression);
+        EXPECT(match.escape() || !expect_escape);
     };
 
     for (auto op : operators) {
@@ -482,13 +483,19 @@ TEST_CASE(match_expression)
         builder.append("1 ");
         builder.append(op.key);
         builder.append(" 1");
-        validate(builder.build(), op.value, false);
+        validate(builder.build(), op.value, false, false);
 
         builder.clear();
         builder.append("1 NOT ");
         builder.append(op.key);
         builder.append(" 1");
-        validate(builder.build(), op.value, true);
+        validate(builder.build(), op.value, true, false);
+
+        builder.clear();
+        builder.append("1 NOT ");
+        builder.append(op.key);
+        builder.append(" 1 ESCAPE '+'");
+        validate(builder.build(), op.value, true, true);
     }
 }
 

+ 22 - 9
Userland/Libraries/LibSQL/AST/Parser.cpp

@@ -739,22 +739,35 @@ RefPtr<Expression> Parser::parse_match_expression(NonnullRefPtr<Expression> lhs,
 {
     auto parse_escape = [this]() {
         RefPtr<Expression> escape;
-        if (consume_if(TokenType::Escape))
+        if (consume_if(TokenType::Escape)) {
             escape = parse_expression();
+        }
         return escape;
     };
 
-    if (consume_if(TokenType::Like))
-        return create_ast_node<MatchExpression>(MatchOperator::Like, move(lhs), parse_expression(), parse_escape(), invert_expression);
+    if (consume_if(TokenType::Like)) {
+        NonnullRefPtr<Expression> rhs = parse_expression();
+        RefPtr<Expression> escape = parse_escape();
+        return create_ast_node<MatchExpression>(MatchOperator::Like, move(lhs), move(rhs), move(escape), invert_expression);
+    }
 
-    if (consume_if(TokenType::Glob))
-        return create_ast_node<MatchExpression>(MatchOperator::Glob, move(lhs), parse_expression(), parse_escape(), invert_expression);
+    if (consume_if(TokenType::Glob)) {
+        NonnullRefPtr<Expression> rhs = parse_expression();
+        RefPtr<Expression> escape = parse_escape();
+        return create_ast_node<MatchExpression>(MatchOperator::Glob, move(lhs), move(rhs), move(escape), invert_expression);
+    }
 
-    if (consume_if(TokenType::Match))
-        return create_ast_node<MatchExpression>(MatchOperator::Match, move(lhs), parse_expression(), parse_escape(), invert_expression);
+    if (consume_if(TokenType::Match)) {
+        NonnullRefPtr<Expression> rhs = parse_expression();
+        RefPtr<Expression> escape = parse_escape();
+        return create_ast_node<MatchExpression>(MatchOperator::Match, move(lhs), move(rhs), move(escape), invert_expression);
+    }
 
-    if (consume_if(TokenType::Regexp))
-        return create_ast_node<MatchExpression>(MatchOperator::Regexp, move(lhs), parse_expression(), parse_escape(), invert_expression);
+    if (consume_if(TokenType::Regexp)) {
+        NonnullRefPtr<Expression> rhs = parse_expression();
+        RefPtr<Expression> escape = parse_escape();
+        return create_ast_node<MatchExpression>(MatchOperator::Regexp, move(lhs), move(rhs), move(escape), invert_expression);
+    }
 
     return {};
 }