{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}

{-|
Implement the v2 parser specified at: https://kdl.dev/spec/#name-full-grammar
-}
module KDL.Parser (
  parse,
  parseFile,

  -- * Configurable parsing
  ParseConfig (..),
  parseWith,
  parseFileWith,
) where

import Data.Bifunctor (first)
import Data.Default (def)
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.IO qualified as Text
import KDL.Parser.Internal (
  ParseConfig (..),
  p_document,
  runParser,
 )
import KDL.Types (Document)
import Text.Megaparsec qualified as Megaparsec

parse :: Text -> Either Text Document
parse :: Text -> Either Text Document
parse = ParseConfig -> Text -> Either Text Document
parseWith ParseConfig
forall a. Default a => a
def

parseFile :: FilePath -> IO (Either Text Document)
parseFile :: FilePath -> IO (Either Text Document)
parseFile = ParseConfig -> FilePath -> IO (Either Text Document)
parseFileWith ParseConfig
forall a. Default a => a
def

parseWith :: ParseConfig -> Text -> Either Text Document
parseWith :: ParseConfig -> Text -> Either Text Document
parseWith ParseConfig
config Text
input =
  (ParseErrorBundle Text Void -> Text)
-> Either (ParseErrorBundle Text Void) Document
-> Either Text Document
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text -> Text
Text.strip (Text -> Text)
-> (ParseErrorBundle Text Void -> Text)
-> ParseErrorBundle Text Void
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
Text.pack (FilePath -> Text)
-> (ParseErrorBundle Text Void -> FilePath)
-> ParseErrorBundle Text Void
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseErrorBundle Text Void -> FilePath
forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> FilePath
Megaparsec.errorBundlePretty) (Either (ParseErrorBundle Text Void) Document
 -> Either Text Document)
-> Either (ParseErrorBundle Text Void) Document
-> Either Text Document
forall a b. (a -> b) -> a -> b
$
    ParseConfig
-> Parser Document
-> Text
-> Either (ParseErrorBundle Text Void) Document
forall a.
ParseConfig
-> Parser a -> Text -> Either (ParseErrorBundle Text Void) a
runParser ParseConfig
config Parser Document
p_document Text
input

parseFileWith :: ParseConfig -> FilePath -> IO (Either Text Document)
parseFileWith :: ParseConfig -> FilePath -> IO (Either Text Document)
parseFileWith ParseConfig
config0 FilePath
fp = ParseConfig -> Text -> Either Text Document
parseWith ParseConfig
config (Text -> Either Text Document)
-> IO Text -> IO (Either Text Document)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO Text
Text.readFile FilePath
fp
 where
  config :: ParseConfig
config = ParseConfig
config0{filepath = fp}