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

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

import Data.ByteString qualified as ByteString

import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import Data.BAByNF.ABNF.Rules.BinVal qualified as BinVal
import Data.BAByNF.ABNF.Rules.DecVal qualified as DecVal
import Data.BAByNF.ABNF.Rules.HexVal qualified as HexVal
import Data.BAByNF.Util.Ascii qualified as Ascii
import Data.BAByNF.Core.Ref qualified as Ref
import Data.BAByNF.ABNF.Model qualified as Model

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

rule :: Model.Rule
rule :: Rule
rule = Rulename -> DefinedAs -> Elements -> Rule
Model.Rule Rulename
ref DefinedAs
Model.BasicDefinition 
    (Elements -> Rule)
-> ([Repetition] -> Elements) -> [Repetition] -> Rule
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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] -> Rule) -> [Repetition] -> Rule
forall a b. (a -> b) -> a -> b
$ 
        [ Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Repetition)
-> (QuotedString -> Element) -> QuotedString -> Repetition
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CharVal -> Element
Model.CharValElement
            (CharVal -> Element)
-> (QuotedString -> CharVal) -> QuotedString -> Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CaseInsensitiveString -> CharVal
Model.CaseInsensitiveCharVal
            (CaseInsensitiveString -> CharVal)
-> (QuotedString -> CaseInsensitiveString)
-> QuotedString
-> CharVal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QuotedString -> CaseInsensitiveString
Model.CaseInsensitiveString
            (QuotedString -> Repetition) -> QuotedString -> Repetition
forall a b. (a -> b) -> a -> b
$ ByteString -> QuotedString
Model.QuotedString (String -> ByteString
Ascii.stringAsBytesUnsafe String
"%")
            
        , Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
            (Element -> Repetition)
-> ([Concatenation] -> Element) -> [Concatenation] -> Repetition
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Group -> Element
Model.GroupElement
            (Group -> Element)
-> ([Concatenation] -> Group) -> [Concatenation] -> Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alternation -> Group
Model.Group
            (Alternation -> Group)
-> ([Concatenation] -> Alternation) -> [Concatenation] -> Group
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Concatenation] -> Alternation
Model.Alternation
            ([Concatenation] -> Repetition) -> [Concatenation] -> Repetition
forall a b. (a -> b) -> a -> b
$ 
                [ [Repetition] -> Concatenation
Model.Concatenation
                    ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
                    (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
                    (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
BinVal.ref
                , [Repetition] -> Concatenation
Model.Concatenation
                    ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
                    (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
                    (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
DecVal.ref
                , [Repetition] -> Concatenation
Model.Concatenation
                    ([Repetition] -> Concatenation)
-> (Element -> [Repetition]) -> Element -> Concatenation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repetition -> [Repetition]
forall a. a -> [a]
List.singleton
                    (Repetition -> [Repetition])
-> (Element -> Repetition) -> Element -> [Repetition]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Repeat -> Element -> Repetition
Model.Repetition Repeat
Model.NoRepeat
                    (Element -> Concatenation) -> Element -> Concatenation
forall a b. (a -> b) -> a -> b
$ Rulename -> Element
Model.RulenameElement Rulename
HexVal.ref
                ]
        ]

fromTree :: Tree Model.Rulename -> Either String Model.NumVal
fromTree :: Tree Rulename -> Either String NumVal
fromTree Tree Rulename
tree = case Tree Rulename -> [Node Rulename]
forall a. Ref a => Tree a -> [Node a]
Tree.nodes Tree Rulename
tree of
    [Tree.StringNode ByteString
b, Tree.RefNode Rulename
r Tree Rulename
subtree] ->
        if ByteString
b ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8 -> ByteString
ByteString.singleton Word8
37
            then String -> Either String NumVal
forall a b. a -> Either a b
Left String
"expected % prefix"
            else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
BinVal.ref then Tree Rulename -> Either String BinVal
BinVal.fromTree Tree Rulename
subtree Either String BinVal -> (BinVal -> NumVal) -> Either String NumVal
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> BinVal -> NumVal
Model.BinNumVal
                else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
DecVal.ref then Tree Rulename -> Either String DecVal
DecVal.fromTree Tree Rulename
subtree Either String DecVal -> (DecVal -> NumVal) -> Either String NumVal
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> DecVal -> NumVal
Model.DecNumVal
                else if Rulename -> Rulename -> Bool
forall a. Ref a => a -> a -> Bool
Ref.eq Rulename
r Rulename
HexVal.ref then Tree Rulename -> Either String HexVal
HexVal.fromTree Tree Rulename
subtree Either String HexVal -> (HexVal -> NumVal) -> Either String NumVal
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> HexVal -> NumVal
Model.HexNumVal
                else String -> Either String NumVal
forall a b. a -> Either a b
Left String
"unexpected rule ref"
    [Node Rulename]
_ -> String -> Either String NumVal
forall a b. a -> Either a b
Left String
"exactly two nodes expected - \"%\" and bin-val | dec-val | hex-val"