module Data.BAByNF.ABNF.Rules.Rule
    ( ref
    , rule
    , fromTree
    ) where

import Data.Functor ((<&>))
import Data.List qualified as List

import Data.BAByNF.Util.Ascii qualified as Ascii

import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import Data.BAByNF.ABNF.Rules.Rulename qualified as Rulename
import Data.BAByNF.ABNF.Rules.DefinedAs qualified as DefinedAs
import Data.BAByNF.ABNF.Rules.Elements qualified as Elements
import Data.BAByNF.ABNF.Rules.CNl qualified as CNl
import Data.BAByNF.ABNF.Model qualified as Model

ref :: Model.Rulename
ref :: Rulename
ref = ByteString -> Rulename
Model.Rulename (String -> ByteString
Ascii.stringAsBytesUnsafe String
"rule")

rule :: Model.Rule
rule :: Rule
rule = Rulename -> DefinedAs -> Elements -> Rule
Model.Rule Rulename
ref DefinedAs
Model.BasicDefinition (Elements -> Rule) -> Elements -> Rule
forall a b. (a -> b) -> a -> b
$
    Alternation -> Elements
Model.Elements (Alternation -> Elements)
-> ([Repetition] -> Alternation) -> [Repetition] -> Elements
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Concatenation] -> Alternation
Model.Alternation  ([Concatenation] -> Alternation)
-> ([Repetition] -> [Concatenation]) -> [Repetition] -> Alternation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Concatenation -> [Concatenation]
forall a. a -> [a]
List.singleton (Concatenation -> [Concatenation])
-> ([Repetition] -> Concatenation)
-> [Repetition]
-> [Concatenation]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Repetition] -> Concatenation
Model.Concatenation ([Repetition] -> Elements) -> [Repetition] -> Elements
forall a b. (a -> b) -> a -> b
$
        [ Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat (Rulename -> Element
Model.RulenameElement Rulename
Rulename.ref)
        , Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat (Rulename -> Element
Model.RulenameElement Rulename
DefinedAs.ref)
        , Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat (Rulename -> Element
Model.RulenameElement Rulename
Elements.ref)
        , Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat (Rulename -> Element
Model.RulenameElement Rulename
CNl.ref)
        ]

fromTree :: Tree Model.Rulename -> Either String Model.Rule
fromTree :: Tree Rulename -> Either String Rule
fromTree Tree Rulename
tree =
    Either String Rulename
name Either String Rulename
-> (Rulename -> Either String Rule) -> Either String Rule
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Rulename
name' ->
    Either String DefinedAs
definedAs Either String DefinedAs
-> (DefinedAs -> Either String Rule) -> Either String Rule
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \DefinedAs
definedAs' ->
    Either String Elements
elements Either String Elements
-> (Elements -> Either String Rule) -> Either String Rule
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Elements
elements' ->
    Rule -> Either String Rule
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Rule -> Either String Rule) -> Rule -> Either String Rule
forall a b. (a -> b) -> a -> b
$ Rulename -> DefinedAs -> Elements -> Rule
Model.Rule Rulename
name' DefinedAs
definedAs' Elements
elements'
    where name :: Either String Rulename
name = Rulename -> Tree Rulename -> Either String (Tree Rulename)
forall a. Ref a => a -> Tree a -> Either String (Tree a)
Tree.tryGetChildWithRef Rulename
Rulename.ref Tree Rulename
tree Either String (Tree Rulename)
-> (Tree Rulename -> Rulename) -> Either String Rulename
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Tree Rulename -> Rulename
Rulename.fromTree
          definedAs :: Either String DefinedAs
definedAs = Rulename -> Tree Rulename -> Either String (Tree Rulename)
forall a. Ref a => a -> Tree a -> Either String (Tree a)
Tree.tryGetChildWithRef Rulename
DefinedAs.ref Tree Rulename
tree Either String (Tree Rulename)
-> (Tree Rulename -> Either String DefinedAs)
-> Either String DefinedAs
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Tree Rulename -> Either String DefinedAs
DefinedAs.fromTree
          elements :: Either String Elements
elements = Rulename -> Tree Rulename -> Either String (Tree Rulename)
forall a. Ref a => a -> Tree a -> Either String (Tree a)
Tree.tryGetChildWithRef Rulename
Elements.ref Tree Rulename
tree Either String (Tree Rulename)
-> (Tree Rulename -> Either String Elements)
-> Either String Elements
forall a b.
Either String a -> (a -> Either String b) -> Either String b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Tree Rulename -> Either String Elements
Elements.fromTree