Repository: DerekStride/tree-sitter-sql (language: python)

Issue:
Node for parenthesized expressions
Hello,

maintainer of [HiPhish/rainbow-delimiters.nvim](https://github.com/hiphish/rainbow-delimiters.nvim) here; I have a problem matching and properly highlighting parenthesized expressions. The problem is that all the parentheses of an expression are on the same level as their siblings. Consider the following query:

```sql
SELECT ((((1))));
```

It's a weird query, but at least in SQLite it is valid. The tree looks like this:

```
  (select
    (keyword_select)
    (select_expression
      (term
        value: "("
        value: "("
        value: "("
        value: "("
        value: (literal)
        value: ")"
        value: ")"
        value: ")"
        value: ")")))
```

All the parentheses are on the same level, it is impossible to build up a tree of "containers" to determine the proper nesting. I propose a sort of `parenthesized_expression` node (or whatever name you consider more appropriate). With that node the `term` would have only one `value`:

```
  (select
    (keyword_select)
    (select_expression
      (term
    	value: (parenthesized_expression
    	  "("
    	  (parenthesized_expression
    	    "("
    	    (parenthesized_expression
    	      "("
    	      (parenthesized_expression
    	        "("
                (literal)
    	        ")")
    	      ")")
    	    ")")
    	  ")"))))
```

Let's take another example:

```sql
SELECT 1 + (2);
```

The original tree:

```
  (select
    (keyword_select)
    (select_expression
      (term
        value: (binary_expression
          left: (literal)
          operator: "+"
          right: "("
          right: (literal)
          right: ")"))))
```

How many `right` nodes can a binary expression reasonably have? Here is what it would look like with `parenthesized_expression`:

```
(select
  (keyword_select)
  (select_expression
    (term
      value: (binary_expression
        left: (literal)
        operator: "+"
        right: (parenthesized_expression
          "("
          (literal)
          ")")))))
```



Discussion / hints:
I agree. I think our AST is sometimes way to "flat". I will take a look later today.

Fix patch:
diff --git a/grammar.js b/grammar.js
index 99f57229..422940f3 100644
--- a/grammar.js
+++ b/grammar.js
@@ -3254,10 +3254,14 @@ module.exports = grammar({
         $.array,
         $.interval,
         $.between_expression,
-        wrapped_in_parenthesis($._expression),
+        $.parenthesized_expression,
       )
     ),
 
+    parenthesized_expression: $ => prec(2,
+      wrapped_in_parenthesis($._expression)
+    ),
+
     subscript: $ => prec.left('binary_is',
       seq(
         field('expression', $._expression),


Test patch:
diff --git a/test/corpus/create.txt b/test/corpus/create.txt
index 50fa83be..4ebbc2c9 100644
--- a/test/corpus/create.txt
+++ b/test/corpus/create.txt
@@ -1703,10 +1703,11 @@ CREATE TABLE "Role" (
           (keyword_generated)
           (keyword_always)
           (keyword_as)
-          (binary_expression
-            left: (field
-              name: (identifier))
-            right: (literal))
+          (parenthesized_expression
+            (binary_expression
+              left: (field
+                name: (identifier))
+              right: (literal)))
           (keyword_stored))
         (column_definition
           name: (identifier)
@@ -1714,21 +1715,22 @@ CREATE TABLE "Role" (
           (keyword_generated)
           (keyword_always)
           (keyword_as)
-          (case
-            (keyword_case)
-            (field
-              name: (identifier))
-            (keyword_when)
-            (literal)
-            (keyword_then)
-            (literal)
-            (keyword_when)
-            (literal)
-            (keyword_then)
-            (literal)
-            (keyword_else)
-            (literal)
-            (keyword_end))
+          (parenthesized_expression
+            (case
+              (keyword_case)
+              (field
+                name: (identifier))
+              (keyword_when)
+              (literal)
+              (keyword_then)
+              (literal)
+              (keyword_when)
+              (literal)
+              (keyword_then)
+              (literal)
+              (keyword_else)
+              (literal)
+              (keyword_end)))
           (keyword_virtual))))))
 
 ================================================================================
