babynf-0.1.0.2: lib/Data/BAByNF/ABNF/Parse.hs
module Data.BAByNF.ABNF.Parse
( parse
, parseRulelist
) where
import Data.List qualified as List
import Data.ByteString (ByteString)
import Data.Attoparsec.ByteString qualified as Attoparsec.ByteString
import Data.BAByNF.Core.Ref qualified as Ref
import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import Data.BAByNF.Core.RefDict (RefDict (..))
import Data.BAByNF.Core.Parseable qualified as Parseable
import Data.BAByNF.Core.Parseable (Parseable)
import Data.BAByNF.ABNF.Model qualified as Model
import Data.BAByNF.ABNF.Rules.Rulelist qualified as Rulelist
import Data.BAByNF.ABNF.Rules (rules)
import Data.BAByNF.ABNF.ToParseable
-- TODO: split parse til end of input?
parse :: ToParseable p => Model.Rulelist -> p -> ByteString -> Either String (Tree Model.Rulename)
parse r p t =
let parser = Parseable.toParser (toRefDict r) (toParseable p)
in Attoparsec.ByteString.parseOnly parser t
parseRulelist :: ByteString -> Either String Model.Rulelist
parseRulelist t =
let toTree = parse rules Rulelist.ref t
in toTree
>>= \tree -> case Tree.nodes tree of
[Tree.RefNode ref subtree]
| Ref.eq ref Rulelist.ref -> Right subtree
| otherwise -> Left "structural mismatch for <rulelist>"
_ -> Left "structural mismatch for <rulelist>"
>>= joinErrors . Rulelist.fromTree
where joinErrors (Right x) = Right x
joinErrors (Left errors) = Left $ "Errors found:\n" ++ List.intercalate "\n" errors
toRefDict :: Model.Rulelist -> RefDict Model.Rulename (Parseable Model.Rulename)
toRefDict (Model.Rulelist r) = RefDict (map (\(Model.Rule ref _ (Model.Elements a)) -> (ref, toParseable a)) r)