-- | Convert a 'Grammar' to a JSON 'Parser'.
parseValue :: Grammar Val t1 t2 -> t1 -> Parser t2
parseValue = \case
  Id        -> return
  g1 :. g2  -> parseValue g2 >=> parseValue g1
  Empty     -> \_ -> fail "empty grammar"
  g1 :<> g2 -> parseValue g1 <> parseValue g2
  Pure f _  -> f
  Many g    -> manyM (parseValue g)

  Literal val -> \(val' :- t) ->
    if val == val'
      then return t
      else typeMismatch "literal" val'

  Label _ g -> parseValue g

  Object g -> \(val :- x) ->
    withObject "object" (\obj -> parseProperties obj g x) val

  Array g -> \(val :- x) -> do
      (arr', y) <- withArray "array" (\arr -> parseElements g (arr, x)) val
      unless (V.null arr') $ typeMismatch "end of array" (V.head arr')
      return y

  Coerce _ g -> parseValue g
parseValue :: Grammar Val t1 t2 -> t1 -> Parser t2
parseValue = \case
  Id        -> return
  g1 :. g2  -> parseValue g2 >=> parseValue g1
  Empty     -> \_ -> fail "empty grammar"
  g1 :<> g2 -> parseValue g1 <> parseValue g2
  Pure f _  -> f
  Many g    -> manyM (parseValue g)

  Literal val -> \(val' :- t) ->
    if val == val'
      then return t
      else typeMismatch "literal" val'

  Label _ g -> parseValue g

  Object g -> \(val :- x) ->
    withObject "object" (\obj -> parseProperties obj g x) val

  Array g -> \(val :- x) -> do
      (arr', y) <- withArray "array" (\arr -> parseElements g (arr, x)) val
      unless (V.null arr') $ typeMismatch "end of array" (V.head arr')
      return y

  Coerce _ g -> parseValue g
parseValue = \case
  Id        -> return
  g1 :. g2  -> parseValue g2 >=> parseValue g1
  Empty     -> \_ -> fail "empty grammar"
  g1 :<> g2 -> parseValue g1 <> parseValue g2
  Pure f _  -> f
  Many g    -> manyM (parseValue g)

  Literal val -> \(val' :- t) ->
    if val == val'
      then return t
      else typeMismatch "literal" val'

  Label _ g -> parseValue g

  Object g -> \(val :- x) ->
    withObject "object" (\obj -> parseProperties obj g x) val

  Array g -> \(val :- x) -> do
      (arr', y) <- withArray "array" (\arr -> parseElements g (arr, x)) val
      unless (V.null arr') $ typeMismatch "end of array" (V.head arr')
      return y

  Coerce _ g -> parseValue g