diff --git a/test/corpus/expressions.txt b/test/corpus/expressions.txt
index a96af4cc..34ea659c 100644
--- a/test/corpus/expressions.txt
+++ b/test/corpus/expressions.txt
@@ -13,7 +13,8 @@ WHERE m.is_not_deleted;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -42,7 +43,8 @@ WHERE m.is_not_deleted AND m.is_visible;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -77,7 +79,8 @@ WHERE NOT m.is_not_deleted;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -109,7 +112,8 @@ WHERE NOT m.is_not_deleted
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -151,7 +155,8 @@ WHERE m.status = "success"
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -207,7 +212,8 @@ WHERE m.status = "success"
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -260,7 +266,8 @@ WHERE NOT m.is_deleted;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -291,7 +298,8 @@ WHERE !m.is_deleted;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -323,7 +331,8 @@ WHERE NOT m.is_deleted
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -362,7 +371,8 @@ WHERE col IS DISTINCT FROM NULL;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -395,7 +405,8 @@ WHERE col IS NOT DISTINCT FROM NULL;
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -430,7 +441,8 @@ WHERE id IS NOT NULL
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -516,7 +528,8 @@ WHERE
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -576,7 +589,8 @@ WHERE
     (select
       (keyword_select)
       (select_expression
-        (term value: (all_fields))))
+        (term
+          value: (all_fields))))
     (from
       (keyword_from)
       (relation
@@ -629,14 +643,15 @@ SELECT 'fat cats ate rats' @@ !! ('cat' <-> 'rat'::tsquery);
             (literal)
             (op_other)
             (unary_expression
-                  (op_unary_other)
-                  (cast
-                    (binary_expression
-                      (literal)
-                      (op_other)
-                      (literal))
-                    (object_reference
-                      (identifier))))))))))
+              (op_unary_other)
+              (parenthesized_expression
+                (cast
+                  (binary_expression
+                    (literal)
+                    (op_other)
+                    (literal))
+                  (object_reference
+                    (identifier)))))))))))
 
 ================================================================================
 Array subscript
@@ -656,21 +671,23 @@ SELECT
       (select_expression
         (term
           value: (subscript
-            expression: (array
-              (keyword_array)
-              (literal)
-              (literal)
-              (literal))
+            expression: (parenthesized_expression
+              (array
+                (keyword_array)
+                (literal)
+                (literal)
+                (literal)))
             subscript: (binary_expression
               left: (literal)
               right: (literal))))
         (term
           value: (subscript
-            expression: (array
-              (keyword_array)
-              (literal)
-              (literal)
-              (literal))
+            expression: (parenthesized_expression
+              (array
+                (keyword_array)
+                (literal)
+                (literal)
+                (literal)))
             lower: (literal)
             upper: (binary_expression
               left: (literal)
@@ -678,11 +695,12 @@ SELECT
         (term
           value: (subscript
             expression: (subscript
-              expression: (array
-                (keyword_array)
-                (literal)
-                (literal)
-                (literal))
+              expression: (parenthesized_expression
+                (array
+                  (keyword_array)
+                  (literal)
+                  (literal)
+                  (literal)))
               lower: (literal)
               upper: (literal))
             subscript: (literal)))))))
diff --git a/test/corpus/functions.txt b/test/corpus/functions.txt
index 5562a943..f99b0262 100644
--- a/test/corpus/functions.txt
+++ b/test/corpus/functions.txt
@@ -421,10 +421,28 @@ WHERE (
           name: (identifier)))
       (where
         (keyword_where)
-        predicate: (binary_expression
-          left: (unary_expression
-            operator: (keyword_not)
-            operand: (exists
+        predicate: (parenthesized_expression
+          (binary_expression
+            left: (unary_expression
+              operator: (keyword_not)
+              operand: (exists
+                (keyword_exists)
+                (subquery
+                  (select
+                    (keyword_select)
+                    (select_expression
+                      (term
+                        value: (literal))))
+                  (from
+                    (keyword_from)
+                    (relation
+                      (object_reference
+                        name: (identifier)))
+                    (where
+                      (keyword_where)
+                      predicate: (literal))))))
+            operator: (keyword_or)
+            right: (exists
               (keyword_exists)
               (subquery
                 (select
@@ -439,24 +457,7 @@ WHERE (
                       name: (identifier)))
                   (where
                     (keyword_where)
-                    predicate: (literal))))))
-          operator: (keyword_or)
-          right: (exists
-            (keyword_exists)
-            (subquery
-              (select
-                (keyword_select)
-                (select_expression
-                  (term
-                    value: (literal))))
-              (from
-                (keyword_from)
-                (relation
-                  (object_reference
-                    name: (identifier)))
-                (where
-                  (keyword_where)
-                  predicate: (literal))))))))))
+                    predicate: (literal)))))))))))
 
 ================================================================================
 Basic SQL function creation
