diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,17 +1,54 @@
 # Changelog for jsonpath-hs
 
+## v0.3.0.0 - Lots of breaking changes, they come with new features
+
+This release aims to address many deviations from similar libraries in other
+programming languages, this is thanks to Christoph Burgmer's
+[json-path-comparison
+project](https://cburgmer.github.io/json-path-comparison/).
+
+There has also been significant work in codifying JSONPath by the IETF-WG for
+JSONPath, the draft spec can be acccessed
+[here](https://ietf-wg-jsonpath.github.io/draft-ietf-jsonpath-base/draft-ietf-jsonpath-base.html).
+This release also aims to adapt some of the ideas from from spec.
+
+As a result there have been significant breaking changes in the types and also
+small changes in the way JSONPaths are executed.
+
+List of changes:
+* Fix compiler warnings and bugs with non-total pattern matches.
+* Allow double quoted literals and field accessors.
+* Ensure termination when start or end of slice are too big/small.
+* Implement slice execution based on IETF draft spec .
+* Ensure that a valid JSONPath never fails to execute.
+* Drop support for GHC <= 8.2.
+* Use megaparsec instead of attoparsec for better error messages.
+* Allow escape sequences in key names.
+* Allow parsing empty paths.
+* Allow spaces arround index selectors.
+* Allow selecting keys in unions and allow many union elements.
+* Implement 'and', 'or' and 'not' operator support in filters.
+* Allow comparison between two singular paths.
+* Allow bools and nulls in filters.
+
+## v0.2.1.0
+
+* Support and require aeson >= 2
+
+## v0.2.0.0
+
+* BreakingChange: Fix typo in `BeginningPoint`.
+* Fix typo in parser error.
+
 ## v0.1.0.2
 
-* Remove upper bounds from dependencies, as most of them are quite stable packages
+* Remove upper bounds from dependencies, as most of them are quite stable packages.
 
 ## v0.1.0.1
 
-* Import Data.Semigroup to support GHC 8
-* Add test json files to make sure test sdist compile and runs
+* Import Data.Semigroup to support GHC 8.
+* Add test json files to make sure test sdist compile and runs.
 
 ## v0.1.0.0
 
-* Start the project
-
-
-## Unreleased changes
+* Start the project.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,9 +1,5 @@
 # jsonpath-hs
 
-
-
-[![Build Status](https://travis-ci.org/akshaymankar/jsonpath-hs.svg?branch=master)](https://travis-ci.org/akshaymankar/jsonpath-hs) [![Matrix Build](https://matrix.hackage.haskell.org/api/v2/packages/jsonpath/badge)](https://matrix.hackage.haskell.org/package/jsonpath)
-
 Implementation of jsonpath as [described by Steffen Göessner](https://goessner.net/articles/JsonPath/).
 
 ## State of this library
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,3 @@
 import Distribution.Simple
+
 main = defaultMain
diff --git a/jsonpath.cabal b/jsonpath.cabal
--- a/jsonpath.cabal
+++ b/jsonpath.cabal
@@ -1,13 +1,7 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.31.2.
---
--- see: https://github.com/sol/hpack
---
--- hash: 05858fc895e0f57cbc4ec4533a099e4e1e46a8fc3cecb94f464ecca44dfec2e1
-
 name:           jsonpath
-version:        0.1.0.2
+version:        0.3.0.0
 synopsis:       Library to parse and execute JSONPath
 description:    Please see the README on GitHub at <https://github.com/akshaymankar/jsonpath-hs#readme>
 category:       Text, Web, JSON
@@ -18,15 +12,11 @@
 copyright:      Akshay Mankar
 license:        BSD3
 license-file:   LICENSE
-tested-with:    GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5
 build-type:     Simple
 extra-source-files:
     README.md
     ChangeLog.md
-    test/resources/json-path-tests/DotOperator.json
-    test/resources/json-path-tests/FilterExpressionSubscriptOperator.json
-    test/resources/json-path-tests/IndexedSubscriptOperator.json
-    test/resources/json-path-tests/SearchOperator.json
+    test/resources/json-path-tests/*.json
 
 source-repository head
   type: git
@@ -36,7 +26,6 @@
   exposed-modules:
       Data.JSONPath
       Data.JSONPath.Execute
-      Data.JSONPath.ExecutionResult
       Data.JSONPath.Parser
       Data.JSONPath.Types
   other-modules:
@@ -44,9 +33,10 @@
   hs-source-dirs:
       src
   build-depends:
-      aeson >=1.1
-    , attoparsec >=0.13
+      aeson >=2
+    , megaparsec
     , base >=4.9 && <5
+    , scientific
     , text >=1.2
     , unordered-containers >=0.2.8
     , vector >=0.12
@@ -66,12 +56,12 @@
   build-depends:
       aeson >=1.1
     , aeson-casing
-    , attoparsec >=0.13
+    , megaparsec
     , base >=4.9 && <5
     , bytestring
     , file-embed
     , hspec
-    , hspec-attoparsec
+    , hspec-megaparsec
     , jsonpath
     , text >=1.2
     , unordered-containers >=0.2.8
diff --git a/src/Data/JSONPath.hs b/src/Data/JSONPath.hs
--- a/src/Data/JSONPath.hs
+++ b/src/Data/JSONPath.hs
@@ -1,11 +1,10 @@
-{-# LANGUAGE OverloadedStrings #-}
 module Data.JSONPath
-  ( module Data.JSONPath.Types
-  , module Data.JSONPath.Parser
-  , module Data.JSONPath.Execute
+  ( module Data.JSONPath.Types,
+    module Data.JSONPath.Parser,
+    module Data.JSONPath.Execute,
   )
 where
 
-import Data.JSONPath.Types
-import Data.JSONPath.Parser
 import Data.JSONPath.Execute
+import Data.JSONPath.Parser
+import Data.JSONPath.Types
diff --git a/src/Data/JSONPath/Execute.hs b/src/Data/JSONPath/Execute.hs
--- a/src/Data/JSONPath/Execute.hs
+++ b/src/Data/JSONPath/Execute.hs
@@ -1,111 +1,212 @@
-{-# LANGUAGE CPP #-}
-module Data.JSONPath.Execute
-  (executeJSONPath, executeJSONPathEither, executeJSONPathElement)
-where
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
+module Data.JSONPath.Execute (executeJSONPath, executeJSONPathElement) where
+
 import Data.Aeson
-import Data.Aeson.Text
-import Data.Function       ((&))
-import Data.HashMap.Strict as Map
+import qualified Data.Aeson.Key as Key
+import qualified Data.Aeson.KeyMap as Map
+import qualified Data.Foldable as Foldable
 import Data.JSONPath.Types
-import Data.Text           (unpack)
+import Data.Maybe (fromMaybe, isJust, maybeToList)
+import Data.Text (Text)
+import qualified Data.Vector as V
 
-#if !MIN_VERSION_base (4,11,0)
-import Data.Semigroup ((<>))
-#endif
+executeJSONPath :: [JSONPathElement] -> Value -> [Value]
+executeJSONPath path rootVal = go path rootVal
+  where
+    go :: [JSONPathElement] -> Value -> [Value]
+    go [] v = [v]
+    go (j : js) v =
+      go js =<< executeJSONPathElement j rootVal v
 
-import qualified Data.Text.Lazy as LazyText
-import qualified Data.Vector    as V
+executeJSONPathElement :: JSONPathElement -> Value -> Value -> [Value]
+executeJSONPathElement (KeyChild key) _ val =
+  executeKeyChildOnValue key val
+executeJSONPathElement AnyChild _ val =
+  case val of
+    Object o -> map snd $ Map.toList o
+    Array a -> V.toList a
+    _ -> []
+executeJSONPathElement (IndexChild i) _ val =
+  executeIndexChildOnValue i val
+executeJSONPathElement (Slice start end step) _ val =
+  executeSliceOnValue start end step val
+executeJSONPathElement (Union elements) _ val =
+  concatMap (flip executeUnionElement val) elements
+executeJSONPathElement (Filter expr) rootVal val =
+  case val of
+    Array a -> executeFilter expr rootVal (V.toList a)
+    Object o -> executeFilter expr rootVal (Map.elems o)
+    _ -> []
+executeJSONPathElement s@(Search js) origVal val =
+  let x = executeJSONPath js val
+      y = mconcat $ valMap (executeJSONPathElement s origVal) val
+   in x <> y
 
-executeJSONPath :: [JSONPathElement] -> Value -> ExecutionResult Value
-executeJSONPath [] val = ResultError "empty json path"
-executeJSONPath (j:[]) val = executeJSONPathElement j val
-executeJSONPath (j:js) val = executeJSONPath js =<< executeJSONPathElement j val
+valMap :: ToJSON b => (Value -> [b]) -> Value -> [[b]]
+valMap f (Object o) = map snd . Map.toList $ Map.map f o
+valMap f (Array a) = V.toList $ V.map f a
+valMap _ _ = []
 
-executeJSONPathEither :: [JSONPathElement] -> Value -> Either String [Value]
-executeJSONPathEither js val = resultToEither $ executeJSONPath js val
+executeConditionOnMaybes :: Maybe Value -> Condition -> Maybe Value -> Bool
+executeConditionOnMaybes (Just val1) c (Just val2) = executeCondition val1 c val2
+executeConditionOnMaybes Nothing Equal Nothing = True
+executeConditionOnMaybes Nothing GreaterThanOrEqual Nothing = True
+executeConditionOnMaybes Nothing SmallerThanOrEqual Nothing = True
+executeConditionOnMaybes Nothing NotEqual (Just _) = True
+executeConditionOnMaybes (Just _) NotEqual Nothing = True
+executeConditionOnMaybes _ _ _ = False
 
-executeJSONPathElement :: JSONPathElement -> Value -> ExecutionResult Value
-executeJSONPathElement (KeyChild key) val =
-  case val of
-    Object o -> Map.lookup key o
-                & (maybeToResult (notFoundErr key o))
-    _ -> ResultError $ expectedObjectErr val
-executeJSONPathElement (AnyChild) val =
-  case val of
-    Object o -> ResultList $ Map.elems o
-    Array a  -> ResultList $ V.toList a
-    _        -> ResultError $ expectedObjectErr val
-executeJSONPathElement (Slice slice) val =
-  case val of
-    Array a -> executeSliceElement slice a
-    _       -> ResultError $ expectedArrayErr val
-executeJSONPathElement (SliceUnion first second) val =
-  case val of
-    Array a -> appendResults (executeSliceElement first a) (executeSliceElement second a)
-    _ -> ResultError $ expectedArrayErr val
-executeJSONPathElement (Filter _ jsonPath cond lit) val =
+{- ORMOLU_DISABLE -}
+isEqualTo :: Value -> Value -> Bool
+(Object _) `isEqualTo` _          = False
+_          `isEqualTo` (Object _) = False
+(Array _)  `isEqualTo` _          = False
+_          `isEqualTo` (Array _)  = False
+val1       `isEqualTo` val2       = val1 == val2
+
+isSmallerThan :: Value -> Value -> Bool
+(Number n1) `isSmallerThan` (Number n2) = n1 < n2
+(String s1) `isSmallerThan` (String s2) = s1 < s2
+_           `isSmallerThan` _ = False
+{- ORMOLU_ENABLE -}
+
+executeCondition :: Value -> Condition -> Value -> Bool
+executeCondition val1 NotEqual val2 = not (executeCondition val1 Equal val2)
+executeCondition val1 Equal val2 = val1 `isEqualTo` val2
+executeCondition val1 SmallerThan val2 = val1 `isSmallerThan` val2
+executeCondition val1 GreaterThan val2 =
+  canCompare val1 val2
+    && not (executeCondition val1 SmallerThan val2)
+    && not (executeCondition val1 Equal val2)
+executeCondition val GreaterThanOrEqual lit =
+  canCompare val lit
+    && not (executeCondition val SmallerThan lit)
+executeCondition val1 SmallerThanOrEqual val2 =
+  canCompare val1 val2
+    && not (executeCondition val1 GreaterThan val2)
+
+canCompare :: Value -> Value -> Bool
+canCompare (Number _) (Number _) = True
+canCompare (String _) (String _) = True
+canCompare _ _ = False
+
+executeSliceOnValue :: Maybe Int -> Maybe Int -> Maybe Int -> Value -> [Value]
+executeSliceOnValue start end step val =
   case val of
-    Array a -> do
-      let l = V.toList a
-      ResultList $ Prelude.map (executeJSONPath jsonPath) l
-        & zip l
-        & excludeSndErrors
-        & Prelude.foldr (\(x,ys) acc -> if length ys == 1 then (x, head ys):acc else acc) []
-        & Prelude.filter (\(origVal, exprVal) -> executeCondition exprVal cond lit)
-        & Prelude.map fst
-    _ -> ResultError $ expectedArrayErr val
-executeJSONPathElement s@(Search js) val =
-  let x = either (const []) id $ executeJSONPathEither js val
-      y = excludeErrors $ valMap (executeJSONPathElement s) val
-  in if Prelude.null x && Prelude.null y
-     then ResultError "Search failed"
-     else ResultList $ x ++ y
+    Array a -> executeSlice start end step a
+    _ -> []
 
-valMap :: ToJSON b => (Value -> ExecutionResult b) -> Value -> [ExecutionResult b]
-valMap f v@(Object o) = elems $ Map.map f o
-valMap f (Array a) = V.toList $ V.map f a
-valMap _ v = pure $ ResultError $ "Expected object or array, found " <> (encodeJSONToString v)
+-- | Implementation is based on
+-- https://ietf-wg-jsonpath.github.io/draft-ietf-jsonpath-base/draft-ietf-jsonpath-base.html#name-array-slice-selector
+executeSlice :: forall a. Maybe Int -> Maybe Int -> Maybe Int -> V.Vector a -> [a]
+executeSlice mStart mEnd mStep v
+  | step == 0 = []
+  | step > 0 = postitiveStepLoop lowerBound
+  | otherwise = negativeStepLoop upperBound
+  where
+    postitiveStepLoop :: Int -> [a]
+    postitiveStepLoop i
+      | i < upperBound = v V.! i : postitiveStepLoop (i + step)
+      | otherwise = []
 
-executeCondition :: Value -> Condition -> Literal -> Bool
-executeCondition (Number n1) Equal (LitNumber n2) = n1 == (fromInteger $ toInteger n2)
-executeCondition (String s1) Equal (LitString s2) = s1 == s2
+    negativeStepLoop :: Int -> [a]
+    negativeStepLoop i
+      | i > lowerBound = v V.! i : negativeStepLoop (i + step)
+      | otherwise = []
 
-executeSliceElement :: SliceElement -> V.Vector Value -> ExecutionResult Value
-executeSliceElement (SingleIndex i) v                = if i < 0
-                                                          then maybeToResult (invalidIndexErr i v) $ (V.!?) v (V.length v + i)
-                                                          else maybeToResult (invalidIndexErr i v) $ (V.!?) v i
-executeSliceElement (SimpleSlice start end) v        = sliceEither v start end 1
-executeSliceElement (SliceWithStep start end step) v = sliceEither v start end step
-executeSliceElement (SliceTo end) v                  = sliceEither v 0 end 1
-executeSliceElement (SliceToWithStep end step) v     = sliceEither v 0 end step
-executeSliceElement (SliceFrom start) v              = sliceEither v start (-1) 1
-executeSliceElement (SliceFromWithStep start step) v = sliceEither v start (-1) step
-executeSliceElement (SliceWithOnlyStep step) v       = sliceEither v 0 (-1) step
+    len = V.length v
+    step = fromMaybe 1 mStep
 
-sliceEither :: ToJSON a
-    => V.Vector a -> Int -> Int -> Int -> ExecutionResult a
-sliceEither v start end step = let len = V.length v
-                                   realStart = if start < 0 then len + start else start
-                                   realEnd = if end < 0 then len + end + 1 else end
-                               in if realStart < realEnd
-                                  then appendResults (indexEither v realStart) (sliceEither v (realStart + step) realEnd step)
-                                  else ResultList []
+    normalizeIndex :: Int -> Int
+    normalizeIndex i =
+      if i >= 0 then i else len + i
 
-indexEither :: ToJSON a => V.Vector a -> Int -> ExecutionResult a
-indexEither v i = (V.!?) v i
-                  & maybeToResult (invalidIndexErr i v)
+    defaultStart
+      | step >= 0 = 0
+      | otherwise = len - 1
+    start = fromMaybe defaultStart mStart
+    normalizedStart = normalizeIndex start
 
-excludeSndErrors :: [(c, ExecutionResult a)] -> [(c, [a])]
-excludeSndErrors xs = Prelude.foldr accumulateFn ([] :: [(c, b)]) xs where
-  accumulateFn (x, ResultList ys) acc = (x, ys):acc
-  accumulateFn (x, ResultValue y) acc = (x, [y]):acc
-  accumulateFn (x, _) acc             = acc
+    defaultEnd
+      | step >= 0 = len
+      | otherwise = negate len - 1
+    end = fromMaybe defaultEnd mEnd
+    normalizedEnd = normalizeIndex end
 
-encodeJSONToString :: ToJSON a => a -> String
-encodeJSONToString x = LazyText.unpack $ encodeToLazyText x
+    lowerBound
+      | step >= 0 = min (max normalizedStart 0) len
+      | otherwise = min (max normalizedEnd (-1)) (len - 1)
+    upperBound
+      | step >= 0 = min (max normalizedEnd 0) len
+      | otherwise = min (max normalizedStart (-1)) (len - 1)
 
-notFoundErr key o = "expected key " <> unpack key <> " in object " <> (encodeJSONToString o)
-invalidIndexErr i a = "index " <> show i <> " invalid for array " <> (encodeJSONToString a)
-expectedObjectErr val = "expected object, found " <> (encodeJSONToString val)
-expectedArrayErr val = "expected array, found " <> (encodeJSONToString val)
+executeIndexChild :: Int -> V.Vector a -> Maybe a
+executeIndexChild i v =
+  if i < 0
+    then (V.!?) v (V.length v + i)
+    else (V.!?) v i
+
+executeUnionElement :: UnionElement -> Value -> [Value]
+executeUnionElement (UEIndexChild i) v = executeIndexChildOnValue i v
+executeUnionElement (UESlice start end step) v = executeSliceOnValue start end step v
+executeUnionElement (UEKeyChild child) v = executeKeyChildOnValue child v
+
+executeKeyChildOnValue :: Text -> Value -> [Value]
+executeKeyChildOnValue key val =
+  maybeToList $ executeSingularPathElement (Key key) val
+
+executeIndexChildOnValue :: Int -> Value -> [Value]
+executeIndexChildOnValue i val =
+  maybeToList $ executeSingularPathElement (Index i) val
+
+executeSingularPathElement :: SingularPathElement -> Value -> Maybe Value
+executeSingularPathElement (Key key) val =
+  case val of
+    Object o -> Map.lookup (Key.fromText key) o
+    _ -> Nothing
+executeSingularPathElement (Index i) val =
+  case val of
+    Array a -> executeIndexChild i a
+    _ -> Nothing
+
+executeSingularPath :: SingularPath -> Value -> Value -> Maybe Value
+executeSingularPath (SingularPath beginnigPoint ps) rootVal currentVal =
+  let val = case beginnigPoint of
+        Root -> rootVal
+        CurrentObject -> currentVal
+   in Foldable.foldl'
+        ( \case
+            Nothing -> const Nothing
+            Just v -> flip executeSingularPathElement v
+        )
+        (Just val)
+        ps
+
+executeFilter :: FilterExpr -> Value -> [Value] -> [Value]
+executeFilter expr rootVal = Prelude.filter (filterExprPred expr rootVal)
+
+comparableToValue :: Comparable -> Value -> Value -> Maybe Value
+comparableToValue (CmpNumber n) _ _ = Just $ Number n
+comparableToValue (CmpString s) _ _ = Just $ String s
+comparableToValue (CmpBool b) _ _ = Just $ Bool b
+comparableToValue CmpNull _ _ = Just Null
+comparableToValue (CmpPath p) rootVal val =
+  executeSingularPath p rootVal val
+
+filterExprPred :: FilterExpr -> Value -> Value -> Bool
+filterExprPred expr rootVal val =
+  case expr of
+    ComparisonExpr cmp1 cond cmp2 ->
+      let val1 = comparableToValue cmp1 rootVal val
+          val2 = comparableToValue cmp2 rootVal val
+       in executeConditionOnMaybes val1 cond val2
+    ExistsExpr path ->
+      isJust $ executeSingularPath path rootVal val
+    Or e1 e2 ->
+      filterExprPred e1 rootVal val || filterExprPred e2 rootVal val
+    And e1 e2 ->
+      filterExprPred e1 rootVal val && filterExprPred e2 rootVal val
+    Not e ->
+      not $ filterExprPred e rootVal val
diff --git a/src/Data/JSONPath/ExecutionResult.hs b/src/Data/JSONPath/ExecutionResult.hs
deleted file mode 100644
--- a/src/Data/JSONPath/ExecutionResult.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-module Data.JSONPath.ExecutionResult where
-
-data ExecutionResult a = ResultList [a]
-                       | ResultValue a
-                       | ResultError String
-
-instance Functor ExecutionResult where
-  fmap f (ResultList xs)   = ResultList $ Prelude.map f xs
-  fmap f (ResultValue x)   = ResultValue $ f x
-  fmap f (ResultError err) = ResultError err
-
-instance Applicative ExecutionResult where
-  pure = ResultValue
-  (<*>) (ResultList fs) (ResultList xs) = ResultList $ fs <*> xs
-  (<*>) (ResultList fs) (ResultValue x) = ResultList $ Prelude.map (\f -> f x) fs
-  (<*>) (ResultValue f) (ResultList xs) = ResultList $ Prelude.map f xs
-  (<*>) (ResultValue f) (ResultValue x) = ResultValue $ f x
-  (<*>) (ResultError e) _               = ResultError e
-  (<*>) _ (ResultError e)               = ResultError e
-
-instance Monad ExecutionResult where
-  (>>=) (ResultValue x) f = f x
-  (>>=) (ResultList xs) f = concatResults $ Prelude.map f xs
-  (>>=) (ResultError e) f = ResultError e
-
-concatResults :: [ExecutionResult a] -> ExecutionResult a
-concatResults [] = ResultList []
-concatResults (ResultList xs:rs) = case concatResults rs of
-                                     ResultList ys -> ResultList (xs ++ ys)
-                                     ResultValue y -> ResultList (y:xs)
-                                     e             -> e
-concatResults (ResultValue x:[]) = ResultValue x
-concatResults (ResultValue x:rs) = case concatResults rs of
-                                     ResultList ys -> ResultList (x:ys)
-                                     ResultValue y -> ResultList [x,y]
-                                     e             -> e
-concatResults (e:_) = e
-
-appendResults :: ExecutionResult a -> ExecutionResult a -> ExecutionResult a
-appendResults (ResultValue x) (ResultValue y) = ResultList [x,y]
-appendResults (ResultValue x) (ResultList ys) = ResultList $ x:ys
-appendResults (ResultList xs) (ResultValue y) = ResultList $ y:xs
-appendResults (ResultList xs) (ResultList ys) = ResultList $ xs ++ ys
-appendResults _ e                             = e
-
-maybeToResult :: String -> Maybe a ->ExecutionResult a
-maybeToResult _ (Just x) = ResultValue x
-maybeToResult err _      = ResultError err
-
-resultToEither :: ExecutionResult a -> Either String [a]
-resultToEither (ResultList xs) = return xs
-resultToEither (ResultValue x) = return [x]
-resultToEither (ResultError e) = Left e
-
-excludeErrors :: [ExecutionResult a] -> [a]
-excludeErrors []                 = []
-excludeErrors (ResultError _:rs) = excludeErrors rs
-excludeErrors (ResultList xs:rs) = xs ++ excludeErrors rs
-excludeErrors (ResultValue x:rs) = x:(excludeErrors rs)
diff --git a/src/Data/JSONPath/Parser.hs b/src/Data/JSONPath/Parser.hs
--- a/src/Data/JSONPath/Parser.hs
+++ b/src/Data/JSONPath/Parser.hs
@@ -1,167 +1,227 @@
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE OverloadedStrings #-}
-module Data.JSONPath.Parser
-  (jsonPathElement, jsonPath)
-where
+{-# LANGUAGE TypeFamilies #-}
 
-import Control.Applicative  ((<|>))
-import Data.Attoparsec.Text as A
+module Data.JSONPath.Parser (jsonPathElement, jsonPath) where
+
+import qualified Data.Char as Char
 import Data.Functor
+import Data.Functor.Identity
 import Data.JSONPath.Types
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Data.Void (Void)
+import Text.Megaparsec as P
+import Text.Megaparsec.Char (char, space, string)
+import qualified Text.Megaparsec.Char.Lexer as L
 
-jsonPath :: Parser [JSONPathElement]
-jsonPath = do
-  _ <- skip (== '$') <|> pure ()
-  many1 jsonPathElement
+type Parser = P.ParsecT Void Text Identity
 
+jsonPath :: Parser a -> Parser [JSONPathElement]
+jsonPath endParser = do
+  _ <- optional $ char '$'
+  manyTill jsonPathElement (hidden $ lookAhead endParser)
+
 jsonPathElement :: Parser JSONPathElement
-jsonPathElement = do
-    (keyChildDot <?> "keyChldDot")
-    <|> (keyChildBracket <?> "keyChildBracket")
-    <|> (keyChildren <?> "keyChildren")
-    <|> (anyChild <?> "anyChild")
-    <|> (slice <?> "slice")
-    <|> (sliceUnion <?> "sliceUnion")
-    <|> (filterParser <?> "filterParser")
-    <|> (search <?> "serach")
-    <|> (searchBeginingWithSlice <?> "serachBegingingWithSlice")
+jsonPathElement =
+  ignoreSurroundingSpace $
+    try anyChild
+      <|> try keyChild
+      <|> try slice
+      <|> try indexChild
+      <|> try union
+      <|> try filterParser
+      <|> try search
+      <|> searchBeginningWithSlice
 
+indexChild :: Parser JSONPathElement
+indexChild = IndexChild <$> inSqBr indexChildWithoutBrackets
+
+indexChildWithoutBrackets :: Parser Int
+indexChildWithoutBrackets = ignoreSurroundingSpace $ L.signed space L.decimal
+
 slice :: Parser JSONPathElement
-slice = Slice <$> ignoreSurroundingSqBr sliceWithoutBrackets
+slice =
+  uncurry3 Slice
+    <$> inSqBr sliceWithoutBrackets
 
-sliceWithoutBrackets = (sliceWithStep <?> "sliceWithStep")
-                       <|> (simpleSlice <?> "simpleSlice")
-                       <|> (sliceFromWithStep <?> "sliceFromWithStep")
-                       <|> (sliceFrom <?> "sliceFrom")
-                       <|> (singleIndex <?> "singleIndex")
-                       <|> (sliceToWithStep <?> "sliceToWithStep")
-                       <|> (sliceTo <?> "sliceTo")
-                       <|> (sliceWithOnlyStep <?> "sliceWithOnlyStep")
+sliceWithoutBrackets :: Parser (Maybe Int, Maybe Int, Maybe Int)
+sliceWithoutBrackets = do
+  (,,)
+    <$> parseStart
+    <*> parseEnd
+    <*> parseStep
+  where
+    parseStart :: Parser (Maybe Int)
+    parseStart =
+      ignoreSurroundingSpace (optional (L.signed space L.decimal))
+        <* char ':'
 
-singleIndex :: Parser SliceElement
-singleIndex = SingleIndex <$> signed decimal
+    parseEnd =
+      ignoreSurroundingSpace $ optional $ L.signed space L.decimal
 
-keyChildBracket :: Parser JSONPathElement
-keyChildBracket = KeyChild
-                  <$> (string "['" *> takeWhile1 (inClass "a-zA-Z0-9_-") <* string "']")
+    parseStep =
+      optional (char ':')
+        *> ignoreSurroundingSpace (optional (L.signed space L.decimal))
 
-keyChildDot :: Parser JSONPathElement
-keyChildDot = KeyChild
-              <$> (char '.' *> takeWhile1 (inClass "a-zA-Z0-9_-"))
+keyChild :: Parser JSONPathElement
+keyChild = KeyChild <$> (try sqBrKeyChild <|> dotKeyChild)
 
-keyChildren :: Parser JSONPathElement
-keyChildren = do
-  _ <- string "['"
-  firstKey <- takeWhile1 (inClass "a-zA-Z0-9_-")
-  restKeys <- many' $ char '.' *> takeWhile1 (inClass "a-zA-Z0-9_-")
-  _ <- string "']"
-  return $ KeyChildren (firstKey:restKeys)
+sqBrKeyChild :: Parser Text
+sqBrKeyChild =
+  inSqBr $ ignoreSurroundingSpace quotedString
 
+dotKeyChild :: Parser Text
+dotKeyChild = char '.' *> takeWhile1P Nothing (\c -> Char.isAlphaNum c || c == '-' || c == '_')
+
 anyChild :: Parser JSONPathElement
-anyChild = AnyChild <$ (string ".*" <|> string "[*]")
+anyChild = ignoreSurroundingSpace $ AnyChild <$ (void (string ".*") <|> void (inSqBr (char '*')))
 
--- peekAssertClosingSqBr :: Parser ()
--- peekAssertClosingSqBr 
+union :: Parser JSONPathElement
+union =
+  inSqBr $
+    Union <$> do
+      firstElement <- unionElement
+      restElements <- some (char ',' *> unionElement)
+      pure (firstElement : restElements)
 
-simpleSlice :: Parser SliceElement
-simpleSlice = do
-  start <- signed decimal
-  _ <- char ':'
-  end <- signed decimal
-  return $ SimpleSlice start end
+unionElement :: Parser UnionElement
+unionElement =
+  try (uncurry3 UESlice <$> sliceWithoutBrackets)
+    <|> try (UEIndexChild <$> indexChildWithoutBrackets)
+    <|> UEKeyChild <$> ignoreSurroundingSpace quotedString
 
-sliceWithStep :: Parser SliceElement
-sliceWithStep = do
-  start <- signed decimal
-  _ <- char ':'
-  end <- signed decimal
-  _ <- char ':'
-  step <- signed decimal
-  return $ SliceWithStep start end step
+filterParser :: Parser JSONPathElement
+filterParser = inSqBr $ do
+  _ <- ignoreSurroundingSpace $ char '?'
+  Filter <$> filterExpr (ignoreSurroundingSpace (char ']'))
 
-sliceFrom :: Parser SliceElement
-sliceFrom = do
-  start <- signed decimal
-  _ <- char ':'
-  return $ SliceFrom start
+filterExpr :: Parser a -> Parser FilterExpr
+filterExpr endParser =
+  try (orFilterExpr endParser)
+    <|> try (andFilterExpr endParser)
+    <|> basicFilterExpr endParser
 
-sliceFromWithStep :: Parser SliceElement
-sliceFromWithStep = do
-  start <- signed decimal
-  _ <- string "::"
-  step <- signed decimal
-  return $ SliceFromWithStep start step
+basicFilterExpr :: Parser a -> Parser FilterExpr
+basicFilterExpr endParser = do
+  maybeNot <- optional (char '!')
+  expr <-
+    try (comparisionFilterExpr endParser)
+      <|> try (existsFilterExpr endParser)
+      <|> (inParens (filterExpr closingParen) <* lookAhead endParser)
+  case maybeNot of
+    Nothing -> pure expr
+    Just _ -> pure $ Not expr
 
-sliceTo :: Parser SliceElement
-sliceTo = do
-  _ <- char ':'
-  end <- signed decimal
-  return $ SliceTo end
+comparisionFilterExpr :: Parser a -> Parser FilterExpr
+comparisionFilterExpr endParser = do
+  expr <-
+    ComparisonExpr
+      <$> comparable condition
+      <*> condition
+      <*> comparable endParser
+  _ <- lookAhead endParser
+  pure expr
 
-sliceToWithStep :: Parser SliceElement
-sliceToWithStep = do
-  _ <- char ':'
-  end <- signed decimal
-  _ <- char ':'
-  step <- signed decimal
-  return $ SliceToWithStep end step
+existsFilterExpr :: Parser a -> Parser FilterExpr
+existsFilterExpr endParser =
+  ExistsExpr <$> singularPath endParser
 
-sliceWithOnlyStep :: Parser SliceElement
-sliceWithOnlyStep = do
-  _ <- string "::"
-  step <- signed decimal
-  return $ SliceWithOnlyStep step
+singularPath :: Parser a -> Parser SingularPath
+singularPath endParser =
+  SingularPath
+    <$> beginningPoint
+    <*> manyTill singularPathElement (lookAhead endParser)
 
-sliceUnion :: Parser JSONPathElement
-sliceUnion = ignoreSurroundingSqBr $  do
-  firstElement <- sliceWithoutBrackets <?> "firstElement"
-  _ <- char ','
-  secondElement <- sliceWithoutBrackets <?> "secondElement"
-  return $ SliceUnion firstElement secondElement
+singularPathElement :: Parser SingularPathElement
+singularPathElement =
+  (Key <$> try dotKeyChild)
+    <|> (Key <$> try sqBrKeyChild)
+    <|> Index <$> inSqBr indexChildWithoutBrackets
 
-filterParser :: Parser JSONPathElement
-filterParser = do
-  _ <- string "[?(" <?> "[?("
-  b <- beginingPoint <?> "begining point"
-  js <- jsonPath <?> "jsonPathElements"
-  c <- condition <?> "condition"
-  l <- literal <?> "literal"
-  _ <- string ")]" <?> ")]"
-  return $ Filter b js c l
+orFilterExpr :: Parser a -> Parser FilterExpr
+orFilterExpr endParser = do
+  let orOperator = ignoreSurroundingSpace $ string "||"
+  e1 <-
+    -- If there is an '&&' operation, it should take precedence over the '||'
+    try (andFilterExpr orOperator)
+      <|> basicFilterExpr orOperator
+  _ <- orOperator
+  Or e1 <$> filterExpr endParser
 
+andFilterExpr :: Parser a -> Parser FilterExpr
+andFilterExpr endParser = do
+  let andOperator = ignoreSurroundingSpace $ string "&&"
+  e1 <- basicFilterExpr andOperator
+  _ <- andOperator
+  And e1 <$> filterExpr endParser
+
 search :: Parser JSONPathElement
 search = do
   _ <- char '.'
-  isDot <- (== '.') <$> peekChar'
-  if isDot
-    then Search <$> many1 jsonPathElement
-    else  fail "not a search element"
+  _ <- lookAhead (char '.')
+  Search <$> some jsonPathElement
 
-searchBeginingWithSlice :: Parser JSONPathElement
-searchBeginingWithSlice = do
+searchBeginningWithSlice :: Parser JSONPathElement
+searchBeginningWithSlice = do
   _ <- string ".."
-  isBracket <- (== '[') <$> peekChar'
-  if isBracket
-    then Search <$> many1 jsonPathElement
-    else  fail "not a search element"
+  _ <- lookAhead (char '[')
+  Search <$> some jsonPathElement
 
-beginingPoint :: Parser BegingingPoint
-beginingPoint = do
-  ((char '$' $> Root) <|> (char '@' $> CurrentObject))
+beginningPoint :: Parser BeginningPoint
+beginningPoint =
+  try (char '$' $> Root)
+    <|> (char '@' $> CurrentObject)
 
 condition :: Parser Condition
-condition = ignoreSurroundingSpace
-            $ string "==" $> Equal
-            <|> string "!=" $> NotEqual
-            <|> string ">" $> GreaterThan
-            <|> string "<" $> SmallerThan
+condition =
+  ignoreSurroundingSpace $
+    string "==" $> Equal
+      <|> string "!=" $> NotEqual
+      <|> string "<=" $> SmallerThanOrEqual
+      <|> string ">=" $> GreaterThanOrEqual
+      <|> string ">" $> GreaterThan
+      <|> string "<" $> SmallerThan
 
-literal :: Parser Literal
-literal = do
-  (LitNumber <$> signed decimal)
-  <|> LitString <$> (char '"' *> A.takeWhile (/= '"') <* char '"')
+comparable :: Parser a -> Parser Comparable
+comparable endParser = do
+  CmpNumber <$> L.scientific
+    <|> CmpString <$> quotedString
+    <|> CmpBool <$> bool
+    <|> CmpNull <$ string "null"
+    <|> CmpPath <$> singularPath endParser
 
+bool :: Parser Bool
+bool =
+  True <$ string "true"
+    <|> False <$ string "false"
+
 ignoreSurroundingSpace :: Parser a -> Parser a
-ignoreSurroundingSpace p = many' space *> p <* many' space
+ignoreSurroundingSpace p = space *> p <* space
 
-ignoreSurroundingSqBr :: Parser a -> Parser a
-ignoreSurroundingSqBr p = char '[' *> p <* char ']'
+inSqBr :: Parser a -> Parser a
+inSqBr p = openingSqBr *> p <* closingSqBr
+
+openingSqBr :: Parser Char
+openingSqBr = ignoreSurroundingSpace (char '[')
+
+closingSqBr :: Parser Char
+closingSqBr = ignoreSurroundingSpace (char ']')
+
+inParens :: Parser a -> Parser a
+inParens p = openingParen *> p <* closingParen
+
+openingParen :: Parser Char
+openingParen = ignoreSurroundingSpace (char '(')
+
+closingParen :: Parser Char
+closingParen = ignoreSurroundingSpace (char ')')
+
+quotedString :: Parser Text
+quotedString = ignoreSurroundingSpace $ Text.pack <$> (inQuotes '"' <|> inQuotes '\'')
+  where
+    inQuotes quoteChar =
+      char quoteChar *> manyTill L.charLiteral (char quoteChar)
+
+uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
+uncurry3 f (a, b, c) = f a b c
diff --git a/src/Data/JSONPath/Types.hs b/src/Data/JSONPath/Types.hs
--- a/src/Data/JSONPath/Types.hs
+++ b/src/Data/JSONPath/Types.hs
@@ -1,45 +1,80 @@
 module Data.JSONPath.Types
-  ( BegingingPoint(..)
-  , Condition(..)
-  , Literal(..)
-  , JSONPathElement(..)
-  , SliceElement(..)
-  , module Data.JSONPath.ExecutionResult
+  ( BeginningPoint (..),
+    Condition (..),
+    Comparable (..),
+    JSONPathElement (..),
+    UnionElement (..),
+    FilterExpr (..),
+    SingularPathElement (..),
+    SingularPath (..),
   )
 where
 
+import Data.Scientific (Scientific)
 import Data.Text
-import Data.JSONPath.ExecutionResult
 
-data BegingingPoint = Root
-                    | CurrentObject
+data BeginningPoint
+  = Root
+  | CurrentObject
   deriving (Show, Eq)
 
-data Condition = Equal
-               | NotEqual
-               | GreaterThan
-               | SmallerThan
+-- | A JSONPath which finds at max one value, given a beginning point. Used by
+-- 'FilterExpr' for 'ExistsExpr' and 'ComparisonExpr'.
+data SingularPath
+  = SingularPath BeginningPoint [SingularPathElement]
   deriving (Show, Eq)
 
-data Literal = LitNumber Int
-             | LitString Text
+data SingularPathElement
+  = Key Text
+  | Index Int
   deriving (Show, Eq)
 
-data SliceElement = SingleIndex Int
-                  | SimpleSlice Int Int
-                  | SliceWithStep Int Int Int
-                  | SliceTo Int
-                  | SliceToWithStep Int Int
-                  | SliceFrom Int
-                  | SliceFromWithStep Int Int
-                  | SliceWithOnlyStep Int
+data Comparable
+  = CmpNumber Scientific
+  | CmpString Text
+  | CmpBool Bool
+  | CmpNull
+  | CmpPath SingularPath
   deriving (Show, Eq)
 
-data JSONPathElement  = KeyChild Text
-                      | KeyChildren [Text]
-                      | AnyChild
-                      | Slice SliceElement
-                      | SliceUnion SliceElement SliceElement
-                      | Filter BegingingPoint [JSONPathElement] Condition Literal
-                      | Search [JSONPathElement]
+data Condition
+  = Equal
+  | NotEqual
+  | GreaterThan
+  | SmallerThan
+  | GreaterThanOrEqual
+  | SmallerThanOrEqual
+  deriving (Show, Eq)
+
+data FilterExpr
+  = ExistsExpr SingularPath
+  | ComparisonExpr Comparable Condition Comparable
+  | And FilterExpr FilterExpr
+  | Or FilterExpr FilterExpr
+  | Not FilterExpr
+  deriving (Show, Eq)
+
+-- | Elements which can occur inside a union
+data UnionElement
+  = UEKeyChild Text
+  | UEIndexChild Int
+  | UESlice (Maybe Int) (Maybe Int) (Maybe Int)
+  deriving (Show, Eq)
+
+-- | A 'JSONPath' is a list of 'JSONPathElement's.
+data JSONPathElement
+  = -- | '$.foo' or '$["foo"]'
+    KeyChild Text
+  | -- | '$[1]'
+    IndexChild Int
+  | -- | '$[*]'
+    AnyChild
+  | -- | '$[1:7]', '$[0:10:2]', '$[::2]', '$[::]', etc.
+    Slice (Maybe Int) (Maybe Int) (Maybe Int)
+  | -- | '$[0,1,9]' or '$[0, 1:2, "foo", "bar"]'
+    Union [UnionElement]
+  | -- | '$[?(@.foo == 42)]', '$[?(@.foo > @.bar)]', etc.
+    Filter FilterExpr
+  | -- | '$..foo.bar'
+    Search [JSONPathElement]
   deriving (Show, Eq)
diff --git a/test/Data/JSONPathSpec.hs b/test/Data/JSONPathSpec.hs
--- a/test/Data/JSONPathSpec.hs
+++ b/test/Data/JSONPathSpec.hs
@@ -1,41 +1,41 @@
-{-# LANGUAGE CPP               #-}
-{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE TemplateHaskell   #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+
 module Data.JSONPathSpec where
 
+import Control.Monad.IO.Class (liftIO)
 import Data.Aeson
 import Data.Aeson.Casing
-import Data.Aeson.Text
 import Data.Aeson.TH
-import Data.Attoparsec.Text
+import Data.Aeson.Text
+import Data.Bifunctor (Bifunctor (first))
+import qualified Data.ByteString.Lazy as LBS
 import Data.Either
 import Data.FileEmbed
 import Data.JSONPath
-import Data.Text             (Text, unpack)
+import Data.Text (Text, unpack)
+import qualified Data.Text.Lazy as LazyText
+import qualified Data.Vector as V
 import GHC.Generics
+import System.Timeout
 import Test.Hspec
-import Test.Hspec.Attoparsec
-
-#if !MIN_VERSION_base (4,11,0)
-import Data.Semigroup ((<>))
-#endif
-
-import qualified Data.ByteString.Lazy as LBS
-import qualified Data.Text.Lazy       as LazyText
-import qualified Data.Vector          as V
+import Test.Hspec.Megaparsec
+import Text.Megaparsec
 
-data Test = Test { path   :: Text
-                 , result :: Value
-                 }
-            deriving (Eq, Show, Generic)
+data Test = Test
+  { path :: Text,
+    result :: Value
+  }
+  deriving (Eq, Show, Generic)
 
-data TestGroup = TestGroup { groupTitle :: Text
-                           , groupData  :: Value
-                           , groupTests :: [Test]
-                           }
-               deriving (Eq, Show, Generic)
+data TestGroup = TestGroup
+  { groupTitle :: Text,
+    groupData :: Value,
+    groupTests :: [Test]
+  }
+  deriving (Eq, Show, Generic)
 
 $(deriveJSON defaultOptions ''Test)
 $(deriveJSON (aesonPrefix snakeCase) ''TestGroup)
@@ -44,35 +44,56 @@
 spec =
   let testFiles = map snd $(embedDir "test/resources/json-path-tests")
       testVals :: Either String [TestGroup]
-      testVals = sequenceA $ map (eitherDecode . LBS.fromStrict) testFiles
-  in case testVals of
-       Left e -> describe "JSONPath Tests"
-                  $ it "shouldn't fail to parse test files"
-                  $ expectationFailure ("failed to parse test files with error: \n" <> e)
-       Right gs -> describe "JSONPath"
-                   $ do
-                     mapM_ group gs
-                     describe "Parser" $ do
-                       it "should parse basic things" $ do
-                         (".foo" :: Text) ~> (jsonPathElement <* endOfInput)
-                           `shouldParse` KeyChild "foo"
-                         ("$.foo" :: Text) ~> (jsonPath <* endOfInput)
-                           `shouldParse` [KeyChild "foo"]
+      testVals = traverse (eitherDecode . LBS.fromStrict) testFiles
+   in case testVals of
+        Left e ->
+          describe "JSONPath Tests" $
+            it "shouldn't fail to parse test files" $
+              expectationFailure ("failed to parse test files with error: \n" <> e)
+        Right gs -> describe "JSONPath" $
+          do
+            mapM_ group gs
+            describe "Parser" $ do
+              it "should parse basic things" $ do
+                parse (jsonPathElement <* eof) "" ".foo"
+                  `shouldParse` KeyChild "foo"
+                parse (jsonPath eof) "" "$.foo"
+                  `shouldParse` [KeyChild "foo"]
 
 parseJSONPath :: Text -> Either String [JSONPathElement]
-parseJSONPath = parseOnly (jsonPath <* endOfInput)
+parseJSONPath = first errorBundlePretty . parse (jsonPath eof) ""
 
 group :: TestGroup -> Spec
-group TestGroup{..} = describe (unpack groupTitle)
-                      $ mapM_ (test groupData) groupTests
+group TestGroup {..} = do
+  describe (unpack groupTitle) $
+    mapM_ (test groupData) groupTests
 
+-- | 100 ms
+timeLimit :: Int
+timeLimit = 100000
+
 test :: Value -> Test -> Spec
 test testData (Test path expected) =
-  let result = parseJSONPath path >>= (flip executeJSONPathEither testData)
-  in it (unpack path) $
-     case expected of
-       Array a -> case result of
-         Left err -> expectationFailure $ "Unexpected Left: " <> err
-         Right r  -> r `shouldMatchList` (V.toList a)
-       Bool False -> result `shouldSatisfy` isLeft
-       v -> expectationFailure $ "Invalid result in test data " <> (LazyText.unpack $ encodeToLazyText v)
+  it (unpack path) $ do
+    mResult <-
+      liftIO $
+        timeout timeLimit $ do
+          -- Using '$!' here ensures that the computation is strict, so this can
+          -- be timed out properly
+          pure $! do
+            parsed <- parseJSONPath path
+            Right $ executeJSONPath parsed testData
+
+    result <- case mResult of
+      Just r -> pure r
+      Nothing -> do
+        expectationFailure "JSONPath execution timed out"
+        undefined
+
+    case expected of
+      Array a -> case result of
+        Left e -> expectationFailure $ "Unexpected Left: " <> e
+        -- TODO: Define order of result and make this `shouldBe`
+        Right r -> r `shouldMatchList` V.toList a
+      Bool False -> result `shouldSatisfy` isLeft
+      v -> expectationFailure $ "Invalid result in test data " <> LazyText.unpack (encodeToLazyText v)
diff --git a/test/resources/json-path-tests/DotOperator.json b/test/resources/json-path-tests/DotOperator.json
--- a/test/resources/json-path-tests/DotOperator.json
+++ b/test/resources/json-path-tests/DotOperator.json
@@ -1,48 +1,41 @@
-{
-	"title": "Dot Operator",
-	"data": {
-		"firstName": "John",
-		"lastName": "Doe",
-		"home": "987-654-3210",
-		"mobile": null
-	},
-	"tests": [
-		{
-			"path": "$.firstName",
-			"result": [
-				"John"
-			]
-		},
-		{
-			"path": "$.lastName",
-			"result": [
-				"Doe"
-			]
-		},
-		{
-			"path": "$.home",
-			"result": [
-				"987-654-3210"
-			]
-		},
-		{
-			"path": "$.mobile",
-			"result": [
-				null
-			]
-		},
-		{
-			"path": "$.missingKey",
-			"result": false
-		},
-		{
-			"path": "$.*",
-			"result": [
-				"John",
-				"Doe",
-				"987-654-3210",
-				null
-			]
-		}
-	]
-}
+{
+    "title": "Dot Operator",
+    "data": {
+        "firstName": "John",
+        "lastName": "Doe",
+        "home": "987-654-3210",
+        "mobile": null
+    },
+    "tests": [{
+        "path": "$.firstName",
+        "result": [
+            "John"
+        ]
+    }, {
+        "path": "$.lastName",
+        "result": [
+            "Doe"
+        ]
+    }, {
+        "path": "$.home",
+        "result": [
+            "987-654-3210"
+        ]
+    }, {
+        "path": "$.mobile",
+        "result": [
+            null
+        ]
+    }, {
+        "path": "$.missingKey",
+        "result": []
+    }, {
+        "path": "$.*",
+        "result": [
+            "John",
+            "Doe",
+            "987-654-3210",
+            null
+        ]
+    }]
+}
diff --git a/test/resources/json-path-tests/EmptyPath.json b/test/resources/json-path-tests/EmptyPath.json
new file mode 100644
--- /dev/null
+++ b/test/resources/json-path-tests/EmptyPath.json
@@ -0,0 +1,50 @@
+{
+    "title" : "Chained Elements",
+    "data" : {
+        "firstName" : "John",
+        "lastName" : "Doe",
+        "eyes" : "blue",
+        "children" : [{
+            "firstName" : "Sally",
+            "lastName" : "Doe",
+            "favoriteGames" : ["Halo", "Minecraft", "Lego: Star Wars"]
+        }, {
+            "firstName" : "Mike",
+            "lastName" : "Doe",
+            "eyes" : "green"
+        }]
+    },
+    "tests" : [{
+        "path" : "",
+        "result" : [{
+            "firstName" : "John",
+            "lastName" : "Doe",
+            "eyes" : "blue",
+            "children" : [{
+                "firstName" : "Sally",
+                "lastName" : "Doe",
+                "favoriteGames" : ["Halo", "Minecraft", "Lego: Star Wars"]
+            }, {
+                "firstName" : "Mike",
+                "lastName" : "Doe",
+                "eyes" : "green"
+            }]
+        }]
+    }, {
+        "path" : "$",
+        "result" : [{
+            "firstName" : "John",
+            "lastName" : "Doe",
+            "eyes" : "blue",
+            "children" : [{
+                "firstName" : "Sally",
+                "lastName" : "Doe",
+                "favoriteGames" : ["Halo", "Minecraft", "Lego: Star Wars"]
+            }, {
+                "firstName" : "Mike",
+                "lastName" : "Doe",
+                "eyes" : "green"
+            }]
+        }]
+    }]
+}
diff --git a/test/resources/json-path-tests/FieldAccess.json b/test/resources/json-path-tests/FieldAccess.json
new file mode 100644
--- /dev/null
+++ b/test/resources/json-path-tests/FieldAccess.json
@@ -0,0 +1,57 @@
+{
+    "title": "Field Access",
+    "data": {
+        "a": 1,
+        "b": {"c" : { "d" : 2 }},
+        "e.f": {"g.h" : 3},
+        "!@#$+=- %)@!(*%\"": 4,
+        ":": 5,
+        "": 6,
+        "'": 7,
+        "\"": 8,
+        "\\'": 9
+    },
+    "tests": [{
+        "path": "$.a",
+        "result": [1]
+    }, {
+        "path": "$['a']",
+        "result": [1]
+    }, {
+        "path": "$[\"a\"]",
+        "result": [1]
+    }, {
+        "path": "$[ 'a']",
+        "result": [1]
+    }, {
+        "path": "$[ \"a\"]",
+        "result": [1]
+    }, {
+        "path": "$['b']['c'].d",
+        "result": [2]
+    }, {
+        "path": "$['e.f']['g.h']",
+        "result": [3]
+    }, {
+        "path": "$['!@#$+=- %)@!(*%\"']",
+        "result": [4]
+    }, {
+        "path": "$[':']",
+        "result": [5]
+    }, {
+        "path": "$['']",
+        "result": [6]
+    }, {
+        "path": "$[\"\"]",
+        "result": [6]
+    }, {
+        "path": "$['\\'']",
+        "result": [7]
+    }, {
+        "path": "$[\"\\\"\"]",
+        "result": [8]
+    }, {
+        "path": "$['\\\\\\'']",
+        "result": [9]
+    }]
+}
diff --git a/test/resources/json-path-tests/FilterExpressionSubscriptOperator.json b/test/resources/json-path-tests/FilterExpressionSubscriptOperator.json
--- a/test/resources/json-path-tests/FilterExpressionSubscriptOperator.json
+++ b/test/resources/json-path-tests/FilterExpressionSubscriptOperator.json
@@ -1,32 +1,326 @@
-{
-	"title" : "Filter Expression Subscript Operator",
-	"data" : [4,
-		"string",
-		false,
-		[1, 2, 3], {
-			"index" : 1,
-			"name" : "John Doe",
-			"occupation" : "Architect"
-		}, {
-			"index" : 2,
-			"name" : "Jane Smith",
-			"occupation" : "Architect",
-			"color" : "blue"
-		}
-	],
-	"tests" : [{
-			"path" : "$[?(@.occupation == \"Architect\")]",
-			"result" : [{
-					"index" : 1,
-					"name" : "John Doe",
-					"occupation" : "Architect"
-				}, {
-					"index" : 2,
-					"name" : "Jane Smith",
-					"occupation" : "Architect",
-					"color" : "blue"
-				}
-			]
-		}
-	]
-}
+{
+    "title" : "Filter Expression Subscript Operator",
+    "data" : {"arr" : [4,
+                       "string",
+                       false,
+                       null,
+                       [1, 2, 3], {
+                           "index" : 1,
+                           "name" : "John Doe",
+                           "occupation" : "Architect"
+                       }, {
+                           "index" : 2,
+                           "name" : "Jane Smith",
+                           "occupation" : "Architect",
+                           "color" : "blue"
+                       } , {
+                           "index" : 3,
+                           "name" : "John Smith",
+                           "occupation" : "Plumber"
+                       }, {
+                           "index" : 4,
+                           "name" : "Jane Doe",
+                           "occupation" : "Pilot"
+                       },
+                       { "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 },
+                       { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+                      ],
+              "obj": {"foo": 1, "bar": 2, "baz": {"qux": 3}, "bux": 4}
+             },
+    "tests" : [{
+            "path" : "$.arr[?(@.occupation == \"Architect\")]",
+            "result" : [{
+                "index" : 1,
+                "name" : "John Doe",
+                "occupation" : "Architect"
+            }, {
+                "index" : 2,
+                "name" : "Jane Smith",
+                "occupation" : "Architect",
+                "color" : "blue"
+            }]
+           }, {
+               "path" : "$.arr[?(@.occupation != \"Architect\")]",
+               "result" : [4,
+                           "string",
+                           false,
+                           null,
+                           [1, 2, 3], {
+                               "index" : 3,
+                               "name" : "John Smith",
+                               "occupation" : "Plumber"
+                           }, {
+                               "index" : 4,
+                               "name" : "Jane Doe",
+                               "occupation" : "Pilot"
+                           },
+                           { "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 },
+                           { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }]
+           }, {
+               "path" : "$.arr[?(@.name == \"John Smith\")]",
+               "result" : [{
+                   "index" : 3,
+                   "name" : "John Smith",
+                   "occupation" : "Plumber"
+               }]
+           }, {
+               "path" : "$.arr[?(@.name == 'John Smith')]",
+               "result" : [{
+                   "index" : 3,
+                   "name" : "John Smith",
+                   "occupation" : "Plumber"
+               }]
+           }, {
+               "path" : "$.arr[?(@.val > 3)]",
+               "result" : [{ "val" : 4 }]
+           }, {
+             "path" : "$.arr[?(3 < @.val)]",
+             "result" : [{ "val" : 4 }]
+           }, {
+               "path" : "$.arr[?@.val > 3]",
+               "result" : [{ "val" : 4 }]
+           }, {
+               "path" : "$.arr[? @.val > 3]",
+               "result" : [{ "val" : 4 }]
+           }, {
+               "path" : "$.arr[?(@.val >= 3)]",
+               "result" : [{ "val" : 4 }, { "val" : 3 }]
+           }, {
+               "path" : "$.arr[?(@.val < 3)]",
+               "result" : [{ "val" : 1 }, { "val" : 2 }]
+           }, {
+               "path" : "$.arr[?@.val]",
+               "result" : [{ "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 }]
+           }, {
+               "path" : "$.arr[?(@.val <= 3)]",
+               "result" : [{ "val" : 1 }, { "val" : 2 }, { "val" : 3 }]
+           }, {
+               "path" : "$.arr[?(@.val <= 1) || (@.val > 3)]",
+               "result" : [{ "val" : 1 }, { "val" : 4 }]
+           }, {
+               "path" : "$.arr[?(@.val <= 1) || (@.val > 1)]",
+               "result" : [{ "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 }]
+           }, {
+             "path" : "$.arr[?@.val <= 1 || @.val > 1]",
+             "result" : [{ "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 }]
+           }, {
+             "path" : "$.arr[?@.val > 1 && @.val < 4]",
+             "result" : [{ "val": 2 }, { "val": 3 }]
+           }, {
+             "path" : "$.arr[?@.val <= 1 && @.val > 4]",
+             "result" : []
+           }, {
+             "path" : "$.arr[?@.val <= 1 && @.val >= 4 || @.val < 3]",
+             "result" : [{ "val": 1 }, { "val": 2 }]
+           }, {
+             "path" : "$.arr[?(@.val <= 1 && @.val >= 4) || @.val < 3]",
+             "result" : [{ "val": 1 }, { "val": 2 }]
+           }, {
+             "path" : "$.arr[?@.val >= 4 || @.val < 3 && @.val <= 1]",
+             "result" : [{ "val": 1 }, { "val": 4 }]
+           }, {
+             "path" : "$.arr[?@.val >= 4 || (@.val < 3 && @.val <= 1)]",
+             "result" : [{ "val": 1 }, { "val": 4 }]
+           }, {
+             "path" : "$.arr[?@.val == 4 || @.val == 3 || @.val == 1]",
+             "result" : [{ "val": 1 }, { "val": 4 }, { "val": 3}]
+           }, {
+             "path" : "$.arr[?@.val <= 4 && @.val <= 3 && @.val <= 1]",
+             "result" : [{ "val": 1 }]
+           }, {
+             "path" : "$.arr[?@.val <= 4 && @.val <= 3 && @.val <= 1 || @.val > 1]",
+             "result" : [{ "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 }]
+           }, {
+             "path" : "$.arr[?!@.val]",
+             "result" : [4,
+                       "string",
+                       false,
+                       null,
+                       [1, 2, 3], {
+                           "index" : 1,
+                           "name" : "John Doe",
+                           "occupation" : "Architect"
+                       }, {
+                           "index" : 2,
+                           "name" : "Jane Smith",
+                           "occupation" : "Architect",
+                           "color" : "blue"
+                       } , {
+                           "index" : 3,
+                           "name" : "John Smith",
+                           "occupation" : "Plumber"
+                       }, {
+                           "index" : 4,
+                           "name" : "Jane Doe",
+                           "occupation" : "Pilot"
+                       },
+                       { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+                      ]
+           }, {
+             "path" : "$.arr[?!@.val == 1]",
+             "comment": "This is not allowed according to the IETF Draft.",
+             "result" : [4,
+                         "string",
+                         false,
+                         null,
+                         [1, 2, 3], {
+                           "index" : 1,
+                           "name" : "John Doe",
+                           "occupation" : "Architect"
+                         }, {
+                           "index" : 2,
+                           "name" : "Jane Smith",
+                           "occupation" : "Architect",
+                           "color" : "blue"
+                         } , {
+                           "index" : 3,
+                           "name" : "John Smith",
+                           "occupation" : "Plumber"
+                         }, {
+                           "index" : 4,
+                           "name" : "Jane Doe",
+                           "occupation" : "Pilot"
+                         },
+                         { "val": 2 }, { "val": 4 }, { "val": 3 },
+                         { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+                        ]
+           }, {
+             "path" : "$.arr[?!(@.val == 1)]",
+             "result" : [4,
+                         "string",
+                         false,
+                         null,
+                         [1, 2, 3], {
+                           "index" : 1,
+                           "name" : "John Doe",
+                           "occupation" : "Architect"
+                         }, {
+                           "index" : 2,
+                           "name" : "Jane Smith",
+                           "occupation" : "Architect",
+                           "color" : "blue"
+                         } , {
+                           "index" : 3,
+                           "name" : "John Smith",
+                           "occupation" : "Plumber"
+                         }, {
+                           "index" : 4,
+                           "name" : "Jane Doe",
+                           "occupation" : "Pilot"
+                         },
+                         { "val": 2 }, { "val": 4 }, { "val": 3 },
+                         { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+                        ]
+           }, {
+               "path" : "$.arr[?(@.textval > \"c\")]",
+               "result" : [{ "textval" : "d" }]
+           }, {
+               "path" : "$.arr[?(@.textval >= \"c\")]",
+               "result" : [{ "textval" : "d" }, { "textval" : "c" }]
+           }, {
+               "path" : "$.arr[?(@.textval < \"b\")]",
+               "result" : [{ "textval" : "a" }]
+           }, {
+               "path" : "$.arr[?(@.textval <= \"b\")]",
+               "result" : [{ "textval" : "a" }, { "textval" : "b" }]
+           }, {
+               "path" : "$.arr[?(@.textval <= 'b')]",
+               "result" : [{ "textval" : "a" }, { "textval" : "b" }]
+           }, {
+               "path" : "$.arr[?(@.val == \"1\")]",
+               "result" : []
+           }, {
+               "path": "$.obj[?@ > 1]",
+               "result": [2, 4]
+           }, {
+               "path": "$.obj[?(@.qux)]",
+               "result": [{"qux": 3}]
+           }, {
+             "path": "$[?@.foo < @.baz.qux]",
+             "result": [{"foo": 1, "bar": 2, "baz": {"qux": 3}, "bux": 4}]
+           }, {
+             "path": "$[?@.foo < @.baz.qux]",
+             "result": [{"foo": 1, "bar": 2, "baz": {"qux": 3}, "bux": 4}]
+           }, {
+             "path": "$[?@[0] == @[8].index]",
+             "comment": "Both arr and obj match this as 4 == 4 for arr and no_path == no_path for obj",
+             "result": [
+               [4,
+                "string",
+                false,
+                null,
+                [1, 2, 3], {
+                  "index" : 1,
+                  "name" : "John Doe",
+                  "occupation" : "Architect"
+                }, {
+                  "index" : 2,
+                  "name" : "Jane Smith",
+                  "occupation" : "Architect",
+                  "color" : "blue"
+                } , {
+                  "index" : 3,
+                  "name" : "John Smith",
+                  "occupation" : "Plumber"
+                }, {
+                  "index" : 4,
+                  "name" : "Jane Doe",
+                  "occupation" : "Pilot"
+                },
+                { "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 },
+                { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+               ],
+               {"foo": 1, "bar": 2, "baz": {"qux": 3}, "bux": 4}
+             ]
+           }, {
+             "path": "$[?@[0] && @[0] == @[8].index]",
+             "result": [
+               [4,
+                "string",
+                false,
+                null,
+                [1, 2, 3], {
+                  "index" : 1,
+                  "name" : "John Doe",
+                  "occupation" : "Architect"
+                }, {
+                  "index" : 2,
+                  "name" : "Jane Smith",
+                  "occupation" : "Architect",
+                  "color" : "blue"
+                } , {
+                  "index" : 3,
+                  "name" : "John Smith",
+                  "occupation" : "Plumber"
+                }, {
+                  "index" : 4,
+                  "name" : "Jane Doe",
+                  "occupation" : "Pilot"
+                },
+                { "val": 1 }, { "val": 2 }, { "val": 4 }, { "val": 3 },
+                { "textval": "a" }, { "textval": "b" }, { "textval": "d" }, { "textval": "c" }
+               ]
+             ]
+           }, {
+             "path": "$.arr[?@ > 3]",
+             "result": [4]
+           }, {
+             "path": "$.arr[?@ == null]",
+             "result": [null]
+           }, {
+             "path": "$.arr[?@ == false]",
+             "result": [false]
+           }, {
+             "path": "$.arr[?@ == true]",
+             "result": []
+           }, {
+             "path": "$.arr[?@.index == $.obj.bux]",
+             "result": [{
+               "index" : 4,
+               "name" : "Jane Doe",
+               "occupation" : "Pilot"
+             }]
+           }
+    ]
+
+}
diff --git a/test/resources/json-path-tests/IndexedSubscriptOperator.json b/test/resources/json-path-tests/IndexedSubscriptOperator.json
--- a/test/resources/json-path-tests/IndexedSubscriptOperator.json
+++ b/test/resources/json-path-tests/IndexedSubscriptOperator.json
@@ -1,58 +1,124 @@
-{
-	"title" : "Indexed Subscript Operator",
-	"data" : [
-		"John Doe",
-		36,
-		"Architect",
-		"one",
-		"three",
-		"five"
-	],
-	"tests" : [{
-			"path" : "$[2]",
-			"result" : ["Architect"]
-		}, {
-			"path" : "$[-1]",
-			"result" : ["five"]
-		}, {
-			"path" : "$[10]",
-			"result" : false
-		}, {
-			"path" : "$[1:4]",
-			"result" : [36, "Architect", "one"]
-		}, {
-			"path" : "$[1:4:2]",
-			"result" : [36, "one"]
-		}, {
-			"path" : "$[:4:2]",
-			"result" : ["John Doe", "Architect"]
-		}, {
-			"path" : "$[1::2]",
-			"result" : [36, "one", "five"]
-		}, {
-			"path" : "$[::2]",
-			"result" : ["John Doe", "Architect", "three"]
-		}, {
-			"path" : "$[1:]",
-			"result" : [36, "Architect", "one", "three", "five"]
-		}, {
-			"path" : "$[:3]",
-			"result" : ["John Doe", 36, "Architect"]
-		}, {
-			"path" : "$[0,3]",
-			"result" : ["John Doe", "one"]
-		}, {
-			"path" : "$[0,1::2]",
-			"result" : ["John Doe", 36, "one", "five"]
-		}, {
-			"path" : "$[0:2,4:6]",
-			"result" : ["John Doe", 36, "three", "five"]
-		}, {
-			"path" : "$[0:2,4]",
-			"result" : ["John Doe", 36, "three"]
-		}, {
-			"path" : "$[*]",
-			"result" : ["John Doe", 36, "Architect", "one", "three", "five"]
-		}
-	]
-}
+{
+    "title" : "Indexed Subscript Operator",
+    "data" : [
+        "John Doe",
+        36,
+        "Architect",
+        "one",
+        "three",
+        "five",
+        {"string": "str", "array": ["arr"]}
+    ],
+    "tests" : [{
+        "path" : "$[2]",
+            "result" : ["Architect"]
+         }, {
+            "path" : "$[ 2 ]",
+            "result" : ["Architect"]
+        },{
+            "path" : "$[-1]",
+            "result" : [{"string": "str", "array": ["arr"]}]
+        }, {
+            "path" : "$[10]",
+            "result" : []
+        }, {
+            "path" : "$[1:4]",
+            "result" : [36, "Architect", "one"]
+        }, {
+            "path" : "$[1:4:2]",
+            "result" : [36, "one"]
+        }, {
+            "path" : "$[ 1 : 4 : 2 ]",
+            "result" : [36, "one"]
+        }, {
+            "path" : "$[:4:2]",
+            "result" : ["John Doe", "Architect"]
+        }, {
+            "path" : "$[1::2]",
+            "result" : [36, "one", "five"]
+        }, {
+            "path" : "$[::2]",
+            "result" : ["John Doe", "Architect", "three", {"string": "str", "array": ["arr"]}]
+        }, {
+            "path" : "$[1:]",
+            "result" : [36, "Architect", "one", "three", "five", {"string": "str", "array": ["arr"]}]
+        }, {
+            "path" : "$[:3]",
+            "result" : ["John Doe", 36, "Architect"]
+        }, {
+            "path" : "$[0,3]",
+            "result" : ["John Doe", "one"]
+        }, {
+            "path" : "$[0,1::2]",
+            "result" : ["John Doe", 36, "one", "five"]
+        }, {
+            "path" : "$[0:2,4:6]",
+            "result" : ["John Doe", 36, "three", "five"]
+        }, {
+            "path" : "$[0:2,4]",
+            "result" : ["John Doe", 36, "three"]
+        }, {
+            "path" : "$[ 0:2 , 4]",
+            "result" : ["John Doe", 36, "three"]
+        }, {
+            "path" : "$[0:2, 'foo']",
+            "result" : ["John Doe", 36]
+        }, {
+            "path" : "$[-1]['string', 'array']",
+            "result" : ["str", ["arr"]]
+        }, {
+            "path" : "$[-1][\"not-here\", \"array\", \"string\"]",
+            "result" : [["arr"], "str"]
+        }, {
+            "path" : "$[*]",
+            "result" : ["John Doe", 36, "Architect", "one", "three", "five", {"string": "str", "array": ["arr"]}]
+        }, {
+            "path": "$[2:113667776004]",
+            "result": ["Architect", "one", "three", "five", {"string": "str", "array": ["arr"]}]
+        }, {
+            "path": "$[-113667776004:2]",
+            "result": ["John Doe", 36]
+        }, {
+            "path": "$[::0]",
+            "result": []
+        }, {
+            "path": "$[5:0:-1]",
+            "result": [
+                "five",
+                "three",
+                "one",
+                "Architect",
+                36
+            ]
+        }, {
+            "path": "$[-1:0:-1]",
+            "result": [
+                "five",
+                "three",
+                "one",
+                "Architect",
+                36,
+                {"string": "str", "array": ["arr"]}
+            ]
+        }, {
+            "path": "$[::-2]",
+            "result": [
+                {"string": "str", "array": ["arr"]},
+                "three",
+                "Architect",
+                "John Doe"
+            ]
+        }, {
+            "path": "$[::]",
+            "result": [
+                "John Doe",
+                36,
+                "Architect",
+                "one",
+                "three",
+                "five",
+                {"string": "str", "array": ["arr"]}
+            ]
+        }
+    ]
+}
diff --git a/test/resources/json-path-tests/SearchOperator.json b/test/resources/json-path-tests/SearchOperator.json
--- a/test/resources/json-path-tests/SearchOperator.json
+++ b/test/resources/json-path-tests/SearchOperator.json
@@ -1,39 +1,38 @@
-{
-	"title" : "Search Operator",
-	"data" : {
-		"firstName" : "John",
-		"lastName" : "Doe",
-		"eyes" : "blue",
-		"children" : [{
-				"firstName" : "Sally",
-				"lastName" : "Doe",
-				"favoriteGames" : ["Halo", "Minecraft", "Lego: Star Wars"]
-			}, {
-				"firstName" : "Mike",
-				"lastName" : "Doe",
-				"eyes" : "green"
-			}
-		]
-	},
-	"tests" : [{
-			"path" : "$..firstName",
-			"result" : ["John", "Sally", "Mike"]
-		}, {
-			"path" : "$..lastName",
-			"result" : ["Doe", "Doe", "Doe"]
-		}, {
-			"path" : "$..eyes",
-			"result" : ["blue", "green"]
-		}, {
-			"path" : "$..missingKey",
-			"result" : false
-		}, {
-			"path" : "$..[1]",
-			"result" : [{
-					"firstName" : "Mike",
-					"lastName" : "Doe",
-					"eyes" : "green"
-				}, "Minecraft"]
-		}
-	]
-}
+{
+    "title" : "Search Operator",
+    "data" : {
+        "firstName" : "John",
+        "lastName" : "Doe",
+        "eyes" : "blue",
+        "children" : [{
+                "firstName" : "Sally",
+                "lastName" : "Doe",
+                "favoriteGames" : ["Halo", "Minecraft", "Lego: Star Wars"]
+            }, {
+                "firstName" : "Mike",
+                "lastName" : "Doe",
+                "eyes" : "green"
+            }
+        ]
+    },
+    "tests" : [{
+        "path" : "$..firstName",
+        "result" : ["John", "Sally", "Mike"]
+    }, {
+        "path" : "$..lastName",
+        "result" : ["Doe", "Doe", "Doe"]
+    }, {
+        "path" : "$..eyes",
+        "result" : ["blue", "green"]
+    }, {
+        "path" : "$..missingKey",
+        "result" : []
+    }, {
+        "path" : "$..[1]",
+        "result" : [{
+            "firstName" : "Mike",
+            "lastName" : "Doe",
+            "eyes" : "green"
+        }, "Minecraft"]
+    }]
+}
