diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,12 @@
 
 All notable changes to this package are documented in this file. This project adheres to [Haskell PVP](https://pvp.haskell.org/) versioning.
 
+## 0.3.0.2
+
+- #43, Fix spaces not allowed in relative query and singular query segments
+- #50, Fix wrong normalized path with descendant segment
+- #30, Fix escape characters not handled properly in normalized path
+
 ## 0.3.0.1
 
 - #31, Fix `test/cts.json` not included in hackage bundle
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # aeson-jsonpath
 
-![ci-badge](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml/badge.svg?event=push) [![hackage-docs](https://img.shields.io/badge/hackage-v0.3.0.1-blue)](https://hackage.haskell.org/package/aeson-jsonpath) [![Donate](https://img.shields.io/badge/Donate-Patreon-red)](https://www.patreon.com/taimoorzaeem) ![Compliance](https://img.shields.io/badge/Compliance-Passing-brightgreen)
+[![Build](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml/badge.svg)](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/build.yml) [![hackage-docs](https://img.shields.io/badge/hackage-v0.3.0.1-blue)](https://hackage.haskell.org/package/aeson-jsonpath) [![Donate](https://img.shields.io/badge/Donate-Patreon-red)](https://www.patreon.com/taimoorzaeem) [![Compliance](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/compliance.yml/badge.svg)](https://github.com/taimoorzaeem/aeson-jsonpath/actions/workflows/compliance.yml)
 
 Run [RFC 9535](https://www.rfc-editor.org/rfc/rfc9535) compliant JSONPath queries on [Data.Aeson](https://hackage.haskell.org/package/aeson).
 
@@ -15,10 +15,11 @@
 - [x] Segments
   - [x] Child Segment
   - [x] Descendant Segment
-- [x] Node Locations (Normalized Path)
+- [x] Normalized Paths
 - [ ] Function Extensions
-- [ ] Setting Values (Non-RFC)
 
+I have decided not to implement Function Extension yet. Please open an issue or discussion if you'd like to see them implemented.
+
 ## Quick Start
 
 ```haskell
@@ -56,7 +57,7 @@
         "year": 2018
       },
       {
-        "title": "Lawrence Anyways",
+        "title": "Laurence Anyways",
         "director": "Xavier Dolan",
         "year": 2012
       }
@@ -111,7 +112,7 @@
 Right [
   Object (fromList [
     ("director",String "Xavier Dolan"),
-    ("title",String "Lawrence Anyways"),
+    ("title",String "Laurence Anyways"),
     ("year",Number 2012.0)
   ])
 ]
diff --git a/aeson-jsonpath.cabal b/aeson-jsonpath.cabal
--- a/aeson-jsonpath.cabal
+++ b/aeson-jsonpath.cabal
@@ -1,5 +1,5 @@
 name:               aeson-jsonpath
-version:            0.3.0.1
+version:            0.3.0.2
 synopsis:           Parse and run JSONPath queries on Aeson documents
 description:        RFC 9535 compliant JSONPath parsing and querying
                     package. JSONPath is similar to XPath for querying
@@ -14,7 +14,7 @@
 build-type:         Simple
 extra-source-files: CHANGELOG.md
 extra-doc-files:    README.md
-data-files:         test/cts.json
+data-files:         jsonpath-compliance-test-suite/cts.json
 cabal-version:      1.18
 
 tested-with:
@@ -36,7 +36,20 @@
   exposed-modules:    Data.Aeson.JSONPath
                       Data.Aeson.JSONPath.Parser
                       Data.Aeson.JSONPath.Query
-                      Data.Aeson.JSONPath.Query.Types
+                      Data.Aeson.JSONPath.Types
+  other-modules:      Data.Aeson.JSONPath.Parser.Query
+                      Data.Aeson.JSONPath.Parser.Filter
+                      Data.Aeson.JSONPath.Parser.Name
+                      Data.Aeson.JSONPath.Parser.Number
+                      Data.Aeson.JSONPath.Parser.Common
+                      Data.Aeson.JSONPath.Query.Query
+                      Data.Aeson.JSONPath.Query.Segment
+                      Data.Aeson.JSONPath.Query.Selector
+                      Data.Aeson.JSONPath.Query.Filter
+                      Data.Aeson.JSONPath.Types.Query
+                      Data.Aeson.JSONPath.Types.Segment
+                      Data.Aeson.JSONPath.Types.Selector
+                      Data.Aeson.JSONPath.Types.Filter
   build-depends:      aeson                     >= 2.0.3 && < 2.3
                     , base                      >= 4.9 && < 4.22
                     , parsec                    >= 3.1.11 && < 3.2
@@ -53,12 +66,29 @@
   default-extensions: OverloadedStrings
                       NoImplicitPrelude
                       QuasiQuotes
-  hs-source-dirs:     test
+  hs-source-dirs:     test/spec
   main-is:            Main.hs
   other-modules:      ParserSpec
                       QuerySpec
-                      ComplianceSpec
                       LocatedSpec
+  build-depends:      aeson                     >= 2.0.3 && < 2.3
+                    , aeson-jsonpath
+                    , base                      >= 4.9 && < 4.22
+                    , hspec                     >= 2.3 && < 2.12
+                    , parsec                    >= 3.1.11 && < 3.2
+                    , vector                    >= 0.11 && < 0.14
+
+  ghc-options:        -Wall -Wunused-packages
+
+test-suite compliance
+  type:               exitcode-stdio-1.0
+  default-language:   Haskell2010
+  default-extensions: OverloadedStrings
+                      NoImplicitPrelude
+                      QuasiQuotes
+  hs-source-dirs:     test/compliance
+  main-is:            Main.hs
+  other-modules:      ComplianceSpec
                       Paths_aeson_jsonpath
   build-depends:      aeson                     >= 2.0.3 && < 2.3
                     , aeson-jsonpath
diff --git a/jsonpath-compliance-test-suite/cts.json b/jsonpath-compliance-test-suite/cts.json
new file mode 100644
--- /dev/null
+++ b/jsonpath-compliance-test-suite/cts.json
@@ -0,0 +1,12702 @@
+{
+  "description": "JSONPath Compliance Test Suite. This file is autogenerated, do not edit.",
+  "tests": [
+    {
+      "name": "basic, root",
+      "selector": "$",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        [
+          "first",
+          "second"
+        ]
+      ],
+      "result_paths": [
+        "$"
+      ]
+    },
+    {
+      "name": "basic, no leading whitespace",
+      "selector": " $",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "basic, no trailing whitespace",
+      "selector": "$ ",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "basic, name shorthand",
+      "selector": "$.a",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['a']"
+      ]
+    },
+    {
+      "name": "basic, name shorthand, extended unicode ☺",
+      "selector": "$.☺",
+      "document": {
+        "☺": "A",
+        "b": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['☺']"
+      ]
+    },
+    {
+      "name": "basic, name shorthand, underscore",
+      "selector": "$._",
+      "document": {
+        "_": "A",
+        "_foo": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['_']"
+      ]
+    },
+    {
+      "name": "basic, name shorthand, symbol",
+      "selector": "$.&",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, name shorthand, number",
+      "selector": "$.1",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, name shorthand, absent data",
+      "selector": "$.c",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "basic, name shorthand, array data",
+      "selector": "$.a",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "basic, name shorthand, object data, nested",
+      "selector": "$.a.b.c",
+      "document": {
+        "a": {
+          "b": {
+            "c": "C"
+          }
+        }
+      },
+      "result": [
+        "C"
+      ],
+      "result_paths": [
+        "$['a']['b']['c']"
+      ]
+    },
+    {
+      "name": "basic, wildcard shorthand, object data",
+      "selector": "$.*",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "results": [
+        [
+          "A",
+          "B"
+        ],
+        [
+          "B",
+          "A"
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']"
+        ],
+        [
+          "$['b']",
+          "$['a']"
+        ]
+      ]
+    },
+    {
+      "name": "basic, wildcard shorthand, array data",
+      "selector": "$.*",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "first",
+        "second"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, wildcard selector, array data",
+      "selector": "$[*]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "first",
+        "second"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, wildcard shorthand, then name shorthand",
+      "selector": "$.*.a",
+      "document": {
+        "x": {
+          "a": "Ax",
+          "b": "Bx"
+        },
+        "y": {
+          "a": "Ay",
+          "b": "By"
+        }
+      },
+      "results": [
+        [
+          "Ax",
+          "Ay"
+        ],
+        [
+          "Ay",
+          "Ax"
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['x']['a']",
+          "$['y']['a']"
+        ],
+        [
+          "$['y']['a']",
+          "$['x']['a']"
+        ]
+      ]
+    },
+    {
+      "name": "basic, multiple selectors",
+      "selector": "$[0,2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        2
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, space instead of comma",
+      "selector": "$[0 2]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "basic, selector, leading comma",
+      "selector": "$[,0]",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, selector, trailing comma",
+      "selector": "$[0,]",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, multiple selectors, name and index, array data",
+      "selector": "$['a',1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, name and index, object data",
+      "selector": "$['a',1]",
+      "document": {
+        "a": 1,
+        "b": 2
+      },
+      "result": [
+        1
+      ],
+      "result_paths": [
+        "$['a']"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, index and slice",
+      "selector": "$[1,5:7]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        5,
+        6
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[5]",
+        "$[6]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, index and slice, overlapping",
+      "selector": "$[1,0:3]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        0,
+        1,
+        2
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[0]",
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, duplicate index",
+      "selector": "$[1,1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        1
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, wildcard and index",
+      "selector": "$[*,1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9,
+        1
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]",
+        "$[7]",
+        "$[8]",
+        "$[9]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, wildcard and name",
+      "selector": "$[*,'a']",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "results": [
+        [
+          "A",
+          "B",
+          "A"
+        ],
+        [
+          "B",
+          "A",
+          "A"
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']",
+          "$['a']"
+        ],
+        [
+          "$['b']",
+          "$['a']",
+          "$['a']"
+        ]
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, wildcard and slice",
+      "selector": "$[*,0:2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9,
+        0,
+        1
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]",
+        "$[7]",
+        "$[8]",
+        "$[9]",
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, multiple selectors, multiple wildcards",
+      "selector": "$[*,*]",
+      "document": [
+        0,
+        1,
+        2
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        0,
+        1,
+        2
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[0]",
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "basic, empty segment",
+      "selector": "$[]",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, descendant segment, index",
+      "selector": "$..[1]",
+      "document": {
+        "o": [
+          0,
+          1,
+          [
+            2,
+            3
+          ]
+        ]
+      },
+      "result": [
+        1,
+        3
+      ],
+      "result_paths": [
+        "$['o'][1]",
+        "$['o'][2][1]"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, name shorthand",
+      "selector": "$..a",
+      "document": {
+        "o": [
+          {
+            "a": "b"
+          },
+          {
+            "a": "c"
+          }
+        ]
+      },
+      "result": [
+        "b",
+        "c"
+      ],
+      "result_paths": [
+        "$['o'][0]['a']",
+        "$['o'][1]['a']"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard shorthand, array data",
+      "selector": "$..*",
+      "document": [
+        0,
+        1
+      ],
+      "result": [
+        0,
+        1
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard selector, array data",
+      "selector": "$..[*]",
+      "document": [
+        0,
+        1
+      ],
+      "result": [
+        0,
+        1
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard selector, nested arrays",
+      "selector": "$..[*]",
+      "document": [
+        [
+          [
+            1
+          ]
+        ],
+        [
+          2
+        ]
+      ],
+      "results": [
+        [
+          [
+            [
+              1
+            ]
+          ],
+          [
+            2
+          ],
+          [
+            1
+          ],
+          1,
+          2
+        ],
+        [
+          [
+            [
+              1
+            ]
+          ],
+          [
+            2
+          ],
+          [
+            1
+          ],
+          2,
+          1
+        ]
+      ],
+      "results_paths": [
+        [
+          "$[0]",
+          "$[1]",
+          "$[0][0]",
+          "$[0][0][0]",
+          "$[1][0]"
+        ],
+        [
+          "$[0]",
+          "$[1]",
+          "$[0][0]",
+          "$[1][0]",
+          "$[0][0][0]"
+        ]
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard selector, nested objects",
+      "selector": "$..[*]",
+      "document": {
+        "a": {
+          "c": {
+            "e": 1
+          }
+        },
+        "b": {
+          "d": 2
+        }
+      },
+      "results": [
+        [
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          {
+            "d": 2
+          },
+          {
+            "e": 1
+          },
+          1,
+          2
+        ],
+        [
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          {
+            "d": 2
+          },
+          {
+            "e": 1
+          },
+          2,
+          1
+        ],
+        [
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          {
+            "d": 2
+          },
+          2,
+          {
+            "e": 1
+          },
+          1
+        ],
+        [
+          {
+            "d": 2
+          },
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          {
+            "e": 1
+          },
+          1,
+          2
+        ],
+        [
+          {
+            "d": 2
+          },
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          {
+            "e": 1
+          },
+          2,
+          1
+        ],
+        [
+          {
+            "d": 2
+          },
+          {
+            "c": {
+              "e": 1
+            }
+          },
+          2,
+          {
+            "e": 1
+          },
+          1
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']",
+          "$['a']['c']",
+          "$['a']['c']['e']",
+          "$['b']['d']"
+        ],
+        [
+          "$['a']",
+          "$['b']",
+          "$['a']['c']",
+          "$['b']['d']",
+          "$['a']['c']['e']"
+        ],
+        [
+          "$['a']",
+          "$['b']",
+          "$['b']['d']",
+          "$['a']['c']",
+          "$['a']['c']['e']"
+        ],
+        [
+          "$['b']",
+          "$['a']",
+          "$['a']['c']",
+          "$['a']['c']['e']",
+          "$['b']['d']"
+        ],
+        [
+          "$['b']",
+          "$['a']",
+          "$['a']['c']",
+          "$['b']['d']",
+          "$['a']['c']['e']"
+        ],
+        [
+          "$['b']",
+          "$['a']",
+          "$['b']['d']",
+          "$['a']['c']",
+          "$['a']['c']['e']"
+        ]
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard shorthand, object data",
+      "selector": "$..*",
+      "document": {
+        "a": "b"
+      },
+      "result": [
+        "b"
+      ],
+      "result_paths": [
+        "$['a']"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, wildcard shorthand, nested data",
+      "selector": "$..*",
+      "document": {
+        "o": [
+          {
+            "a": "b"
+          }
+        ]
+      },
+      "result": [
+        [
+          {
+            "a": "b"
+          }
+        ],
+        {
+          "a": "b"
+        },
+        "b"
+      ],
+      "result_paths": [
+        "$['o']",
+        "$['o'][0]",
+        "$['o'][0]['a']"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, multiple selectors",
+      "selector": "$..['a','d']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        "b",
+        "e",
+        "c",
+        "f"
+      ],
+      "result_paths": [
+        "$[0]['a']",
+        "$[0]['d']",
+        "$[1]['a']",
+        "$[1]['d']"
+      ]
+    },
+    {
+      "name": "basic, descendant segment, object traversal, multiple selectors",
+      "selector": "$..['a','d']",
+      "document": {
+        "x": {
+          "a": "b",
+          "d": "e"
+        },
+        "y": {
+          "a": "c",
+          "d": "f"
+        }
+      },
+      "results": [
+        [
+          "b",
+          "e",
+          "c",
+          "f"
+        ],
+        [
+          "c",
+          "f",
+          "b",
+          "e"
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['x']['a']",
+          "$['x']['d']",
+          "$['y']['a']",
+          "$['y']['d']"
+        ],
+        [
+          "$['y']['a']",
+          "$['y']['d']",
+          "$['x']['a']",
+          "$['x']['d']"
+        ]
+      ]
+    },
+    {
+      "name": "basic, bald descendant segment",
+      "selector": "$..",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, current node identifier without filter selector",
+      "selector": "$[@.a]",
+      "invalid_selector": true
+    },
+    {
+      "name": "basic, root node identifier in brackets without filter selector",
+      "selector": "$[$.a]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, existence, without segments",
+      "selector": "$[?@]",
+      "document": {
+        "a": 1,
+        "b": null
+      },
+      "results": [
+        [
+          1,
+          null
+        ],
+        [
+          null,
+          1
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']"
+        ],
+        [
+          "$['b']",
+          "$['a']"
+        ]
+      ]
+    },
+    {
+      "name": "filter, existence",
+      "selector": "$[?@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, existence, present with null",
+      "selector": "$[?@.a]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": null,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, absolute existence, without segments",
+      "selector": "$[?$]",
+      "document": {
+        "a": 1,
+        "b": null
+      },
+      "results": [
+        [
+          1,
+          null
+        ],
+        [
+          null,
+          1
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']"
+        ],
+        [
+          "$['b']",
+          "$['a']"
+        ]
+      ]
+    },
+    {
+      "name": "filter, absolute existence, with segments",
+      "selector": "$[?$.*.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, equals string, single quotes",
+      "selector": "$[?@.a=='b']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals numeric string, single quotes",
+      "selector": "$[?@.a=='1']",
+      "document": [
+        {
+          "a": "1",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "1",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals string, double quotes",
+      "selector": "$[?@.a==\"b\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals numeric string, double quotes",
+      "selector": "$[?@.a==\"1\"]",
+      "document": [
+        {
+          "a": "1",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "1",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number",
+      "selector": "$[?@.a==1]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals null",
+      "selector": "$[?@.a==null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": null,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals null, absent from data",
+      "selector": "$[?@.a==null]",
+      "document": [
+        {
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, equals true",
+      "selector": "$[?@.a==true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": true,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals false",
+      "selector": "$[?@.a==false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": false,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals self",
+      "selector": "$[?@==@]",
+      "document": [
+        1,
+        null,
+        true,
+        {
+          "a": "b"
+        },
+        [
+          false
+        ]
+      ],
+      "result": [
+        1,
+        null,
+        true,
+        {
+          "a": "b"
+        },
+        [
+          false
+        ]
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]"
+      ]
+    },
+    {
+      "name": "filter, absolute, equals self",
+      "selector": "$[?$==$]",
+      "document": [
+        1,
+        null,
+        true,
+        {
+          "a": "b"
+        },
+        [
+          false
+        ]
+      ],
+      "result": [
+        1,
+        null,
+        true,
+        {
+          "a": "b"
+        },
+        [
+          false
+        ]
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]"
+      ]
+    },
+    {
+      "name": "filter, equals, absent from index selector equals absent from name selector",
+      "selector": "$[?@.absent==@.list[9]]",
+      "document": [
+        {
+          "list": [
+            1
+          ]
+        }
+      ],
+      "result": [
+        {
+          "list": [
+            1
+          ]
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, deep equality, arrays",
+      "selector": "$[?@.a==@.b]",
+      "document": [
+        {
+          "a": false,
+          "b": [
+            1,
+            2
+          ]
+        },
+        {
+          "a": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ],
+          "b": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ]
+        },
+        {
+          "a": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ],
+          "b": [
+            [
+              [
+                2
+              ],
+              1
+            ]
+          ]
+        },
+        {
+          "a": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ],
+          "b": [
+            [
+              1,
+              2
+            ]
+          ]
+        }
+      ],
+      "result": [
+        {
+          "a": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ],
+          "b": [
+            [
+              1,
+              [
+                2
+              ]
+            ]
+          ]
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, deep equality, objects",
+      "selector": "$[?@.a==@.b]",
+      "document": [
+        {
+          "a": false,
+          "b": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          }
+        },
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          }
+        },
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "y": {
+              "z": 1
+            },
+            "x": 1
+          }
+        },
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "x": 1
+          }
+        },
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "x": 1,
+            "y": {
+              "z": 2
+            }
+          }
+        }
+      ],
+      "result": [
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          }
+        },
+        {
+          "a": {
+            "x": 1,
+            "y": {
+              "z": 1
+            }
+          },
+          "b": {
+            "y": {
+              "z": 1
+            },
+            "x": 1
+          }
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, not-equals string, single quotes",
+      "selector": "$[?@.a!='b']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals numeric string, single quotes",
+      "selector": "$[?@.a!='1']",
+      "document": [
+        {
+          "a": "1",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals string, single quotes, different type",
+      "selector": "$[?@.a!='b']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals string, double quotes",
+      "selector": "$[?@.a!=\"b\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals numeric string, double quotes",
+      "selector": "$[?@.a!=\"1\"]",
+      "document": [
+        {
+          "a": "1",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals string, double quotes, different types",
+      "selector": "$[?@.a!=\"b\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals number",
+      "selector": "$[?@.a!=1]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, not-equals number, different types",
+      "selector": "$[?@.a!=1]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals null",
+      "selector": "$[?@.a!=null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals null, absent from data",
+      "selector": "$[?@.a!=null]",
+      "document": [
+        {
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals true",
+      "selector": "$[?@.a!=true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not-equals false",
+      "selector": "$[?@.a!=false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, less than string, single quotes",
+      "selector": "$[?@.a<'c']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, less than string, double quotes",
+      "selector": "$[?@.a<\"c\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, less than number",
+      "selector": "$[?@.a<10]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 10,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, less than null",
+      "selector": "$[?@.a<null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, less than true",
+      "selector": "$[?@.a<true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, less than false",
+      "selector": "$[?@.a<false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, less than or equal to string, single quotes",
+      "selector": "$[?@.a<='c']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, less than or equal to string, double quotes",
+      "selector": "$[?@.a<=\"c\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, less than or equal to number",
+      "selector": "$[?@.a<=10]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 10,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 10,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, less than or equal to null",
+      "selector": "$[?@.a<=null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": null,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, less than or equal to true",
+      "selector": "$[?@.a<=true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": true,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, less than or equal to false",
+      "selector": "$[?@.a<=false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": false,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, greater than string, single quotes",
+      "selector": "$[?@.a>'c']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, greater than string, double quotes",
+      "selector": "$[?@.a>\"c\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, greater than number",
+      "selector": "$[?@.a>10]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 10,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, greater than null",
+      "selector": "$[?@.a>null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, greater than true",
+      "selector": "$[?@.a>true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, greater than false",
+      "selector": "$[?@.a>false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, greater than or equal to string, single quotes",
+      "selector": "$[?@.a>='c']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, greater than or equal to string, double quotes",
+      "selector": "$[?@.a>=\"c\"]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, greater than or equal to number",
+      "selector": "$[?@.a>=10]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 10,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 10,
+          "d": "e"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, greater than or equal to null",
+      "selector": "$[?@.a>=null]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": null,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, greater than or equal to true",
+      "selector": "$[?@.a>=true]",
+      "document": [
+        {
+          "a": true,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": true,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, greater than or equal to false",
+      "selector": "$[?@.a>=false]",
+      "document": [
+        {
+          "a": false,
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": false,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, exists and not-equals null, absent from data",
+      "selector": "$[?@.a&&@.a!=null]",
+      "document": [
+        {
+          "d": "e"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, exists and exists, data false",
+      "selector": "$[?@.a&&@.b]",
+      "document": [
+        {
+          "a": false,
+          "b": false
+        },
+        {
+          "b": false
+        },
+        {
+          "c": false
+        }
+      ],
+      "result": [
+        {
+          "a": false,
+          "b": false
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, exists or exists, data false",
+      "selector": "$[?@.a||@.b]",
+      "document": [
+        {
+          "a": false,
+          "b": false
+        },
+        {
+          "b": false
+        },
+        {
+          "c": false
+        }
+      ],
+      "result": [
+        {
+          "a": false,
+          "b": false
+        },
+        {
+          "b": false
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, and",
+      "selector": "$[?@.a>0&&@.a<10]",
+      "document": [
+        {
+          "a": -10,
+          "d": "e"
+        },
+        {
+          "a": 5,
+          "d": "f"
+        },
+        {
+          "a": 20,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": 5,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, or",
+      "selector": "$[?@.a=='b'||@.a=='d']",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "c",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, not expression",
+      "selector": "$[?!(@.a=='b')]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, not exists",
+      "selector": "$[?!@.a]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, not exists, data null",
+      "selector": "$[?!@.a]",
+      "document": [
+        {
+          "a": null,
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, non-singular existence, wildcard",
+      "selector": "$[?@.*]",
+      "document": [
+        1,
+        [],
+        [
+          2
+        ],
+        {},
+        {
+          "a": 3
+        }
+      ],
+      "result": [
+        [
+          2
+        ],
+        {
+          "a": 3
+        }
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[4]"
+      ]
+    },
+    {
+      "name": "filter, non-singular existence, multiple",
+      "selector": "$[?@[0, 0, 'a']]",
+      "document": [
+        1,
+        [],
+        [
+          2
+        ],
+        [
+          2,
+          3
+        ],
+        {
+          "a": 3
+        },
+        {
+          "b": 4
+        },
+        {
+          "a": 3,
+          "b": 4
+        }
+      ],
+      "result": [
+        [
+          2
+        ],
+        [
+          2,
+          3
+        ],
+        {
+          "a": 3
+        },
+        {
+          "a": 3,
+          "b": 4
+        }
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[6]"
+      ]
+    },
+    {
+      "name": "filter, non-singular existence, slice",
+      "selector": "$[?@[0:2]]",
+      "document": [
+        1,
+        [],
+        [
+          2
+        ],
+        [
+          2,
+          3,
+          4
+        ],
+        {},
+        {
+          "a": 3
+        }
+      ],
+      "result": [
+        [
+          2
+        ],
+        [
+          2,
+          3,
+          4
+        ]
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, non-singular existence, negated",
+      "selector": "$[?!@.*]",
+      "document": [
+        1,
+        [],
+        [
+          2
+        ],
+        {},
+        {
+          "a": 3
+        }
+      ],
+      "result": [
+        1,
+        [],
+        {}
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, non-singular query in comparison, slice",
+      "selector": "$[?@[0:0]==0]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, non-singular query in comparison, all children",
+      "selector": "$[?@[*]==0]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, non-singular query in comparison, descendants",
+      "selector": "$[?@..a==0]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, non-singular query in comparison, combined",
+      "selector": "$[?@.a[*].a==0]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, nested",
+      "selector": "$[?@[?@>1]]",
+      "document": [
+        [
+          0
+        ],
+        [
+          0,
+          1
+        ],
+        [
+          0,
+          1,
+          2
+        ],
+        [
+          42
+        ]
+      ],
+      "result": [
+        [
+          0,
+          1,
+          2
+        ],
+        [
+          42
+        ]
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[3]"
+      ]
+    },
+    {
+      "name": "filter, name segment on primitive, selects nothing",
+      "selector": "$[?@.a == 1]",
+      "document": {
+        "a": 1
+      },
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, name segment on array, selects nothing",
+      "selector": "$[?@['0'] == 5]",
+      "document": [
+        [
+          5,
+          6
+        ]
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, index segment on object, selects nothing",
+      "selector": "$[?@[0] == 5]",
+      "document": [
+        {
+          "0": 5
+        }
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "filter, followed by name selector",
+      "selector": "$[?@.a==1].b.x",
+      "document": [
+        {
+          "a": 1,
+          "b": {
+            "x": 2
+          }
+        }
+      ],
+      "result": [
+        2
+      ],
+      "result_paths": [
+        "$[0]['b']['x']"
+      ]
+    },
+    {
+      "name": "filter, followed by child segment that selects multiple elements",
+      "selector": "$[?@.z=='_']['x','y']",
+      "document": [
+        {
+          "x": 1,
+          "y": null,
+          "z": "_"
+        }
+      ],
+      "result": [
+        1,
+        null
+      ],
+      "result_paths": [
+        "$[0]['x']",
+        "$[0]['y']"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, index, equal",
+      "selector": "$[?(@[0, 0]==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, index, not equal",
+      "selector": "$[?(@[0, 0]!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, index, less-or-equal",
+      "selector": "$[?(@[0, 0]<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, name, equal",
+      "selector": "$[?(@['a', 'a']==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, name, not equal",
+      "selector": "$[?(@['a', 'a']!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, name, less-or-equal",
+      "selector": "$[?(@['a', 'a']<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, combined, equal",
+      "selector": "$[?(@[0, '0']==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, combined, not equal",
+      "selector": "$[?(@[0, '0']!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, combined, less-or-equal",
+      "selector": "$[?(@[0, '0']<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, relative non-singular query, wildcard, equal",
+      "selector": "$[?(@.*==42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, relative non-singular query, wildcard, not equal",
+      "selector": "$[?(@.*!=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, relative non-singular query, wildcard, less-or-equal",
+      "selector": "$[?(@.*<=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, relative non-singular query, slice, equal",
+      "selector": "$[?(@[0:0]==42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, relative non-singular query, slice, not equal",
+      "selector": "$[?(@[0:0]!=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, relative non-singular query, slice, less-or-equal",
+      "selector": "$[?(@[0:0]<=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, index, equal",
+      "selector": "$[?($[0, 0]==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, index, not equal",
+      "selector": "$[?($[0, 0]!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, index, less-or-equal",
+      "selector": "$[?($[0, 0]<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, name, equal",
+      "selector": "$[?($['a', 'a']==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, name, not equal",
+      "selector": "$[?($['a', 'a']!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, name, less-or-equal",
+      "selector": "$[?($['a', 'a']<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, combined, equal",
+      "selector": "$[?($[0, '0']==42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, combined, not equal",
+      "selector": "$[?($[0, '0']!=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, combined, less-or-equal",
+      "selector": "$[?($[0, '0']<=42)]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, absolute non-singular query, wildcard, equal",
+      "selector": "$[?($.*==42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, wildcard, not equal",
+      "selector": "$[?($.*!=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, wildcard, less-or-equal",
+      "selector": "$[?($.*<=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, slice, equal",
+      "selector": "$[?($[0:0]==42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, slice, not equal",
+      "selector": "$[?($[0:0]!=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, absolute non-singular query, slice, less-or-equal",
+      "selector": "$[?($[0:0]<=42)]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, multiple selectors",
+      "selector": "$[?@.a,?@.b]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, comparison",
+      "selector": "$[?@.a=='b',?@.b=='x']",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, overlapping",
+      "selector": "$[?@.a,?@.d]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, filter and index",
+      "selector": "$[?@.a,1]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, filter and wildcard",
+      "selector": "$[?@.a,*]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[0]",
+        "$[1]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, filter and slice",
+      "selector": "$[?@.a,1:]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        },
+        {
+          "g": "h"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        },
+        {
+          "g": "h"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, multiple selectors, comparison filter, index and slice",
+      "selector": "$[1, ?@.a=='b', 1:]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "b": "c",
+          "d": "f"
+        },
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, equals number, zero and negative zero",
+      "selector": "$[?@.a==0]",
+      "document": [
+        {
+          "a": 0,
+          "d": "e"
+        },
+        {
+          "a": 0.1,
+          "d": "f"
+        },
+        {
+          "a": "0",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 0,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, negative zero and zero",
+      "selector": "$[?@.a==-0]",
+      "document": [
+        {
+          "a": 0,
+          "d": "e"
+        },
+        {
+          "a": 0.1,
+          "d": "f"
+        },
+        {
+          "a": "0",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 0,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, with and without decimal fraction",
+      "selector": "$[?@.a==1.0]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent",
+      "selector": "$[?@.a==1e2]",
+      "document": [
+        {
+          "a": 100,
+          "d": "e"
+        },
+        {
+          "a": 100.1,
+          "d": "f"
+        },
+        {
+          "a": "100",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 100,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent upper e",
+      "selector": "$[?@.a==1E2]",
+      "document": [
+        {
+          "a": 100,
+          "d": "e"
+        },
+        {
+          "a": 100.1,
+          "d": "f"
+        },
+        {
+          "a": "100",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 100,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, positive exponent",
+      "selector": "$[?@.a==1e+2]",
+      "document": [
+        {
+          "a": 100,
+          "d": "e"
+        },
+        {
+          "a": 100.1,
+          "d": "f"
+        },
+        {
+          "a": "100",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 100,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, negative exponent",
+      "selector": "$[?@.a==1e-2]",
+      "document": [
+        {
+          "a": 0.01,
+          "d": "e"
+        },
+        {
+          "a": 0.02,
+          "d": "f"
+        },
+        {
+          "a": "0.01",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 0.01,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent 0",
+      "selector": "$[?@.a==1e0]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent -0",
+      "selector": "$[?@.a==1e-0]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent +0",
+      "selector": "$[?@.a==1e+0]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent leading -0",
+      "selector": "$[?@.a==1e-02]",
+      "document": [
+        {
+          "a": 0.01,
+          "d": "e"
+        },
+        {
+          "a": 0.02,
+          "d": "f"
+        },
+        {
+          "a": "0.01",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 0.01,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, exponent +00",
+      "selector": "$[?@.a==1e+00]",
+      "document": [
+        {
+          "a": 1,
+          "d": "e"
+        },
+        {
+          "a": 2,
+          "d": "f"
+        },
+        {
+          "a": "1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, decimal fraction",
+      "selector": "$[?@.a==1.1]",
+      "document": [
+        {
+          "a": 1.1,
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        },
+        {
+          "a": "1.1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1.1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, decimal fraction, trailing 0",
+      "selector": "$[?@.a==1.10]",
+      "document": [
+        {
+          "a": 1.1,
+          "d": "e"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        },
+        {
+          "a": "1.1",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 1.1,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, decimal fraction, exponent",
+      "selector": "$[?@.a==1.1e2]",
+      "document": [
+        {
+          "a": 110,
+          "d": "e"
+        },
+        {
+          "a": 110.1,
+          "d": "f"
+        },
+        {
+          "a": "110",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 110,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, decimal fraction, positive exponent",
+      "selector": "$[?@.a==1.1e+2]",
+      "document": [
+        {
+          "a": 110,
+          "d": "e"
+        },
+        {
+          "a": 110.1,
+          "d": "f"
+        },
+        {
+          "a": "110",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 110,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, decimal fraction, negative exponent",
+      "selector": "$[?@.a==1.1e-2]",
+      "document": [
+        {
+          "a": 0.011,
+          "d": "e"
+        },
+        {
+          "a": 0.012,
+          "d": "f"
+        },
+        {
+          "a": "0.011",
+          "d": "g"
+        }
+      ],
+      "result": [
+        {
+          "a": 0.011,
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, equals number, invalid plus",
+      "selector": "$[?@.a==+1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid minus space",
+      "selector": "$[?@.a==- 1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid double minus",
+      "selector": "$[?@.a==--1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid no int digit",
+      "selector": "$[?@.a==.1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid minus no int digit",
+      "selector": "$[?@.a==-.1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid 00",
+      "selector": "$[?@.a==00]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid leading 0",
+      "selector": "$[?@.a==01]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid no fractional digit",
+      "selector": "$[?@.a==1.]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid middle minus",
+      "selector": "$[?@.a==1.-1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid no fractional digit e",
+      "selector": "$[?@.a==1.e1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid no e digit",
+      "selector": "$[?@.a==1e]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid no e digit minus",
+      "selector": "$[?@.a==1e-]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid double e",
+      "selector": "$[?@.a==1eE1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid e digit double minus",
+      "selector": "$[?@.a==1e--1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid e digit plus minus",
+      "selector": "$[?@.a==1e+-1]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid e decimal",
+      "selector": "$[?@.a==1e2.3]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals number, invalid multi e",
+      "selector": "$[?@.a==1e2e3]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, equals, special nothing",
+      "selector": "$.values[?length(@.a) == value($..c)]",
+      "document": {
+        "c": "cd",
+        "values": [
+          {
+            "a": "ab"
+          },
+          {
+            "c": "d"
+          },
+          {
+            "a": null
+          }
+        ]
+      },
+      "result": [
+        {
+          "c": "d"
+        },
+        {
+          "a": null
+        }
+      ],
+      "result_paths": [
+        "$['values'][1]",
+        "$['values'][2]"
+      ],
+      "tags": [
+        "function"
+      ]
+    },
+    {
+      "name": "filter, equals, empty node list and empty node list",
+      "selector": "$[?@.a == @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ]
+    },
+    {
+      "name": "filter, equals, empty node list and special nothing",
+      "selector": "$[?@.a == length(@.b)]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, object data",
+      "selector": "$[?@<3]",
+      "document": {
+        "a": 1,
+        "b": 2,
+        "c": 3
+      },
+      "results": [
+        [
+          1,
+          2
+        ],
+        [
+          2,
+          1
+        ]
+      ],
+      "results_paths": [
+        [
+          "$['a']",
+          "$['b']"
+        ],
+        [
+          "$['b']",
+          "$['a']"
+        ]
+      ]
+    },
+    {
+      "name": "filter, and binds more tightly than or",
+      "selector": "$[?@.a || @.b && @.c]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2,
+          "c": 3
+        },
+        {
+          "c": 3
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2,
+          "c": 3
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[4]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, left to right evaluation",
+      "selector": "$[?@.a && @.b || @.c]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 1,
+          "c": 3
+        },
+        {
+          "b": 1,
+          "c": 3
+        },
+        {
+          "c": 3
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 1,
+          "c": 3
+        },
+        {
+          "b": 1,
+          "c": 3
+        },
+        {
+          "c": 3
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, group terms, left",
+      "selector": "$[?(@.a || @.b) && @.c]",
+      "document": [
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 1,
+          "c": 3
+        },
+        {
+          "b": 2,
+          "c": 3
+        },
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "c": 3
+        },
+        {
+          "b": 2,
+          "c": 3
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]",
+        "$[6]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, group terms, right",
+      "selector": "$[?@.a && (@.b || @.c)]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 1,
+          "c": 2
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 2
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 1,
+          "c": 2
+        },
+        {
+          "a": 1,
+          "b": 2,
+          "c": 3
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]",
+        "$[5]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, string literal, single quote in double quotes",
+      "selector": "$[?@ == \"quoted' literal\"]",
+      "document": [
+        "quoted' literal",
+        "a",
+        "quoted\\' literal"
+      ],
+      "result": [
+        "quoted' literal"
+      ],
+      "result_paths": [
+        "$[0]"
+      ]
+    },
+    {
+      "name": "filter, string literal, double quote in single quotes",
+      "selector": "$[?@ == 'quoted\" literal']",
+      "document": [
+        "quoted\" literal",
+        "a",
+        "quoted\\\" literal",
+        "'quoted\" literal'"
+      ],
+      "result": [
+        "quoted\" literal"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, string literal, escaped single quote in single quotes",
+      "selector": "$[?@ == 'quoted\\' literal']",
+      "document": [
+        "quoted' literal",
+        "a",
+        "quoted\\' literal",
+        "'quoted\" literal'"
+      ],
+      "result": [
+        "quoted' literal"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, string literal, escaped double quote in double quotes",
+      "selector": "$[?@ == \"quoted\\\" literal\"]",
+      "document": [
+        "quoted\" literal",
+        "a",
+        "quoted\\\" literal",
+        "'quoted\" literal'"
+      ],
+      "result": [
+        "quoted\" literal"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, literal true must be compared",
+      "selector": "$[?true]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, literal false must be compared",
+      "selector": "$[?false]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, literal string must be compared",
+      "selector": "$[?'abc']",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, literal int must be compared",
+      "selector": "$[?2]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, literal float must be compared",
+      "selector": "$[?2.2]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, literal null must be compared",
+      "selector": "$[?null]",
+      "invalid_selector": true
+    },
+    {
+      "name": "filter, and, literals must be compared",
+      "selector": "$[?true && false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, or, literals must be compared",
+      "selector": "$[?true || false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, and, right hand literal must be compared",
+      "selector": "$[?true == false && false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, or, right hand literal must be compared",
+      "selector": "$[?true == false || false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, and, left hand literal must be compared",
+      "selector": "$[?false && true == false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, or, left hand literal must be compared",
+      "selector": "$[?false || true == false]",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "filter, true, incorrectly capitalized",
+      "selector": "$[?@==True]",
+      "invalid_selector": true,
+      "tags": [
+        "case"
+      ]
+    },
+    {
+      "name": "filter, false, incorrectly capitalized",
+      "selector": "$[?@==False]",
+      "invalid_selector": true,
+      "tags": [
+        "case"
+      ]
+    },
+    {
+      "name": "filter, null, incorrectly capitalized",
+      "selector": "$[?@==Null]",
+      "invalid_selector": true,
+      "tags": [
+        "case"
+      ]
+    },
+    {
+      "name": "index selector, first element",
+      "selector": "$[0]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "first"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, second element",
+      "selector": "$[1]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "second"
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, out of bound",
+      "selector": "$[2]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, min exact index",
+      "selector": "$[-9007199254740991]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, max exact index",
+      "selector": "$[9007199254740991]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, min exact index - 1",
+      "selector": "$[-9007199254740992]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, max exact index + 1",
+      "selector": "$[9007199254740992]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, overflowing index",
+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, not actually an index, overflowing index leads into general text",
+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168SomeRandomText]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, negative",
+      "selector": "$[-1]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "second"
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, more negative",
+      "selector": "$[-2]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [
+        "first"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, negative out of bound",
+      "selector": "$[-3]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, on object",
+      "selector": "$[0]",
+      "document": {
+        "foo": 1
+      },
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, leading 0",
+      "selector": "$[01]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, decimal",
+      "selector": "$[1.0]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, plus",
+      "selector": "$[+1]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, minus space",
+      "selector": "$[- 1]",
+      "invalid_selector": true,
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "index selector, -0",
+      "selector": "$[-0]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "index selector, leading -0",
+      "selector": "$[-01]",
+      "invalid_selector": true,
+      "tags": [
+        "index"
+      ]
+    },
+    {
+      "name": "name selector, double quotes",
+      "selector": "$[\"a\"]",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['a']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, absent data",
+      "selector": "$[\"c\"]",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "name selector, double quotes, array data",
+      "selector": "$[\"a\"]",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "name selector, name, double quotes, contains single quote",
+      "selector": "$[\"a'\"]",
+      "document": {
+        "a'": "A",
+        "b": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['a\\'']"
+      ]
+    },
+    {
+      "name": "name selector, name, double quotes, nested",
+      "selector": "$[\"a\"][\"b\"][\"c\"]",
+      "document": {
+        "a": {
+          "b": {
+            "c": "C"
+          }
+        }
+      },
+      "result": [
+        "C"
+      ],
+      "result_paths": [
+        "$['a']['b']['c']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0000",
+      "selector": "$[\"\u0000\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0001",
+      "selector": "$[\"\u0001\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0002",
+      "selector": "$[\"\u0002\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0003",
+      "selector": "$[\"\u0003\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0004",
+      "selector": "$[\"\u0004\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0005",
+      "selector": "$[\"\u0005\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0006",
+      "selector": "$[\"\u0006\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0007",
+      "selector": "$[\"\u0007\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0008",
+      "selector": "$[\"\b\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0009",
+      "selector": "$[\"\t\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000A",
+      "selector": "$[\"\n\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000B",
+      "selector": "$[\"\u000b\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000C",
+      "selector": "$[\"\f\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000D",
+      "selector": "$[\"\r\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000E",
+      "selector": "$[\"\u000e\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+000F",
+      "selector": "$[\"\u000f\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0010",
+      "selector": "$[\"\u0010\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0011",
+      "selector": "$[\"\u0011\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0012",
+      "selector": "$[\"\u0012\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0013",
+      "selector": "$[\"\u0013\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0014",
+      "selector": "$[\"\u0014\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0015",
+      "selector": "$[\"\u0015\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0016",
+      "selector": "$[\"\u0016\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0017",
+      "selector": "$[\"\u0017\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0018",
+      "selector": "$[\"\u0018\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0019",
+      "selector": "$[\"\u0019\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001A",
+      "selector": "$[\"\u001a\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001B",
+      "selector": "$[\"\u001b\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001C",
+      "selector": "$[\"\u001c\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001D",
+      "selector": "$[\"\u001d\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001E",
+      "selector": "$[\"\u001e\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+001F",
+      "selector": "$[\"\u001f\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+0020",
+      "selector": "$[\" \"]",
+      "document": {
+        " ": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$[' ']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, embedded U+007F",
+      "selector": "$[\"\"]",
+      "document": {
+        "": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, supplementary plane character",
+      "selector": "$[\"𝄞\"]",
+      "document": {
+        "𝄞": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['𝄞']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped double quote",
+      "selector": "$[\"\\\"\"]",
+      "document": {
+        "\"": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\"']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped reverse solidus",
+      "selector": "$[\"\\\\\"]",
+      "document": {
+        "\\": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\\\']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped solidus",
+      "selector": "$[\"\\/\"]",
+      "document": {
+        "/": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['/']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped backspace",
+      "selector": "$[\"\\b\"]",
+      "document": {
+        "\b": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\b']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped form feed",
+      "selector": "$[\"\\f\"]",
+      "document": {
+        "\f": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\f']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped line feed",
+      "selector": "$[\"\\n\"]",
+      "document": {
+        "\n": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\n']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped carriage return",
+      "selector": "$[\"\\r\"]",
+      "document": {
+        "\r": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\r']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped tab",
+      "selector": "$[\"\\t\"]",
+      "document": {
+        "\t": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\t']"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped ☺, upper case hex",
+      "selector": "$[\"\\u263A\"]",
+      "document": {
+        "☺": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['☺']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, escaped ☺, lower case hex",
+      "selector": "$[\"\\u263a\"]",
+      "document": {
+        "☺": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['☺']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, surrogate pair 𝄞",
+      "selector": "$[\"\\uD834\\uDD1E\"]",
+      "document": {
+        "𝄞": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['𝄞']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, surrogate pair 😀",
+      "selector": "$[\"\\uD83D\\uDE00\"]",
+      "document": {
+        "😀": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['😀']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, before high surrogates",
+      "selector": "$[\"\\uD7FF\\uD7FF\"]",
+      "document": {
+        "퟿퟿": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['퟿퟿']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, after low surrogates",
+      "selector": "$[\"\\uE000\\uE000\"]",
+      "document": {
+        "": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, invalid escaped single quote",
+      "selector": "$[\"\\'\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, embedded double quote",
+      "selector": "$[\"\"\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, incomplete escape",
+      "selector": "$[\"\\\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, escape at end of line",
+      "selector": "$[\"\\\n\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, question mark escape",
+      "selector": "$[\"\\?\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, bell escape",
+      "selector": "$[\"\\a\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, vertical tab escape",
+      "selector": "$[\"\\v\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, 0 escape",
+      "selector": "$[\"\\0\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, x escape",
+      "selector": "$[\"\\x12\"]",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, n escape",
+      "selector": "$[\"\\N{LATIN CAPITAL LETTER A}\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape no hex",
+      "selector": "$[\"\\u\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape too few hex",
+      "selector": "$[\"\\u123\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape upper u",
+      "selector": "$[\"\\U1234\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape upper u long",
+      "selector": "$[\"\\U0010FFFF\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape plus",
+      "selector": "$[\"\\u+1234\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape brackets",
+      "selector": "$[\"\\u{1234}\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, unicode escape brackets long",
+      "selector": "$[\"\\u{10ffff}\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, single high surrogate",
+      "selector": "$[\"\\uD800\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, single low surrogate",
+      "selector": "$[\"\\uDC00\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, high high surrogate",
+      "selector": "$[\"\\uD800\\uD800\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, low low surrogate",
+      "selector": "$[\"\\uDC00\\uDC00\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, surrogate non-surrogate",
+      "selector": "$[\"\\uD800\\u1234\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, non-surrogate surrogate",
+      "selector": "$[\"\\u1234\\uDC00\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, surrogate supplementary",
+      "selector": "$[\"\\uD800𝄞\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, supplementary surrogate",
+      "selector": "$[\"𝄞\\uDC00\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, double quotes, surrogate incomplete low",
+      "selector": "$[\"\\uD800\\uDC0\"]",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes",
+      "selector": "$['a']",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['a']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, absent data",
+      "selector": "$['c']",
+      "document": {
+        "a": "A",
+        "b": "B"
+      },
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "name selector, single quotes, array data",
+      "selector": "$['a']",
+      "document": [
+        "first",
+        "second"
+      ],
+      "result": [],
+      "result_paths": []
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0000",
+      "selector": "$['\u0000']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0001",
+      "selector": "$['\u0001']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0002",
+      "selector": "$['\u0002']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0003",
+      "selector": "$['\u0003']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0004",
+      "selector": "$['\u0004']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0005",
+      "selector": "$['\u0005']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0006",
+      "selector": "$['\u0006']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0007",
+      "selector": "$['\u0007']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0008",
+      "selector": "$['\b']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0009",
+      "selector": "$['\t']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000A",
+      "selector": "$['\n']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000B",
+      "selector": "$['\u000b']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000C",
+      "selector": "$['\f']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000D",
+      "selector": "$['\r']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000E",
+      "selector": "$['\u000e']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+000F",
+      "selector": "$['\u000f']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0010",
+      "selector": "$['\u0010']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0011",
+      "selector": "$['\u0011']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0012",
+      "selector": "$['\u0012']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0013",
+      "selector": "$['\u0013']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0014",
+      "selector": "$['\u0014']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0015",
+      "selector": "$['\u0015']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0016",
+      "selector": "$['\u0016']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0017",
+      "selector": "$['\u0017']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0018",
+      "selector": "$['\u0018']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0019",
+      "selector": "$['\u0019']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001A",
+      "selector": "$['\u001a']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001B",
+      "selector": "$['\u001b']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001C",
+      "selector": "$['\u001c']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001D",
+      "selector": "$['\u001d']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001E",
+      "selector": "$['\u001e']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+001F",
+      "selector": "$['\u001f']",
+      "invalid_selector": true,
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, embedded U+0020",
+      "selector": "$[' ']",
+      "document": {
+        " ": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$[' ']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped single quote",
+      "selector": "$['\\'']",
+      "document": {
+        "'": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\'']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped reverse solidus",
+      "selector": "$['\\\\']",
+      "document": {
+        "\\": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\\\']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped solidus",
+      "selector": "$['\\/']",
+      "document": {
+        "/": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['/']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped backspace",
+      "selector": "$['\\b']",
+      "document": {
+        "\b": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\b']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped form feed",
+      "selector": "$['\\f']",
+      "document": {
+        "\f": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\f']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped line feed",
+      "selector": "$['\\n']",
+      "document": {
+        "\n": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\n']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped carriage return",
+      "selector": "$['\\r']",
+      "document": {
+        "\r": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\r']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped tab",
+      "selector": "$['\\t']",
+      "document": {
+        "\t": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['\\t']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped ☺, upper case hex",
+      "selector": "$['\\u263A']",
+      "document": {
+        "☺": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['☺']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, escaped ☺, lower case hex",
+      "selector": "$['\\u263a']",
+      "document": {
+        "☺": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['☺']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, surrogate pair 𝄞",
+      "selector": "$['\\uD834\\uDD1E']",
+      "document": {
+        "𝄞": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['𝄞']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, surrogate pair 😀",
+      "selector": "$['\\uD83D\\uDE00']",
+      "document": {
+        "😀": "A"
+      },
+      "result": [
+        "A"
+      ],
+      "result_paths": [
+        "$['😀']"
+      ],
+      "tags": [
+        "unicode"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, invalid escaped double quote",
+      "selector": "$['\\\"']",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, single quotes, embedded single quote",
+      "selector": "$[''']",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, single quotes, incomplete escape",
+      "selector": "$['\\']",
+      "invalid_selector": true
+    },
+    {
+      "name": "name selector, double quotes, empty",
+      "selector": "$[\"\"]",
+      "document": {
+        "a": "A",
+        "b": "B",
+        "": "C"
+      },
+      "result": [
+        "C"
+      ],
+      "result_paths": [
+        "$['']"
+      ]
+    },
+    {
+      "name": "name selector, single quotes, empty",
+      "selector": "$['']",
+      "document": {
+        "a": "A",
+        "b": "B",
+        "": "C"
+      },
+      "result": [
+        "C"
+      ],
+      "result_paths": [
+        "$['']"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector",
+      "selector": "$[1:3]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        2
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with step",
+      "selector": "$[1:6:2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        3,
+        5
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]",
+        "$[5]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with everything omitted, short form",
+      "selector": "$[:]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with everything omitted, long form",
+      "selector": "$[::]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with start omitted",
+      "selector": "$[:2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        1
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with start and end omitted",
+      "selector": "$[::2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        2,
+        4,
+        6,
+        8
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]",
+        "$[4]",
+        "$[6]",
+        "$[8]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative step with default start and end",
+      "selector": "$[::-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        3,
+        2,
+        1,
+        0
+      ],
+      "result_paths": [
+        "$[3]",
+        "$[2]",
+        "$[1]",
+        "$[0]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative step with default start",
+      "selector": "$[:0:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        3,
+        2,
+        1
+      ],
+      "result_paths": [
+        "$[3]",
+        "$[2]",
+        "$[1]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative step with default end",
+      "selector": "$[2::-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        2,
+        1,
+        0
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[1]",
+        "$[0]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, larger negative step",
+      "selector": "$[::-2]",
+      "document": [
+        0,
+        1,
+        2,
+        3
+      ],
+      "result": [
+        3,
+        1
+      ],
+      "result_paths": [
+        "$[3]",
+        "$[1]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative range with default step",
+      "selector": "$[-1:-3]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative range with negative step",
+      "selector": "$[-1:-3:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        8
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[8]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative range with larger negative step",
+      "selector": "$[-1:-6:-2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        7,
+        5
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[7]",
+        "$[5]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, larger negative range with larger negative step",
+      "selector": "$[-1:-7:-2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        7,
+        5
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[7]",
+        "$[5]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative from, positive to",
+      "selector": "$[-5:7]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        5,
+        6
+      ],
+      "result_paths": [
+        "$[5]",
+        "$[6]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative from",
+      "selector": "$[-2:]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        8,
+        9
+      ],
+      "result_paths": [
+        "$[8]",
+        "$[9]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, positive from, negative to",
+      "selector": "$[1:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]",
+        "$[7]",
+        "$[8]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative from, positive to, negative step",
+      "selector": "$[-1:1:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        8,
+        7,
+        6,
+        5,
+        4,
+        3,
+        2
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[8]",
+        "$[7]",
+        "$[6]",
+        "$[5]",
+        "$[4]",
+        "$[3]",
+        "$[2]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, positive from, negative to, negative step",
+      "selector": "$[7:-5:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        7,
+        6
+      ],
+      "result_paths": [
+        "$[7]",
+        "$[6]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, in serial, on nested array",
+      "selector": "$[1:3][1:2]",
+      "document": [
+        [
+          "a",
+          "b",
+          "c"
+        ],
+        [
+          "d",
+          "e",
+          "f"
+        ],
+        [
+          "g",
+          "h",
+          "i"
+        ]
+      ],
+      "result": [
+        "e",
+        "h"
+      ],
+      "result_paths": [
+        "$[1][1]",
+        "$[2][1]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, in serial, on flat array",
+      "selector": "$[1:3][::]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative from, negative to, positive step",
+      "selector": "$[-5:-2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        5,
+        6,
+        7
+      ],
+      "result_paths": [
+        "$[5]",
+        "$[6]",
+        "$[7]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, too many colons",
+      "selector": "$[1:2:3:4]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, non-integer array index",
+      "selector": "$[1:2:a]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, zero step",
+      "selector": "$[1:2:0]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, empty range",
+      "selector": "$[2:2]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, slice selector with everything omitted with empty array",
+      "selector": "$[:]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, negative step with empty array",
+      "selector": "$[::-1]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, maximal range with positive step",
+      "selector": "$[0:10]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]",
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]",
+        "$[7]",
+        "$[8]",
+        "$[9]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, maximal range with negative step",
+      "selector": "$[9:0:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        8,
+        7,
+        6,
+        5,
+        4,
+        3,
+        2,
+        1
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[8]",
+        "$[7]",
+        "$[6]",
+        "$[5]",
+        "$[4]",
+        "$[3]",
+        "$[2]",
+        "$[1]"
+      ],
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively large to value",
+      "selector": "$[2:113667776004]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result_paths": [
+        "$[2]",
+        "$[3]",
+        "$[4]",
+        "$[5]",
+        "$[6]",
+        "$[7]",
+        "$[8]",
+        "$[9]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively small from value",
+      "selector": "$[-113667776004:1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        0
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively large from value with negative step",
+      "selector": "$[113667776004:0:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9,
+        8,
+        7,
+        6,
+        5,
+        4,
+        3,
+        2,
+        1
+      ],
+      "result_paths": [
+        "$[9]",
+        "$[8]",
+        "$[7]",
+        "$[6]",
+        "$[5]",
+        "$[4]",
+        "$[3]",
+        "$[2]",
+        "$[1]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively small to value with negative step",
+      "selector": "$[3:-113667776004:-1]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        3,
+        2,
+        1,
+        0
+      ],
+      "result_paths": [
+        "$[3]",
+        "$[2]",
+        "$[1]",
+        "$[0]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively large step",
+      "selector": "$[1:10:113667776004]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        1
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, excessively small step",
+      "selector": "$[-1:-10:-113667776004]",
+      "document": [
+        0,
+        1,
+        2,
+        3,
+        4,
+        5,
+        6,
+        7,
+        8,
+        9
+      ],
+      "result": [
+        9
+      ],
+      "result_paths": [
+        "$[9]"
+      ],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, min exact",
+      "selector": "$[-9007199254740991::]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, max exact",
+      "selector": "$[9007199254740991::]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, min exact - 1",
+      "selector": "$[-9007199254740992::]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, max exact + 1",
+      "selector": "$[9007199254740992::]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, min exact",
+      "selector": "$[:-9007199254740991:]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, max exact",
+      "selector": "$[:9007199254740991:]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, min exact - 1",
+      "selector": "$[:-9007199254740992:]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, max exact + 1",
+      "selector": "$[:9007199254740992:]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, min exact",
+      "selector": "$[::-9007199254740991]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, max exact",
+      "selector": "$[::9007199254740991]",
+      "document": [],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, min exact - 1",
+      "selector": "$[::-9007199254740992]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, max exact + 1",
+      "selector": "$[::9007199254740992]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, overflowing to value",
+      "selector": "$[2:231584178474632390847141970017375815706539969331281128078915168015826259279872]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, underflowing from value",
+      "selector": "$[-231584178474632390847141970017375815706539969331281128078915168015826259279872:1]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, overflowing from value with negative step",
+      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872:0:-1]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, underflowing to value with negative step",
+      "selector": "$[3:-231584178474632390847141970017375815706539969331281128078915168015826259279872:-1]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, overflowing step",
+      "selector": "$[1:10:231584178474632390847141970017375815706539969331281128078915168015826259279872]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, underflowing step",
+      "selector": "$[-1:-10:-231584178474632390847141970017375815706539969331281128078915168015826259279872]",
+      "invalid_selector": true,
+      "tags": [
+        "boundary",
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, leading 0",
+      "selector": "$[01::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, decimal",
+      "selector": "$[1.0::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, plus",
+      "selector": "$[+1::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, minus space",
+      "selector": "$[- 1::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, -0",
+      "selector": "$[-0::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, start, leading -0",
+      "selector": "$[-01::]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, leading 0",
+      "selector": "$[:01:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, decimal",
+      "selector": "$[:1.0:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, plus",
+      "selector": "$[:+1:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, minus space",
+      "selector": "$[:- 1:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, -0",
+      "selector": "$[:-0:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, end, leading -0",
+      "selector": "$[:-01:]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, leading 0",
+      "selector": "$[::01]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, decimal",
+      "selector": "$[::1.0]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, plus",
+      "selector": "$[::+1]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, minus space",
+      "selector": "$[::- 1]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, -0",
+      "selector": "$[::-0]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "slice selector, step, leading -0",
+      "selector": "$[::-01]",
+      "invalid_selector": true,
+      "tags": [
+        "slice"
+      ]
+    },
+    {
+      "name": "functions, count, count function",
+      "selector": "$[?count(@..*)>2]",
+      "document": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        },
+        {
+          "a": [
+            1
+          ],
+          "d": "f"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        },
+        {
+          "a": [
+            1
+          ],
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, single-node arg",
+      "selector": "$[?count(@.a)>1]",
+      "document": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        },
+        {
+          "a": [
+            1
+          ],
+          "d": "f"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, multiple-selector arg",
+      "selector": "$[?count(@['a','d'])>1]",
+      "document": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        },
+        {
+          "a": [
+            1
+          ],
+          "d": "f"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": [
+            1
+          ],
+          "d": "f"
+        },
+        {
+          "a": 1,
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[2]"
+      ],
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, non-query arg, number",
+      "selector": "$[?count(1)>2]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, non-query arg, string",
+      "selector": "$[?count('string')>2]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, non-query arg, true",
+      "selector": "$[?count(true)>2]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, non-query arg, false",
+      "selector": "$[?count(false)>2]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, non-query arg, null",
+      "selector": "$[?count(null)>2]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, result must be compared",
+      "selector": "$[?count(@..*)]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, no params",
+      "selector": "$[?count()==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, count, too many params",
+      "selector": "$[?count(@.a,@.b)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function"
+      ]
+    },
+    {
+      "name": "functions, length, string data",
+      "selector": "$[?length(@.a)>=2]",
+      "document": [
+        {
+          "a": "ab"
+        },
+        {
+          "a": "d"
+        }
+      ],
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, string data, unicode",
+      "selector": "$[?length(@)==2]",
+      "document": [
+        "☺",
+        "☺☺",
+        "☺☺☺",
+        "ж",
+        "жж",
+        "жжж",
+        "磨",
+        "阿美",
+        "形声字"
+      ],
+      "result": [
+        "☺☺",
+        "жж",
+        "阿美"
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[4]",
+        "$[7]"
+      ],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, array data",
+      "selector": "$[?length(@.a)>=2]",
+      "document": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        },
+        {
+          "a": [
+            1
+          ]
+        }
+      ],
+      "result": [
+        {
+          "a": [
+            1,
+            2,
+            3
+          ]
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, missing data",
+      "selector": "$[?length(@.a)>=2]",
+      "document": [
+        {
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, number arg",
+      "selector": "$[?length(1)>=2]",
+      "document": [
+        {
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, true arg",
+      "selector": "$[?length(true)>=2]",
+      "document": [
+        {
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, false arg",
+      "selector": "$[?length(false)>=2]",
+      "document": [
+        {
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, null arg",
+      "selector": "$[?length(null)>=2]",
+      "document": [
+        {
+          "d": "f"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, result must be compared",
+      "selector": "$[?length(@.a)]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, no params",
+      "selector": "$[?length()==1]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, too many params",
+      "selector": "$[?length(@.a,@.b)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, non-singular query arg",
+      "selector": "$[?length(@.*)<3]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, arg is a function expression",
+      "selector": "$.values[?length(@.a)==length(value($..c))]",
+      "document": {
+        "c": "cd",
+        "values": [
+          {
+            "a": "ab"
+          },
+          {
+            "a": "d"
+          }
+        ]
+      },
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$['values'][0]"
+      ],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, length, arg is special nothing",
+      "selector": "$[?length(value(@.a))>0]",
+      "document": [
+        {
+          "a": "ab"
+        },
+        {
+          "c": "d"
+        },
+        {
+          "a": null
+        }
+      ],
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length"
+      ]
+    },
+    {
+      "name": "functions, match, found match",
+      "selector": "$[?match(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, double quotes",
+      "selector": "$[?match(@.a, \"a.*\")]",
+      "document": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, regex from the document",
+      "selector": "$.values[?match(@, $.regex)]",
+      "document": {
+        "regex": "b.?b",
+        "values": [
+          "abc",
+          "bcd",
+          "bab",
+          "bba",
+          "bbab",
+          "b",
+          true,
+          [],
+          {}
+        ]
+      },
+      "result": [
+        "bab"
+      ],
+      "result_paths": [
+        "$['values'][2]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, don't select match",
+      "selector": "$[?!match(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, not a match",
+      "selector": "$[?match(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, select non-match",
+      "selector": "$[?!match(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, non-string first arg",
+      "selector": "$[?match(1, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, non-string second arg",
+      "selector": "$[?match(@.a, 1)]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, filter, match function, unicode char class, uppercase",
+      "selector": "$[?match(@, '\\\\p{Lu}')]",
+      "document": [
+        "ж",
+        "Ж",
+        "1",
+        "жЖ",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "Ж"
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, filter, match function, unicode char class negated, uppercase",
+      "selector": "$[?match(@, '\\\\P{Lu}')]",
+      "document": [
+        "ж",
+        "Ж",
+        "1",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "ж",
+        "1"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, filter, match function, unicode, surrogate pair",
+      "selector": "$[?match(@, 'a.b')]",
+      "document": [
+        "a𐄁b",
+        "ab",
+        "1",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "a𐄁b"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, dot matcher on \\u2028",
+      "selector": "$[?match(@, '.')]",
+      "document": [
+        " ",
+        "\r",
+        "\n",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        " "
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, dot matcher on \\u2029",
+      "selector": "$[?match(@, '.')]",
+      "document": [
+        " ",
+        "\r",
+        "\n",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        " "
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, result cannot be compared",
+      "selector": "$[?match(@.a, 'a.*')==true]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, too few params",
+      "selector": "$[?match(@.a)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, too many params",
+      "selector": "$[?match(@.a,@.b,@.c)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, arg is a function expression",
+      "selector": "$.values[?match(@.a, value($..['regex']))]",
+      "document": {
+        "regex": "a.*",
+        "values": [
+          {
+            "a": "ab"
+          },
+          {
+            "a": "ba"
+          }
+        ]
+      },
+      "result": [
+        {
+          "a": "ab"
+        }
+      ],
+      "result_paths": [
+        "$['values'][0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, dot in character class",
+      "selector": "$[?match(@, 'a[.b]c')]",
+      "document": [
+        "abc",
+        "a.c",
+        "axc"
+      ],
+      "result": [
+        "abc",
+        "a.c"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, escaped dot",
+      "selector": "$[?match(@, 'a\\\\.c')]",
+      "document": [
+        "abc",
+        "a.c",
+        "axc"
+      ],
+      "result": [
+        "a.c"
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, escaped backslash before dot",
+      "selector": "$[?match(@, 'a\\\\\\\\.c')]",
+      "document": [
+        "abc",
+        "a.c",
+        "axc",
+        "a\\ c"
+      ],
+      "result": [
+        "a\\ c"
+      ],
+      "result_paths": [
+        "$[3]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, escaped left square bracket",
+      "selector": "$[?match(@, 'a\\\\[.c')]",
+      "document": [
+        "abc",
+        "a.c",
+        "a[ c"
+      ],
+      "result": [
+        "a[ c"
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, escaped right square bracket",
+      "selector": "$[?match(@, 'a[\\\\].]c')]",
+      "document": [
+        "abc",
+        "a.c",
+        "a c",
+        "a]c"
+      ],
+      "result": [
+        "a.c",
+        "a]c"
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, explicit caret",
+      "selector": "$[?match(@, '^ab.*')]",
+      "document": [
+        "abc",
+        "axc",
+        "ab",
+        "xab"
+      ],
+      "result": [
+        "abc",
+        "ab"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, match, explicit dollar",
+      "selector": "$[?match(@, '.*bc$')]",
+      "document": [
+        "abc",
+        "axc",
+        "ab",
+        "abcx"
+      ],
+      "result": [
+        "abc"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "match"
+      ]
+    },
+    {
+      "name": "functions, search, at the end",
+      "selector": "$[?search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "the end is ab"
+        }
+      ],
+      "result": [
+        {
+          "a": "the end is ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, double quotes",
+      "selector": "$[?search(@.a, \"a.*\")]",
+      "document": [
+        {
+          "a": "the end is ab"
+        }
+      ],
+      "result": [
+        {
+          "a": "the end is ab"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, at the start",
+      "selector": "$[?search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "ab is at the start"
+        }
+      ],
+      "result": [
+        {
+          "a": "ab is at the start"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, in the middle",
+      "selector": "$[?search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "contains two matches"
+        }
+      ],
+      "result": [
+        {
+          "a": "contains two matches"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, regex from the document",
+      "selector": "$.values[?search(@, $.regex)]",
+      "document": {
+        "regex": "b.?b",
+        "values": [
+          "abc",
+          "bcd",
+          "bab",
+          "bba",
+          "bbab",
+          "b",
+          true,
+          [],
+          {}
+        ]
+      },
+      "result": [
+        "bab",
+        "bba",
+        "bbab"
+      ],
+      "result_paths": [
+        "$['values'][2]",
+        "$['values'][3]",
+        "$['values'][4]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, don't select match",
+      "selector": "$[?!search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "contains two matches"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, not a match",
+      "selector": "$[?search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, select non-match",
+      "selector": "$[?!search(@.a, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, non-string first arg",
+      "selector": "$[?search(1, 'a.*')]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, non-string second arg",
+      "selector": "$[?search(@.a, 1)]",
+      "document": [
+        {
+          "a": "bc"
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, filter, search function, unicode char class, uppercase",
+      "selector": "$[?search(@, '\\\\p{Lu}')]",
+      "document": [
+        "ж",
+        "Ж",
+        "1",
+        "жЖ",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "Ж",
+        "жЖ"
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, filter, search function, unicode char class negated, uppercase",
+      "selector": "$[?search(@, '\\\\P{Lu}')]",
+      "document": [
+        "ж",
+        "Ж",
+        "1",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "ж",
+        "1"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, filter, search function, unicode, surrogate pair",
+      "selector": "$[?search(@, 'a.b')]",
+      "document": [
+        "a𐄁bc",
+        "abc",
+        "1",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        "a𐄁bc"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, dot matcher on \\u2028",
+      "selector": "$[?search(@, '.')]",
+      "document": [
+        " ",
+        "\r \n",
+        "\r",
+        "\n",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        " ",
+        "\r \n"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, dot matcher on \\u2029",
+      "selector": "$[?search(@, '.')]",
+      "document": [
+        " ",
+        "\r \n",
+        "\r",
+        "\n",
+        true,
+        [],
+        {}
+      ],
+      "result": [
+        " ",
+        "\r \n"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, result cannot be compared",
+      "selector": "$[?search(@.a, 'a.*')==true]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, too few params",
+      "selector": "$[?search(@.a)]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, too many params",
+      "selector": "$[?search(@.a,@.b,@.c)]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, arg is a function expression",
+      "selector": "$.values[?search(@, value($..['regex']))]",
+      "document": {
+        "regex": "b.?b",
+        "values": [
+          "abc",
+          "bcd",
+          "bab",
+          "bba",
+          "bbab",
+          "b",
+          true,
+          [],
+          {}
+        ]
+      },
+      "result": [
+        "bab",
+        "bba",
+        "bbab"
+      ],
+      "result_paths": [
+        "$['values'][2]",
+        "$['values'][3]",
+        "$['values'][4]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, dot in character class",
+      "selector": "$[?search(@, 'a[.b]c')]",
+      "document": [
+        "x abc y",
+        "x a.c y",
+        "x axc y"
+      ],
+      "result": [
+        "x abc y",
+        "x a.c y"
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, escaped dot",
+      "selector": "$[?search(@, 'a\\\\.c')]",
+      "document": [
+        "x abc y",
+        "x a.c y",
+        "x axc y"
+      ],
+      "result": [
+        "x a.c y"
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, escaped backslash before dot",
+      "selector": "$[?search(@, 'a\\\\\\\\.c')]",
+      "document": [
+        "x abc y",
+        "x a.c y",
+        "x axc y",
+        "x a\\ c y"
+      ],
+      "result": [
+        "x a\\ c y"
+      ],
+      "result_paths": [
+        "$[3]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, escaped left square bracket",
+      "selector": "$[?search(@, 'a\\\\[.c')]",
+      "document": [
+        "x abc y",
+        "x a.c y",
+        "x a[ c y"
+      ],
+      "result": [
+        "x a[ c y"
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, search, escaped right square bracket",
+      "selector": "$[?search(@, 'a[\\\\].]c')]",
+      "document": [
+        "x abc y",
+        "x a.c y",
+        "x a c y",
+        "x a]c y"
+      ],
+      "result": [
+        "x a.c y",
+        "x a]c y"
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "function",
+        "search"
+      ]
+    },
+    {
+      "name": "functions, value, single-value nodelist",
+      "selector": "$[?value(@.*)==4]",
+      "document": [
+        [
+          4
+        ],
+        {
+          "foo": 4
+        },
+        [
+          5
+        ],
+        {
+          "foo": 5
+        },
+        4
+      ],
+      "result": [
+        [
+          4
+        ],
+        {
+          "foo": 4
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "value"
+      ]
+    },
+    {
+      "name": "functions, value, multi-value nodelist",
+      "selector": "$[?value(@.*)==4]",
+      "document": [
+        [
+          4,
+          4
+        ],
+        {
+          "foo": 4,
+          "bar": 4
+        }
+      ],
+      "result": [],
+      "result_paths": [],
+      "tags": [
+        "function",
+        "value"
+      ]
+    },
+    {
+      "name": "functions, value, too few params",
+      "selector": "$[?value()==4]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "value"
+      ]
+    },
+    {
+      "name": "functions, value, too many params",
+      "selector": "$[?value(@.a,@.b)==4]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "value"
+      ]
+    },
+    {
+      "name": "functions, value, result must be compared",
+      "selector": "$[?value(@.a)]",
+      "invalid_selector": true,
+      "tags": [
+        "function",
+        "value"
+      ]
+    },
+    {
+      "name": "whitespace, filter, space between question mark and expression",
+      "selector": "$[? @.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, newline between question mark and expression",
+      "selector": "$[?\n@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, tab between question mark and expression",
+      "selector": "$[?\t@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, return between question mark and expression",
+      "selector": "$[?\r@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, space between question mark and parenthesized expression",
+      "selector": "$[? (@.a)]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, newline between question mark and parenthesized expression",
+      "selector": "$[?\n(@.a)]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, tab between question mark and parenthesized expression",
+      "selector": "$[?\t(@.a)]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, return between question mark and parenthesized expression",
+      "selector": "$[?\r(@.a)]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, space between parenthesized expression and bracket",
+      "selector": "$[?(@.a) ]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, newline between parenthesized expression and bracket",
+      "selector": "$[?(@.a)\n]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, tab between parenthesized expression and bracket",
+      "selector": "$[?(@.a)\t]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, return between parenthesized expression and bracket",
+      "selector": "$[?(@.a)\r]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, space between bracket and question mark",
+      "selector": "$[ ?@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, newline between bracket and question mark",
+      "selector": "$[\n?@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, tab between bracket and question mark",
+      "selector": "$[\t?@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, filter, return between bracket and question mark",
+      "selector": "$[\r?@.a]",
+      "document": [
+        {
+          "a": "b",
+          "d": "e"
+        },
+        {
+          "b": "c",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "b",
+          "d": "e"
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, space between function name and parenthesis",
+      "selector": "$[?count (@.*)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newline between function name and parenthesis",
+      "selector": "$[?count\n(@.*)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tab between function name and parenthesis",
+      "selector": "$[?count\t(@.*)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, return between function name and parenthesis",
+      "selector": "$[?count\r(@.*)==1]",
+      "invalid_selector": true,
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, space between parenthesis and arg",
+      "selector": "$[?count( @.*)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newline between parenthesis and arg",
+      "selector": "$[?count(\n@.*)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tab between parenthesis and arg",
+      "selector": "$[?count(\t@.*)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, return between parenthesis and arg",
+      "selector": "$[?count(\r@.*)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, space between arg and comma",
+      "selector": "$[?search(@ ,'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newline between arg and comma",
+      "selector": "$[?search(@\n,'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tab between arg and comma",
+      "selector": "$[?search(@\t,'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, return between arg and comma",
+      "selector": "$[?search(@\r,'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, space between comma and arg",
+      "selector": "$[?search(@, '[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newline between comma and arg",
+      "selector": "$[?search(@,\n'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tab between comma and arg",
+      "selector": "$[?search(@,\t'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, return between comma and arg",
+      "selector": "$[?search(@,\r'[a-z]+')]",
+      "document": [
+        "foo",
+        "123"
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, space between arg and parenthesis",
+      "selector": "$[?count(@.* )==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "function",
+        "search",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newline between arg and parenthesis",
+      "selector": "$[?count(@.*\n)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tab between arg and parenthesis",
+      "selector": "$[?count(@.*\t)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, return between arg and parenthesis",
+      "selector": "$[?count(@.*\r)==1]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "count",
+        "function",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, spaces in a relative singular selector",
+      "selector": "$[?length(@ .a .b) == 3]",
+      "document": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        },
+        {}
+      ],
+      "result": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newlines in a relative singular selector",
+      "selector": "$[?length(@\n.a\n.b) == 3]",
+      "document": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        },
+        {}
+      ],
+      "result": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tabs in a relative singular selector",
+      "selector": "$[?length(@\t.a\t.b) == 3]",
+      "document": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        },
+        {}
+      ],
+      "result": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, returns in a relative singular selector",
+      "selector": "$[?length(@\r.a\r.b) == 3]",
+      "document": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        },
+        {}
+      ],
+      "result": [
+        {
+          "a": {
+            "b": "foo"
+          }
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, spaces in an absolute singular selector",
+      "selector": "$..[?length(@)==length($ [0] .a)]",
+      "document": [
+        {
+          "a": "foo"
+        },
+        {}
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]['a']"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, newlines in an absolute singular selector",
+      "selector": "$..[?length(@)==length($\n[0]\n.a)]",
+      "document": [
+        {
+          "a": "foo"
+        },
+        {}
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]['a']"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, tabs in an absolute singular selector",
+      "selector": "$..[?length(@)==length($\t[0]\t.a)]",
+      "document": [
+        {
+          "a": "foo"
+        },
+        {}
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]['a']"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, functions, returns in an absolute singular selector",
+      "selector": "$..[?length(@)==length($\r[0]\r.a)]",
+      "document": [
+        {
+          "a": "foo"
+        },
+        {}
+      ],
+      "result": [
+        "foo"
+      ],
+      "result_paths": [
+        "$[0]['a']"
+      ],
+      "tags": [
+        "function",
+        "length",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before ||",
+      "selector": "$[?@.a ||@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before ||",
+      "selector": "$[?@.a\n||@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before ||",
+      "selector": "$[?@.a\t||@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before ||",
+      "selector": "$[?@.a\r||@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after ||",
+      "selector": "$[?@.a|| @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after ||",
+      "selector": "$[?@.a||\n@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after ||",
+      "selector": "$[?@.a||\t@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after ||",
+      "selector": "$[?@.a||\r@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "c": 3
+        }
+      ],
+      "result": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before &&",
+      "selector": "$[?@.a &&@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before &&",
+      "selector": "$[?@.a\n&&@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before &&",
+      "selector": "$[?@.a\t&&@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before &&",
+      "selector": "$[?@.a\r&&@.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after &&",
+      "selector": "$[?@.a&& @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after &&",
+      "selector": "$[?@.a&& @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after &&",
+      "selector": "$[?@.a&& @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after &&",
+      "selector": "$[?@.a&& @.b]",
+      "document": [
+        {
+          "a": 1
+        },
+        {
+          "b": 2
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before ==",
+      "selector": "$[?@.a ==@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before ==",
+      "selector": "$[?@.a\n==@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before ==",
+      "selector": "$[?@.a\t==@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before ==",
+      "selector": "$[?@.a\r==@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after ==",
+      "selector": "$[?@.a== @.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after ==",
+      "selector": "$[?@.a==\n@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after ==",
+      "selector": "$[?@.a==\t@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after ==",
+      "selector": "$[?@.a==\r@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        }
+      ],
+      "result_paths": [
+        "$[0]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before !=",
+      "selector": "$[?@.a !=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before !=",
+      "selector": "$[?@.a\n!=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before !=",
+      "selector": "$[?@.a\t!=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before !=",
+      "selector": "$[?@.a\r!=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after !=",
+      "selector": "$[?@.a!= @.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after !=",
+      "selector": "$[?@.a!=\n@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after !=",
+      "selector": "$[?@.a!=\t@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after !=",
+      "selector": "$[?@.a!=\r@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before <",
+      "selector": "$[?@.a <@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before <",
+      "selector": "$[?@.a\n<@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before <",
+      "selector": "$[?@.a\t<@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before <",
+      "selector": "$[?@.a\r<@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after <",
+      "selector": "$[?@.a< @.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after <",
+      "selector": "$[?@.a<\n@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after <",
+      "selector": "$[?@.a<\t@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after <",
+      "selector": "$[?@.a<\r@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before >",
+      "selector": "$[?@.b >@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before >",
+      "selector": "$[?@.b\n>@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before >",
+      "selector": "$[?@.b\t>@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before >",
+      "selector": "$[?@.b\r>@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after >",
+      "selector": "$[?@.b> @.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after >",
+      "selector": "$[?@.b>\n@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after >",
+      "selector": "$[?@.b>\t@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after >",
+      "selector": "$[?@.b>\r@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before <=",
+      "selector": "$[?@.a <=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before <=",
+      "selector": "$[?@.a\n<=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before <=",
+      "selector": "$[?@.a\t<=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before <=",
+      "selector": "$[?@.a\r<=@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after <=",
+      "selector": "$[?@.a<= @.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after <=",
+      "selector": "$[?@.a<=\n@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after <=",
+      "selector": "$[?@.a<=\t@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after <=",
+      "selector": "$[?@.a<=\r@.b]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space before >=",
+      "selector": "$[?@.b >=@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline before >=",
+      "selector": "$[?@.b\n>=@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab before >=",
+      "selector": "$[?@.b\t>=@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return before >=",
+      "selector": "$[?@.b\r>=@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space after >=",
+      "selector": "$[?@.b>= @.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline after >=",
+      "selector": "$[?@.b>=\n@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab after >=",
+      "selector": "$[?@.b>=\t@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return after >=",
+      "selector": "$[?@.b>=\r@.a]",
+      "document": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        },
+        {
+          "a": 2,
+          "b": 1
+        }
+      ],
+      "result": [
+        {
+          "a": 1,
+          "b": 1
+        },
+        {
+          "a": 1,
+          "b": 2
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space between logical not and test expression",
+      "selector": "$[?! @.a]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline between logical not and test expression",
+      "selector": "$[?!\n@.a]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab between logical not and test expression",
+      "selector": "$[?!\t@.a]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return between logical not and test expression",
+      "selector": "$[?!\r@.a]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[1]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, space between logical not and parenthesized expression",
+      "selector": "$[?! (@.a=='b')]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, newline between logical not and parenthesized expression",
+      "selector": "$[?!\n(@.a=='b')]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, tab between logical not and parenthesized expression",
+      "selector": "$[?!\t(@.a=='b')]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, operators, return between logical not and parenthesized expression",
+      "selector": "$[?!\r(@.a=='b')]",
+      "document": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "b",
+          "d": "f"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result": [
+        {
+          "a": "a",
+          "d": "e"
+        },
+        {
+          "a": "d",
+          "d": "f"
+        }
+      ],
+      "result_paths": [
+        "$[0]",
+        "$[2]"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between root and bracket",
+      "selector": "$ ['a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between root and bracket",
+      "selector": "$\n['a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between root and bracket",
+      "selector": "$\t['a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between root and bracket",
+      "selector": "$\r['a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between bracket and bracket",
+      "selector": "$['a'] ['b']",
+      "document": {
+        "a": {
+          "b": "ab"
+        }
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between bracket and bracket",
+      "selector": "$['a'] \n['b']",
+      "document": {
+        "a": {
+          "b": "ab"
+        }
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between bracket and bracket",
+      "selector": "$['a'] \t['b']",
+      "document": {
+        "a": {
+          "b": "ab"
+        }
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between bracket and bracket",
+      "selector": "$['a'] \r['b']",
+      "document": {
+        "a": {
+          "b": "ab"
+        }
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between root and dot",
+      "selector": "$ .a",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between root and dot",
+      "selector": "$\n.a",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between root and dot",
+      "selector": "$\t.a",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between root and dot",
+      "selector": "$\r.a",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between dot and name",
+      "selector": "$. a",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between dot and name",
+      "selector": "$.\na",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between dot and name",
+      "selector": "$.\ta",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between dot and name",
+      "selector": "$.\ra",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between recursive descent and name",
+      "selector": "$.. a",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between recursive descent and name",
+      "selector": "$..\na",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between recursive descent and name",
+      "selector": "$..\ta",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between recursive descent and name",
+      "selector": "$..\ra",
+      "invalid_selector": true,
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between bracket and selector",
+      "selector": "$[ 'a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between bracket and selector",
+      "selector": "$[\n'a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between bracket and selector",
+      "selector": "$[\t'a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between bracket and selector",
+      "selector": "$[\r'a']",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between selector and bracket",
+      "selector": "$['a' ]",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between selector and bracket",
+      "selector": "$['a'\n]",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between selector and bracket",
+      "selector": "$['a'\t]",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between selector and bracket",
+      "selector": "$['a'\r]",
+      "document": {
+        "a": "ab"
+      },
+      "result": [
+        "ab"
+      ],
+      "result_paths": [
+        "$['a']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between selector and comma",
+      "selector": "$['a' ,'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between selector and comma",
+      "selector": "$['a'\n,'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between selector and comma",
+      "selector": "$['a'\t,'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between selector and comma",
+      "selector": "$['a'\r,'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, space between comma and selector",
+      "selector": "$['a', 'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, newline between comma and selector",
+      "selector": "$['a',\n'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, tab between comma and selector",
+      "selector": "$['a',\t'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, selectors, return between comma and selector",
+      "selector": "$['a',\r'b']",
+      "document": {
+        "a": "ab",
+        "b": "bc"
+      },
+      "result": [
+        "ab",
+        "bc"
+      ],
+      "result_paths": [
+        "$['a']",
+        "$['b']"
+      ],
+      "tags": [
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, space between start and colon",
+      "selector": "$[1 :5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, newline between start and colon",
+      "selector": "$[1\n:5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, tab between start and colon",
+      "selector": "$[1\t:5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, return between start and colon",
+      "selector": "$[1\r:5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, space between colon and end",
+      "selector": "$[1: 5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, newline between colon and end",
+      "selector": "$[1:\n5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, tab between colon and end",
+      "selector": "$[1:\t5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, return between colon and end",
+      "selector": "$[1:\r5:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, space between end and colon",
+      "selector": "$[1:5 :2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, newline between end and colon",
+      "selector": "$[1:5\n:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, tab between end and colon",
+      "selector": "$[1:5\t:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, return between end and colon",
+      "selector": "$[1:5\r:2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, space between colon and step",
+      "selector": "$[1:5: 2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, newline between colon and step",
+      "selector": "$[1:5:\n2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, tab between colon and step",
+      "selector": "$[1:5:\t2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    },
+    {
+      "name": "whitespace, slice, return between colon and step",
+      "selector": "$[1:5:\r2]",
+      "document": [
+        1,
+        2,
+        3,
+        4,
+        5,
+        6
+      ],
+      "result": [
+        2,
+        4
+      ],
+      "result_paths": [
+        "$[1]",
+        "$[3]"
+      ],
+      "tags": [
+        "index",
+        "whitespace"
+      ]
+    }
+  ]
+}
diff --git a/src/Data/Aeson/JSONPath.hs b/src/Data/Aeson/JSONPath.hs
--- a/src/Data/Aeson/JSONPath.hs
+++ b/src/Data/Aeson/JSONPath.hs
@@ -27,15 +27,16 @@
 
 import qualified Text.ParserCombinators.Parsec as P
 
-import Data.Aeson                   (Value)
-import Data.Vector                  (Vector)
-import Language.Haskell.TH.Quote    (QuasiQuoter (..))
-import Language.Haskell.TH.Syntax   (lift)
+import Data.Aeson                  (Value)
+import Data.Vector                 (Vector)
+import Language.Haskell.TH.Quote   (QuasiQuoter (..))
+import Language.Haskell.TH.Syntax  (lift)
 
-import Data.Aeson.JSONPath.Query.Types (Query (..))
-import Data.Aeson.JSONPath.Query       (Queryable (..))
-import Data.Aeson.JSONPath.Parser      (pQuery)
+import Data.Aeson.JSONPath.Parser  (pQuery)
+import Data.Aeson.JSONPath.Query   (qQuery, qQueryLocated)
 
+import Data.Aeson.JSONPath.Types
+
 import Prelude
 
 -- |
@@ -85,7 +86,11 @@
 -- artist = queryQQ [jsonPath|$.art[ist|] json -- fails at compilation time
 -- @
 queryQQ :: Query -> Value -> Vector Value
-queryQQ q root = query' q root root
+queryQQ q root = qQuery q QueryState {
+    rootVal = root
+  , curVal = root
+  , executeQuery = qQuery
+}
 
 -- |
 -- Get the location of the returned nodes along with the node
@@ -110,7 +115,11 @@
 --  ("$[\'title\']",String "Space Oddity")]
 -- @
 queryLocatedQQ :: Query -> Value -> Vector (String, Value)
-queryLocatedQQ q root = queryLocated' q root root "$"
+queryLocatedQQ q root = qQueryLocated q QueryState {
+    rootVal = root
+  , curVal = root
+  , executeQuery = qQuery
+} "$"
 
 -- $use
 --
diff --git a/src/Data/Aeson/JSONPath/Parser.hs b/src/Data/Aeson/JSONPath/Parser.hs
--- a/src/Data/Aeson/JSONPath/Parser.hs
+++ b/src/Data/Aeson/JSONPath/Parser.hs
@@ -1,375 +1,26 @@
 {-# OPTIONS_GHC -Wno-unused-do-bind #-}
 {- |
 Module      : Data.Aeson.JSONPath.Parser
-Description : Parses the raw query to ADT
+Description : JSONPath Query Parser
 Copyright   : (c) 2024-2025 Taimoor Zaeem
 License     : MIT
 Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>
 Stability   : Experimental
 Portability : Portable
 
-Parses raw query to Haskell Algebraic Data Types
+This module is responsible for parsing the JSONPath query
 -}
 module Data.Aeson.JSONPath.Parser
   ( pQuery )
   where
 
-import qualified Data.Text                      as T
 import qualified Text.ParserCombinators.Parsec  as P
 
-import Data.Functor                  (($>))
-import Data.Char                     (ord, chr)
-import Data.Maybe                    (isNothing, fromMaybe)
-import Data.Scientific               (Scientific, scientific)
-import GHC.Num                       (integerFromInt, integerToInt)
-import Text.ParserCombinators.Parsec ((<|>))
-
-import Data.Aeson.JSONPath.Query.Types
+import Data.Aeson.JSONPath.Parser.Query (pRootQuery)
+import Data.Aeson.JSONPath.Types
 
 import Prelude
 
 -- | Query parser
 pQuery :: P.Parser Query
-pQuery = P.try pRootQuery <* P.eof
-
-pRootQuery :: P.Parser Query
-pRootQuery = do
-  P.char '$'
-  segs <- P.many (pSpaces *> pQuerySegment)
-  return $ Query { queryType = Root, querySegments = segs }
-
-pCurrentQuery :: P.Parser Query
-pCurrentQuery = do
-  P.char '@'
-  segs <- P.many pQuerySegment
-  return $ Query { queryType = Current, querySegments = segs }
-
-
-pQuerySegment :: P.Parser QuerySegment
-pQuerySegment = do
-  dotdot <- P.optionMaybe (P.try $ P.string "..")
-  seg <- pSegment $ isNothing dotdot
-  let segType = if isNothing dotdot then Child else Descendant
-  return $ QuerySegment { segmentType = segType, segment = seg }
-
-pSegment :: Bool -> P.Parser Segment
-pSegment isChild = P.try pBracketed
-                <|> P.try (pDotted isChild)
-                <|> P.try (pWildcardSeg isChild)
-
-
-pBracketed :: P.Parser Segment
-pBracketed = do
-  P.char '['
-  pSpaces
-  sel <- pSelector
-  optionalSels <- P.many pCommaSepSelectors
-  pSpaces
-  P.char ']'
-  return $ Bracketed (sel:optionalSels)
-    where
-      pCommaSepSelectors :: P.Parser Selector
-      pCommaSepSelectors = P.try $ pSpaces *> P.char ',' *> pSpaces *> pSelector
-
-
-pDotted :: Bool -> P.Parser Segment
-pDotted isChild = do
-  (if isChild then P.string "." else P.string "")
-  P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)
-  key <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)
-  return $ Dotted key
-
-
-pWildcardSeg :: Bool -> P.Parser Segment
-pWildcardSeg isChild = (if isChild then P.string "." else P.string "") *> P.char '*' $> WildcardSegment
-  
-pSelector :: P.Parser Selector
-pSelector = P.try pName
-         <|> P.try pSlice 
-         <|> P.try pIndex
-         <|> P.try pWildcardSel
-         <|> P.try pFilter
-
-pName :: P.Parser Selector
-pName = Name . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
-
-pIndex :: P.Parser Selector
-pIndex = Index <$> pSignedInt
-
-pSlice :: P.Parser Selector
-pSlice = do
-  start <- P.optionMaybe (pSignedInt <* pSpaces)
-  P.char ':'
-  pSpaces
-  end <- P.optionMaybe (pSignedInt <* pSpaces)
-  step <- P.optionMaybe (P.char ':' *> P.optionMaybe (pSpaces *> pSignedInt))
-  return $ ArraySlice (start, end, case step of
-    Just (Just n) -> n
-    _ -> 1)
-
-
-pWildcardSel :: P.Parser Selector
-pWildcardSel = P.char '*' $> WildcardSelector
-
-
-pFilter :: P.Parser Selector
-pFilter = do
-  P.char '?'
-  pSpaces
-  Filter <$> pLogicalOrExpr
-
-
-pLogicalOrExpr :: P.Parser LogicalOrExpr
-pLogicalOrExpr = do
-  expr <- pLogicalAndExpr
-  optionalExprs <- P.many pOrSepLogicalAndExprs
-  return $ LogicalOr (expr:optionalExprs)
-    where
-      pOrSepLogicalAndExprs :: P.Parser LogicalAndExpr
-      pOrSepLogicalAndExprs = P.try $ pSpaces *> P.string "||" *> pSpaces *> pLogicalAndExpr
-
-pLogicalAndExpr :: P.Parser LogicalAndExpr
-pLogicalAndExpr = do
-  expr <- pBasicExpr
-  optionalExprs <- P.many pAndSepBasicExprs
-  return $ LogicalAnd (expr:optionalExprs)
-    where
-      pAndSepBasicExprs :: P.Parser BasicExpr
-      pAndSepBasicExprs = P.try $ pSpaces *> P.string "&&" *> pSpaces *> pBasicExpr
-
-pBasicExpr :: P.Parser BasicExpr
-pBasicExpr = P.try pParenExpr
-          <|> P.try pComparisonExpr
-          <|> P.try pTestExpr
-
-pParenExpr :: P.Parser BasicExpr
-pParenExpr = do
-  notOp <- P.optionMaybe (P.char '!' <* pSpaces)
-  P.char '('
-  pSpaces
-  expr <- pLogicalOrExpr
-  pSpaces
-  P.char ')'
-  let parenExp = if isNothing notOp then Paren expr else NotParen expr
-  return parenExp
-
-pTestExpr :: P.Parser BasicExpr
-pTestExpr = do
-  notOp <- P.optionMaybe (P.char '!' <* pSpaces)
-  q <- P.try pRootQuery <|> P.try pCurrentQuery
-  let testExp = if isNothing notOp then Test q else NotTest q
-  return testExp
-
-pComparisonExpr :: P.Parser BasicExpr
-pComparisonExpr = do
-  leftC <- pComparable
-  pSpaces
-  compOp <- pComparisonOp
-  pSpaces
-  Comparison . Comp leftC compOp <$> pComparable
-
-pComparisonOp :: P.Parser ComparisonOp
-pComparisonOp = P.try (P.string ">=" $> GreaterOrEqual)
-                <|> P.try (P.string "<=" $> LessOrEqual)
-                <|> P.try (P.char '>' $> Greater)
-                <|> P.try (P.char '<' $> Less)
-                <|> P.try (P.string "!=" $> NotEqual)
-                <|> P.try (P.string "==" $> Equal)
-
-pComparable :: P.Parser Comparable
-pComparable = P.try pCompLitString
-              <|> P.try pCompLitNum
-              <|> P.try pCompLitBool
-              <|> P.try pCompLitNull
-              <|> P.try pCompSQ
-
-pCompLitString :: P.Parser Comparable
-pCompLitString = CompLitString . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
-
-pCompLitNum :: P.Parser Comparable
-pCompLitNum = CompLitNum 
-           <$> (P.try (P.string "-0" $> (0 :: Scientific)) -- edge case
-           <|> P.try pDoubleScientific 
-           <|> P.try pScientific)
-
-pCompLitBool :: P.Parser Comparable
-pCompLitBool = CompLitBool <$> (P.try (P.string "true" $> True) <|> P.try (P.string "false" $> False))
-
-pCompLitNull :: P.Parser Comparable
-pCompLitNull = P.string "null" $> CompLitNull
-
-pCompSQ :: P.Parser Comparable
-pCompSQ = CompSQ <$> (P.try pCurrentSingleQ <|> P.try pRootSingleQ)
-
-pCurrentSingleQ :: P.Parser SingularQuery
-pCurrentSingleQ = do
-  P.char '@'
-  segs <- P.many pSingularQuerySegment
-  return $ SingularQuery { singularQueryType = CurrentSQ, singularQuerySegments = segs }
-
-pRootSingleQ :: P.Parser SingularQuery
-pRootSingleQ = do
-  P.char '$'
-  segs <- P.many pSingularQuerySegment
-  return $ SingularQuery { singularQueryType = RootSQ, singularQuerySegments = segs }
-
-pSingularQuerySegment :: P.Parser SingularQuerySegment
-pSingularQuerySegment = P.try pSingularQNameSeg <|> P.try pSingularQIndexSeg
-
-pSingularQNameSeg :: P.Parser SingularQuerySegment
-pSingularQNameSeg = P.try pSingularQNameBracketed <|> P.try pSingularQNameDotted
-  where
-    pSingularQNameBracketed = do
-      P.char '['
-      name <- T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
-      P.char ']'
-      return $ NameSQSeg name
-
-    pSingularQNameDotted = do
-      P.char '.'
-      P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)
-      name <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)
-      return $ NameSQSeg name
-
-pSingularQIndexSeg :: P.Parser SingularQuerySegment
-pSingularQIndexSeg = do
-  P.char '['
-  idx <- pSignedInt
-  P.char ']'
-  return $ IndexSQSeg idx
-
-pSignedInt :: P.Parser Int
-pSignedInt = do
-  P.notFollowedBy (P.string "-0" *> P.optional P.digit) -- no leading -011... etc
-  P.notFollowedBy (P.char   '0' *> P.digit) -- no leading 011... etc
-  sign <- P.optionMaybe $ P.char '-'
-  num <- (read <$> P.many1 P.digit) :: P.Parser Integer
-  checkNumOutOfRange num sign
-  where
-    minInt = -9007199254740991
-    maxInt = 9007199254740991
-    checkNumOutOfRange num (Just _) =
-      if -num < minInt then fail "out of range"
-      else return $ integerToInt (-num)
-
-    checkNumOutOfRange num Nothing =
-      if num > maxInt then fail "out of range"
-      else return $ integerToInt num
-
--- TODO: Fix Double parse error  "1.12e+23"
-pScientific :: P.Parser Scientific
-pScientific = do
-  mantissa <- pSignedInt
-  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)
-  return $ scientific (integerFromInt mantissa) (fromMaybe 0 expo)
-
-pDoubleScientific :: P.Parser Scientific
-pDoubleScientific = do
-  whole <- P.many1 P.digit
-  P.char '.'
-  frac <- P.many1 P.digit
-  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)
-  let num = read (whole ++ "." ++ frac ++ maybe "" (\x -> "e" ++ show x) expo) :: Scientific
-  return num
-
-pExponent :: P.Parser Int
-pExponent = do
-  sign <- P.optionMaybe (P.oneOf "+-")
-  num <- read <$> P.many1 P.digit
-  return $ case sign of
-    Just '-' -> -num
-    _        -> num
-
-pUnicodeChar :: P.Parser Char
-pUnicodeChar = P.satisfy inRange
-  where
-    inRange c = let code = ord c in
-      (code >= 0x80 && code <= 0xD7FF) ||
-      (code >= 0xE000 && code <= 0x10FFFF)
-
--- https://www.rfc-editor.org/rfc/rfc9535#name-syntax
-pSpaces :: P.Parser [Char]
-pSpaces = P.many (P.oneOf " \n\r\t")
-
-pSingleQuotted :: P.Parser String
-pSingleQuotted = P.char '\'' *> P.many inQuote <* P.char '\''
-  where
-    inQuote = P.try pUnescaped
-           <|> P.try (P.char '\"')
-           <|> P.try (P.string "\\\'" $> '\'')
-           <|> P.try pEscaped
-
-pDoubleQuotted :: P.Parser String
-pDoubleQuotted = P.char '\"' *> P.many inQuote <* P.char '\"'
-  where
-    inQuote = P.try pUnescaped
-           <|> P.try (P.char '\'')
-           <|> P.try (P.string "\\\"" $> '\"')
-           <|> P.try pEscaped
-
-pUnescaped :: P.Parser Char
-pUnescaped = P.satisfy inRange
-  where
-    inRange c = let code = ord c in
-      (code >= 0x20 && code <= 0x21) ||
-      (code >= 0x23 && code <= 0x26) ||
-      (code >= 0x28 && code <= 0x5B) ||
-      (code >= 0x5D && code <= 0xD7FF) ||
-      (code >= 0xE000 && code <= 0x10FFFF)
-
-pEscaped :: P.Parser Char
-pEscaped = do
-  P.char '\\'
-  P.try pEscapees <|> P.try pHexUnicode
-  where
-    pEscapees = P.try (P.char 'b' $> '\b')
-            <|> P.try (P.char 'f' $> '\f')
-            <|> P.try (P.char 'n' $> '\n')
-            <|> P.try (P.char 'r' $> '\r')
-            <|> P.try (P.char 't' $> '\t')
-            <|> P.try (P.char '/')
-            <|> P.try (P.char '\\')
-
-pHexUnicode :: P.Parser Char
-pHexUnicode = P.try pNonSurrogate <|> P.try pSurrogatePair
-  where
-    pNonSurrogate = P.try pNonSurrogateFirst <|> P.try pNonSurrogateSecond
-      where
-        pNonSurrogateFirst = do
-          P.char 'u'
-          c1 <- P.digit <|> P.oneOf "AaBbCcEeFf"
-          c2 <- P.hexDigit
-          c3 <- P.hexDigit
-          c4 <- P.hexDigit
-          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
-
-        pNonSurrogateSecond = do
-          P.char 'u'
-          c1 <- P.oneOf "Dd"
-          c2 <- P.oneOf "01234567"
-          c3 <- P.hexDigit
-          c4 <- P.hexDigit
-          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
-
-    pSurrogatePair = do
-      P.char 'u'
-      high <- pHighSurrogate
-      P.char '\\'
-      P.char 'u'
-      fromHighAndLow high <$> pLowSurrogate
-      where
-        pHighSurrogate = do
-          c1 <- P.oneOf "Dd"
-          c2 <- P.oneOf "89AaBb"
-          c3 <- P.hexDigit
-          c4 <- P.hexDigit
-          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
-
-        pLowSurrogate = do
-          c1 <- P.oneOf "Dd"
-          c2 <- P.oneOf "CcDdEeFf"
-          c3 <- P.hexDigit
-          c4 <- P.hexDigit
-          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
-          
-        fromHighAndLow hi lo = chr $ ((hi - 0xD800) * 0x400) + (lo - 0xDC00) + 0x10000
+pQuery = pRootQuery <* P.eof
diff --git a/src/Data/Aeson/JSONPath/Parser/Common.hs b/src/Data/Aeson/JSONPath/Parser/Common.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Parser/Common.hs
@@ -0,0 +1,21 @@
+module Data.Aeson.JSONPath.Parser.Common
+  ( pSpaces
+  , pUnicodeChar
+  )
+  where
+
+import qualified Text.ParserCombinators.Parsec as P
+import           Data.Char (ord)
+
+import Prelude
+
+-- https://www.rfc-editor.org/rfc/rfc9535#name-syntax
+pSpaces :: P.Parser [Char]
+pSpaces = P.many (P.oneOf " \n\r\t")
+
+pUnicodeChar :: P.Parser Char
+pUnicodeChar = P.satisfy inRange
+  where
+    inRange c = let code = ord c in
+      (code >= 0x80 && code <= 0xD7FF) ||
+      (code >= 0xE000 && code <= 0x10FFFF)
diff --git a/src/Data/Aeson/JSONPath/Parser/Filter.hs b/src/Data/Aeson/JSONPath/Parser/Filter.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Parser/Filter.hs
@@ -0,0 +1,150 @@
+{-# OPTIONS_GHC -Wno-unused-do-bind #-}
+module Data.Aeson.JSONPath.Parser.Filter
+  ( pFilter )
+  where
+
+import qualified Data.Text                      as T
+import qualified Text.ParserCombinators.Parsec  as P
+
+import Data.Functor                  (($>))
+import Data.Maybe                    (isNothing)
+import Data.Scientific               (Scientific)
+import Text.ParserCombinators.Parsec ((<|>))
+
+import Data.Aeson.JSONPath.Parser.Name
+import Data.Aeson.JSONPath.Parser.Number
+import Data.Aeson.JSONPath.Parser.Common
+
+import Data.Aeson.JSONPath.Types
+
+import Prelude
+
+pFilter :: P.Parser a -> P.Parser (Selector a)
+pFilter pQ = do
+  P.char '?'
+  pSpaces
+  Filter <$> pLogicalOrExpr pQ
+
+
+pLogicalOrExpr :: P.Parser a -> P.Parser (LogicalOrExpr a)
+pLogicalOrExpr pQ = do
+  expr <- pLogicalAndExpr pQ
+  optionalExprs <- P.many $ pOrSepLogicalAndExprs pQ
+  return $ LogicalOr (expr:optionalExprs)
+    where
+      pOrSepLogicalAndExprs :: P.Parser a -> P.Parser (LogicalAndExpr a)
+      pOrSepLogicalAndExprs pQ' = P.try $ pSpaces *> P.string "||" *> pSpaces *> pLogicalAndExpr pQ'
+
+pLogicalAndExpr :: P.Parser a -> P.Parser (LogicalAndExpr a)
+pLogicalAndExpr pQ = do
+  expr <- pBasicExpr pQ
+  optionalExprs <- P.many $ pAndSepBasicExprs pQ
+  return $ LogicalAnd (expr:optionalExprs)
+    where
+      pAndSepBasicExprs :: P.Parser a -> P.Parser (BasicExpr a)
+      pAndSepBasicExprs pQ' = P.try $ pSpaces *> P.string "&&" *> pSpaces *> pBasicExpr pQ'
+
+pBasicExpr :: P.Parser a -> P.Parser (BasicExpr a)
+pBasicExpr pQ 
+  = P.try (pParenExpr pQ)
+ <|> P.try pComparisonExpr
+ <|> P.try (pTestExpr pQ)
+
+pParenExpr :: P.Parser a -> P.Parser (BasicExpr a)
+pParenExpr pQ = do
+  notOp <- P.optionMaybe (P.char '!' <* pSpaces)
+  P.char '('
+  pSpaces
+  expr <- pLogicalOrExpr pQ
+  pSpaces
+  P.char ')'
+  let parenExp = if isNothing notOp then Paren expr else NotParen expr
+  return parenExp
+
+pTestExpr :: P.Parser a -> P.Parser (BasicExpr a)
+pTestExpr pQ = do
+  notOp <- P.optionMaybe (P.char '!' <* pSpaces)
+  q <- P.try (FilterQuery <$> pQ)
+  let testExp = if isNothing notOp then Test q else NotTest q
+  return testExp
+
+pComparisonExpr :: P.Parser (BasicExpr a)
+pComparisonExpr = do
+  leftC <- pComparable
+  pSpaces
+  compOp <- pComparisonOp
+  pSpaces
+  Comparison . Comp leftC compOp <$> pComparable
+
+pComparisonOp :: P.Parser ComparisonOp
+pComparisonOp = P.try (P.string ">=" $> GreaterOrEqual)
+             <|> P.try (P.string "<=" $> LessOrEqual)
+             <|> P.try (P.char '>' $> Greater)
+             <|> P.try (P.char '<' $> Less)
+             <|> P.try (P.string "!=" $> NotEqual)
+             <|> P.try (P.string "==" $> Equal)
+
+pComparable :: P.Parser Comparable
+pComparable = P.try pCompLit <|> P.try pCompSQ
+
+pCompLit :: P.Parser Comparable
+pCompLit = CompLit
+            <$> (P.try pLitString
+            <|> P.try pLitNum
+            <|> P.try pLitBool
+            <|> P.try pLitNull)
+
+pLitString :: P.Parser Literal
+pLitString = LitString . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
+
+pLitNum :: P.Parser Literal
+pLitNum = LitNum 
+           <$> (P.try (P.string "-0" $> (0 :: Scientific)) -- edge case
+           <|> P.try pDoubleScientific 
+           <|> P.try pScientific)
+
+pLitBool :: P.Parser Literal
+pLitBool = LitBool <$> (P.try (P.string "true" $> True) <|> P.try (P.string "false" $> False))
+
+pLitNull :: P.Parser Literal
+pLitNull = P.string "null" $> LitNull
+
+pCompSQ :: P.Parser Comparable
+pCompSQ = CompSQ <$> (P.try pCurrentSingleQ <|> P.try pRootSingleQ)
+
+pCurrentSingleQ :: P.Parser SingularQuery
+pCurrentSingleQ = do
+  P.char '@'
+  segs <- P.many $ P.try (pSpaces *> pSingularQuerySegment)
+  return $ SingularQuery { singularQueryType = CurrentSQ, singularQuerySegments = segs }
+
+pRootSingleQ :: P.Parser SingularQuery
+pRootSingleQ = do
+  P.char '$'
+  segs <- P.many $ P.try (pSpaces *> pSingularQuerySegment)
+  return $ SingularQuery { singularQueryType = RootSQ, singularQuerySegments = segs }
+
+pSingularQuerySegment :: P.Parser SingularQuerySegment
+pSingularQuerySegment = P.try pSingularQNameSeg <|> P.try pSingularQIndexSeg
+
+pSingularQNameSeg :: P.Parser SingularQuerySegment
+pSingularQNameSeg = P.try pSingularQNameBracketed <|> P.try pSingularQNameDotted
+  where
+    pSingularQNameBracketed = do
+      P.char '['
+      name <- T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
+      P.char ']'
+      return $ NameSQSeg name
+
+    pSingularQNameDotted = do
+      P.char '.'
+      P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)
+      name <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)
+      return $ NameSQSeg name
+
+pSingularQIndexSeg :: P.Parser SingularQuerySegment
+pSingularQIndexSeg = do
+  P.char '['
+  idx <- pSignedInt
+  P.char ']'
+  return $ IndexSQSeg idx
diff --git a/src/Data/Aeson/JSONPath/Parser/Name.hs b/src/Data/Aeson/JSONPath/Parser/Name.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Parser/Name.hs
@@ -0,0 +1,97 @@
+{-# OPTIONS_GHC -Wno-unused-do-bind #-}
+module Data.Aeson.JSONPath.Parser.Name
+  ( pSingleQuotted
+  , pDoubleQuotted
+  )
+  where
+
+import qualified Text.ParserCombinators.Parsec  as P
+
+import Data.Functor                  (($>))
+import Data.Char                     (ord, chr)
+import Text.ParserCombinators.Parsec ((<|>))
+
+import Prelude
+
+pSingleQuotted :: P.Parser String
+pSingleQuotted = P.char '\'' *> P.many inQuote <* P.char '\''
+  where
+    inQuote = P.try pUnescaped
+           <|> P.try (P.char '\"')
+           <|> P.try (P.string "\\\'" $> '\'')
+           <|> P.try pEscaped
+
+pDoubleQuotted :: P.Parser String
+pDoubleQuotted = P.char '\"' *> P.many inQuote <* P.char '\"'
+  where
+    inQuote = P.try pUnescaped
+           <|> P.try (P.char '\'')
+           <|> P.try (P.string "\\\"" $> '\"')
+           <|> P.try pEscaped
+
+pUnescaped :: P.Parser Char
+pUnescaped = P.satisfy inRange
+  where
+    inRange c = let code = ord c in
+      (code >= 0x20 && code <= 0x21) ||
+      (code >= 0x23 && code <= 0x26) ||
+      (code >= 0x28 && code <= 0x5B) ||
+      (code >= 0x5D && code <= 0xD7FF) ||
+      (code >= 0xE000 && code <= 0x10FFFF)
+
+pEscaped :: P.Parser Char
+pEscaped = do
+  P.char '\\'
+  P.try pEscapees <|> P.try pHexUnicode
+  where
+    pEscapees = P.try (P.char 'b' $> '\b')
+            <|> P.try (P.char 'f' $> '\f')
+            <|> P.try (P.char 'n' $> '\n')
+            <|> P.try (P.char 'r' $> '\r')
+            <|> P.try (P.char 't' $> '\t')
+            <|> P.try (P.char '/')
+            <|> P.try (P.char '\\')
+
+pHexUnicode :: P.Parser Char
+pHexUnicode = P.try pNonSurrogate <|> P.try pSurrogatePair
+  where
+    pNonSurrogate = P.try pNonSurrogateFirst <|> P.try pNonSurrogateSecond
+      where
+        pNonSurrogateFirst = do
+          P.char 'u'
+          c1 <- P.digit <|> P.oneOf "AaBbCcEeFf"
+          c2 <- P.hexDigit
+          c3 <- P.hexDigit
+          c4 <- P.hexDigit
+          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
+
+        pNonSurrogateSecond = do
+          P.char 'u'
+          c1 <- P.oneOf "Dd"
+          c2 <- P.oneOf "01234567"
+          c3 <- P.hexDigit
+          c4 <- P.hexDigit
+          return $ chr (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
+
+    pSurrogatePair = do
+      P.char 'u'
+      high <- pHighSurrogate
+      P.char '\\'
+      P.char 'u'
+      fromHighAndLow high <$> pLowSurrogate
+      where
+        pHighSurrogate = do
+          c1 <- P.oneOf "Dd"
+          c2 <- P.oneOf "89AaBb"
+          c3 <- P.hexDigit
+          c4 <- P.hexDigit
+          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
+
+        pLowSurrogate = do
+          c1 <- P.oneOf "Dd"
+          c2 <- P.oneOf "CcDdEeFf"
+          c3 <- P.hexDigit
+          c4 <- P.hexDigit
+          return (read ("0x" ++ [c1,c2,c3,c4]) :: Int)
+
+        fromHighAndLow hi lo = chr $ ((hi - 0xD800) * 0x400) + (lo - 0xDC00) + 0x10000
diff --git a/src/Data/Aeson/JSONPath/Parser/Number.hs b/src/Data/Aeson/JSONPath/Parser/Number.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Parser/Number.hs
@@ -0,0 +1,57 @@
+{-# OPTIONS_GHC -Wno-unused-do-bind #-}
+module Data.Aeson.JSONPath.Parser.Number
+  ( pSignedInt
+  , pScientific
+  , pDoubleScientific
+  )
+  where
+
+import qualified Text.ParserCombinators.Parsec  as P
+
+import Data.Maybe                    (fromMaybe)
+import Data.Scientific               (Scientific, scientific)
+import GHC.Num                       (integerFromInt, integerToInt)
+
+import Prelude
+
+pSignedInt :: P.Parser Int
+pSignedInt = do
+  P.notFollowedBy (P.string "-0" *> P.optional P.digit) -- no leading -011... etc
+  P.notFollowedBy (P.char   '0' *> P.digit) -- no leading 011... etc
+  sign <- P.optionMaybe $ P.char '-'
+  num <- (read <$> P.many1 P.digit) :: P.Parser Integer
+  checkNumOutOfRange num sign
+  where
+    minInt = -9007199254740991
+    maxInt = 9007199254740991
+    checkNumOutOfRange num (Just _) =
+      if -num < minInt then fail "out of range"
+      else return $ integerToInt (-num)
+
+    checkNumOutOfRange num Nothing =
+      if num > maxInt then fail "out of range"
+      else return $ integerToInt num
+
+-- TODO: Fix Double parse error  "1.12e+23"
+pScientific :: P.Parser Scientific
+pScientific = do
+  mantissa <- pSignedInt
+  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)
+  return $ scientific (integerFromInt mantissa) (fromMaybe 0 expo)
+
+pDoubleScientific :: P.Parser Scientific
+pDoubleScientific = do
+  whole <- P.many1 P.digit
+  P.char '.'
+  frac <- P.many1 P.digit
+  expo <- P.optionMaybe (P.oneOf "eE" *> pExponent)
+  let num = read (whole ++ "." ++ frac ++ maybe "" (\x -> "e" ++ show x) expo) :: Scientific
+  return num
+
+pExponent :: P.Parser Int
+pExponent = do
+  sign <- P.optionMaybe (P.oneOf "+-")
+  num <- read <$> P.many1 P.digit
+  return $ case sign of
+    Just '-' -> -num
+    _        -> num
diff --git a/src/Data/Aeson/JSONPath/Parser/Query.hs b/src/Data/Aeson/JSONPath/Parser/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Parser/Query.hs
@@ -0,0 +1,105 @@
+{-# OPTIONS_GHC -Wno-unused-do-bind #-}
+module Data.Aeson.JSONPath.Parser.Query
+  ( pRootQuery
+  , pCurrentQuery )
+  where
+
+import qualified Data.Text                      as T
+import qualified Text.ParserCombinators.Parsec  as P
+
+import Data.Functor                  (($>))
+import Data.Maybe                    (isNothing)
+import Text.ParserCombinators.Parsec ((<|>))
+
+import Data.Aeson.JSONPath.Parser.Filter (pFilter)
+import Data.Aeson.JSONPath.Parser.Name
+import Data.Aeson.JSONPath.Parser.Number
+import Data.Aeson.JSONPath.Parser.Common
+import Data.Aeson.JSONPath.Types
+
+import Prelude
+
+pRootQuery :: P.Parser Query
+pRootQuery = do
+  P.char '$'
+  segs <- P.many $ P.try pSpacedOutSegments
+  return $ Query { queryType = Root, querySegments = segs }
+    where
+      pQ = P.try pRootQuery <|> P.try pCurrentQuery
+      pSpacedOutSegments = pSpaces *> pQuerySegment pQ
+
+pCurrentQuery :: P.Parser Query
+pCurrentQuery = do
+  P.char '@'
+  segs <- P.many $ P.try pSpacedOutSegments
+  return $ Query { queryType = Current, querySegments = segs }
+    where
+      pQ = P.try pRootQuery <|> P.try pCurrentQuery
+      pSpacedOutSegments = pSpaces *> pQuerySegment pQ
+
+
+pQuerySegment :: P.Parser a -> P.Parser (QuerySegment a)
+pQuerySegment pQ = do
+  dotdot <- P.optionMaybe (P.try $ P.string "..")
+  seg <- pSegment pQ $ isNothing dotdot
+  let segType = if isNothing dotdot then Child else Descendant
+  return $ QuerySegment { segmentType = segType, segment = seg }
+
+pSegment :: P.Parser a -> Bool -> P.Parser (Segment a)
+pSegment pQ isChild
+        = P.try (pBracketed pQ)
+       <|> P.try (pDotted isChild)
+       <|> P.try (pWildcardSeg isChild)
+
+pBracketed :: P.Parser a -> P.Parser (Segment a)
+pBracketed pQ = do
+  P.char '['
+  pSpaces
+  sel <- pSelector pQ
+  optionalSels <- P.many $ pCommaSepSelectors pQ
+  pSpaces
+  P.char ']'
+  return $ Bracketed (sel:optionalSels)
+    where
+      pCommaSepSelectors :: P.Parser a -> P.Parser (Selector a)
+      pCommaSepSelectors p = P.try $ pSpaces *> P.char ',' *> pSpaces *> pSelector p
+
+
+pDotted :: Bool -> P.Parser (Segment a)
+pDotted isChild = do
+  (if isChild then P.string "." else P.string "")
+  P.lookAhead (P.letter <|> P.oneOf "_" <|> pUnicodeChar)
+  key <- T.pack <$> P.many1 (P.alphaNum <|> P.oneOf "_" <|> pUnicodeChar)
+  return $ Dotted key
+
+
+pWildcardSeg :: Bool -> P.Parser (Segment a)
+pWildcardSeg isChild = (if isChild then P.string "." else P.string "") *> P.char '*' $> WildcardSegment
+  
+pSelector :: P.Parser a -> P.Parser (Selector a)
+pSelector pQ = P.try pName
+                   <|> P.try pSlice 
+                   <|> P.try pIndex
+                   <|> P.try pWildcardSel
+                   <|> P.try (pFilter pQ)
+
+pName :: P.Parser (Selector a)
+pName = Name . T.pack <$> (P.try pSingleQuotted <|> P.try pDoubleQuotted)
+
+pIndex :: P.Parser (Selector a)
+pIndex = Index <$> pSignedInt
+
+pSlice :: P.Parser (Selector a)
+pSlice = do
+  start <- P.optionMaybe (pSignedInt <* pSpaces)
+  P.char ':'
+  pSpaces
+  end <- P.optionMaybe (pSignedInt <* pSpaces)
+  step <- P.optionMaybe (P.char ':' *> P.optionMaybe (pSpaces *> pSignedInt))
+  return $ ArraySlice (start, end, case step of
+    Just (Just n) -> n
+    _ -> 1)
+
+
+pWildcardSel :: P.Parser (Selector a)
+pWildcardSel = P.char '*' $> WildcardSelector
diff --git a/src/Data/Aeson/JSONPath/Query.hs b/src/Data/Aeson/JSONPath/Query.hs
--- a/src/Data/Aeson/JSONPath/Query.hs
+++ b/src/Data/Aeson/JSONPath/Query.hs
@@ -1,290 +1,18 @@
-{-# LANGUAGE RecordWildCards #-}
 {- |
 Module      : Data.Aeson.JSONPath.Query
-Description : Algorithm for query runner
+Description : Execute JSONPath Query after parsing
 Copyright   : (c) 2024-2025 Taimoor Zaeem
 License     : MIT
 Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>
 Stability   : Experimental
 Portability : Portable
 
-This module contains core functions that runs the query on 'Value'.
+This module is responsible for executing the JSONPath query
 -}
 module Data.Aeson.JSONPath.Query
-  ( Queryable (..) )
+  (
+    module Data.Aeson.JSONPath.Query.Query
+  )
   where
 
-import Control.Monad                   (join)
-import Data.Aeson                      (Value)
-import Data.Vector                     (Vector)
-
-import qualified Data.Aeson            as JSON
-import qualified Data.Aeson.KeyMap     as KM
-import qualified Data.Aeson.Key        as K
-import qualified Data.Text             as T
-import qualified Data.Vector           as V
-
-import Data.Aeson.JSONPath.Query.Types
-
-import Prelude
-
--- |
-class Queryable a where
-  query'        :: a -> Value -> Value -> Vector Value
-  queryLocated' :: a -> Value -> Value -> String -> Vector (String,Value)
-
-instance Queryable Query where
-  query'        = qQuery
-  queryLocated' = qQueryLocated
-
-instance Queryable QuerySegment where
-  query'        = qQuerySegment
-  queryLocated' = qQuerySegmentLocated
-
-instance Queryable Segment where
-  query'        = qSegment
-  queryLocated' = qSegmentLocated
-
-instance Queryable Selector where
-  query'        = qSelector
-  queryLocated' = qSelectorLocated
-
--- TODO: the whole module is kinda bloated, refactor
---    Blockers with refactoring: qQuery is used recursively
-
-qQuery :: Query -> Value -> Value -> Vector Value
-qQuery Query{..} root current = case queryType of
-  Root    -> foldl applySegment (V.singleton root)    querySegments
-  Current -> foldl applySegment (V.singleton current) querySegments
-  where
-    applySegment :: Vector Value -> QuerySegment -> Vector Value
-    applySegment vec seg = join $ V.map (qQuerySegment seg root) vec
-
-qQueryLocated :: Query -> Value -> Value -> String -> Vector (String,Value)
-qQueryLocated Query{..} root current loc = case queryType of
-  Root    -> foldl applySegment (V.singleton (loc,root))    querySegments
-  Current -> foldl applySegment (V.singleton (loc,current)) querySegments
-  where
-    applySegment :: Vector (String,Value) -> QuerySegment -> Vector (String,Value)
-    applySegment vec seg = join $ V.map (\(location,cur) -> qQuerySegmentLocated seg root cur location) vec
-
-qQuerySegment :: QuerySegment -> Value -> Value -> Vector Value
-qQuerySegment QuerySegment{..} root current = case segmentType of
-  Child      -> joinAfterMap $ V.singleton current
-  Descendant -> joinAfterMap $ allElemsRecursive current
-  where
-    joinAfterMap x = join $ V.map (qSegment segment root) x
-
-qQuerySegmentLocated :: QuerySegment -> Value -> Value -> String -> Vector (String, Value)
-qQuerySegmentLocated QuerySegment{..} root current loc = case segmentType of
-  Child      -> joinAfterMap $ V.singleton (loc,current)
-  Descendant -> joinAfterMap $ allElemsRecursiveLocated (loc,current)
-  where
-    joinAfterMap x = join $ V.map (\(location,cur) -> qSegmentLocated segment root cur location) x
-
-qSegment :: Segment -> Value -> Value -> Vector Value
-qSegment (Bracketed sels) root current = V.concat $ map (\sel -> qSelector sel root current) sels
-qSegment (Dotted key) root current = qSelector (Name key) root current
-qSegment WildcardSegment root current = qSelector WildcardSelector root current
-
-qSegmentLocated :: Segment -> Value -> Value -> String -> Vector (String,Value)
-qSegmentLocated (Bracketed sels) root current loc = V.concat $ map (\sel -> qSelectorLocated sel root current loc) sels
-qSegmentLocated (Dotted key) root current loc = qSelectorLocated (Name key) root current loc
-qSegmentLocated WildcardSegment root current loc = qSelectorLocated WildcardSelector root current loc
-
-
--- TODO: Looks kinda ugly, make it pretty <3
-allElemsRecursive :: Value -> Vector Value
-allElemsRecursive o@(JSON.Object obj) = V.concat [
-    V.singleton o,
-    V.concat $ map allElemsRecursive (KM.elems obj)
-  ]
-allElemsRecursive a@(JSON.Array arr) = V.concat [
-    V.singleton a,
-    V.concat $ map allElemsRecursive (V.toList arr)
-  ]
-allElemsRecursive _ = V.empty
-
--- TODO: Looks kinda ugly, make it pretty <3
-allElemsRecursiveLocated :: (String,Value) -> Vector (String,Value)
-allElemsRecursiveLocated (loc, o@(JSON.Object obj)) = V.concat [
-    V.singleton (loc,o),
-    V.concat $ zipWith (curry allElemsRecursiveLocated) (replicate (length (KM.elems obj)) loc) (KM.elems obj)
-  ]
-allElemsRecursiveLocated (loc, a@(JSON.Array arr)) = V.concat [
-    V.singleton (loc,a),
-    V.concat $ zipWith (curry allElemsRecursiveLocated) (replicate (V.length arr) loc) (V.toList arr)
-  ]
-allElemsRecursiveLocated _ = V.empty
-
-
-qSelector :: Selector -> Value -> Value -> Vector Value
-qSelector (Name key) _ (JSON.Object obj) = maybe V.empty  V.singleton $ KM.lookup (K.fromText key) obj
-qSelector (Name _) _ _ = V.empty
-qSelector (Index idx) _ (JSON.Array arr) = maybe V.empty V.singleton $ if idx >= 0 then (V.!?) arr idx else (V.!?) arr (idx + V.length arr)
-qSelector (Index _) _ _ = V.empty
-qSelector (ArraySlice startEndStep) _ (JSON.Array arr) = sliceArray startEndStep arr
-qSelector (ArraySlice _) _ _ = V.empty
-qSelector (Filter orExpr) root current = filterOrExpr orExpr root current
-qSelector WildcardSelector _ cur = case cur of
-    (JSON.Object obj) -> V.fromList $ KM.elems obj
-    (JSON.Array arr)  -> arr
-    _                 -> V.empty
-
-qSelectorLocated :: Selector -> Value -> Value -> String -> Vector (String,Value)
-qSelectorLocated (Name key) _ (JSON.Object obj) loc = maybe V.empty (\x-> V.singleton (loc ++ "['" ++ T.unpack key ++ "']", x)) $ KM.lookup (K.fromText key) obj
-qSelectorLocated (Name _) _ _ _ = V.empty
-qSelectorLocated (Index idx) _ (JSON.Array arr) loc = maybe V.empty (\x-> V.singleton (newLocation, x)) $ (V.!?) arr (getIndex idx)
-  where
-    newLocation = loc ++ "[" ++ show (getIndex idx) ++ "]"
-    getIndex i = if i >= 0 then i else i + V.length arr
-qSelectorLocated (Index _) _ _ _ = V.empty
-qSelectorLocated (ArraySlice (start,end,step)) _ (JSON.Array arr) loc = sliceArrayLocated (start,end,step) $ V.zip (V.fromList locs) arr
-  where
-    locs = [ loc ++ "[" ++ show i ++ "]" | i <- indices ]
-    indices = [0..(V.length arr - 1)]
-qSelectorLocated (ArraySlice _) _ _ _ = V.empty
-qSelectorLocated (Filter orExpr) root cur loc = filterOrExprLocated orExpr root cur loc
-qSelectorLocated WildcardSelector _ cur loc = case cur of
-    (JSON.Object obj) -> V.fromList $ zip (locsWithKeys obj) (KM.elems obj)
-    (JSON.Array arr)  -> V.zip (V.fromList (locsWithIdxs arr)) arr
-    _                 -> V.empty
-    where
-      locsWithKeys obj = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)
-      locsWithIdxs arr = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr)]
-
-
-sliceArray :: (Maybe Int, Maybe Int, Int) -> Vector Value -> Vector Value
-sliceArray (start,end,step) vec =
-  case compare step 0 of
-    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec
-    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec
-    EQ -> V.empty
-    where
-      -- TODO: Looks kinda ugly, make it pretty <3
-      len = V.length vec
-      normalize i = if i >= 0 then i else len + i
-
-      getSliceForward st en stp arr = loop lower V.empty
-        where
-          (lower,upper) = (min (max st 0) len, min (max en 0) len)
-
-          loop i acc =
-            if i < upper
-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
-            else
-              acc
-
-      getSliceReverse st en stp arr = loop upper V.empty
-        where
-          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))
-
-          loop i acc =
-            if lower < i
-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
-            else
-              acc
-
-
-sliceArrayLocated :: (Maybe Int, Maybe Int, Int) -> Vector (String,Value) -> Vector (String,Value)
-sliceArrayLocated (start,end,step) vec =
-  case compare step 0 of
-    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec
-    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec
-    EQ -> V.empty
-    where
-      -- TODO: Looks kinda ugly, make it pretty <3
-      len = V.length vec
-      normalize i = if i >= 0 then i else len + i
-
-      getSliceForward st en stp arr = loop lower V.empty
-        where
-          (lower,upper) = (min (max st 0) len, min (max en 0) len)
-
-          loop i acc =
-            if i < upper
-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
-            else
-              acc
-
-      getSliceReverse st en stp arr = loop upper V.empty
-        where
-          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))
-
-          loop i acc =
-            if lower < i
-              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
-            else
-              acc
-
-filterOrExpr :: LogicalOrExpr -> Value -> Value -> Vector Value
-filterOrExpr expr root (JSON.Object obj) = V.filter (evaluateLogicalOrExpr expr root) (V.fromList $ KM.elems obj)
-filterOrExpr expr root (JSON.Array arr) = V.filter (evaluateLogicalOrExpr expr root) arr
-filterOrExpr _ _ _ = V.empty
-
-filterOrExprLocated :: LogicalOrExpr -> Value -> Value -> String -> Vector (String,Value)
-filterOrExprLocated expr root (JSON.Object obj) loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr root x) (V.fromList $ zip locsWithKeys (KM.elems obj))
-  where
-    locsWithKeys = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)
-filterOrExprLocated expr root (JSON.Array arr) loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr root x) (V.zip (V.fromList locsWithIdxs) arr)
-  where
-    locsWithIdxs = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr - 1)]
-filterOrExprLocated _ _ _ _ = V.empty
-
-
-evaluateLogicalOrExpr :: LogicalOrExpr -> Value -> Value -> Bool
-evaluateLogicalOrExpr (LogicalOr exprs) root cur = any (\x -> evaluateLogicalAndExpr x root cur) exprs
-
-
-evaluateLogicalAndExpr :: LogicalAndExpr -> Value -> Value -> Bool
-evaluateLogicalAndExpr (LogicalAnd exprs) root cur = all (\x -> evaluateBasicExpr x root cur) exprs
-
-
-evaluateBasicExpr :: BasicExpr -> Value -> Value -> Bool
-evaluateBasicExpr (Paren expr) root cur = evaluateLogicalOrExpr expr root cur
-evaluateBasicExpr (NotParen expr) root cur = not $ evaluateLogicalOrExpr expr root cur
-evaluateBasicExpr (Test expr) root cur = evaluateTestExpr expr root cur
-evaluateBasicExpr (NotTest expr) root cur = not $ evaluateTestExpr expr root cur
-evaluateBasicExpr (Comparison expr) root cur = evaluateCompExpr expr root cur
-
-
-evaluateTestExpr :: TestExpr -> Value -> Value -> Bool
-evaluateTestExpr expr root cur = not $ null $ qQuery expr root cur
-
-
-evaluateCompExpr :: ComparisonExpr -> Value -> Value -> Bool
-evaluateCompExpr (Comp leftC op rightC) root cur  = compareVals op (getComparableVal leftC root cur) (getComparableVal rightC root cur)
-
-
-compareVals :: ComparisonOp -> Maybe Value -> Maybe Value -> Bool
-compareVals Less (Just (JSON.String s1)) (Just (JSON.String s2)) = s1 < s2
-compareVals Less (Just (JSON.Number n1)) (Just (JSON.Number n2)) = n1 < n2
-compareVals Less _  _ = False
-
-compareVals LessOrEqual    o1 o2 = compareVals Less o1 o2 || compareVals Equal o1 o2
-compareVals Greater        o1 o2 = compareVals Less o2 o1
-compareVals GreaterOrEqual o1 o2 = compareVals Less o2 o1 || compareVals Equal o1 o2
-compareVals Equal          o1 o2 = o1 == o2
-compareVals NotEqual       o1 o2 = o1 /= o2
-
-
-getComparableVal :: Comparable -> Value -> Value -> Maybe Value
-getComparableVal (CompLitNum num) _ _ = Just $ JSON.Number num
-getComparableVal (CompLitString txt) _ _ = Just $ JSON.String txt
-getComparableVal (CompLitBool bool) _ _ = Just $ JSON.Bool bool
-getComparableVal CompLitNull _ _ = Just JSON.Null
-getComparableVal (CompSQ SingularQuery{..}) root cur = case singularQueryType of
-  RootSQ -> traverseSingularQSegs (Just root) singularQuerySegments
-  CurrentSQ -> traverseSingularQSegs (Just cur) singularQuerySegments
-
-
-traverseSingularQSegs :: Maybe Value -> [SingularQuerySegment] -> Maybe Value
-traverseSingularQSegs = foldl lookupSingleQSeg
-
-
--- TODO: There is a bug here, not existing shouldn't give null
--- See: https://www.rfc-editor.org/rfc/rfc9535#name-examples-6
-lookupSingleQSeg :: Maybe Value -> SingularQuerySegment -> Maybe Value
-lookupSingleQSeg (Just (JSON.Object obj)) (NameSQSeg txt) = KM.lookup (K.fromText txt) obj
-lookupSingleQSeg (Just (JSON.Array arr)) (IndexSQSeg idx) = (V.!?) arr idx
-lookupSingleQSeg _ _ = Nothing
+import Data.Aeson.JSONPath.Query.Query
diff --git a/src/Data/Aeson/JSONPath/Query/Filter.hs b/src/Data/Aeson/JSONPath/Query/Filter.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Query/Filter.hs
@@ -0,0 +1,90 @@
+{-# LANGUAGE RecordWildCards #-}
+module Data.Aeson.JSONPath.Query.Filter
+  ( filterOrExpr
+  , filterOrExprLocated )
+  where
+
+import Data.Aeson                      (Value)
+import Data.Vector                     (Vector)
+
+import qualified Data.Aeson            as JSON
+import qualified Data.Aeson.KeyMap     as KM
+import qualified Data.Aeson.Key        as K
+import qualified Data.Vector           as V
+
+import Data.Aeson.JSONPath.Types
+
+import Prelude
+
+filterOrExpr :: LogicalOrExpr Query -> QueryState -> Vector Value
+filterOrExpr expr qS@QueryState{ curVal=(JSON.Object obj) } = V.filter (\cur -> evaluateLogicalOrExpr expr qS{ curVal=cur}) (V.fromList $ KM.elems obj)
+filterOrExpr expr qS@QueryState{ curVal=(JSON.Array arr) } = V.filter (\cur -> evaluateLogicalOrExpr expr qS{ curVal=cur }) arr
+filterOrExpr _ _ = V.empty
+
+filterOrExprLocated :: LogicalOrExpr Query -> QueryState -> String -> Vector (String,Value)
+filterOrExprLocated expr  qS@QueryState{ curVal=(JSON.Object obj) } loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr qS{ curVal=x}) (V.fromList $ zip locsWithKeys (KM.elems obj))
+  where
+    locsWithKeys = map (\x -> loc ++ "['" ++ K.toString x ++ "']") (KM.keys obj)
+filterOrExprLocated expr qS@QueryState{ curVal=(JSON.Array arr) } loc = V.filter (\(_,x) -> evaluateLogicalOrExpr expr qS{ curVal=x}) (V.zip (V.fromList locsWithIdxs) arr)
+  where
+    locsWithIdxs = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr - 1)]
+filterOrExprLocated _ _ _ = V.empty
+
+
+evaluateLogicalOrExpr :: LogicalOrExpr Query -> QueryState -> Bool
+evaluateLogicalOrExpr (LogicalOr exprs) qS = any (`evaluateLogicalAndExpr` qS) exprs
+
+
+evaluateLogicalAndExpr :: LogicalAndExpr Query -> QueryState -> Bool
+evaluateLogicalAndExpr (LogicalAnd exprs) qS = all (`evaluateBasicExpr` qS) exprs
+
+
+evaluateBasicExpr :: BasicExpr Query -> QueryState -> Bool
+evaluateBasicExpr (Paren expr)      qS = evaluateLogicalOrExpr expr qS
+evaluateBasicExpr (NotParen expr)   qS = not $ evaluateLogicalOrExpr expr qS
+evaluateBasicExpr (Test expr)       qS = evaluateTestExpr expr qS
+evaluateBasicExpr (NotTest expr)    qS = not $ evaluateTestExpr expr qS
+evaluateBasicExpr (Comparison expr) qS = evaluateCompExpr expr qS
+
+
+evaluateTestExpr :: TestExpr Query -> QueryState -> Bool
+evaluateTestExpr (FilterQuery expr) qS@QueryState{..} = not $ null $ executeQuery expr qS
+
+
+evaluateCompExpr :: ComparisonExpr -> QueryState -> Bool
+evaluateCompExpr (Comp leftC op rightC) qS  = compareVals op (getComparableVal leftC qS) (getComparableVal rightC qS)
+
+
+compareVals :: ComparisonOp -> Maybe Value -> Maybe Value -> Bool
+compareVals Less (Just (JSON.String s1)) (Just (JSON.String s2)) = s1 < s2
+compareVals Less (Just (JSON.Number n1)) (Just (JSON.Number n2)) = n1 < n2
+compareVals Less _  _ = False
+
+compareVals LessOrEqual    o1 o2 = compareVals Less o1 o2 || compareVals Equal o1 o2
+compareVals Greater        o1 o2 = compareVals Less o2 o1
+compareVals GreaterOrEqual o1 o2 = compareVals Less o2 o1 || compareVals Equal o1 o2
+compareVals Equal          o1 o2 = o1 == o2
+compareVals NotEqual       o1 o2 = o1 /= o2
+
+
+getComparableVal :: Comparable -> QueryState -> Maybe Value
+getComparableVal (CompLit lit) _ = 
+  case lit of
+    LitString txt -> Just $ JSON.String txt
+    LitNum num    -> Just $ JSON.Number num
+    LitBool bool  -> Just $ JSON.Bool bool
+    LitNull       -> Just JSON.Null
+
+getComparableVal (CompSQ SingularQuery{..}) QueryState{..} = case singularQueryType of
+  RootSQ -> traverseSingularQSegs (Just rootVal) singularQuerySegments
+  CurrentSQ -> traverseSingularQSegs (Just curVal) singularQuerySegments
+
+
+traverseSingularQSegs :: Maybe Value -> [SingularQuerySegment] -> Maybe Value
+traverseSingularQSegs = foldl lookupSingleQSeg
+
+
+lookupSingleQSeg :: Maybe Value -> SingularQuerySegment -> Maybe Value
+lookupSingleQSeg (Just (JSON.Object obj)) (NameSQSeg txt) = KM.lookup (K.fromText txt) obj
+lookupSingleQSeg (Just (JSON.Array arr)) (IndexSQSeg idx) = (V.!?) arr idx
+lookupSingleQSeg _ _ = Nothing
diff --git a/src/Data/Aeson/JSONPath/Query/Query.hs b/src/Data/Aeson/JSONPath/Query/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Query/Query.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE RecordWildCards #-}
+module Data.Aeson.JSONPath.Query.Query
+  ( qQuery
+  , qQueryLocated
+  )
+  where
+
+import Control.Monad                   (join)
+import Data.Aeson                      (Value)
+import Data.Vector                     (Vector)
+
+import qualified Data.Vector           as V
+
+import Data.Aeson.JSONPath.Types
+import Data.Aeson.JSONPath.Query.Segment
+
+import Prelude
+
+-- | Runs the JSONPath Query
+qQuery :: Query -> QueryState -> Vector Value
+qQuery Query{..} qS@QueryState{..} = case queryType of
+  Root    -> foldl applySegment (V.singleton rootVal) querySegments
+  Current -> foldl applySegment (V.singleton curVal) querySegments
+  where
+    applySegment :: Vector Value -> QuerySegment Query -> Vector Value
+    applySegment vec seg = join $ V.map (\x -> qQuerySegment seg qS{ curVal = x }) vec
+
+-- | Runs the JSONPath Query also returning node locations
+qQueryLocated :: Query -> QueryState -> String -> Vector (String,Value)
+qQueryLocated Query{..} qS@QueryState{..} loc = case queryType of
+  Root    -> foldl applySegment (V.singleton (loc,rootVal)) querySegments
+  Current -> foldl applySegment (V.singleton (loc,curVal)) querySegments
+  where
+    applySegment :: Vector (String,Value) -> QuerySegment Query -> Vector (String,Value)
+    applySegment vec seg = join $ V.map (\(location,cur) -> qQuerySegmentLocated seg qS{ curVal = cur } location) vec
diff --git a/src/Data/Aeson/JSONPath/Query/Segment.hs b/src/Data/Aeson/JSONPath/Query/Segment.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Query/Segment.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE RecordWildCards #-}
+module Data.Aeson.JSONPath.Query.Segment
+  ( qQuerySegment
+  , qQuerySegmentLocated
+  )
+  where
+
+import Control.Monad (join)
+import Data.Aeson    (Value)
+import Data.Vector   (Vector)
+
+import qualified Data.Aeson         as JSON
+import qualified Data.Aeson.KeyMap  as KM
+import qualified Data.Aeson.Key     as K
+import qualified Data.Vector        as V
+
+import Data.Aeson.JSONPath.Types
+import Data.Aeson.JSONPath.Query.Selector
+
+import Prelude
+
+qQuerySegment :: QuerySegment Query -> QueryState -> Vector Value
+qQuerySegment QuerySegment{..} qS@QueryState{..} = case segmentType of
+  Child      -> joinAfterMap $ V.singleton curVal
+  Descendant -> joinAfterMap $ allElemsRecursive curVal
+  where
+    joinAfterMap vec = join $ V.map (\cur -> qSegment segment qS{ curVal = cur }) vec
+
+qQuerySegmentLocated :: QuerySegment Query -> QueryState-> String -> Vector (String, Value)
+qQuerySegmentLocated QuerySegment{..} qS@QueryState{..} loc = case segmentType of
+  Child      -> joinAfterMap $ V.singleton (loc,curVal)
+  Descendant -> joinAfterMap $ allElemsRecursiveLocated (loc,curVal)
+  where
+    joinAfterMap vec = join $ V.map (\(location,cur) -> qSegmentLocated segment qS{ curVal = cur } location) vec
+
+qSegment :: Segment Query -> QueryState -> Vector Value
+qSegment (Bracketed sels) qS = V.concat $ map (`qSelector` qS) sels
+qSegment (Dotted key) qS = qSelector (Name key) qS
+qSegment WildcardSegment qS = qSelector WildcardSelector qS
+
+qSegmentLocated :: Segment Query -> QueryState -> String -> Vector (String,Value)
+qSegmentLocated (Bracketed sels) qS loc = V.concat $ map (\sel -> qSelectorLocated sel qS loc) sels
+qSegmentLocated (Dotted key) qS loc = qSelectorLocated (Name key) qS loc
+qSegmentLocated WildcardSegment qS loc = qSelectorLocated WildcardSelector qS loc
+
+-- TODO: Looks kinda ugly, make it pretty <3
+allElemsRecursive :: Value -> Vector Value
+allElemsRecursive o@(JSON.Object obj) = V.concat [
+    V.singleton o,
+    V.concat $ map allElemsRecursive (KM.elems obj)
+  ]
+allElemsRecursive a@(JSON.Array arr) = V.concat [
+    V.singleton a,
+    V.concat $ map allElemsRecursive (V.toList arr)
+  ]
+allElemsRecursive _ = V.empty
+
+-- TODO: Looks kinda ugly, make it pretty <3
+allElemsRecursiveLocated :: (String,Value) -> Vector (String,Value)
+allElemsRecursiveLocated (loc, o@(JSON.Object obj)) = V.concat [
+    V.singleton (loc,o),
+    V.concat $ zipWith (curry allElemsRecursiveLocated) keys (KM.elems obj)
+  ]
+  where
+    keys = map (toPathKey loc) $ KM.keys obj
+allElemsRecursiveLocated (loc, a@(JSON.Array arr)) = V.concat [
+    V.singleton (loc,a),
+    V.concat $ zipWith (curry allElemsRecursiveLocated) indices (V.toList arr)
+  ]
+  where
+    indices = map (toPathIdx loc) [0..V.length arr - 1]
+allElemsRecursiveLocated _ = V.empty
+
+toPathKey :: String -> KM.Key -> String
+toPathKey loc key = loc ++ "['" ++ escapeEscapees (K.toString key) ++ "']"
+  where
+    escapeEscapees :: String -> String
+    escapeEscapees [] = []
+    escapeEscapees (x:xs) = checkChar x ++ escapeEscapees xs
+      where
+        -- TODO: Do we need to escape unicode chars?
+        checkChar '\\' = ['\\', '\\']
+        checkChar '\'' = ['\\', '\'']
+        checkChar '\b' = ['\\', 'b']
+        checkChar '\r' = ['\\', 'r']
+        checkChar '\t' = ['\\', 't']
+        checkChar '\f' = ['\\', 'f']
+        checkChar '\n' = ['\\', 'n']
+        checkChar c = [c]
+
+toPathIdx :: String -> Int -> String
+toPathIdx loc idx = loc ++ "[" ++ show idx ++ "]"
diff --git a/src/Data/Aeson/JSONPath/Query/Selector.hs b/src/Data/Aeson/JSONPath/Query/Selector.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Query/Selector.hs
@@ -0,0 +1,139 @@
+{-# LANGUAGE RecordWildCards #-}
+module Data.Aeson.JSONPath.Query.Selector
+  ( qSelector
+  , qSelectorLocated
+  )
+  where
+
+import Data.Aeson     (Value)
+import Data.Vector    (Vector)
+import Data.Text      (Text)
+
+import qualified Data.Aeson            as JSON
+import qualified Data.Aeson.KeyMap     as KM
+import qualified Data.Aeson.Key        as K
+import qualified Data.Text             as T
+import qualified Data.Vector           as V
+
+import Data.Aeson.JSONPath.Types
+import Data.Aeson.JSONPath.Query.Filter
+
+import Prelude
+
+qSelector :: Selector Query -> QueryState -> Vector Value
+qSelector (Name key) QueryState{curVal=(JSON.Object obj)} = maybe V.empty V.singleton $ KM.lookup (K.fromText key) obj
+qSelector (Name _) _ = V.empty
+qSelector (Index idx) QueryState{curVal=(JSON.Array arr)} = maybe V.empty V.singleton $ if idx >= 0 then (V.!?) arr idx else (V.!?) arr (idx + V.length arr)
+qSelector (Index _) _ = V.empty
+qSelector (ArraySlice startEndStep) QueryState{curVal=(JSON.Array arr) } = sliceArray startEndStep arr
+qSelector (ArraySlice _) _ = V.empty
+qSelector (Filter orExpr) qS = filterOrExpr orExpr qS
+qSelector WildcardSelector QueryState{..} = case curVal of
+    (JSON.Object obj) -> V.fromList $ KM.elems obj
+    (JSON.Array arr)  -> arr
+    _                 -> V.empty
+
+
+qSelectorLocated :: Selector Query -> QueryState -> String -> Vector (String,Value)
+qSelectorLocated (Name key) QueryState{curVal=(JSON.Object obj)} loc = maybe V.empty (\x-> V.singleton (toPathKey loc key, x)) $ KM.lookup (K.fromText key) obj
+qSelectorLocated (Name _) _ _ = V.empty
+qSelectorLocated (Index idx) QueryState{curVal=(JSON.Array arr)} loc = maybe V.empty (\x-> V.singleton (newLocation, x)) $ (V.!?) arr (getIndex idx)
+  where
+    newLocation = loc ++ "[" ++ show (getIndex idx) ++ "]"
+    getIndex i = if i >= 0 then i else i + V.length arr
+qSelectorLocated (Index _) _ _ = V.empty
+qSelectorLocated (ArraySlice (start,end,step)) QueryState{curVal=(JSON.Array arr)} loc = sliceArrayLocated (start,end,step) $ V.zip (V.fromList locs) arr
+  where
+    locs = [ loc ++ "[" ++ show i ++ "]" | i <- indices ]
+    indices = [0..(V.length arr - 1)]
+qSelectorLocated (ArraySlice _) _ _ = V.empty
+qSelectorLocated (Filter orExpr) qS loc = filterOrExprLocated orExpr qS loc
+qSelectorLocated WildcardSelector QueryState{..} loc = case curVal of
+    (JSON.Object obj) -> V.fromList $ zip (locsWithKeys obj) (KM.elems obj)
+    (JSON.Array arr)  -> V.zip (V.fromList (locsWithIdxs arr)) arr
+    _                 -> V.empty
+    where
+      locsWithKeys obj = map (toPathKey loc . K.toText) (KM.keys obj)
+      locsWithIdxs arr = map (\x -> loc ++ "[" ++ show x ++ "]") [0..(V.length arr)]
+
+
+sliceArray :: (Maybe Int, Maybe Int, Int) -> Vector Value -> Vector Value
+sliceArray (start,end,step) vec =
+  case compare step 0 of
+    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec
+    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec
+    EQ -> V.empty
+    where
+      -- TODO: Looks kinda ugly, make it pretty <3
+      len = V.length vec
+      normalize i = if i >= 0 then i else len + i
+
+      getSliceForward st en stp arr = loop lower V.empty
+        where
+          (lower,upper) = (min (max st 0) len, min (max en 0) len)
+
+          loop i acc =
+            if i < upper
+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
+            else
+              acc
+
+      getSliceReverse st en stp arr = loop upper V.empty
+        where
+          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))
+
+          loop i acc =
+            if lower < i
+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
+            else
+              acc
+
+
+sliceArrayLocated :: (Maybe Int, Maybe Int, Int) -> Vector (String,Value) -> Vector (String,Value)
+sliceArrayLocated (start,end,step) vec =
+  case compare step 0 of
+    GT -> getSliceForward (maybe 0 normalize start) (maybe len normalize end) step vec
+    LT -> getSliceReverse (maybe (len-1) normalize start) (maybe (-1) normalize end) step vec
+    EQ -> V.empty
+    where
+      -- TODO: Looks kinda ugly, make it pretty <3
+      len = V.length vec
+      normalize i = if i >= 0 then i else len + i
+
+      getSliceForward st en stp arr = loop lower V.empty
+        where
+          (lower,upper) = (min (max st 0) len, min (max en 0) len)
+
+          loop i acc =
+            if i < upper
+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
+            else
+              acc
+
+      getSliceReverse st en stp arr = loop upper V.empty
+        where
+          (lower,upper) = (min (max en (-1)) (len-1), min (max st (-1)) (len-1))
+
+          loop i acc =
+            if lower < i
+              then loop (i+stp) $ V.snoc acc $ (V.!) arr (normalize i)
+            else
+              acc
+
+
+toPathKey :: String -> Text -> String
+toPathKey loc key = loc ++ "['" ++ escapeEscapees (T.unpack key) ++ "']"
+  where
+    escapeEscapees :: String -> String
+    escapeEscapees [] = []
+    escapeEscapees (x:xs) = checkChar x ++ escapeEscapees xs
+      where
+        -- TODO: Do we need to escape unicode chars?
+        checkChar '\\' = ['\\', '\\']
+        checkChar '\'' = ['\\', '\'']
+        checkChar '\b' = ['\\', 'b']
+        checkChar '\r' = ['\\', 'r']
+        checkChar '\t' = ['\\', 't']
+        checkChar '\f' = ['\\', 'f']
+        checkChar '\n' = ['\\', 'n']
+        checkChar c = [c]
diff --git a/src/Data/Aeson/JSONPath/Query/Types.hs b/src/Data/Aeson/JSONPath/Query/Types.hs
deleted file mode 100644
--- a/src/Data/Aeson/JSONPath/Query/Types.hs
+++ /dev/null
@@ -1,139 +0,0 @@
-{-# LANGUAGE DeriveLift #-}
-{- |
-Module      : Data.Aeson.JSONPath.Query.Types
-Description : ADTs used internally
-Copyright   : (c) 2024-2025 Taimoor Zaeem
-License     : MIT
-Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>
-Stability   : Experimental
-Portability : Portable
-
-This module contains the data structures.
--}
-module Data.Aeson.JSONPath.Query.Types
-  (Query (..)
-  , QueryType (..)
-  , Segment (..)
-  , QuerySegment (..)
-  , SegmentType (..)
-  , Selector (..)
-  , LogicalOrExpr (..)
-  , LogicalAndExpr (..)
-  , BasicExpr (..)
-  , TestExpr
-  , ComparisonExpr (..)
-  , ComparisonOp (..)
-  , Comparable(..)
-  , SingularQuery (..)
-  , SingularQueryType (..)
-  , SingularQuerySegment (..)
-  )
-  where
-
-import Data.Text                   (Text)
-import Data.Scientific             (Scientific)
-import Language.Haskell.TH.Syntax  (Lift)
-
-import Prelude
-
--- |
-data QueryType 
-  = Root 
-  | Current
-  deriving (Eq, Show, Lift)
-
--- |
-data Query = Query
-  { queryType     :: QueryType
-  , querySegments :: [QuerySegment]
-  } deriving (Eq, Show, Lift)
-
--- |
-data SegmentType
-  = Child
-  | Descendant
-  deriving (Eq, Show, Lift)
-
--- |
-data QuerySegment = QuerySegment
-  { segmentType :: SegmentType
-  , segment     :: Segment
-  } deriving (Eq, Show, Lift)
-
--- |
-data Segment
-  = Bracketed [Selector]
-  | Dotted Text
-  | WildcardSegment
-  deriving (Eq, Show, Lift)
-
--- |
-data Selector
-  = Name Text
-  | Index Int
-  | ArraySlice (Maybe Int, Maybe Int, Int)
-  | Filter LogicalOrExpr
-  | WildcardSelector
-  deriving (Eq, Show, Lift)
-
--- |
-newtype LogicalOrExpr
-  = LogicalOr [LogicalAndExpr]
-  deriving (Eq, Show, Lift)
-
--- |
-newtype LogicalAndExpr
-  = LogicalAnd [BasicExpr]
-  deriving (Eq, Show, Lift)
-
--- |
-data BasicExpr
-  = Paren LogicalOrExpr -- ( expr )
-  | NotParen LogicalOrExpr -- not (expr)
-  | Test TestExpr -- expr
-  | NotTest TestExpr -- not expr
-  | Comparison ComparisonExpr
-  deriving (Eq, Show, Lift)
-
--- |
-type TestExpr = Query
-
--- |
-data ComparisonExpr
-  = Comp Comparable ComparisonOp Comparable
-  deriving (Eq, Show, Lift)
-
--- |
-data ComparisonOp
-  = Less
-  | LessOrEqual
-  | Greater
-  | GreaterOrEqual
-  | Equal
-  | NotEqual
-  deriving (Eq, Show, Lift)
-
--- |
-data Comparable
-  = CompLitString Text
-  | CompLitNum Scientific
-  | CompLitBool Bool
-  | CompLitNull
-  | CompSQ SingularQuery
-  deriving (Eq, Show, Lift)
-
--- |
-data SingularQueryType = RootSQ | CurrentSQ
-  deriving (Eq, Show, Lift)
-
--- |
-data SingularQuery = SingularQuery
-  { singularQueryType     :: SingularQueryType
-  , singularQuerySegments :: [SingularQuerySegment]
-  } deriving (Eq, Show, Lift)
-
--- |
-data SingularQuerySegment
-  = NameSQSeg Text
-  | IndexSQSeg Int
-  deriving (Eq, Show, Lift)
diff --git a/src/Data/Aeson/JSONPath/Types.hs b/src/Data/Aeson/JSONPath/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Types.hs
@@ -0,0 +1,30 @@
+{- |
+Module      : Data.Aeson.JSONPath.Types
+Description : Types related to JSONPath elements
+Copyright   : (c) 2024-2025 Taimoor Zaeem
+License     : MIT
+Maintainer  : Taimoor Zaeem <mtaimoorzaeem@gmail.com>
+Stability   : Experimental
+Portability : Portable
+
+This module contains all the data structures related to JSONPath
+-}
+module Data.Aeson.JSONPath.Types
+  ( 
+    module Data.Aeson.JSONPath.Types.Query
+
+  , module Data.Aeson.JSONPath.Types.Segment
+
+  , module Data.Aeson.JSONPath.Types.Selector
+
+  , module Data.Aeson.JSONPath.Types.Filter
+  )
+  where
+
+import Data.Aeson.JSONPath.Types.Query
+
+import Data.Aeson.JSONPath.Types.Segment
+
+import Data.Aeson.JSONPath.Types.Selector
+
+import Data.Aeson.JSONPath.Types.Filter
diff --git a/src/Data/Aeson/JSONPath/Types/Filter.hs b/src/Data/Aeson/JSONPath/Types/Filter.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Types/Filter.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE DeriveLift #-}
+module Data.Aeson.JSONPath.Types.Filter
+  (LogicalOrExpr (..)
+  , LogicalAndExpr (..)
+  , BasicExpr (..)
+  , TestExpr (..)
+  , ComparisonExpr (..)
+  , ComparisonOp (..)
+  , Comparable (..)
+  , Literal (..)
+  , SingularQueryType (..)
+  , SingularQuery (..)
+  , SingularQuerySegment (..)
+  )
+  where
+
+import Data.Text                   (Text)
+import Data.Scientific             (Scientific)
+
+import Language.Haskell.TH.Syntax  (Lift)
+
+import Prelude
+
+-- |
+newtype LogicalOrExpr a
+  = LogicalOr [LogicalAndExpr a]
+  deriving (Eq, Show, Lift)
+
+-- |
+newtype LogicalAndExpr a
+  = LogicalAnd [BasicExpr a]
+  deriving (Eq, Show, Lift)
+
+-- |
+data BasicExpr a
+  = Paren (LogicalOrExpr a) -- ( expr )
+  | NotParen (LogicalOrExpr a) -- not (expr)
+  | Test (TestExpr a) -- query
+  | NotTest (TestExpr a) -- not query
+  | Comparison ComparisonExpr
+  deriving (Eq, Show, Lift)
+
+-- |
+newtype TestExpr a
+  = FilterQuery a
+  deriving (Eq, Show, Lift)
+
+-- |
+data ComparisonExpr
+  = Comp Comparable ComparisonOp Comparable
+  deriving (Eq, Show, Lift)
+
+-- |
+data ComparisonOp
+  = Less
+  | LessOrEqual
+  | Greater
+  | GreaterOrEqual
+  | Equal
+  | NotEqual
+  deriving (Eq, Show, Lift)
+
+-- |
+data Comparable
+  = CompLit Literal
+  | CompSQ SingularQuery
+  deriving (Eq, Show, Lift)
+
+-- |
+data Literal
+  = LitString Text
+  | LitNum Scientific
+  | LitBool Bool
+  | LitNull
+  deriving (Eq, Show, Lift)
+
+-- |
+data SingularQueryType = RootSQ | CurrentSQ
+  deriving (Eq, Show, Lift)
+
+-- |
+data SingularQuery = SingularQuery
+  { singularQueryType     :: SingularQueryType
+  , singularQuerySegments :: [SingularQuerySegment]
+  } deriving (Eq, Show, Lift)
+
+-- |
+data SingularQuerySegment
+  = NameSQSeg Text
+  | IndexSQSeg Int
+  deriving (Eq, Show, Lift)
diff --git a/src/Data/Aeson/JSONPath/Types/Query.hs b/src/Data/Aeson/JSONPath/Types/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Types/Query.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE DeriveLift #-}
+module Data.Aeson.JSONPath.Types.Query
+  ( Query (..)
+  , QueryType (..)
+  , QueryState (..)
+  )
+  where
+
+import Data.Aeson  (Value)
+import Data.Vector (Vector)
+
+import Data.Aeson.JSONPath.Types.Segment (QuerySegment (..))
+import Language.Haskell.TH.Syntax        (Lift)
+
+import Prelude
+
+-- |
+data QueryState = QueryState
+  { rootVal      :: Value
+  , curVal       :: Value
+  , executeQuery :: Query -> QueryState -> Vector Value
+  }
+
+-- |
+data QueryType 
+  = Root 
+  | Current
+  deriving (Eq, Show, Lift)
+
+-- |
+data Query = Query
+  { queryType     :: QueryType
+  , querySegments :: [QuerySegment Query]
+  } deriving (Eq, Show, Lift)
diff --git a/src/Data/Aeson/JSONPath/Types/Segment.hs b/src/Data/Aeson/JSONPath/Types/Segment.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Types/Segment.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE DeriveLift #-}
+module Data.Aeson.JSONPath.Types.Segment
+  (Segment (..)
+  , QuerySegment (..)
+  , SegmentType (..)
+  )
+  where
+
+import Data.Aeson.JSONPath.Types.Selector (Selector (..))
+import Data.Text                          (Text)
+import Language.Haskell.TH.Syntax         (Lift)
+
+import Prelude
+
+-- |
+data SegmentType
+  = Child
+  | Descendant
+  deriving (Eq, Show, Lift)
+
+-- |
+data QuerySegment a = QuerySegment
+  { segmentType :: SegmentType
+  , segment     :: Segment a
+  } deriving (Eq, Show, Lift)
+
+-- |
+data Segment a
+  = Bracketed [Selector a]
+  | Dotted Text
+  | WildcardSegment
+  deriving (Eq, Show, Lift)
diff --git a/src/Data/Aeson/JSONPath/Types/Selector.hs b/src/Data/Aeson/JSONPath/Types/Selector.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/JSONPath/Types/Selector.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE DeriveLift #-}
+module Data.Aeson.JSONPath.Types.Selector
+  (Selector (..))
+  where
+
+import Data.Aeson.JSONPath.Types.Filter (LogicalOrExpr (..))
+import Data.Text                        (Text)
+import Language.Haskell.TH.Syntax       (Lift)
+
+import Prelude
+
+-- |
+data Selector a
+  = Name Text
+  | Index Int
+  | ArraySlice (Maybe Int, Maybe Int, Int)
+  | Filter (LogicalOrExpr a)
+  | WildcardSelector
+  deriving (Eq, Show, Lift)
diff --git a/test/ComplianceSpec.hs b/test/ComplianceSpec.hs
deleted file mode 100644
--- a/test/ComplianceSpec.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE NamedFieldPuns #-}
-module ComplianceSpec
-  ( spec
-  , TestSuite (..))
-  where
-
-import qualified Data.Aeson                    as JSON
-import qualified Data.Vector                   as V
-import qualified Text.ParserCombinators.Parsec as P
-
-import Control.Monad              (mzero)
-import Data.Aeson                 ((.:),(.:?),Value)
-import Data.Aeson.JSONPath        (query)
-import Data.Aeson.JSONPath.Parser (pQuery)
-import Data.Either                (isLeft, fromRight)
-import Data.Vector                (Vector)
-
-import Test.Hspec
-import Prelude
-
-data TestSuite = TestSuite
-  { tests :: [TestCase]
-  } deriving (Show)
-
-instance JSON.FromJSON TestSuite where
-  parseJSON (JSON.Object o) =
-    TestSuite
-    <$> o .: "tests"
-
-  parseJSON _ = mzero
-
-data TestCase = TestCase
-  { name       :: String
-  , selector   :: String
-  , document   :: Maybe Value
-  , result     :: Maybe (Vector Value)
-  , results    :: Maybe [Vector Value]
-  , invalidSel :: Maybe Bool
-  , tags       :: Maybe [String]
-  } deriving (Show)
-
-instance JSON.FromJSON TestCase where
-  parseJSON (JSON.Object o) =
-    TestCase
-    <$> o .: "name"
-    <*> o .: "selector"
-    <*> o .:? "document"
-    <*> o .:? "result"
-    <*> o .:? "results"
-    <*> o .:? "invalid_selector"
-    <*> o .:? "tags"
-
-  parseJSON _ = mzero
-
-spec :: TestSuite -> Spec
-spec TestSuite{tests} = do
-  describe "compliance tests" $ do
-    mapM_ runTestCase tests
-
-
-runTestCase :: TestCase -> SpecWith ()
--- skip function extension tests
-runTestCase tc@TestCase{tags=Just xs, ..} =
-  if (elem "function" xs)
-    then xit name pending
-  else
-    runTestCase tc{tags=Nothing}
-
--- invalid selector should not parse correctly
-runTestCase TestCase{invalidSel=(Just True), ..} =
-  it name $
-    P.parse pQuery "" selector `shouldSatisfy` isLeft
-
--- if result is deterministic (one json)
-runTestCase TestCase{result=(Just r), document=(Just doc), ..} =
-  it name $
-    query selector doc `shouldBe` Right r
-
--- if result is non-deterministic (any json from the list of results)
-runTestCase TestCase{results=(Just rs), document=(Just doc), ..} = do
-  it name $
-    query selector doc `shouldSatisfy` (\x -> elem (fromRight V.empty x) rs)
-
-runTestCase _ = pure ()
diff --git a/test/LocatedSpec.hs b/test/LocatedSpec.hs
deleted file mode 100644
--- a/test/LocatedSpec.hs
+++ /dev/null
@@ -1,143 +0,0 @@
-module LocatedSpec
-  ( spec )
-  where
-
-import qualified Data.Aeson        as JSON
-import qualified Data.Vector       as V
-
-import Data.Aeson.JSONPath  (queryLocatedQQ, jsonPath)
-import Data.Aeson.QQ.Simple (aesonQQ)
-import Data.Vector          (Vector)
-import Test.Hspec
-
-import Prelude
-
-getVector :: JSON.Value -> Vector JSON.Value
-getVector (JSON.Array arr) = arr
-getVector _ = V.empty
-
--- taken from https://serdejsonpath.live/
-rootDoc :: JSON.Value
-rootDoc = [aesonQQ|{
-    "store": {
-      "books": [
-        {
-          "title": "Guns, Germs, and Steel",
-          "author": "Jared Diamond",
-          "category": "reference",
-          "price": 24.99
-        },
-        {
-          "title": "David Copperfield",
-          "author": "Charles Dickens",
-          "category": "fiction",
-          "price": 12.99
-        },
-        {
-          "title": "Moby Dick",
-          "author": "Herman Melville",
-          "category": "fiction",
-          "price": 8.99
-        },
-        {
-          "title": "Crime and Punishment",
-          "author": "Fyodor Dostoevsky",
-          "category": "fiction",
-          "price": 19.99
-        }
-      ]
-    }
-  }|]
-
-
-storeDoc :: JSON.Value
-storeDoc = [aesonQQ|
-  {
-    "books": [
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Crime and Punishment",
-        "author": "Fyodor Dostoevsky",
-        "category": "fiction",
-        "price": 19.99
-      }
-    ]
-  }|]
-
-booksDoc :: JSON.Value
-booksDoc = [aesonQQ| [
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Crime and Punishment",
-        "author": "Fyodor Dostoevsky",
-        "category": "fiction",
-        "price": 19.99
-      }
-  ]|]
-
-
-books0Doc :: JSON.Value
-books0Doc = [aesonQQ|[
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      }
-  ]|]
-
-
-spec :: Spec
-spec = do
-  describe "test queryLocated" $ do
-    it "returns root document when query is $" $
-      queryLocatedQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton ("$",rootDoc)
-
-    it "returns store object when queryQQ is $.store" $
-      queryLocatedQQ [jsonPath|$.store|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]
-
-    it "returns store object when queryQQ is $['store']" $
-      queryLocatedQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]
-
-    it "returns books array when queryQQ is $.store.books" $
-      queryLocatedQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.fromList [("$['store']['books']",booksDoc)]
-
-    it "returns 0-index book item, $.store.books[0]" $
-      queryLocatedQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
-
-    it "returns 0-index book item, $.store.books[-4]" $
-      queryLocatedQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
diff --git a/test/Main.hs b/test/Main.hs
deleted file mode 100644
--- a/test/Main.hs
+++ /dev/null
@@ -1,45 +0,0 @@
-module Main
-  ( main )
-  where
-
-import qualified Data.Aeson         as JSON
-import qualified Test.Hspec         as HS
-import qualified Data.Text.Encoding as T
-import qualified Data.Text.IO       as TIO
-
-import Data.Either                  (fromRight)
-
-import qualified ParserSpec
-import qualified QuerySpec
-import qualified ComplianceSpec
-import qualified LocatedSpec
-import qualified Paths_aeson_jsonpath as Paths
-
-import ComplianceSpec   (TestSuite (..))
-
-import Test.Hspec.Runner
-import Prelude
-
-allSpecs :: Either String TestSuite -> Spec
-allSpecs cts = do
-  HS.describe "Run all tests" $ do
-    ParserSpec.spec
-    QuerySpec.spec
-    ComplianceSpec.spec (fromRight TestSuite{tests=[]} cts)
-    LocatedSpec.spec
-
-readCtsFile :: FilePath -> IO (Either String TestSuite)
-readCtsFile filePath = do
-  contents <- TIO.readFile filePath
-  return $ JSON.eitherDecodeStrict' $ T.encodeUtf8 contents
-
-main :: IO ()
-main = do
-  file <- Paths.getDataFileName "test/cts.json"
-  cts <- readCtsFile file
-  summary <- hspecWithResult defaultConfig 
-    { configColorMode = ColorAuto
-    } (allSpecs cts)
-  
-  putStrLn $ "Total tests: " ++ show (summaryExamples summary)
-  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
diff --git a/test/ParserSpec.hs b/test/ParserSpec.hs
deleted file mode 100644
--- a/test/ParserSpec.hs
+++ /dev/null
@@ -1,442 +0,0 @@
-module ParserSpec
-  ( spec )
-  where
-
-import qualified Text.ParserCombinators.Parsec as P
-
-import Data.Aeson.JSONPath.Parser       (pQuery)
-import Data.Either                      (isLeft)
-
-import Data.Aeson.JSONPath.Query.Types
-import Test.Hspec
-import Prelude
-
-spec :: Spec
-spec = do
-  describe "Parse query string" $ do
-    it "parses query: $" $
-      P.parse pQuery "" "$"
-      `shouldBe`
-      Right (Query{queryType=Root,querySegments=[]})
-
-    it "parses query: $.store" $
-      P.parse pQuery "" "$.store"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }]
-      }
-
-    it "parses query: $['store']" $
-      P.parse pQuery "" "$['store']"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [Name "store"]
-        }]
-      }
-
-    it "parses query: $.store.books" $
-      P.parse pQuery "" "$.store.books"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-          }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }]
-      }
-
-    it "parses query: $.store.books[0]" $
-      P.parse pQuery "" "$.store.books[0]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [Index 0]
-        }]
-      }
-
-    it "parses query: $.store.books[0,2]" $
-      P.parse pQuery "" "$.store.books[0,2]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [Index 0, Index 2]
-        }]
-      }
-
-    it "parses query: $.store.books[1:3]" $
-      P.parse pQuery "" "$.store.books[1:3]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [ArraySlice (Just 1, Just 3, 1)]
-        }]
-      }
-
-    it "parses query: $.store.books[1:4:2]" $
-      P.parse pQuery "" "$.store.books[1:4:2]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [ArraySlice (Just 1, Just 4, 2)]
-        }]
-      }
-
-    it "parses query: $.store.books[-1:-4:-2]" $
-      P.parse pQuery "" "$.store.books[-1:-4:-2]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [ArraySlice (Just (-1), Just (-4), (-2))]
-        }]
-      }
-
-    it "parses query: $.store.books[1:3, 0, 1]" $
-      P.parse pQuery "" "$.store.books[1:3, 0, 1]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "store"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Dotted "books"
-        }, QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [ArraySlice (Just 1, Just 3, 1), Index 0, Index 1]
-        }]
-      }
-
-    it "parses query: $.*" $
-      P.parse pQuery "" "$.*" 
-      `shouldBe` 
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = WildcardSegment
-        }]
-      }
-
-    it "parses query: $[*]" $
-      P.parse pQuery "" "$[*]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [WildcardSelector]
-        }]
-      }
-
-    it "parses query: $..*" $
-      P.parse pQuery "" "$..*"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Descendant,
-          segment = WildcardSegment
-        }]
-      }
-
-    it "parses query: $..[*]" $
-      P.parse pQuery "" "$..[*]"
-      `shouldBe` 
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Descendant,
-          segment = Bracketed [WildcardSelector]
-        }]
-      }
-
-    it "fails with $.1startsWithNum" $
-      P.parse pQuery "" "$.1startsWithNum"
-      `shouldSatisfy` isLeft
-
-    it "parses query $.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ" $
-      P.parse pQuery "" "$.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
-        }]
-      }
-
-    it "parses query: $._" $
-      P.parse pQuery "" "$._"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "_"
-        }]
-      }
-
-    it "parses query: $.underscore_key" $
-      P.parse pQuery "" "$.underscore_key"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Dotted "underscore_key"
-        }]
-      }
-
-    it "parses query: $[0,TAB/LINEFEED/RETURN/SPACE1]" $
-      P.parse pQuery "" "$[0,\n\t\r 1]"
-      `shouldBe`
-      Right Query {
-        queryType = Root,
-        querySegments = [QuerySegment {
-          segmentType = Child,
-          segment = Bracketed [Index 0, Index 1]
-        }]
-      }
-
-    describe "parses JSPFilter Query" $ do
-      it "$[?@.category == 'reference']" $
-        P.parse pQuery "" "$[?@.category == 'reference']"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "category"]
-            }) Equal (CompLitString "reference"))]])]
-          }]
-        }
-
-      it "test expr: $..books[?@.price].title" $
-        P.parse pQuery "" "$..books[?@.price].title"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Descendant,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {
-              queryType = Current,
-              querySegments = [QuerySegment {
-                segmentType = Child,
-                segment = Dotted "price"
-              }]
-            }]])]
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "title"
-          }]
-        }
-
-      it "and expr: $[?@.price < 20 && @.price > 10]" $
-        P.parse pQuery "" "$[?@.price < 20 && @.price > 10]" 
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Greater (CompLitNum 10.0))]])]
-          }]
-        }
-
-      it "or expr: $[?@.price < 20 || @.price > 10]" $
-        P.parse pQuery "" "$[?@.price < 20 || @.price > 10]"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Less (CompLitNum 20.0))], LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Greater (CompLitNum 10.0))]])]
-          }]
-        }
-
-      it "root filter: $..books[?$.price].title" $
-        P.parse pQuery "" "$..books[?$.price].title"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Descendant,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test Query {
-              queryType = Root,
-              querySegments = [QuerySegment {
-                segmentType = Child,
-                segment = Dotted "price"
-              }]
-            }]])]
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "title"
-          }]
-        }
-
-      it "not expr: $[?!(@.price < 20 && @.price > 10)]" $
-        P.parse pQuery "" "$[?!(@.price < 20 && @.price > 10)]" 
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [NotParen (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            })  Less (CompLitNum 20.0)), Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Greater (CompLitNum 10.0))]])]])]
-          }]
-        }
-
-      it "scientific: $.store.books[?@.price < -1e20]" $
-        P.parse pQuery "" "$.store.books[?@['price'] < -1e20]"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Dotted "store"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Less (CompLitNum (-1.0e20)))]])]
-          }]
-        }
-
-      it "double: $.store.books[?@.price < 0.01]" $
-        P.parse pQuery "" "$.store.books[?@['price'] < 0.01]"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Dotted "store"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "price"]
-            }) Less (CompLitNum (1.0e-2)))]])]
-          }]
-        }
-
-      it "bool: $.store.books[?@.is_available == true]" $
-        P.parse pQuery "" "$.store.books[?@.is_available == true]"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Dotted "store"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "is_available"]
-            }) Equal (CompLitBool True))]])]
-          }]
-        }
-
-      it "null: $.store.books[?@.is_available == null]" $
-        P.parse pQuery "" "$.store.books[?@.is_available == null]"
-        `shouldBe`
-        Right Query {
-          queryType = Root,
-          querySegments = [QuerySegment {
-            segmentType = Child,
-            segment = Dotted "store"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Dotted "books"
-          }, QuerySegment {
-            segmentType = Child,
-            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
-              singularQueryType = CurrentSQ,
-              singularQuerySegments = [NameSQSeg "is_available"]
-            }) Equal CompLitNull)]])]
-          }]
-        }
diff --git a/test/QuerySpec.hs b/test/QuerySpec.hs
deleted file mode 100644
--- a/test/QuerySpec.hs
+++ /dev/null
@@ -1,342 +0,0 @@
-module QuerySpec
-  ( spec )
-  where
-
-import qualified Data.Aeson        as JSON
-import qualified Data.Vector       as V
-
-import Data.Aeson.JSONPath  (queryQQ, jsonPath)
-import Data.Aeson.QQ.Simple (aesonQQ)
-import Data.Vector          (Vector)
-import Test.Hspec
-
-import Prelude
-
-getVector :: JSON.Value -> Vector JSON.Value
-getVector (JSON.Array arr) = arr
-getVector _ = V.empty
-
--- taken from https://serdejsonpath.live/
-rootDoc :: JSON.Value
-rootDoc = [aesonQQ|{
-    "store": {
-      "books": [
-        {
-          "title": "Guns, Germs, and Steel",
-          "author": "Jared Diamond",
-          "category": "reference",
-          "price": 24.99
-        },
-        {
-          "title": "David Copperfield",
-          "author": "Charles Dickens",
-          "category": "fiction",
-          "price": 12.99
-        },
-        {
-          "title": "Moby Dick",
-          "author": "Herman Melville",
-          "category": "fiction",
-          "price": 8.99
-        },
-        {
-          "title": "Crime and Punishment",
-          "author": "Fyodor Dostoevsky",
-          "category": "fiction",
-          "price": 19.99
-        }
-      ]
-    }
-  }|]
-
-
-storeDoc :: JSON.Value
-storeDoc = [aesonQQ|
-  {
-    "books": [
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Crime and Punishment",
-        "author": "Fyodor Dostoevsky",
-        "category": "fiction",
-        "price": 19.99
-      }
-    ]
-  }|]
-
-booksDoc :: JSON.Value
-booksDoc = [aesonQQ| [
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Crime and Punishment",
-        "author": "Fyodor Dostoevsky",
-        "category": "fiction",
-        "price": 19.99
-      }
-  ]|]
-
-
-books0Doc :: JSON.Value
-books0Doc = [aesonQQ|[
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      }
-  ]|]
-
-books0And2Doc :: JSON.Value
-books0And2Doc = [aesonQQ|[
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      }
-  ]|]
-
-books1To3Doc :: JSON.Value
-books1To3Doc = [aesonQQ|[
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      }
-  ]|]
-
-books1To3And0And1Doc :: JSON.Value
-books1To3And0And1Doc = [aesonQQ|[
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Guns, Germs, and Steel",
-        "author": "Jared Diamond",
-        "category": "reference",
-        "price": 24.99
-      },
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      }
-  ]|]
-
-lessThanPrice20Books :: JSON.Value
-lessThanPrice20Books = [aesonQQ| [
-      {
-        "title": "David Copperfield",
-        "author": "Charles Dickens",
-        "category": "fiction",
-        "price": 12.99
-      },
-      {
-        "title": "Moby Dick",
-        "author": "Herman Melville",
-        "category": "fiction",
-        "price": 8.99
-      },
-      {
-        "title": "Crime and Punishment",
-        "author": "Fyodor Dostoevsky",
-        "category": "fiction",
-        "price": 19.99
-      }
-  ]|]
-
-alphaArr :: JSON.Value
-alphaArr = [aesonQQ| ["a","b","c","d","e","f","g"] |]
-
-fgArr :: JSON.Value
-fgArr = [aesonQQ| ["f","g"] |]
-
-bdArr :: JSON.Value
-bdArr = [aesonQQ| ["b","d"] |]
-
-fdArr :: JSON.Value
-fdArr = [aesonQQ| ["f","d"] |]
-
-gfedcbaArr :: JSON.Value
-gfedcbaArr = [aesonQQ| ["g","f","e","d","c","b","a"] |]
-
-rfcExample1 :: JSON.Value
-rfcExample1 = [aesonQQ| {
-    "o": {"j": 1, "k": 2},
-    "a": [5, 3, [{"j": 4}, {"k": 6}]]
-  } |]
-
-rfcExample1Desc :: JSON.Value
-rfcExample1Desc = [aesonQQ| [
-    [5, 3, [{"j": 4}, {"k": 6}]],
-    {"j": 1, "k": 2},
-    5,
-    3,
-    [{"j": 4}, {"k": 6}],
-    {"j": 4},
-    {"k": 6},
-    4,
-    6,
-    1,
-    2
-  ]|]
-
-boolsAndNulls :: JSON.Value
-boolsAndNulls = [aesonQQ| [
-    { "a": true },
-    { "a": false },
-    { "a": null }
-  ]|]
-
-
-boolsAndNullsA :: JSON.Value
-boolsAndNullsA = [aesonQQ| [{ "a": true }] |]
-
-boolsAndNullsB :: JSON.Value
-boolsAndNullsB = [aesonQQ| [{ "a": false }] |]
-
-boolsAndNullsC :: JSON.Value
-boolsAndNullsC = [aesonQQ| [{ "a": null }] |]
-
-spec :: Spec
-spec = do
-  describe "test query" $ do
-    it "returns root document when query is $" $
-      queryQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton rootDoc
-
-    it "returns store object when queryQQ is $.store" $
-      queryQQ [jsonPath|$.store|] rootDoc `shouldBe` V.singleton storeDoc
-
-    it "returns store object when queryQQ is $['store']" $
-      queryQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.singleton storeDoc
-
-    it "returns books array when queryQQ is $.store.books" $
-      queryQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.singleton booksDoc
-
-    it "returns 0-index book item when queryQQ is $.store.books[0]" $
-      queryQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` getVector books0Doc
-
-    it "returns 0-index book item when queryQQ is $.store.books[-4]" $
-      queryQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` getVector books0Doc
-
-    it "returns 0,2-index item when queryQQ is $.store.books[0,2]" $
-      queryQQ [jsonPath|$.store.books[0,2]|] rootDoc `shouldBe` getVector books0And2Doc
-
-    it "returns 1To3-index when queryQQ is $.store.books[1:3]" $
-      queryQQ [jsonPath|$.store.books[1:3]|] rootDoc `shouldBe` getVector books1To3Doc
-
-    it "returns 1To3-index and 0,1-index when queryQQ is $.store.books[1:3,0,1]" $
-      queryQQ [jsonPath|$.store.books[1:3,0,1]|] rootDoc `shouldBe` getVector books1To3And0And1Doc
-
-    it "returns slice with queryQQ $[5:]" $
-      queryQQ [jsonPath|$[5:]|] alphaArr `shouldBe` getVector fgArr
-
-    it "returns slice with queryQQ $[1:5:2]" $
-      queryQQ [jsonPath|$[1:5:2]|] alphaArr `shouldBe` getVector bdArr
-
-    it "returns slice with queryQQ $[5:1:-2]" $
-      queryQQ [jsonPath|$[5:1:-2]|] alphaArr `shouldBe` getVector fdArr
-
-    it "returns slice with queryQQ $[::-1]" $
-      queryQQ [jsonPath|$[::-1]|] alphaArr `shouldBe` getVector gfedcbaArr
-
-    it "returns root with queryQQ $.*" $
-      queryQQ [jsonPath|$.*|] rootDoc `shouldBe` V.singleton storeDoc
-
-    it "returns root with queryQQ $[*]" $
-      queryQQ [jsonPath|$[*]|] rootDoc `shouldBe` V.singleton storeDoc
-
-    it "returns descendants with queryQQ $..*" $
-      queryQQ [jsonPath|$..*|] rfcExample1 `shouldBe` getVector rfcExample1Desc
-
-    it "returns descendants with queryQQ $..[*]" $
-      queryQQ [jsonPath|$..[*]|] rfcExample1 `shouldBe` getVector rfcExample1Desc
-
-    it "returns with filtering: number comparison" $
-      queryQQ [jsonPath|$.store.books[?@.price < 20]|] rootDoc
-      `shouldBe` getVector lessThanPrice20Books
-
-    it "returns with filtering: not operator" $
-      queryQQ [jsonPath|$.store.books[?!(@.price < 20)]|] rootDoc
-      `shouldBe` getVector books0Doc
-
-    it "returns with filtering: true value" $
-      queryQQ [jsonPath|$[?@.a == true]|] boolsAndNulls
-      `shouldBe` getVector boolsAndNullsA
-
-    it "returns with filtering: false value" $
-      queryQQ [jsonPath|$[?@.a == false]|] boolsAndNulls
-      `shouldBe` getVector boolsAndNullsB
-
-    it "returns with filtering: null value" $
-      queryQQ [jsonPath|$[?@.a == null]|] boolsAndNulls
-      `shouldBe` getVector boolsAndNullsC
-
-    it "returns with filtering: string comparison" $
-      queryQQ [jsonPath|$.store.books[?@.author == 'Jared Diamond']|] rootDoc
-      `shouldBe` getVector books0Doc
-
-    it "returns with filtering: test expression" $
-      queryQQ [jsonPath|$.store.books[?@.author]|] rootDoc
-      `shouldBe` getVector booksDoc
-
-    it "returns with filtering: test expr gives empty with non-existent key" $
-      queryQQ [jsonPath|$.store.books[?@.not_here]|] rootDoc
-      `shouldBe` V.empty
diff --git a/test/compliance/ComplianceSpec.hs b/test/compliance/ComplianceSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/compliance/ComplianceSpec.hs
@@ -0,0 +1,93 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NamedFieldPuns #-}
+module ComplianceSpec
+  ( spec
+  , TestSuite (..))
+  where
+
+import qualified Data.Aeson                    as JSON
+import qualified Data.Vector                   as V
+import qualified Text.ParserCombinators.Parsec as P
+
+import Control.Monad              (mzero)
+import Data.Aeson                 ((.:),(.:?),Value)
+import Data.Aeson.JSONPath        (query, queryLocated)
+import Data.Aeson.JSONPath.Parser (pQuery)
+import Data.Either                (isLeft, fromRight)
+import Data.Vector                (Vector)
+
+import Test.Hspec
+import Prelude
+
+newtype TestSuite = TestSuite
+  { tests :: [TestCase]
+  } deriving (Show)
+
+instance JSON.FromJSON TestSuite where
+  parseJSON (JSON.Object o) =
+    TestSuite
+    <$> o .: "tests"
+
+  parseJSON _ = mzero
+
+data TestCase = TestCase
+  { name         :: String
+  , selector     :: String
+  , document     :: Maybe Value
+  , result       :: Maybe (Vector Value)
+  , results      :: Maybe [Vector Value]
+  , resultPaths  :: Maybe (Vector String)
+  , resultsPaths :: Maybe [Vector String]
+  , invalidSel   :: Maybe Bool
+  , tags         :: Maybe [String]
+  } deriving (Show)
+
+instance JSON.FromJSON TestCase where
+  parseJSON (JSON.Object o) =
+    TestCase
+    <$> o .: "name"
+    <*> o .: "selector"
+    <*> o .:? "document"
+    <*> o .:? "result"
+    <*> o .:? "results"
+    <*> o .:? "result_paths"
+    <*> o .:? "results_paths"
+    <*> o .:? "invalid_selector"
+    <*> o .:? "tags"
+
+  parseJSON _ = mzero
+
+spec :: TestSuite -> Spec
+spec TestSuite{tests} = do
+  describe "compliance tests" $ do
+    mapM_ runTestCase tests
+
+
+runTestCase :: TestCase -> SpecWith ()
+-- skip function extension tests
+runTestCase tc@TestCase{tags=Just xs, ..} =
+  if "function" `elem` xs
+    then xit name pending
+  else
+    runTestCase tc{tags=Nothing}
+
+-- invalid selector should not parse correctly
+runTestCase TestCase{invalidSel=(Just True), ..} =
+  it name $
+    P.parse pQuery "" selector `shouldSatisfy` isLeft
+
+-- if result is deterministic (one json)
+runTestCase TestCase{result=(Just r), resultPaths=(Just rp), document=(Just doc), ..} =
+  it name $ do
+    query selector doc `shouldBe` Right r
+    queryLocated selector doc `shouldBe` Right (V.zip rp r)
+
+-- if result is non-deterministic (any json from the list of results)
+runTestCase TestCase{results=(Just rs), resultsPaths=(Just rsp), document=(Just doc), ..} = do
+  it name $ do
+    query selector doc `shouldSatisfy` (\x -> fromRight V.empty x `elem` rs)
+    queryLocated selector doc `shouldSatisfy` (\x -> fromRight V.empty x `elem` vecList)
+    where
+      vecList = [ V.zip rp r | rp <- rsp, r <- rs]
+
+runTestCase _ = pure ()
diff --git a/test/compliance/Main.hs b/test/compliance/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/compliance/Main.hs
@@ -0,0 +1,39 @@
+module Main
+  ( main )
+  where
+
+import qualified Data.Aeson         as JSON
+import qualified Test.Hspec         as HS
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.IO       as TIO
+
+import Data.Either                  (fromRight)
+
+import qualified ComplianceSpec
+import qualified Paths_aeson_jsonpath as Paths
+
+import ComplianceSpec   (TestSuite (..))
+
+import Test.Hspec.Runner
+import Prelude
+
+compliance :: Either String TestSuite -> Spec
+compliance cts = do
+  HS.describe "Run compliance tests" $
+    ComplianceSpec.spec (fromRight TestSuite{tests=[]} cts)
+
+readCtsFile :: FilePath -> IO (Either String TestSuite)
+readCtsFile filePath = do
+  contents <- TIO.readFile filePath
+  return $ JSON.eitherDecodeStrict' $ T.encodeUtf8 contents
+
+main :: IO ()
+main = do
+  file <- Paths.getDataFileName "jsonpath-compliance-test-suite/cts.json"
+  cts <- readCtsFile file
+  summary <- hspecWithResult defaultConfig 
+    { configColorMode = ColorAuto
+    } (compliance cts)
+  
+  putStrLn $ "Total tests: " ++ show (summaryExamples summary)
+  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
diff --git a/test/cts.json b/test/cts.json
deleted file mode 100644
--- a/test/cts.json
+++ /dev/null
@@ -1,10941 +0,0 @@
-{
-  "description": "JSONPath Compliance Test Suite. This file is autogenerated, do not edit.",
-  "tests": [
-    {
-      "name": "basic, root",
-      "selector": "$",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        [
-          "first",
-          "second"
-        ]
-      ]
-    },
-    {
-      "name": "basic, no leading whitespace",
-      "selector": " $",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "basic, no trailing whitespace",
-      "selector": "$ ",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "basic, name shorthand",
-      "selector": "$.a",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "basic, name shorthand, extended unicode ☺",
-      "selector": "$.☺",
-      "document": {
-        "☺": "A",
-        "b": "B"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "basic, name shorthand, underscore",
-      "selector": "$._",
-      "document": {
-        "_": "A",
-        "_foo": "B"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "basic, name shorthand, symbol",
-      "selector": "$.&",
-      "invalid_selector": true
-    },
-    {
-      "name": "basic, name shorthand, number",
-      "selector": "$.1",
-      "invalid_selector": true
-    },
-    {
-      "name": "basic, name shorthand, absent data",
-      "selector": "$.c",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": []
-    },
-    {
-      "name": "basic, name shorthand, array data",
-      "selector": "$.a",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": []
-    },
-    {
-      "name": "basic, wildcard shorthand, object data",
-      "selector": "$.*",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "results": [
-        [
-          "A",
-          "B"
-        ],
-        [
-          "B",
-          "A"
-        ]
-      ]
-    },
-    {
-      "name": "basic, wildcard shorthand, array data",
-      "selector": "$.*",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "first",
-        "second"
-      ]
-    },
-    {
-      "name": "basic, wildcard selector, array data",
-      "selector": "$[*]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "first",
-        "second"
-      ]
-    },
-    {
-      "name": "basic, wildcard shorthand, then name shorthand",
-      "selector": "$.*.a",
-      "document": {
-        "x": {
-          "a": "Ax",
-          "b": "Bx"
-        },
-        "y": {
-          "a": "Ay",
-          "b": "By"
-        }
-      },
-      "results": [
-        [
-          "Ax",
-          "Ay"
-        ],
-        [
-          "Ay",
-          "Ax"
-        ]
-      ]
-    },
-    {
-      "name": "basic, multiple selectors",
-      "selector": "$[0,2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        2
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, space instead of comma",
-      "selector": "$[0 2]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "basic, selector, leading comma",
-      "selector": "$[,0]",
-      "invalid_selector": true
-    },
-    {
-      "name": "basic, selector, trailing comma",
-      "selector": "$[0,]",
-      "invalid_selector": true
-    },
-    {
-      "name": "basic, multiple selectors, name and index, array data",
-      "selector": "$['a',1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, name and index, object data",
-      "selector": "$['a',1]",
-      "document": {
-        "a": 1,
-        "b": 2
-      },
-      "result": [
-        1
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, index and slice",
-      "selector": "$[1,5:7]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        5,
-        6
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, index and slice, overlapping",
-      "selector": "$[1,0:3]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        0,
-        1,
-        2
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, duplicate index",
-      "selector": "$[1,1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        1
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, wildcard and index",
-      "selector": "$[*,1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9,
-        1
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, wildcard and name",
-      "selector": "$[*,'a']",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "results": [
-        [
-          "A",
-          "B",
-          "A"
-        ],
-        [
-          "B",
-          "A",
-          "A"
-        ]
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, wildcard and slice",
-      "selector": "$[*,0:2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9,
-        0,
-        1
-      ]
-    },
-    {
-      "name": "basic, multiple selectors, multiple wildcards",
-      "selector": "$[*,*]",
-      "document": [
-        0,
-        1,
-        2
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        0,
-        1,
-        2
-      ]
-    },
-    {
-      "name": "basic, empty segment",
-      "selector": "$[]",
-      "invalid_selector": true
-    },
-    {
-      "name": "basic, descendant segment, index",
-      "selector": "$..[1]",
-      "document": {
-        "o": [
-          0,
-          1,
-          [
-            2,
-            3
-          ]
-        ]
-      },
-      "result": [
-        1,
-        3
-      ]
-    },
-    {
-      "name": "basic, descendant segment, name shorthand",
-      "selector": "$..a",
-      "document": {
-        "o": [
-          {
-            "a": "b"
-          },
-          {
-            "a": "c"
-          }
-        ]
-      },
-      "result": [
-        "b",
-        "c"
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard shorthand, array data",
-      "selector": "$..*",
-      "document": [
-        0,
-        1
-      ],
-      "result": [
-        0,
-        1
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard selector, array data",
-      "selector": "$..[*]",
-      "document": [
-        0,
-        1
-      ],
-      "result": [
-        0,
-        1
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard selector, nested arrays",
-      "selector": "$..[*]",
-      "document": [
-        [
-          [
-            1
-          ]
-        ],
-        [
-          2
-        ]
-      ],
-      "results": [
-        [
-          [
-            [
-              1
-            ]
-          ],
-          [
-            2
-          ],
-          [
-            1
-          ],
-          1,
-          2
-        ],
-        [
-          [
-            [
-              1
-            ]
-          ],
-          [
-            2
-          ],
-          [
-            1
-          ],
-          2,
-          1
-        ]
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard selector, nested objects",
-      "selector": "$..[*]",
-      "document": {
-        "a": {
-          "c": {
-            "e": 1
-          }
-        },
-        "b": {
-          "d": 2
-        }
-      },
-      "results": [
-        [
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          {
-            "d": 2
-          },
-          {
-            "e": 1
-          },
-          1,
-          2
-        ],
-        [
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          {
-            "d": 2
-          },
-          {
-            "e": 1
-          },
-          2,
-          1
-        ],
-        [
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          {
-            "d": 2
-          },
-          2,
-          {
-            "e": 1
-          },
-          1
-        ],
-        [
-          {
-            "d": 2
-          },
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          {
-            "e": 1
-          },
-          1,
-          2
-        ],
-        [
-          {
-            "d": 2
-          },
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          {
-            "e": 1
-          },
-          2,
-          1
-        ],
-        [
-          {
-            "d": 2
-          },
-          {
-            "c": {
-              "e": 1
-            }
-          },
-          2,
-          {
-            "e": 1
-          },
-          1
-        ]
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard shorthand, object data",
-      "selector": "$..*",
-      "document": {
-        "a": "b"
-      },
-      "result": [
-        "b"
-      ]
-    },
-    {
-      "name": "basic, descendant segment, wildcard shorthand, nested data",
-      "selector": "$..*",
-      "document": {
-        "o": [
-          {
-            "a": "b"
-          }
-        ]
-      },
-      "result": [
-        [
-          {
-            "a": "b"
-          }
-        ],
-        {
-          "a": "b"
-        },
-        "b"
-      ]
-    },
-    {
-      "name": "basic, descendant segment, multiple selectors",
-      "selector": "$..['a','d']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        "b",
-        "e",
-        "c",
-        "f"
-      ]
-    },
-    {
-      "name": "basic, descendant segment, object traversal, multiple selectors",
-      "selector": "$..['a','d']",
-      "document": {
-        "x": {
-          "a": "b",
-          "d": "e"
-        },
-        "y": {
-          "a": "c",
-          "d": "f"
-        }
-      },
-      "results": [
-        [
-          "b",
-          "e",
-          "c",
-          "f"
-        ],
-        [
-          "c",
-          "f",
-          "b",
-          "e"
-        ]
-      ]
-    },
-    {
-      "name": "basic, bald descendant segment",
-      "selector": "$..",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, existence, without segments",
-      "selector": "$[?@]",
-      "document": {
-        "a": 1,
-        "b": null
-      },
-      "results": [
-        [
-          1,
-          null
-        ],
-        [
-          null,
-          1
-        ]
-      ]
-    },
-    {
-      "name": "filter, existence",
-      "selector": "$[?@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, existence, present with null",
-      "selector": "$[?@.a]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": null,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, absolute existence, without segments",
-      "selector": "$[?$]",
-      "document": {
-        "a": 1,
-        "b": null
-      },
-      "results": [
-        [
-          1,
-          null
-        ],
-        [
-          null,
-          1
-        ]
-      ]
-    },
-    {
-      "name": "filter, absolute existence, with segments",
-      "selector": "$[?$.*.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals string, single quotes",
-      "selector": "$[?@.a=='b']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals numeric string, single quotes",
-      "selector": "$[?@.a=='1']",
-      "document": [
-        {
-          "a": "1",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "1",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals string, double quotes",
-      "selector": "$[?@.a==\"b\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals numeric string, double quotes",
-      "selector": "$[?@.a==\"1\"]",
-      "document": [
-        {
-          "a": "1",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "1",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number",
-      "selector": "$[?@.a==1]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals null",
-      "selector": "$[?@.a==null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": null,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals null, absent from data",
-      "selector": "$[?@.a==null]",
-      "document": [
-        {
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, equals true",
-      "selector": "$[?@.a==true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": true,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals false",
-      "selector": "$[?@.a==false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": false,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals self",
-      "selector": "$[?@==@]",
-      "document": [
-        1,
-        null,
-        true,
-        {
-          "a": "b"
-        },
-        [
-          false
-        ]
-      ],
-      "result": [
-        1,
-        null,
-        true,
-        {
-          "a": "b"
-        },
-        [
-          false
-        ]
-      ]
-    },
-    {
-      "name": "filter, absolute, equals self",
-      "selector": "$[?$==$]",
-      "document": [
-        1,
-        null,
-        true,
-        {
-          "a": "b"
-        },
-        [
-          false
-        ]
-      ],
-      "result": [
-        1,
-        null,
-        true,
-        {
-          "a": "b"
-        },
-        [
-          false
-        ]
-      ]
-    },
-    {
-      "name": "filter, deep equality, arrays",
-      "selector": "$[?@.a==@.b]",
-      "document": [
-        {
-          "a": false,
-          "b": [
-            1,
-            2
-          ]
-        },
-        {
-          "a": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ],
-          "b": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ]
-        },
-        {
-          "a": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ],
-          "b": [
-            [
-              [
-                2
-              ],
-              1
-            ]
-          ]
-        },
-        {
-          "a": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ],
-          "b": [
-            [
-              1,
-              2
-            ]
-          ]
-        }
-      ],
-      "result": [
-        {
-          "a": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ],
-          "b": [
-            [
-              1,
-              [
-                2
-              ]
-            ]
-          ]
-        }
-      ]
-    },
-    {
-      "name": "filter, deep equality, objects",
-      "selector": "$[?@.a==@.b]",
-      "document": [
-        {
-          "a": false,
-          "b": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          }
-        },
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          }
-        },
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "y": {
-              "z": 1
-            },
-            "x": 1
-          }
-        },
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "x": 1
-          }
-        },
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "x": 1,
-            "y": {
-              "z": 2
-            }
-          }
-        }
-      ],
-      "result": [
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          }
-        },
-        {
-          "a": {
-            "x": 1,
-            "y": {
-              "z": 1
-            }
-          },
-          "b": {
-            "y": {
-              "z": 1
-            },
-            "x": 1
-          }
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals string, single quotes",
-      "selector": "$[?@.a!='b']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals numeric string, single quotes",
-      "selector": "$[?@.a!='1']",
-      "document": [
-        {
-          "a": "1",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals string, single quotes, different type",
-      "selector": "$[?@.a!='b']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals string, double quotes",
-      "selector": "$[?@.a!=\"b\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals numeric string, double quotes",
-      "selector": "$[?@.a!=\"1\"]",
-      "document": [
-        {
-          "a": "1",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals string, double quotes, different types",
-      "selector": "$[?@.a!=\"b\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals number",
-      "selector": "$[?@.a!=1]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals number, different types",
-      "selector": "$[?@.a!=1]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals null",
-      "selector": "$[?@.a!=null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals null, absent from data",
-      "selector": "$[?@.a!=null]",
-      "document": [
-        {
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals true",
-      "selector": "$[?@.a!=true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not-equals false",
-      "selector": "$[?@.a!=false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than string, single quotes",
-      "selector": "$[?@.a<'c']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than string, double quotes",
-      "selector": "$[?@.a<\"c\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than number",
-      "selector": "$[?@.a<10]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 10,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than null",
-      "selector": "$[?@.a<null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, less than true",
-      "selector": "$[?@.a<true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, less than false",
-      "selector": "$[?@.a<false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, less than or equal to string, single quotes",
-      "selector": "$[?@.a<='c']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than or equal to string, double quotes",
-      "selector": "$[?@.a<=\"c\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than or equal to number",
-      "selector": "$[?@.a<=10]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 10,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 10,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than or equal to null",
-      "selector": "$[?@.a<=null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": null,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than or equal to true",
-      "selector": "$[?@.a<=true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": true,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, less than or equal to false",
-      "selector": "$[?@.a<=false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": false,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than string, single quotes",
-      "selector": "$[?@.a>'c']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than string, double quotes",
-      "selector": "$[?@.a>\"c\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than number",
-      "selector": "$[?@.a>10]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 10,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than null",
-      "selector": "$[?@.a>null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, greater than true",
-      "selector": "$[?@.a>true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, greater than false",
-      "selector": "$[?@.a>false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, greater than or equal to string, single quotes",
-      "selector": "$[?@.a>='c']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than or equal to string, double quotes",
-      "selector": "$[?@.a>=\"c\"]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than or equal to number",
-      "selector": "$[?@.a>=10]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 10,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 10,
-          "d": "e"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than or equal to null",
-      "selector": "$[?@.a>=null]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": null,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than or equal to true",
-      "selector": "$[?@.a>=true]",
-      "document": [
-        {
-          "a": true,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": true,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, greater than or equal to false",
-      "selector": "$[?@.a>=false]",
-      "document": [
-        {
-          "a": false,
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": false,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, exists and not-equals null, absent from data",
-      "selector": "$[?@.a&&@.a!=null]",
-      "document": [
-        {
-          "d": "e"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, exists and exists, data false",
-      "selector": "$[?@.a&&@.b]",
-      "document": [
-        {
-          "a": false,
-          "b": false
-        },
-        {
-          "b": false
-        },
-        {
-          "c": false
-        }
-      ],
-      "result": [
-        {
-          "a": false,
-          "b": false
-        }
-      ]
-    },
-    {
-      "name": "filter, exists or exists, data false",
-      "selector": "$[?@.a||@.b]",
-      "document": [
-        {
-          "a": false,
-          "b": false
-        },
-        {
-          "b": false
-        },
-        {
-          "c": false
-        }
-      ],
-      "result": [
-        {
-          "a": false,
-          "b": false
-        },
-        {
-          "b": false
-        }
-      ]
-    },
-    {
-      "name": "filter, and",
-      "selector": "$[?@.a>0&&@.a<10]",
-      "document": [
-        {
-          "a": -10,
-          "d": "e"
-        },
-        {
-          "a": 5,
-          "d": "f"
-        },
-        {
-          "a": 20,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": 5,
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, or",
-      "selector": "$[?@.a=='b'||@.a=='d']",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "c",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not expression",
-      "selector": "$[?!(@.a=='b')]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not exists",
-      "selector": "$[?!@.a]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, not exists, data null",
-      "selector": "$[?!@.a]",
-      "document": [
-        {
-          "a": null,
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, non-singular existence, wildcard",
-      "selector": "$[?@.*]",
-      "document": [
-        1,
-        [],
-        [
-          2
-        ],
-        {},
-        {
-          "a": 3
-        }
-      ],
-      "result": [
-        [
-          2
-        ],
-        {
-          "a": 3
-        }
-      ]
-    },
-    {
-      "name": "filter, non-singular existence, multiple",
-      "selector": "$[?@[0, 0, 'a']]",
-      "document": [
-        1,
-        [],
-        [
-          2
-        ],
-        [
-          2,
-          3
-        ],
-        {
-          "a": 3
-        },
-        {
-          "b": 4
-        },
-        {
-          "a": 3,
-          "b": 4
-        }
-      ],
-      "result": [
-        [
-          2
-        ],
-        [
-          2,
-          3
-        ],
-        {
-          "a": 3
-        },
-        {
-          "a": 3,
-          "b": 4
-        }
-      ]
-    },
-    {
-      "name": "filter, non-singular existence, slice",
-      "selector": "$[?@[0:2]]",
-      "document": [
-        1,
-        [],
-        [
-          2
-        ],
-        [
-          2,
-          3,
-          4
-        ],
-        {},
-        {
-          "a": 3
-        }
-      ],
-      "result": [
-        [
-          2
-        ],
-        [
-          2,
-          3,
-          4
-        ]
-      ]
-    },
-    {
-      "name": "filter, non-singular existence, negated",
-      "selector": "$[?!@.*]",
-      "document": [
-        1,
-        [],
-        [
-          2
-        ],
-        {},
-        {
-          "a": 3
-        }
-      ],
-      "result": [
-        1,
-        [],
-        {}
-      ]
-    },
-    {
-      "name": "filter, non-singular query in comparison, slice",
-      "selector": "$[?@[0:0]==0]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, non-singular query in comparison, all children",
-      "selector": "$[?@[*]==0]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, non-singular query in comparison, descendants",
-      "selector": "$[?@..a==0]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, non-singular query in comparison, combined",
-      "selector": "$[?@.a[*].a==0]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, nested",
-      "selector": "$[?@[?@>1]]",
-      "document": [
-        [
-          0
-        ],
-        [
-          0,
-          1
-        ],
-        [
-          0,
-          1,
-          2
-        ],
-        [
-          42
-        ]
-      ],
-      "result": [
-        [
-          0,
-          1,
-          2
-        ],
-        [
-          42
-        ]
-      ]
-    },
-    {
-      "name": "filter, name segment on primitive, selects nothing",
-      "selector": "$[?@.a == 1]",
-      "document": {
-        "a": 1
-      },
-      "result": []
-    },
-    {
-      "name": "filter, name segment on array, selects nothing",
-      "selector": "$[?@['0'] == 5]",
-      "document": [
-        [
-          5,
-          6
-        ]
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, index segment on object, selects nothing",
-      "selector": "$[?@[0] == 5]",
-      "document": [
-        {
-          "0": 5
-        }
-      ],
-      "result": []
-    },
-    {
-      "name": "filter, relative non-singular query, index, equal",
-      "selector": "$[?(@[0, 0]==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, index, not equal",
-      "selector": "$[?(@[0, 0]!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, index, less-or-equal",
-      "selector": "$[?(@[0, 0]<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, name, equal",
-      "selector": "$[?(@['a', 'a']==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, name, not equal",
-      "selector": "$[?(@['a', 'a']!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, name, less-or-equal",
-      "selector": "$[?(@['a', 'a']<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, combined, equal",
-      "selector": "$[?(@[0, '0']==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, combined, not equal",
-      "selector": "$[?(@[0, '0']!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, combined, less-or-equal",
-      "selector": "$[?(@[0, '0']<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, relative non-singular query, wildcard, equal",
-      "selector": "$[?(@.*==42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, relative non-singular query, wildcard, not equal",
-      "selector": "$[?(@.*!=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, relative non-singular query, wildcard, less-or-equal",
-      "selector": "$[?(@.*<=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, relative non-singular query, slice, equal",
-      "selector": "$[?(@[0:0]==42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, relative non-singular query, slice, not equal",
-      "selector": "$[?(@[0:0]!=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, relative non-singular query, slice, less-or-equal",
-      "selector": "$[?(@[0:0]<=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, index, equal",
-      "selector": "$[?($[0, 0]==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, index, not equal",
-      "selector": "$[?($[0, 0]!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, index, less-or-equal",
-      "selector": "$[?($[0, 0]<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, name, equal",
-      "selector": "$[?($['a', 'a']==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, name, not equal",
-      "selector": "$[?($['a', 'a']!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, name, less-or-equal",
-      "selector": "$[?($['a', 'a']<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, combined, equal",
-      "selector": "$[?($[0, '0']==42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, combined, not equal",
-      "selector": "$[?($[0, '0']!=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, combined, less-or-equal",
-      "selector": "$[?($[0, '0']<=42)]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, absolute non-singular query, wildcard, equal",
-      "selector": "$[?($.*==42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, wildcard, not equal",
-      "selector": "$[?($.*!=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, wildcard, less-or-equal",
-      "selector": "$[?($.*<=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, slice, equal",
-      "selector": "$[?($[0:0]==42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, slice, not equal",
-      "selector": "$[?($[0:0]!=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, absolute non-singular query, slice, less-or-equal",
-      "selector": "$[?($[0:0]<=42)]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, multiple selectors",
-      "selector": "$[?@.a,?@.b]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, comparison",
-      "selector": "$[?@.a=='b',?@.b=='x']",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, overlapping",
-      "selector": "$[?@.a,?@.d]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, filter and index",
-      "selector": "$[?@.a,1]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, filter and wildcard",
-      "selector": "$[?@.a,*]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, filter and slice",
-      "selector": "$[?@.a,1:]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        },
-        {
-          "g": "h"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        },
-        {
-          "g": "h"
-        }
-      ]
-    },
-    {
-      "name": "filter, multiple selectors, comparison filter, index and slice",
-      "selector": "$[1, ?@.a=='b', 1:]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "b": "c",
-          "d": "f"
-        },
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, equals number, zero and negative zero",
-      "selector": "$[?@.a==0]",
-      "document": [
-        {
-          "a": 0,
-          "d": "e"
-        },
-        {
-          "a": 0.1,
-          "d": "f"
-        },
-        {
-          "a": "0",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 0,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, negative zero and zero",
-      "selector": "$[?@.a==-0]",
-      "document": [
-        {
-          "a": 0,
-          "d": "e"
-        },
-        {
-          "a": 0.1,
-          "d": "f"
-        },
-        {
-          "a": "0",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 0,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, with and without decimal fraction",
-      "selector": "$[?@.a==1.0]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent",
-      "selector": "$[?@.a==1e2]",
-      "document": [
-        {
-          "a": 100,
-          "d": "e"
-        },
-        {
-          "a": 100.1,
-          "d": "f"
-        },
-        {
-          "a": "100",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 100,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent upper e",
-      "selector": "$[?@.a==1E2]",
-      "document": [
-        {
-          "a": 100,
-          "d": "e"
-        },
-        {
-          "a": 100.1,
-          "d": "f"
-        },
-        {
-          "a": "100",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 100,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, positive exponent",
-      "selector": "$[?@.a==1e+2]",
-      "document": [
-        {
-          "a": 100,
-          "d": "e"
-        },
-        {
-          "a": 100.1,
-          "d": "f"
-        },
-        {
-          "a": "100",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 100,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, negative exponent",
-      "selector": "$[?@.a==1e-2]",
-      "document": [
-        {
-          "a": 0.01,
-          "d": "e"
-        },
-        {
-          "a": 0.02,
-          "d": "f"
-        },
-        {
-          "a": "0.01",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 0.01,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent 0",
-      "selector": "$[?@.a==1e0]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent -0",
-      "selector": "$[?@.a==1e-0]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent +0",
-      "selector": "$[?@.a==1e+0]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent leading -0",
-      "selector": "$[?@.a==1e-02]",
-      "document": [
-        {
-          "a": 0.01,
-          "d": "e"
-        },
-        {
-          "a": 0.02,
-          "d": "f"
-        },
-        {
-          "a": "0.01",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 0.01,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, exponent +00",
-      "selector": "$[?@.a==1e+00]",
-      "document": [
-        {
-          "a": 1,
-          "d": "e"
-        },
-        {
-          "a": 2,
-          "d": "f"
-        },
-        {
-          "a": "1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, decimal fraction",
-      "selector": "$[?@.a==1.1]",
-      "document": [
-        {
-          "a": 1.1,
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        },
-        {
-          "a": "1.1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1.1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, decimal fraction, trailing 0",
-      "selector": "$[?@.a==1.10]",
-      "document": [
-        {
-          "a": 1.1,
-          "d": "e"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        },
-        {
-          "a": "1.1",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 1.1,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, decimal fraction, exponent",
-      "selector": "$[?@.a==1.1e2]",
-      "document": [
-        {
-          "a": 110,
-          "d": "e"
-        },
-        {
-          "a": 110.1,
-          "d": "f"
-        },
-        {
-          "a": "110",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 110,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, decimal fraction, positive exponent",
-      "selector": "$[?@.a==1.1e+2]",
-      "document": [
-        {
-          "a": 110,
-          "d": "e"
-        },
-        {
-          "a": 110.1,
-          "d": "f"
-        },
-        {
-          "a": "110",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 110,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, decimal fraction, negative exponent",
-      "selector": "$[?@.a==1.1e-2]",
-      "document": [
-        {
-          "a": 0.011,
-          "d": "e"
-        },
-        {
-          "a": 0.012,
-          "d": "f"
-        },
-        {
-          "a": "0.011",
-          "d": "g"
-        }
-      ],
-      "result": [
-        {
-          "a": 0.011,
-          "d": "e"
-        }
-      ]
-    },
-    {
-      "name": "filter, equals number, invalid plus",
-      "selector": "$[?@.a==+1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid minus space",
-      "selector": "$[?@.a==- 1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid double minus",
-      "selector": "$[?@.a==--1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid no int digit",
-      "selector": "$[?@.a==.1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid minus no int digit",
-      "selector": "$[?@.a==-.1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid 00",
-      "selector": "$[?@.a==00]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid leading 0",
-      "selector": "$[?@.a==01]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid no fractional digit",
-      "selector": "$[?@.a==1.]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid middle minus",
-      "selector": "$[?@.a==1.-1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid no fractional digit e",
-      "selector": "$[?@.a==1.e1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid no e digit",
-      "selector": "$[?@.a==1e]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid no e digit minus",
-      "selector": "$[?@.a==1e-]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid double e",
-      "selector": "$[?@.a==1eE1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid e digit double minus",
-      "selector": "$[?@.a==1e--1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid e digit plus minus",
-      "selector": "$[?@.a==1e+-1]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid e decimal",
-      "selector": "$[?@.a==1e2.3]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals number, invalid multi e",
-      "selector": "$[?@.a==1e2e3]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, equals, special nothing",
-      "selector": "$.values[?length(@.a) == value($..c)]",
-      "document": {
-        "c": "cd",
-        "values": [
-          {
-            "a": "ab"
-          },
-          {
-            "c": "d"
-          },
-          {
-            "a": null
-          }
-        ]
-      },
-      "result": [
-        {
-          "c": "d"
-        },
-        {
-          "a": null
-        }
-      ],
-      "tags": [
-        "function"
-      ]
-    },
-    {
-      "name": "filter, equals, empty node list and empty node list",
-      "selector": "$[?@.a == @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "c": 3
-        }
-      ]
-    },
-    {
-      "name": "filter, equals, empty node list and special nothing",
-      "selector": "$[?@.a == length(@.b)]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "tags": [
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, object data",
-      "selector": "$[?@<3]",
-      "document": {
-        "a": 1,
-        "b": 2,
-        "c": 3
-      },
-      "results": [
-        [
-          1,
-          2
-        ],
-        [
-          2,
-          1
-        ]
-      ]
-    },
-    {
-      "name": "filter, and binds more tightly than or",
-      "selector": "$[?@.a || @.b && @.c]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2,
-          "c": 3
-        },
-        {
-          "c": 3
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2,
-          "c": 3
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, left to right evaluation",
-      "selector": "$[?@.a && @.b || @.c]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 1,
-          "c": 3
-        },
-        {
-          "b": 1,
-          "c": 3
-        },
-        {
-          "c": 3
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 1,
-          "c": 3
-        },
-        {
-          "b": 1,
-          "c": 3
-        },
-        {
-          "c": 3
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, group terms, left",
-      "selector": "$[?(@.a || @.b) && @.c]",
-      "document": [
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 1,
-          "c": 3
-        },
-        {
-          "b": 2,
-          "c": 3
-        },
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "c": 3
-        },
-        {
-          "b": 2,
-          "c": 3
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, group terms, right",
-      "selector": "$[?@.a && (@.b || @.c)]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 1,
-          "c": 2
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 2
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 1,
-          "c": 2
-        },
-        {
-          "a": 1,
-          "b": 2,
-          "c": 3
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, string literal, single quote in double quotes",
-      "selector": "$[?@ == \"quoted' literal\"]",
-      "document": [
-        "quoted' literal",
-        "a",
-        "quoted\\' literal"
-      ],
-      "result": [
-        "quoted' literal"
-      ]
-    },
-    {
-      "name": "filter, string literal, double quote in single quotes",
-      "selector": "$[?@ == 'quoted\" literal']",
-      "document": [
-        "quoted\" literal",
-        "a",
-        "quoted\\\" literal",
-        "'quoted\" literal'"
-      ],
-      "result": [
-        "quoted\" literal"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, string literal, escaped single quote in single quotes",
-      "selector": "$[?@ == 'quoted\\' literal']",
-      "document": [
-        "quoted' literal",
-        "a",
-        "quoted\\' literal",
-        "'quoted\" literal'"
-      ],
-      "result": [
-        "quoted' literal"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, string literal, escaped double quote in double quotes",
-      "selector": "$[?@ == \"quoted\\\" literal\"]",
-      "document": [
-        "quoted\" literal",
-        "a",
-        "quoted\\\" literal",
-        "'quoted\" literal'"
-      ],
-      "result": [
-        "quoted\" literal"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, literal true must be compared",
-      "selector": "$[?true]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, literal false must be compared",
-      "selector": "$[?false]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, literal string must be compared",
-      "selector": "$[?'abc']",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, literal int must be compared",
-      "selector": "$[?2]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, literal float must be compared",
-      "selector": "$[?2.2]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, literal null must be compared",
-      "selector": "$[?null]",
-      "invalid_selector": true
-    },
-    {
-      "name": "filter, and, literals must be compared",
-      "selector": "$[?true && false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, or, literals must be compared",
-      "selector": "$[?true || false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, and, right hand literal must be compared",
-      "selector": "$[?true == false && false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, or, right hand literal must be compared",
-      "selector": "$[?true == false || false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, and, left hand literal must be compared",
-      "selector": "$[?false && true == false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, or, left hand literal must be compared",
-      "selector": "$[?false || true == false]",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "filter, true, incorrectly capitalized",
-      "selector": "$[?@==True]",
-      "invalid_selector": true,
-      "tags": [
-        "case"
-      ]
-    },
-    {
-      "name": "filter, false, incorrectly capitalized",
-      "selector": "$[?@==False]",
-      "invalid_selector": true,
-      "tags": [
-        "case"
-      ]
-    },
-    {
-      "name": "filter, null, incorrectly capitalized",
-      "selector": "$[?@==Null]",
-      "invalid_selector": true,
-      "tags": [
-        "case"
-      ]
-    },
-    {
-      "name": "index selector, first element",
-      "selector": "$[0]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "first"
-      ],
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, second element",
-      "selector": "$[1]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "second"
-      ],
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, out of bound",
-      "selector": "$[2]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [],
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, min exact index",
-      "selector": "$[-9007199254740991]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [],
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, max exact index",
-      "selector": "$[9007199254740991]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [],
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, min exact index - 1",
-      "selector": "$[-9007199254740992]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, max exact index + 1",
-      "selector": "$[9007199254740992]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, overflowing index",
-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, not actually an index, overflowing index leads into general text",
-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168SomeRandomText]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, negative",
-      "selector": "$[-1]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "second"
-      ],
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, more negative",
-      "selector": "$[-2]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [
-        "first"
-      ],
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, negative out of bound",
-      "selector": "$[-3]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": [],
-      "tags": [
-        "boundary",
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, on object",
-      "selector": "$[0]",
-      "document": {
-        "foo": 1
-      },
-      "result": [],
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, leading 0",
-      "selector": "$[01]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, decimal",
-      "selector": "$[1.0]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, plus",
-      "selector": "$[+1]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, minus space",
-      "selector": "$[- 1]",
-      "invalid_selector": true,
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "index selector, -0",
-      "selector": "$[-0]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "index selector, leading -0",
-      "selector": "$[-01]",
-      "invalid_selector": true,
-      "tags": [
-        "index"
-      ]
-    },
-    {
-      "name": "name selector, double quotes",
-      "selector": "$[\"a\"]",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, absent data",
-      "selector": "$[\"c\"]",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": []
-    },
-    {
-      "name": "name selector, double quotes, array data",
-      "selector": "$[\"a\"]",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": []
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0000",
-      "selector": "$[\"\u0000\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0001",
-      "selector": "$[\"\u0001\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0002",
-      "selector": "$[\"\u0002\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0003",
-      "selector": "$[\"\u0003\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0004",
-      "selector": "$[\"\u0004\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0005",
-      "selector": "$[\"\u0005\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0006",
-      "selector": "$[\"\u0006\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0007",
-      "selector": "$[\"\u0007\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0008",
-      "selector": "$[\"\b\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0009",
-      "selector": "$[\"\t\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000A",
-      "selector": "$[\"\n\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000B",
-      "selector": "$[\"\u000b\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000C",
-      "selector": "$[\"\f\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000D",
-      "selector": "$[\"\r\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000E",
-      "selector": "$[\"\u000e\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+000F",
-      "selector": "$[\"\u000f\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0010",
-      "selector": "$[\"\u0010\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0011",
-      "selector": "$[\"\u0011\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0012",
-      "selector": "$[\"\u0012\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0013",
-      "selector": "$[\"\u0013\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0014",
-      "selector": "$[\"\u0014\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0015",
-      "selector": "$[\"\u0015\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0016",
-      "selector": "$[\"\u0016\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0017",
-      "selector": "$[\"\u0017\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0018",
-      "selector": "$[\"\u0018\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0019",
-      "selector": "$[\"\u0019\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001A",
-      "selector": "$[\"\u001a\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001B",
-      "selector": "$[\"\u001b\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001C",
-      "selector": "$[\"\u001c\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001D",
-      "selector": "$[\"\u001d\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001E",
-      "selector": "$[\"\u001e\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+001F",
-      "selector": "$[\"\u001f\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+0020",
-      "selector": "$[\" \"]",
-      "document": {
-        " ": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, embedded U+007F",
-      "selector": "$[\"\"]",
-      "document": {
-        "": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, supplementary plane character",
-      "selector": "$[\"𝄞\"]",
-      "document": {
-        "𝄞": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped double quote",
-      "selector": "$[\"\\\"\"]",
-      "document": {
-        "\"": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped reverse solidus",
-      "selector": "$[\"\\\\\"]",
-      "document": {
-        "\\": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped solidus",
-      "selector": "$[\"\\/\"]",
-      "document": {
-        "/": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped backspace",
-      "selector": "$[\"\\b\"]",
-      "document": {
-        "\b": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped form feed",
-      "selector": "$[\"\\f\"]",
-      "document": {
-        "\f": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped line feed",
-      "selector": "$[\"\\n\"]",
-      "document": {
-        "\n": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped carriage return",
-      "selector": "$[\"\\r\"]",
-      "document": {
-        "\r": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped tab",
-      "selector": "$[\"\\t\"]",
-      "document": {
-        "\t": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped ☺, upper case hex",
-      "selector": "$[\"\\u263A\"]",
-      "document": {
-        "☺": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, escaped ☺, lower case hex",
-      "selector": "$[\"\\u263a\"]",
-      "document": {
-        "☺": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, surrogate pair 𝄞",
-      "selector": "$[\"\\uD834\\uDD1E\"]",
-      "document": {
-        "𝄞": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, surrogate pair 😀",
-      "selector": "$[\"\\uD83D\\uDE00\"]",
-      "document": {
-        "😀": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, before high surrogates",
-      "selector": "$[\"\\uD7FF\\uD7FF\"]",
-      "document": {
-        "퟿퟿": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, after low surrogates",
-      "selector": "$[\"\\uE000\\uE000\"]",
-      "document": {
-        "": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, invalid escaped single quote",
-      "selector": "$[\"\\'\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, embedded double quote",
-      "selector": "$[\"\"\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, incomplete escape",
-      "selector": "$[\"\\\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, escape at end of line",
-      "selector": "$[\"\\\n\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, question mark escape",
-      "selector": "$[\"\\?\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, bell escape",
-      "selector": "$[\"\\a\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, vertical tab escape",
-      "selector": "$[\"\\v\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, 0 escape",
-      "selector": "$[\"\\0\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, x escape",
-      "selector": "$[\"\\x12\"]",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, n escape",
-      "selector": "$[\"\\N{LATIN CAPITAL LETTER A}\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape no hex",
-      "selector": "$[\"\\u\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape too few hex",
-      "selector": "$[\"\\u123\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape upper u",
-      "selector": "$[\"\\U1234\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape upper u long",
-      "selector": "$[\"\\U0010FFFF\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape plus",
-      "selector": "$[\"\\u+1234\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape brackets",
-      "selector": "$[\"\\u{1234}\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, unicode escape brackets long",
-      "selector": "$[\"\\u{10ffff}\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, single high surrogate",
-      "selector": "$[\"\\uD800\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, single low surrogate",
-      "selector": "$[\"\\uDC00\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, high high surrogate",
-      "selector": "$[\"\\uD800\\uD800\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, low low surrogate",
-      "selector": "$[\"\\uDC00\\uDC00\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, surrogate non-surrogate",
-      "selector": "$[\"\\uD800\\u1234\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, non-surrogate surrogate",
-      "selector": "$[\"\\u1234\\uDC00\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, surrogate supplementary",
-      "selector": "$[\"\\uD800𝄞\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, supplementary surrogate",
-      "selector": "$[\"𝄞\\uDC00\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, double quotes, surrogate incomplete low",
-      "selector": "$[\"\\uD800\\uDC0\"]",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes",
-      "selector": "$['a']",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, absent data",
-      "selector": "$['c']",
-      "document": {
-        "a": "A",
-        "b": "B"
-      },
-      "result": []
-    },
-    {
-      "name": "name selector, single quotes, array data",
-      "selector": "$['a']",
-      "document": [
-        "first",
-        "second"
-      ],
-      "result": []
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0000",
-      "selector": "$['\u0000']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0001",
-      "selector": "$['\u0001']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0002",
-      "selector": "$['\u0002']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0003",
-      "selector": "$['\u0003']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0004",
-      "selector": "$['\u0004']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0005",
-      "selector": "$['\u0005']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0006",
-      "selector": "$['\u0006']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0007",
-      "selector": "$['\u0007']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0008",
-      "selector": "$['\b']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0009",
-      "selector": "$['\t']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000A",
-      "selector": "$['\n']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000B",
-      "selector": "$['\u000b']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000C",
-      "selector": "$['\f']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000D",
-      "selector": "$['\r']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000E",
-      "selector": "$['\u000e']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+000F",
-      "selector": "$['\u000f']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0010",
-      "selector": "$['\u0010']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0011",
-      "selector": "$['\u0011']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0012",
-      "selector": "$['\u0012']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0013",
-      "selector": "$['\u0013']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0014",
-      "selector": "$['\u0014']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0015",
-      "selector": "$['\u0015']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0016",
-      "selector": "$['\u0016']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0017",
-      "selector": "$['\u0017']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0018",
-      "selector": "$['\u0018']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0019",
-      "selector": "$['\u0019']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001A",
-      "selector": "$['\u001a']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001B",
-      "selector": "$['\u001b']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001C",
-      "selector": "$['\u001c']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001D",
-      "selector": "$['\u001d']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001E",
-      "selector": "$['\u001e']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+001F",
-      "selector": "$['\u001f']",
-      "invalid_selector": true,
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, embedded U+0020",
-      "selector": "$[' ']",
-      "document": {
-        " ": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped single quote",
-      "selector": "$['\\'']",
-      "document": {
-        "'": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped reverse solidus",
-      "selector": "$['\\\\']",
-      "document": {
-        "\\": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped solidus",
-      "selector": "$['\\/']",
-      "document": {
-        "/": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped backspace",
-      "selector": "$['\\b']",
-      "document": {
-        "\b": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped form feed",
-      "selector": "$['\\f']",
-      "document": {
-        "\f": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped line feed",
-      "selector": "$['\\n']",
-      "document": {
-        "\n": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped carriage return",
-      "selector": "$['\\r']",
-      "document": {
-        "\r": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped tab",
-      "selector": "$['\\t']",
-      "document": {
-        "\t": "A"
-      },
-      "result": [
-        "A"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped ☺, upper case hex",
-      "selector": "$['\\u263A']",
-      "document": {
-        "☺": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, escaped ☺, lower case hex",
-      "selector": "$['\\u263a']",
-      "document": {
-        "☺": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, surrogate pair 𝄞",
-      "selector": "$['\\uD834\\uDD1E']",
-      "document": {
-        "𝄞": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, surrogate pair 😀",
-      "selector": "$['\\uD83D\\uDE00']",
-      "document": {
-        "😀": "A"
-      },
-      "result": [
-        "A"
-      ],
-      "tags": [
-        "unicode"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, invalid escaped double quote",
-      "selector": "$['\\\"']",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, single quotes, embedded single quote",
-      "selector": "$[''']",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, single quotes, incomplete escape",
-      "selector": "$['\\']",
-      "invalid_selector": true
-    },
-    {
-      "name": "name selector, double quotes, empty",
-      "selector": "$[\"\"]",
-      "document": {
-        "a": "A",
-        "b": "B",
-        "": "C"
-      },
-      "result": [
-        "C"
-      ]
-    },
-    {
-      "name": "name selector, single quotes, empty",
-      "selector": "$['']",
-      "document": {
-        "a": "A",
-        "b": "B",
-        "": "C"
-      },
-      "result": [
-        "C"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector",
-      "selector": "$[1:3]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        2
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with step",
-      "selector": "$[1:6:2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        3,
-        5
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with everything omitted, short form",
-      "selector": "$[:]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with everything omitted, long form",
-      "selector": "$[::]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with start omitted",
-      "selector": "$[:2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        1
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with start and end omitted",
-      "selector": "$[::2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        2,
-        4,
-        6,
-        8
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative step with default start and end",
-      "selector": "$[::-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        3,
-        2,
-        1,
-        0
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative step with default start",
-      "selector": "$[:0:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        3,
-        2,
-        1
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative step with default end",
-      "selector": "$[2::-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        2,
-        1,
-        0
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, larger negative step",
-      "selector": "$[::-2]",
-      "document": [
-        0,
-        1,
-        2,
-        3
-      ],
-      "result": [
-        3,
-        1
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative range with default step",
-      "selector": "$[-1:-3]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative range with negative step",
-      "selector": "$[-1:-3:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        8
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative range with larger negative step",
-      "selector": "$[-1:-6:-2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        7,
-        5
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, larger negative range with larger negative step",
-      "selector": "$[-1:-7:-2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        7,
-        5
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative from, positive to",
-      "selector": "$[-5:7]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        5,
-        6
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative from",
-      "selector": "$[-2:]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        8,
-        9
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, positive from, negative to",
-      "selector": "$[1:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative from, positive to, negative step",
-      "selector": "$[-1:1:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        8,
-        7,
-        6,
-        5,
-        4,
-        3,
-        2
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, positive from, negative to, negative step",
-      "selector": "$[7:-5:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        7,
-        6
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, too many colons",
-      "selector": "$[1:2:3:4]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, non-integer array index",
-      "selector": "$[1:2:a]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, zero step",
-      "selector": "$[1:2:0]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, empty range",
-      "selector": "$[2:2]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, slice selector with everything omitted with empty array",
-      "selector": "$[:]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, negative step with empty array",
-      "selector": "$[::-1]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, maximal range with positive step",
-      "selector": "$[0:10]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, maximal range with negative step",
-      "selector": "$[9:0:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        8,
-        7,
-        6,
-        5,
-        4,
-        3,
-        2,
-        1
-      ],
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively large to value",
-      "selector": "$[2:113667776004]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively small from value",
-      "selector": "$[-113667776004:1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        0
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively large from value with negative step",
-      "selector": "$[113667776004:0:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9,
-        8,
-        7,
-        6,
-        5,
-        4,
-        3,
-        2,
-        1
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively small to value with negative step",
-      "selector": "$[3:-113667776004:-1]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        3,
-        2,
-        1,
-        0
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively large step",
-      "selector": "$[1:10:113667776004]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        1
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, excessively small step",
-      "selector": "$[-1:-10:-113667776004]",
-      "document": [
-        0,
-        1,
-        2,
-        3,
-        4,
-        5,
-        6,
-        7,
-        8,
-        9
-      ],
-      "result": [
-        9
-      ],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, min exact",
-      "selector": "$[-9007199254740991::]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, max exact",
-      "selector": "$[9007199254740991::]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, min exact - 1",
-      "selector": "$[-9007199254740992::]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, max exact + 1",
-      "selector": "$[9007199254740992::]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, min exact",
-      "selector": "$[:-9007199254740991:]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, max exact",
-      "selector": "$[:9007199254740991:]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, min exact - 1",
-      "selector": "$[:-9007199254740992:]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, max exact + 1",
-      "selector": "$[:9007199254740992:]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, min exact",
-      "selector": "$[::-9007199254740991]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, max exact",
-      "selector": "$[::9007199254740991]",
-      "document": [],
-      "result": [],
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, min exact - 1",
-      "selector": "$[::-9007199254740992]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, max exact + 1",
-      "selector": "$[::9007199254740992]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, overflowing to value",
-      "selector": "$[2:231584178474632390847141970017375815706539969331281128078915168015826259279872]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, underflowing from value",
-      "selector": "$[-231584178474632390847141970017375815706539969331281128078915168015826259279872:1]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, overflowing from value with negative step",
-      "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872:0:-1]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, underflowing to value with negative step",
-      "selector": "$[3:-231584178474632390847141970017375815706539969331281128078915168015826259279872:-1]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, overflowing step",
-      "selector": "$[1:10:231584178474632390847141970017375815706539969331281128078915168015826259279872]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, underflowing step",
-      "selector": "$[-1:-10:-231584178474632390847141970017375815706539969331281128078915168015826259279872]",
-      "invalid_selector": true,
-      "tags": [
-        "boundary",
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, leading 0",
-      "selector": "$[01::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, decimal",
-      "selector": "$[1.0::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, plus",
-      "selector": "$[+1::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, minus space",
-      "selector": "$[- 1::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, -0",
-      "selector": "$[-0::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, start, leading -0",
-      "selector": "$[-01::]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, leading 0",
-      "selector": "$[:01:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, decimal",
-      "selector": "$[:1.0:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, plus",
-      "selector": "$[:+1:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, minus space",
-      "selector": "$[:- 1:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, -0",
-      "selector": "$[:-0:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, end, leading -0",
-      "selector": "$[:-01:]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, leading 0",
-      "selector": "$[::01]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, decimal",
-      "selector": "$[::1.0]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, plus",
-      "selector": "$[::+1]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, minus space",
-      "selector": "$[::- 1]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, -0",
-      "selector": "$[::-0]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "slice selector, step, leading -0",
-      "selector": "$[::-01]",
-      "invalid_selector": true,
-      "tags": [
-        "slice"
-      ]
-    },
-    {
-      "name": "functions, count, count function",
-      "selector": "$[?count(@..*)>2]",
-      "document": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        },
-        {
-          "a": [
-            1
-          ],
-          "d": "f"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        },
-        {
-          "a": [
-            1
-          ],
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, single-node arg",
-      "selector": "$[?count(@.a)>1]",
-      "document": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        },
-        {
-          "a": [
-            1
-          ],
-          "d": "f"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, multiple-selector arg",
-      "selector": "$[?count(@['a','d'])>1]",
-      "document": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        },
-        {
-          "a": [
-            1
-          ],
-          "d": "f"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": [
-            1
-          ],
-          "d": "f"
-        },
-        {
-          "a": 1,
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, non-query arg, number",
-      "selector": "$[?count(1)>2]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, non-query arg, string",
-      "selector": "$[?count('string')>2]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, non-query arg, true",
-      "selector": "$[?count(true)>2]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, non-query arg, false",
-      "selector": "$[?count(false)>2]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, non-query arg, null",
-      "selector": "$[?count(null)>2]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, result must be compared",
-      "selector": "$[?count(@..*)]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, no params",
-      "selector": "$[?count()==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, count, too many params",
-      "selector": "$[?count(@.a,@.b)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function"
-      ]
-    },
-    {
-      "name": "functions, length, string data",
-      "selector": "$[?length(@.a)>=2]",
-      "document": [
-        {
-          "a": "ab"
-        },
-        {
-          "a": "d"
-        }
-      ],
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, string data, unicode",
-      "selector": "$[?length(@)==2]",
-      "document": [
-        "☺",
-        "☺☺",
-        "☺☺☺",
-        "ж",
-        "жж",
-        "жжж",
-        "磨",
-        "阿美",
-        "形声字"
-      ],
-      "result": [
-        "☺☺",
-        "жж",
-        "阿美"
-      ],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, array data",
-      "selector": "$[?length(@.a)>=2]",
-      "document": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        },
-        {
-          "a": [
-            1
-          ]
-        }
-      ],
-      "result": [
-        {
-          "a": [
-            1,
-            2,
-            3
-          ]
-        }
-      ],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, missing data",
-      "selector": "$[?length(@.a)>=2]",
-      "document": [
-        {
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, number arg",
-      "selector": "$[?length(1)>=2]",
-      "document": [
-        {
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, true arg",
-      "selector": "$[?length(true)>=2]",
-      "document": [
-        {
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, false arg",
-      "selector": "$[?length(false)>=2]",
-      "document": [
-        {
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, null arg",
-      "selector": "$[?length(null)>=2]",
-      "document": [
-        {
-          "d": "f"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, result must be compared",
-      "selector": "$[?length(@.a)]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, no params",
-      "selector": "$[?length()==1]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, too many params",
-      "selector": "$[?length(@.a,@.b)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, non-singular query arg",
-      "selector": "$[?length(@.*)<3]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, arg is a function expression",
-      "selector": "$.values[?length(@.a)==length(value($..c))]",
-      "document": {
-        "c": "cd",
-        "values": [
-          {
-            "a": "ab"
-          },
-          {
-            "a": "d"
-          }
-        ]
-      },
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, length, arg is special nothing",
-      "selector": "$[?length(value(@.a))>0]",
-      "document": [
-        {
-          "a": "ab"
-        },
-        {
-          "c": "d"
-        },
-        {
-          "a": null
-        }
-      ],
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "length"
-      ]
-    },
-    {
-      "name": "functions, match, found match",
-      "selector": "$[?match(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "ab"
-        }
-      ],
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, double quotes",
-      "selector": "$[?match(@.a, \"a.*\")]",
-      "document": [
-        {
-          "a": "ab"
-        }
-      ],
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, regex from the document",
-      "selector": "$.values[?match(@, $.regex)]",
-      "document": {
-        "regex": "b.?b",
-        "values": [
-          "abc",
-          "bcd",
-          "bab",
-          "bba",
-          "bbab",
-          "b",
-          true,
-          [],
-          {}
-        ]
-      },
-      "result": [
-        "bab"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, don't select match",
-      "selector": "$[?!match(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "ab"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, not a match",
-      "selector": "$[?match(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, select non-match",
-      "selector": "$[?!match(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [
-        {
-          "a": "bc"
-        }
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, non-string first arg",
-      "selector": "$[?match(1, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, non-string second arg",
-      "selector": "$[?match(@.a, 1)]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, filter, match function, unicode char class, uppercase",
-      "selector": "$[?match(@, '\\\\p{Lu}')]",
-      "document": [
-        "ж",
-        "Ж",
-        "1",
-        "жЖ",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "Ж"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, filter, match function, unicode char class negated, uppercase",
-      "selector": "$[?match(@, '\\\\P{Lu}')]",
-      "document": [
-        "ж",
-        "Ж",
-        "1",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "ж",
-        "1"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, filter, match function, unicode, surrogate pair",
-      "selector": "$[?match(@, 'a.b')]",
-      "document": [
-        "a𐄁b",
-        "ab",
-        "1",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "a𐄁b"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, dot matcher on \\u2028",
-      "selector": "$[?match(@, '.')]",
-      "document": [
-        " ",
-        "\r",
-        "\n",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        " "
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, dot matcher on \\u2029",
-      "selector": "$[?match(@, '.')]",
-      "document": [
-        " ",
-        "\r",
-        "\n",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        " "
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, result cannot be compared",
-      "selector": "$[?match(@.a, 'a.*')==true]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, too few params",
-      "selector": "$[?match(@.a)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, too many params",
-      "selector": "$[?match(@.a,@.b,@.c)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, arg is a function expression",
-      "selector": "$.values[?match(@.a, value($..['regex']))]",
-      "document": {
-        "regex": "a.*",
-        "values": [
-          {
-            "a": "ab"
-          },
-          {
-            "a": "ba"
-          }
-        ]
-      },
-      "result": [
-        {
-          "a": "ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, dot in character class",
-      "selector": "$[?match(@, 'a[.b]c')]",
-      "document": [
-        "abc",
-        "a.c",
-        "axc"
-      ],
-      "result": [
-        "abc",
-        "a.c"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, escaped dot",
-      "selector": "$[?match(@, 'a\\\\.c')]",
-      "document": [
-        "abc",
-        "a.c",
-        "axc"
-      ],
-      "result": [
-        "a.c"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, escaped backslash before dot",
-      "selector": "$[?match(@, 'a\\\\\\\\.c')]",
-      "document": [
-        "abc",
-        "a.c",
-        "axc",
-        "a\\ c"
-      ],
-      "result": [
-        "a\\ c"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, escaped left square bracket",
-      "selector": "$[?match(@, 'a\\\\[.c')]",
-      "document": [
-        "abc",
-        "a.c",
-        "a[ c"
-      ],
-      "result": [
-        "a[ c"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, escaped right square bracket",
-      "selector": "$[?match(@, 'a[\\\\].]c')]",
-      "document": [
-        "abc",
-        "a.c",
-        "a c",
-        "a]c"
-      ],
-      "result": [
-        "a.c",
-        "a]c"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, explicit caret",
-      "selector": "$[?match(@, '^ab.*')]",
-      "document": [
-        "abc",
-        "axc",
-        "ab",
-        "xab"
-      ],
-      "result": [
-        "abc",
-        "ab"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, match, explicit dollar",
-      "selector": "$[?match(@, '.*bc$')]",
-      "document": [
-        "abc",
-        "axc",
-        "ab",
-        "abcx"
-      ],
-      "result": [
-        "abc"
-      ],
-      "tags": [
-        "function",
-        "match"
-      ]
-    },
-    {
-      "name": "functions, search, at the end",
-      "selector": "$[?search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "the end is ab"
-        }
-      ],
-      "result": [
-        {
-          "a": "the end is ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, double quotes",
-      "selector": "$[?search(@.a, \"a.*\")]",
-      "document": [
-        {
-          "a": "the end is ab"
-        }
-      ],
-      "result": [
-        {
-          "a": "the end is ab"
-        }
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, at the start",
-      "selector": "$[?search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "ab is at the start"
-        }
-      ],
-      "result": [
-        {
-          "a": "ab is at the start"
-        }
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, in the middle",
-      "selector": "$[?search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "contains two matches"
-        }
-      ],
-      "result": [
-        {
-          "a": "contains two matches"
-        }
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, regex from the document",
-      "selector": "$.values[?search(@, $.regex)]",
-      "document": {
-        "regex": "b.?b",
-        "values": [
-          "abc",
-          "bcd",
-          "bab",
-          "bba",
-          "bbab",
-          "b",
-          true,
-          [],
-          {}
-        ]
-      },
-      "result": [
-        "bab",
-        "bba",
-        "bbab"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, don't select match",
-      "selector": "$[?!search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "contains two matches"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, not a match",
-      "selector": "$[?search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, select non-match",
-      "selector": "$[?!search(@.a, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [
-        {
-          "a": "bc"
-        }
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, non-string first arg",
-      "selector": "$[?search(1, 'a.*')]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, non-string second arg",
-      "selector": "$[?search(@.a, 1)]",
-      "document": [
-        {
-          "a": "bc"
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, filter, search function, unicode char class, uppercase",
-      "selector": "$[?search(@, '\\\\p{Lu}')]",
-      "document": [
-        "ж",
-        "Ж",
-        "1",
-        "жЖ",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "Ж",
-        "жЖ"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, filter, search function, unicode char class negated, uppercase",
-      "selector": "$[?search(@, '\\\\P{Lu}')]",
-      "document": [
-        "ж",
-        "Ж",
-        "1",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "ж",
-        "1"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, filter, search function, unicode, surrogate pair",
-      "selector": "$[?search(@, 'a.b')]",
-      "document": [
-        "a𐄁bc",
-        "abc",
-        "1",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        "a𐄁bc"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, dot matcher on \\u2028",
-      "selector": "$[?search(@, '.')]",
-      "document": [
-        " ",
-        "\r \n",
-        "\r",
-        "\n",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        " ",
-        "\r \n"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, dot matcher on \\u2029",
-      "selector": "$[?search(@, '.')]",
-      "document": [
-        " ",
-        "\r \n",
-        "\r",
-        "\n",
-        true,
-        [],
-        {}
-      ],
-      "result": [
-        " ",
-        "\r \n"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, result cannot be compared",
-      "selector": "$[?search(@.a, 'a.*')==true]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, too few params",
-      "selector": "$[?search(@.a)]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, too many params",
-      "selector": "$[?search(@.a,@.b,@.c)]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, arg is a function expression",
-      "selector": "$.values[?search(@, value($..['regex']))]",
-      "document": {
-        "regex": "b.?b",
-        "values": [
-          "abc",
-          "bcd",
-          "bab",
-          "bba",
-          "bbab",
-          "b",
-          true,
-          [],
-          {}
-        ]
-      },
-      "result": [
-        "bab",
-        "bba",
-        "bbab"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, dot in character class",
-      "selector": "$[?search(@, 'a[.b]c')]",
-      "document": [
-        "x abc y",
-        "x a.c y",
-        "x axc y"
-      ],
-      "result": [
-        "x abc y",
-        "x a.c y"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, escaped dot",
-      "selector": "$[?search(@, 'a\\\\.c')]",
-      "document": [
-        "x abc y",
-        "x a.c y",
-        "x axc y"
-      ],
-      "result": [
-        "x a.c y"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, escaped backslash before dot",
-      "selector": "$[?search(@, 'a\\\\\\\\.c')]",
-      "document": [
-        "x abc y",
-        "x a.c y",
-        "x axc y",
-        "x a\\ c y"
-      ],
-      "result": [
-        "x a\\ c y"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, escaped left square bracket",
-      "selector": "$[?search(@, 'a\\\\[.c')]",
-      "document": [
-        "x abc y",
-        "x a.c y",
-        "x a[ c y"
-      ],
-      "result": [
-        "x a[ c y"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, search, escaped right square bracket",
-      "selector": "$[?search(@, 'a[\\\\].]c')]",
-      "document": [
-        "x abc y",
-        "x a.c y",
-        "x a c y",
-        "x a]c y"
-      ],
-      "result": [
-        "x a.c y",
-        "x a]c y"
-      ],
-      "tags": [
-        "function",
-        "search"
-      ]
-    },
-    {
-      "name": "functions, value, single-value nodelist",
-      "selector": "$[?value(@.*)==4]",
-      "document": [
-        [
-          4
-        ],
-        {
-          "foo": 4
-        },
-        [
-          5
-        ],
-        {
-          "foo": 5
-        },
-        4
-      ],
-      "result": [
-        [
-          4
-        ],
-        {
-          "foo": 4
-        }
-      ],
-      "tags": [
-        "function",
-        "value"
-      ]
-    },
-    {
-      "name": "functions, value, multi-value nodelist",
-      "selector": "$[?value(@.*)==4]",
-      "document": [
-        [
-          4,
-          4
-        ],
-        {
-          "foo": 4,
-          "bar": 4
-        }
-      ],
-      "result": [],
-      "tags": [
-        "function",
-        "value"
-      ]
-    },
-    {
-      "name": "functions, value, too few params",
-      "selector": "$[?value()==4]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "value"
-      ]
-    },
-    {
-      "name": "functions, value, too many params",
-      "selector": "$[?value(@.a,@.b)==4]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "value"
-      ]
-    },
-    {
-      "name": "functions, value, result must be compared",
-      "selector": "$[?value(@.a)]",
-      "invalid_selector": true,
-      "tags": [
-        "function",
-        "value"
-      ]
-    },
-    {
-      "name": "whitespace, filter, space between question mark and expression",
-      "selector": "$[? @.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, newline between question mark and expression",
-      "selector": "$[?\n@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, tab between question mark and expression",
-      "selector": "$[?\t@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, return between question mark and expression",
-      "selector": "$[?\r@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, space between question mark and parenthesized expression",
-      "selector": "$[? (@.a)]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, newline between question mark and parenthesized expression",
-      "selector": "$[?\n(@.a)]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, tab between question mark and parenthesized expression",
-      "selector": "$[?\t(@.a)]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, return between question mark and parenthesized expression",
-      "selector": "$[?\r(@.a)]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, space between parenthesized expression and bracket",
-      "selector": "$[?(@.a) ]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, newline between parenthesized expression and bracket",
-      "selector": "$[?(@.a)\n]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, tab between parenthesized expression and bracket",
-      "selector": "$[?(@.a)\t]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, return between parenthesized expression and bracket",
-      "selector": "$[?(@.a)\r]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, space between bracket and question mark",
-      "selector": "$[ ?@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, newline between bracket and question mark",
-      "selector": "$[\n?@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, tab between bracket and question mark",
-      "selector": "$[\t?@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, filter, return between bracket and question mark",
-      "selector": "$[\r?@.a]",
-      "document": [
-        {
-          "a": "b",
-          "d": "e"
-        },
-        {
-          "b": "c",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "b",
-          "d": "e"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, space between function name and parenthesis",
-      "selector": "$[?count (@.*)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newline between function name and parenthesis",
-      "selector": "$[?count\n(@.*)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tab between function name and parenthesis",
-      "selector": "$[?count\t(@.*)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, return between function name and parenthesis",
-      "selector": "$[?count\r(@.*)==1]",
-      "invalid_selector": true,
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, space between parenthesis and arg",
-      "selector": "$[?count( @.*)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newline between parenthesis and arg",
-      "selector": "$[?count(\n@.*)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tab between parenthesis and arg",
-      "selector": "$[?count(\t@.*)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, return between parenthesis and arg",
-      "selector": "$[?count(\r@.*)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, space between arg and comma",
-      "selector": "$[?search(@ ,'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newline between arg and comma",
-      "selector": "$[?search(@\n,'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tab between arg and comma",
-      "selector": "$[?search(@\t,'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, return between arg and comma",
-      "selector": "$[?search(@\r,'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, space between comma and arg",
-      "selector": "$[?search(@, '[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newline between comma and arg",
-      "selector": "$[?search(@,\n'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tab between comma and arg",
-      "selector": "$[?search(@,\t'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, return between comma and arg",
-      "selector": "$[?search(@,\r'[a-z]+')]",
-      "document": [
-        "foo",
-        "123"
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, space between arg and parenthesis",
-      "selector": "$[?count(@.* )==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "function",
-        "search",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newline between arg and parenthesis",
-      "selector": "$[?count(@.*\n)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tab between arg and parenthesis",
-      "selector": "$[?count(@.*\t)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, return between arg and parenthesis",
-      "selector": "$[?count(@.*\r)==1]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "count",
-        "function",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, spaces in a relative singular selector",
-      "selector": "$[?length(@ .a .b) == 3]",
-      "document": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        },
-        {}
-      ],
-      "result": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        }
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newlines in a relative singular selector",
-      "selector": "$[?length(@\n.a\n.b) == 3]",
-      "document": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        },
-        {}
-      ],
-      "result": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        }
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tabs in a relative singular selector",
-      "selector": "$[?length(@\t.a\t.b) == 3]",
-      "document": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        },
-        {}
-      ],
-      "result": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        }
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, returns in a relative singular selector",
-      "selector": "$[?length(@\r.a\r.b) == 3]",
-      "document": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        },
-        {}
-      ],
-      "result": [
-        {
-          "a": {
-            "b": "foo"
-          }
-        }
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, spaces in an absolute singular selector",
-      "selector": "$..[?length(@)==length($ [0] .a)]",
-      "document": [
-        {
-          "a": "foo"
-        },
-        {}
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, newlines in an absolute singular selector",
-      "selector": "$..[?length(@)==length($\n[0]\n.a)]",
-      "document": [
-        {
-          "a": "foo"
-        },
-        {}
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, tabs in an absolute singular selector",
-      "selector": "$..[?length(@)==length($\t[0]\t.a)]",
-      "document": [
-        {
-          "a": "foo"
-        },
-        {}
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, functions, returns in an absolute singular selector",
-      "selector": "$..[?length(@)==length($\r[0]\r.a)]",
-      "document": [
-        {
-          "a": "foo"
-        },
-        {}
-      ],
-      "result": [
-        "foo"
-      ],
-      "tags": [
-        "function",
-        "length",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before ||",
-      "selector": "$[?@.a ||@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before ||",
-      "selector": "$[?@.a\n||@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before ||",
-      "selector": "$[?@.a\t||@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before ||",
-      "selector": "$[?@.a\r||@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after ||",
-      "selector": "$[?@.a|| @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after ||",
-      "selector": "$[?@.a||\n@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after ||",
-      "selector": "$[?@.a||\t@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after ||",
-      "selector": "$[?@.a||\r@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "c": 3
-        }
-      ],
-      "result": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before &&",
-      "selector": "$[?@.a &&@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before &&",
-      "selector": "$[?@.a\n&&@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before &&",
-      "selector": "$[?@.a\t&&@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before &&",
-      "selector": "$[?@.a\r&&@.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after &&",
-      "selector": "$[?@.a&& @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after &&",
-      "selector": "$[?@.a&& @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after &&",
-      "selector": "$[?@.a&& @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after &&",
-      "selector": "$[?@.a&& @.b]",
-      "document": [
-        {
-          "a": 1
-        },
-        {
-          "b": 2
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before ==",
-      "selector": "$[?@.a ==@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before ==",
-      "selector": "$[?@.a\n==@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before ==",
-      "selector": "$[?@.a\t==@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before ==",
-      "selector": "$[?@.a\r==@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after ==",
-      "selector": "$[?@.a== @.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after ==",
-      "selector": "$[?@.a==\n@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after ==",
-      "selector": "$[?@.a==\t@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after ==",
-      "selector": "$[?@.a==\r@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before !=",
-      "selector": "$[?@.a !=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before !=",
-      "selector": "$[?@.a\n!=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before !=",
-      "selector": "$[?@.a\t!=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before !=",
-      "selector": "$[?@.a\r!=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after !=",
-      "selector": "$[?@.a!= @.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after !=",
-      "selector": "$[?@.a!=\n@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after !=",
-      "selector": "$[?@.a!=\t@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after !=",
-      "selector": "$[?@.a!=\r@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before <",
-      "selector": "$[?@.a <@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before <",
-      "selector": "$[?@.a\n<@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before <",
-      "selector": "$[?@.a\t<@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before <",
-      "selector": "$[?@.a\r<@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after <",
-      "selector": "$[?@.a< @.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after <",
-      "selector": "$[?@.a<\n@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after <",
-      "selector": "$[?@.a<\t@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after <",
-      "selector": "$[?@.a<\r@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before >",
-      "selector": "$[?@.b >@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before >",
-      "selector": "$[?@.b\n>@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before >",
-      "selector": "$[?@.b\t>@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before >",
-      "selector": "$[?@.b\r>@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after >",
-      "selector": "$[?@.b> @.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after >",
-      "selector": "$[?@.b>\n@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after >",
-      "selector": "$[?@.b>\t@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after >",
-      "selector": "$[?@.b>\r@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before <=",
-      "selector": "$[?@.a <=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before <=",
-      "selector": "$[?@.a\n<=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before <=",
-      "selector": "$[?@.a\t<=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before <=",
-      "selector": "$[?@.a\r<=@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after <=",
-      "selector": "$[?@.a<= @.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after <=",
-      "selector": "$[?@.a<=\n@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after <=",
-      "selector": "$[?@.a<=\t@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after <=",
-      "selector": "$[?@.a<=\r@.b]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space before >=",
-      "selector": "$[?@.b >=@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline before >=",
-      "selector": "$[?@.b\n>=@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab before >=",
-      "selector": "$[?@.b\t>=@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return before >=",
-      "selector": "$[?@.b\r>=@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space after >=",
-      "selector": "$[?@.b>= @.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline after >=",
-      "selector": "$[?@.b>=\n@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab after >=",
-      "selector": "$[?@.b>=\t@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return after >=",
-      "selector": "$[?@.b>=\r@.a]",
-      "document": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        },
-        {
-          "a": 2,
-          "b": 1
-        }
-      ],
-      "result": [
-        {
-          "a": 1,
-          "b": 1
-        },
-        {
-          "a": 1,
-          "b": 2
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space between logical not and test expression",
-      "selector": "$[?! @.a]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline between logical not and test expression",
-      "selector": "$[?!\n@.a]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab between logical not and test expression",
-      "selector": "$[?!\t@.a]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return between logical not and test expression",
-      "selector": "$[?!\r@.a]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, space between logical not and parenthesized expression",
-      "selector": "$[?! (@.a=='b')]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, newline between logical not and parenthesized expression",
-      "selector": "$[?!\n(@.a=='b')]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, tab between logical not and parenthesized expression",
-      "selector": "$[?!\t(@.a=='b')]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, operators, return between logical not and parenthesized expression",
-      "selector": "$[?!\r(@.a=='b')]",
-      "document": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "b",
-          "d": "f"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "result": [
-        {
-          "a": "a",
-          "d": "e"
-        },
-        {
-          "a": "d",
-          "d": "f"
-        }
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between root and bracket",
-      "selector": "$ ['a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between root and bracket",
-      "selector": "$\n['a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between root and bracket",
-      "selector": "$\t['a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between root and bracket",
-      "selector": "$\r['a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between bracket and bracket",
-      "selector": "$['a'] ['b']",
-      "document": {
-        "a": {
-          "b": "ab"
-        }
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between bracket and bracket",
-      "selector": "$['a'] \n['b']",
-      "document": {
-        "a": {
-          "b": "ab"
-        }
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between bracket and bracket",
-      "selector": "$['a'] \t['b']",
-      "document": {
-        "a": {
-          "b": "ab"
-        }
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between bracket and bracket",
-      "selector": "$['a'] \r['b']",
-      "document": {
-        "a": {
-          "b": "ab"
-        }
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between root and dot",
-      "selector": "$ .a",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between root and dot",
-      "selector": "$\n.a",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between root and dot",
-      "selector": "$\t.a",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between root and dot",
-      "selector": "$\r.a",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between dot and name",
-      "selector": "$. a",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between dot and name",
-      "selector": "$.\na",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between dot and name",
-      "selector": "$.\ta",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between dot and name",
-      "selector": "$.\ra",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between recursive descent and name",
-      "selector": "$.. a",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between recursive descent and name",
-      "selector": "$..\na",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between recursive descent and name",
-      "selector": "$..\ta",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between recursive descent and name",
-      "selector": "$..\ra",
-      "invalid_selector": true,
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between bracket and selector",
-      "selector": "$[ 'a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between bracket and selector",
-      "selector": "$[\n'a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between bracket and selector",
-      "selector": "$[\t'a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between bracket and selector",
-      "selector": "$[\r'a']",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between selector and bracket",
-      "selector": "$['a' ]",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between selector and bracket",
-      "selector": "$['a'\n]",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between selector and bracket",
-      "selector": "$['a'\t]",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between selector and bracket",
-      "selector": "$['a'\r]",
-      "document": {
-        "a": "ab"
-      },
-      "result": [
-        "ab"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between selector and comma",
-      "selector": "$['a' ,'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between selector and comma",
-      "selector": "$['a'\n,'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between selector and comma",
-      "selector": "$['a'\t,'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between selector and comma",
-      "selector": "$['a'\r,'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, space between comma and selector",
-      "selector": "$['a', 'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, newline between comma and selector",
-      "selector": "$['a',\n'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, tab between comma and selector",
-      "selector": "$['a',\t'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, selectors, return between comma and selector",
-      "selector": "$['a',\r'b']",
-      "document": {
-        "a": "ab",
-        "b": "bc"
-      },
-      "result": [
-        "ab",
-        "bc"
-      ],
-      "tags": [
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, space between start and colon",
-      "selector": "$[1 :5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, newline between start and colon",
-      "selector": "$[1\n:5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, tab between start and colon",
-      "selector": "$[1\t:5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, return between start and colon",
-      "selector": "$[1\r:5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, space between colon and end",
-      "selector": "$[1: 5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, newline between colon and end",
-      "selector": "$[1:\n5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, tab between colon and end",
-      "selector": "$[1:\t5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, return between colon and end",
-      "selector": "$[1:\r5:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, space between end and colon",
-      "selector": "$[1:5 :2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, newline between end and colon",
-      "selector": "$[1:5\n:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, tab between end and colon",
-      "selector": "$[1:5\t:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, return between end and colon",
-      "selector": "$[1:5\r:2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, space between colon and step",
-      "selector": "$[1:5: 2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, newline between colon and step",
-      "selector": "$[1:5:\n2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, tab between colon and step",
-      "selector": "$[1:5:\t2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    },
-    {
-      "name": "whitespace, slice, return between colon and step",
-      "selector": "$[1:5:\r2]",
-      "document": [
-        1,
-        2,
-        3,
-        4,
-        5,
-        6
-      ],
-      "result": [
-        2,
-        4
-      ],
-      "tags": [
-        "index",
-        "whitespace"
-      ]
-    }
-  ]
-}
diff --git a/test/spec/LocatedSpec.hs b/test/spec/LocatedSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/spec/LocatedSpec.hs
@@ -0,0 +1,144 @@
+module LocatedSpec
+  ( spec )
+  where
+
+import qualified Data.Aeson        as JSON
+import qualified Data.Vector       as V
+
+import Data.Aeson.JSONPath  (queryLocatedQQ, jsonPath)
+import Data.Aeson.QQ.Simple (aesonQQ)
+import Data.Aeson           (Value)
+import Data.Vector          (Vector)
+import Test.Hspec
+
+import Prelude
+
+getVector :: Value -> Vector Value
+getVector (JSON.Array arr) = arr
+getVector _ = V.empty
+
+-- taken from https://serdejsonpath.live/
+rootDoc :: Value
+rootDoc = [aesonQQ|{
+    "store": {
+      "books": [
+        {
+          "title": "Guns, Germs, and Steel",
+          "author": "Jared Diamond",
+          "category": "reference",
+          "price": 24.99
+        },
+        {
+          "title": "David Copperfield",
+          "author": "Charles Dickens",
+          "category": "fiction",
+          "price": 12.99
+        },
+        {
+          "title": "Moby Dick",
+          "author": "Herman Melville",
+          "category": "fiction",
+          "price": 8.99
+        },
+        {
+          "title": "Crime and Punishment",
+          "author": "Fyodor Dostoevsky",
+          "category": "fiction",
+          "price": 19.99
+        }
+      ]
+    }
+  }|]
+
+
+storeDoc :: Value
+storeDoc = [aesonQQ|
+  {
+    "books": [
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Crime and Punishment",
+        "author": "Fyodor Dostoevsky",
+        "category": "fiction",
+        "price": 19.99
+      }
+    ]
+  }|]
+
+booksDoc :: Value
+booksDoc = [aesonQQ| [
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Crime and Punishment",
+        "author": "Fyodor Dostoevsky",
+        "category": "fiction",
+        "price": 19.99
+      }
+  ]|]
+
+
+books0Doc :: Value
+books0Doc = [aesonQQ|[
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      }
+  ]|]
+
+
+spec :: Spec
+spec = do
+  describe "test queryLocated" $ do
+    it "returns root document when query is $" $
+      queryLocatedQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton ("$",rootDoc)
+
+    it "returns store object when queryQQ is $.store" $
+      queryLocatedQQ [jsonPath|$.store|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]
+
+    it "returns store object when queryQQ is $['store']" $
+      queryLocatedQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.fromList [("$['store']",storeDoc)]
+
+    it "returns books array when queryQQ is $.store.books" $
+      queryLocatedQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.fromList [("$['store']['books']",booksDoc)]
+
+    it "returns 0-index book item, $.store.books[0]" $
+      queryLocatedQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
+
+    it "returns 0-index book item, $.store.books[-4]" $
+      queryLocatedQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` V.zip (V.singleton "$['store']['books'][0]") (getVector books0Doc)
diff --git a/test/spec/Main.hs b/test/spec/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/spec/Main.hs
@@ -0,0 +1,29 @@
+module Main
+  ( main )
+  where
+
+import qualified Test.Hspec as HS
+
+import qualified ParserSpec
+import qualified QuerySpec
+import qualified LocatedSpec
+
+import Test.Hspec.Runner
+import Prelude
+
+specs :: Spec
+specs = do
+  HS.describe "Run all tests" $ do
+    ParserSpec.spec
+    QuerySpec.spec
+    LocatedSpec.spec
+
+
+main :: IO ()
+main = do
+  summary <- hspecWithResult defaultConfig 
+    { configColorMode = ColorAuto
+    } specs
+  
+  putStrLn $ "Total tests: " ++ show (summaryExamples summary)
+  putStrLn $ "Failures: "    ++ show (summaryFailures summary)
diff --git a/test/spec/ParserSpec.hs b/test/spec/ParserSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/spec/ParserSpec.hs
@@ -0,0 +1,443 @@
+module ParserSpec
+  ( spec )
+  where
+
+import qualified Text.ParserCombinators.Parsec as P
+
+import Data.Aeson.JSONPath.Parser       (pQuery)
+import Data.Either                      (isLeft)
+
+import Data.Aeson.JSONPath.Types
+import Test.Hspec
+
+import Prelude
+
+spec :: Spec
+spec = do
+  describe "Parse query string" $ do
+    it "parses query: $" $
+      P.parse pQuery "" "$"
+      `shouldBe`
+      Right (Query{queryType=Root,querySegments=[]})
+
+    it "parses query: $.store" $
+      P.parse pQuery "" "$.store"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }]
+      }
+
+    it "parses query: $['store']" $
+      P.parse pQuery "" "$['store']"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [Name "store"]
+        }]
+      }
+
+    it "parses query: $.store.books" $
+      P.parse pQuery "" "$.store.books"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+          }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }]
+      }
+
+    it "parses query: $.store.books[0]" $
+      P.parse pQuery "" "$.store.books[0]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [Index 0]
+        }]
+      }
+
+    it "parses query: $.store.books[0,2]" $
+      P.parse pQuery "" "$.store.books[0,2]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [Index 0, Index 2]
+        }]
+      }
+
+    it "parses query: $.store.books[1:3]" $
+      P.parse pQuery "" "$.store.books[1:3]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [ArraySlice (Just 1, Just 3, 1)]
+        }]
+      }
+
+    it "parses query: $.store.books[1:4:2]" $
+      P.parse pQuery "" "$.store.books[1:4:2]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [ArraySlice (Just 1, Just 4, 2)]
+        }]
+      }
+
+    it "parses query: $.store.books[-1:-4:-2]" $
+      P.parse pQuery "" "$.store.books[-1:-4:-2]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [ArraySlice (Just (-1), Just (-4), (-2))]
+        }]
+      }
+
+    it "parses query: $.store.books[1:3, 0, 1]" $
+      P.parse pQuery "" "$.store.books[1:3, 0, 1]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "store"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Dotted "books"
+        }, QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [ArraySlice (Just 1, Just 3, 1), Index 0, Index 1]
+        }]
+      }
+
+    it "parses query: $.*" $
+      P.parse pQuery "" "$.*" 
+      `shouldBe` 
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = WildcardSegment
+        }]
+      }
+
+    it "parses query: $[*]" $
+      P.parse pQuery "" "$[*]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [WildcardSelector]
+        }]
+      }
+
+    it "parses query: $..*" $
+      P.parse pQuery "" "$..*"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Descendant,
+          segment = WildcardSegment
+        }]
+      }
+
+    it "parses query: $..[*]" $
+      P.parse pQuery "" "$..[*]"
+      `shouldBe` 
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Descendant,
+          segment = Bracketed [WildcardSelector]
+        }]
+      }
+
+    it "fails with $.1startsWithNum" $
+      P.parse pQuery "" "$.1startsWithNum"
+      `shouldSatisfy` isLeft
+
+    it "parses query $.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ" $
+      P.parse pQuery "" "$.©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "©®±×÷Ωπ•€→∀∃∈≠≤≥✓λ"
+        }]
+      }
+
+    it "parses query: $._" $
+      P.parse pQuery "" "$._"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "_"
+        }]
+      }
+
+    it "parses query: $.underscore_key" $
+      P.parse pQuery "" "$.underscore_key"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Dotted "underscore_key"
+        }]
+      }
+
+    it "parses query: $[0,TAB/LINEFEED/RETURN/SPACE1]" $
+      P.parse pQuery "" "$[0,\n\t\r 1]"
+      `shouldBe`
+      Right Query {
+        queryType = Root,
+        querySegments = [QuerySegment {
+          segmentType = Child,
+          segment = Bracketed [Index 0, Index 1]
+        }]
+      }
+
+    describe "parses JSPFilter Query" $ do
+      it "$[?@.category == 'reference']" $
+        P.parse pQuery "" "$[?@.category == 'reference']"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "category"]
+            }) Equal (CompLit (LitString "reference")))]])]
+          }]
+        }
+
+      it "test expr: $..books[?@.price].title" $
+        P.parse pQuery "" "$..books[?@.price].title"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Descendant,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test (FilterQuery Query {
+              queryType = Current,
+              querySegments = [QuerySegment {
+                segmentType = Child,
+                segment = Dotted "price"
+              }]
+            })]])]
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "title"
+          }]
+        }
+
+      it "and expr: $[?@.price < 20 && @.price > 10]" $
+        P.parse pQuery "" "$[?@.price < 20 && @.price > 10]" 
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Less (CompLit (LitNum 20.0))), Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Greater (CompLit (LitNum 10.0)))]])]
+          }]
+        }
+
+      it "or expr: $[?@.price < 20 || @.price > 10]" $
+        P.parse pQuery "" "$[?@.price < 20 || @.price > 10]"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Less (CompLit (LitNum 20.0)))], LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Greater (CompLit (LitNum 10.0)))]])]
+          }]
+        }
+
+      it "root filter: $..books[?$.price].title" $
+        P.parse pQuery "" "$..books[?$.price].title"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Descendant,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Test (FilterQuery Query {
+              queryType = Root,
+              querySegments = [QuerySegment {
+                segmentType = Child,
+                segment = Dotted "price"
+              }]
+            })]])]
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "title"
+          }]
+        }
+
+      it "not expr: $[?!(@.price < 20 && @.price > 10)]" $
+        P.parse pQuery "" "$[?!(@.price < 20 && @.price > 10)]" 
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [NotParen (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            })  Less (CompLit (LitNum 20.0))), Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Greater (CompLit (LitNum 10.0)))]])]])]
+          }]
+        }
+
+      it "scientific: $.store.books[?@.price < -1e20]" $
+        P.parse pQuery "" "$.store.books[?@['price'] < -1e20]"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Dotted "store"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Less (CompLit (LitNum (-1.0e20))))]])]
+          }]
+        }
+
+      it "double: $.store.books[?@.price < 0.01]" $
+        P.parse pQuery "" "$.store.books[?@['price'] < 0.01]"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Dotted "store"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "price"]
+            }) Less (CompLit (LitNum (1.0e-2))))]])]
+          }]
+        }
+
+      it "bool: $.store.books[?@.is_available == true]" $
+        P.parse pQuery "" "$.store.books[?@.is_available == true]"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Dotted "store"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "is_available"]
+            }) Equal (CompLit (LitBool True)))]])]
+          }]
+        }
+
+      it "null: $.store.books[?@.is_available == null]" $
+        P.parse pQuery "" "$.store.books[?@.is_available == null]"
+        `shouldBe`
+        Right Query {
+          queryType = Root,
+          querySegments = [QuerySegment {
+            segmentType = Child,
+            segment = Dotted "store"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Dotted "books"
+          }, QuerySegment {
+            segmentType = Child,
+            segment = Bracketed [Filter (LogicalOr [LogicalAnd [Comparison (Comp (CompSQ SingularQuery {
+              singularQueryType = CurrentSQ,
+              singularQuerySegments = [NameSQSeg "is_available"]
+            }) Equal (CompLit LitNull))]])]
+          }]
+        }
diff --git a/test/spec/QuerySpec.hs b/test/spec/QuerySpec.hs
new file mode 100644
--- /dev/null
+++ b/test/spec/QuerySpec.hs
@@ -0,0 +1,348 @@
+module QuerySpec
+  ( spec )
+  where
+
+import qualified Data.Vector       as V
+import qualified Data.Aeson        as JSON
+
+import Data.Aeson.QQ.Simple (aesonQQ)
+import Data.Aeson           (Value)
+import Data.Vector          (Vector)
+import Test.Hspec
+
+import Data.Aeson.JSONPath  (queryQQ, jsonPath)
+
+import Prelude
+
+getVector :: Value -> Vector Value
+getVector (JSON.Array arr) = arr
+getVector _ = V.empty
+
+-- taken from https://serdejsonpath.live/
+rootDoc :: Value
+rootDoc = [aesonQQ|{
+    "store": {
+      "books": [
+        {
+          "title": "Guns, Germs, and Steel",
+          "author": "Jared Diamond",
+          "category": "reference",
+          "price": 24.99
+        },
+        {
+          "title": "David Copperfield",
+          "author": "Charles Dickens",
+          "category": "fiction",
+          "price": 12.99
+        },
+        {
+          "title": "Moby Dick",
+          "author": "Herman Melville",
+          "category": "fiction",
+          "price": 8.99
+        },
+        {
+          "title": "Crime and Punishment",
+          "author": "Fyodor Dostoevsky",
+          "category": "fiction",
+          "price": 19.99
+        }
+      ]
+    }
+  }|]
+
+
+storeDoc :: Value
+storeDoc = [aesonQQ|
+  {
+    "books": [
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Crime and Punishment",
+        "author": "Fyodor Dostoevsky",
+        "category": "fiction",
+        "price": 19.99
+      }
+    ]
+  }|]
+
+booksDoc :: Value
+booksDoc = [aesonQQ| [
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Crime and Punishment",
+        "author": "Fyodor Dostoevsky",
+        "category": "fiction",
+        "price": 19.99
+      }
+  ]|]
+
+
+books0Doc :: Value
+books0Doc = [aesonQQ|[
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      }
+  ]|]
+
+books0And2Doc :: Value
+books0And2Doc = [aesonQQ|[
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      }
+  ]|]
+
+books1To3Doc :: Value
+books1To3Doc = [aesonQQ|[
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      }
+  ]|]
+
+books1To3And0And1Doc :: Value
+books1To3And0And1Doc = [aesonQQ|[
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Guns, Germs, and Steel",
+        "author": "Jared Diamond",
+        "category": "reference",
+        "price": 24.99
+      },
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      }
+  ]|]
+
+lessThanPrice20Books :: Value
+lessThanPrice20Books = [aesonQQ| [
+      {
+        "title": "David Copperfield",
+        "author": "Charles Dickens",
+        "category": "fiction",
+        "price": 12.99
+      },
+      {
+        "title": "Moby Dick",
+        "author": "Herman Melville",
+        "category": "fiction",
+        "price": 8.99
+      },
+      {
+        "title": "Crime and Punishment",
+        "author": "Fyodor Dostoevsky",
+        "category": "fiction",
+        "price": 19.99
+      }
+  ]|]
+
+alphaArr :: Value
+alphaArr = [aesonQQ| ["a","b","c","d","e","f","g"] |]
+
+fgArr :: Value
+fgArr = [aesonQQ| ["f","g"] |]
+
+bdArr :: Value
+bdArr = [aesonQQ| ["b","d"] |]
+
+fdArr :: Value
+fdArr = [aesonQQ| ["f","d"] |]
+
+gfedcbaArr :: Value
+gfedcbaArr = [aesonQQ| ["g","f","e","d","c","b","a"] |]
+
+rfcExample1 :: Value
+rfcExample1 = [aesonQQ| {
+    "o": {"j": 1, "k": 2},
+    "a": [5, 3, [{"j": 4}, {"k": 6}]]
+  } |]
+
+rfcExample1Desc :: Value
+rfcExample1Desc = [aesonQQ| [
+    [5, 3, [{"j": 4}, {"k": 6}]],
+    {"j": 1, "k": 2},
+    5,
+    3,
+    [{"j": 4}, {"k": 6}],
+    {"j": 4},
+    {"k": 6},
+    4,
+    6,
+    1,
+    2
+  ]|]
+
+boolsAndNulls :: Value
+boolsAndNulls = [aesonQQ| [
+    { "a": true },
+    { "a": false },
+    { "a": null }
+  ]|]
+
+
+boolsAndNullsA :: Value
+boolsAndNullsA = [aesonQQ| [{ "a": true }] |]
+
+boolsAndNullsB :: Value
+boolsAndNullsB = [aesonQQ| [{ "a": false }] |]
+
+boolsAndNullsC :: Value
+boolsAndNullsC = [aesonQQ| [{ "a": null }] |]
+
+spec :: Spec
+spec = do
+  describe "test query" $ do
+    it "returns root document when query is $" $
+      queryQQ [jsonPath|$|] rootDoc `shouldBe` V.singleton rootDoc
+
+    it "returns store object when queryQQ is $.store" $
+      queryQQ [jsonPath|$.store|] rootDoc `shouldBe` V.singleton storeDoc
+
+    it "returns store object when queryQQ is $['store']" $
+      queryQQ [jsonPath|$['store']|] rootDoc `shouldBe` V.singleton storeDoc
+
+    it "returns books array when queryQQ is $.store.books" $
+      queryQQ [jsonPath|$.store.books|] rootDoc `shouldBe` V.singleton booksDoc
+
+    it "returns 0-index book item when queryQQ is $.store.books[0]" $
+      queryQQ [jsonPath|$.store.books[0]|] rootDoc `shouldBe` getVector books0Doc
+
+    it "returns 0-index book item when queryQQ is $.store.books[-4]" $
+      queryQQ [jsonPath|$.store.books[-4]|] rootDoc `shouldBe` getVector books0Doc
+
+    it "returns 0,2-index item when queryQQ is $.store.books[0,2]" $
+      queryQQ [jsonPath|$.store.books[0,2]|] rootDoc `shouldBe` getVector books0And2Doc
+
+    it "returns 1To3-index when queryQQ is $.store.books[1:3]" $
+      queryQQ [jsonPath|$.store.books[1:3]|] rootDoc `shouldBe` getVector books1To3Doc
+
+    it "returns 1To3-index and 0,1-index when queryQQ is $.store.books[1:3,0,1]" $
+      queryQQ [jsonPath|$.store.books[1:3,0,1]|] rootDoc `shouldBe` getVector books1To3And0And1Doc
+
+    it "returns slice with queryQQ $[5:]" $
+      queryQQ [jsonPath|$[5:]|] alphaArr `shouldBe` getVector fgArr
+
+    it "returns slice with queryQQ $[1:5:2]" $
+      queryQQ [jsonPath|$[1:5:2]|] alphaArr `shouldBe` getVector bdArr
+
+    it "returns slice with queryQQ $[5:1:-2]" $
+      queryQQ [jsonPath|$[5:1:-2]|] alphaArr `shouldBe` getVector fdArr
+
+    it "returns slice with queryQQ $[::-1]" $
+      queryQQ [jsonPath|$[::-1]|] alphaArr `shouldBe` getVector gfedcbaArr
+
+    it "returns root with queryQQ $.*" $
+      queryQQ [jsonPath|$.*|] rootDoc `shouldBe` V.singleton storeDoc
+
+    it "returns root with queryQQ $[*]" $
+      queryQQ [jsonPath|$[*]|] rootDoc `shouldBe` V.singleton storeDoc
+
+    it "returns descendants with queryQQ $..*" $
+      queryQQ [jsonPath|$..*|] rfcExample1 `shouldBe` getVector rfcExample1Desc
+
+    it "returns descendants with queryQQ $..[*]" $
+      queryQQ [jsonPath|$..[*]|] rfcExample1 `shouldBe` getVector rfcExample1Desc
+
+    it "returns with filtering: number comparison" $
+      queryQQ [jsonPath|$.store.books[?@.price < 20]|] rootDoc
+      `shouldBe` getVector lessThanPrice20Books
+
+    it "returns with filtering: not operator" $
+      queryQQ [jsonPath|$.store.books[?!(@.price < 20)]|] rootDoc
+      `shouldBe` getVector books0Doc
+
+    it "returns with filtering: true value" $
+      queryQQ [jsonPath|$[?@.a == true]|] boolsAndNulls
+      `shouldBe` getVector boolsAndNullsA
+
+    it "returns with filtering: false value" $
+      queryQQ [jsonPath|$[?@.a == false]|] boolsAndNulls
+      `shouldBe` getVector boolsAndNullsB
+
+    it "returns with filtering: null value" $
+      queryQQ [jsonPath|$[?@.a == null]|] boolsAndNulls
+      `shouldBe` getVector boolsAndNullsC
+
+    it "returns with filtering: string comparison" $
+      queryQQ [jsonPath|$.store.books[?@.author == 'Jared Diamond']|] rootDoc
+      `shouldBe` getVector books0Doc
+
+    it "returns with filtering: test expression" $
+      queryQQ [jsonPath|$.store.books[?@.author]|] rootDoc
+      `shouldBe` getVector booksDoc
+
+    it "returns with filtering with spaced out segments: test expression" $
+      queryQQ [jsonPath|$  .store  .books[?@  .author]|] rootDoc
+      `shouldBe` getVector booksDoc
+
+    it "returns with filtering: test expr gives empty with non-existent key" $
+      queryQQ [jsonPath|$.store.books[?@.not_here]|] rootDoc
+      `shouldBe` V.empty