diff --git a/test/corpus/merge.txt b/test/corpus/merge.txt
index 35fa68b2..214d19a0 100644
--- a/test/corpus/merge.txt
+++ b/test/corpus/merge.txt
@@ -64,15 +64,16 @@ USING monthly_accounts_update s
       (identifier))
     (identifier)
     (keyword_on)
-    (binary_expression
-      (field
-        (object_reference
-          (identifier))
-        (identifier))
-      (field
-        (object_reference
+    (parenthesized_expression
+      (binary_expression
+        (field
+          (object_reference
+            (identifier))
           (identifier))
-        (identifier)))
+        (field
+          (object_reference
+            (identifier))
+          (identifier))))
     (when_clause
       (keyword_when)
       (keyword_matched)
@@ -149,15 +150,16 @@ USING monthly_accounts_update s
       (identifier))
     (identifier)
     (keyword_on)
-    (binary_expression
-      (field
-        (object_reference
-          (identifier))
-        (identifier))
-      (field
-        (object_reference
+    (parenthesized_expression
+      (binary_expression
+        (field
+          (object_reference
+            (identifier))
           (identifier))
-        (identifier)))
+        (field
+          (object_reference
+            (identifier))
+          (identifier))))
     (when_clause
       (keyword_when)
       (keyword_matched)
diff --git a/test/corpus/select.txt b/test/corpus/select.txt
index 6f98ad10..a003d4b3 100644
--- a/test/corpus/select.txt
+++ b/test/corpus/select.txt
@@ -821,8 +821,9 @@ FROM my_table;
       (keyword_distinct)
       (select_expression
         (term
-          value: (field
-            name: (identifier)))))
+          value: (parenthesized_expression
+            (field
+              name: (identifier))))))
     (from
       (keyword_from)
       (relation
@@ -871,8 +872,9 @@ FROM my_table;
               name: (identifier))
             (keyword_distinct)
             parameter: (term
-              value: (field
-                name: (identifier)))))))
+              value: (parenthesized_expression
+                (field
+                  name: (identifier))))))))
     (from
       (keyword_from)
       (relation
@@ -1958,19 +1960,7 @@ FROM my_table;
             (keyword_then)
             (literal)
             (keyword_when)
-            (binary_expression
-              (field
-                (identifier))
-              (literal))
-            (keyword_then)
-            (literal)
-            (keyword_when)
-            (binary_expression
-              (binary_expression
-                (field
-                  (identifier))
-                (literal))
-              (keyword_and)
+            (parenthesized_expression
               (binary_expression
                 (field
                   (identifier))
@@ -1978,6 +1968,22 @@ FROM my_table;
             (keyword_then)
             (literal)
             (keyword_when)
+            (parenthesized_expression
+              (binary_expression
+                (parenthesized_expression
+                  (binary_expression
+                    (field
+                      (identifier))
+                    (literal)))
+                (keyword_and)
+                (parenthesized_expression
+                  (binary_expression
+                    (field
+                      (identifier))
+                    (literal)))))
+            (keyword_then)
+            (literal)
+            (keyword_when)
             (binary_expression
               (field
                 (identifier))
@@ -2849,12 +2855,13 @@ WHERE (foo OR bar) AND baz
       (where
         (keyword_where)
         predicate: (binary_expression
-          left: (binary_expression
-            left: (field
-              name: (identifier))
-            operator: (keyword_or)
-            right: (field
-              name: (identifier)))
+          left: (parenthesized_expression
+            (binary_expression
+              left: (field
+                name: (identifier))
+              operator: (keyword_or)
+              right: (field
+                name: (identifier))))
           operator: (keyword_and)
           right: (field
             name: (identifier)))))))