kdl-hs-0.2.0: src/KDL/Parser.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module KDL.Parser (
parse,
parseFile,
) where
import Data.Map qualified as Map
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.IO qualified as Text
import KDL.Parser.Hustle qualified as Hustle
import KDL.Types (
Ann (..),
Document,
Entry (..),
Identifier (..),
Node (..),
NodeList (..),
Value (..),
ValueData (..),
ValueFormat (..),
)
-- TODO: Implement our own parser that implements the v2.0.0 spec + preserves formatting and comments
parse :: Text -> Either Text Document
parse input =
case Hustle.parse Hustle.document "" input of
Left e -> Left . Text.strip . Text.pack . Hustle.errorBundlePretty $ e
Right (Hustle.Document nodes) -> Right $ fromNodes nodes
where
fromNodes nodes =
NodeList
{ nodes = map fromNode nodes
, format = Nothing
}
fromAnn identifier =
Ann
{ identifier = fromIdentifier identifier
, format = Nothing
}
fromNode Hustle.Node{..} =
Node
{ ann = fromAnn <$> nodeAnn
, name = fromIdentifier nodeName
, entries = map fromArgEntry nodeArgs <> map fromPropEntry (Map.toList nodeProps)
, children = Just $ fromNodes nodeChildren
, format = Nothing
}
fromArgEntry v =
Entry
{ name = Nothing
, value = fromValue v
, format = Nothing
}
fromPropEntry (name, v) =
Entry
{ name = Just $ fromIdentifier name
, value = fromValue v
, format = Nothing
}
fromValue Hustle.Value{..} =
Value
{ ann = fromAnn <$> valueAnn
, data_ =
case valueExp of
Hustle.StringValue s -> Text s
Hustle.IntegerValue x -> Number (fromInteger x)
Hustle.SciValue x -> Number x
Hustle.BooleanValue x -> Bool x
Hustle.NullValue -> Null
, format =
case valueExp of
Hustle.IntegerValue x -> Just ValueFormat{repr = Text.pack $ show x}
_ -> Nothing
}
fromIdentifier (Hustle.Identifier s) =
Identifier
{ value = s
, format = Nothing
}
parseFile :: FilePath -> IO (Either Text Document)
parseFile = fmap parse . Text.readFile