babynf-0.1.0.2: lib/Data/BAByNF/ABNF/Rules/Group.hs
{-# LANGUAGE LambdaCase #-}
module Data.BAByNF.ABNF.Rules.Group
( 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.Ref qualified as Ref
import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import {-# SOURCE #-} Data.BAByNF.ABNF.Rules.Alternation qualified as Alternation
import Data.BAByNF.ABNF.Rules.CWsp qualified as CWsp
import Data.BAByNF.ABNF.Model qualified as Model
ref :: Model.Rulename
ref = Model.Rulename (Ascii.stringAsBytesUnsafe "group")
rule :: Model.Rule
rule = Model.Rule ref Model.BasicDefinition
. Model.Elements
. Model.Alternation
. List.singleton
. Model.Concatenation
$
[ Model.Repetition Model.NoRepeat
. Model.CharValElement
. Model.CaseInsensitiveCharVal
. Model.CaseInsensitiveString
$ Model.QuotedString (Ascii.stringAsBytesUnsafe "(")
, Model.Repetition (Model.RangedRepeat Model.UnBound Model.UnBound) (Model.RulenameElement CWsp.ref)
, Model.Repetition Model.NoRepeat (Model.RulenameElement Alternation.ref)
, Model.Repetition (Model.RangedRepeat Model.UnBound Model.UnBound) (Model.RulenameElement CWsp.ref)
, Model.Repetition Model.NoRepeat
. Model.CharValElement
. Model.CaseInsensitiveCharVal
. Model.CaseInsensitiveString
$ Model.QuotedString (Ascii.stringAsBytesUnsafe ")")
]
fromTree :: Tree Model.Rulename -> Either String Model.Group
fromTree tree =
let nodes = Tree.nodes tree
in (tryDropLeftParens nodes
>>= (\case
(Tree.RefNode r subtree):rest
| Ref.eq Alternation.ref r -> Right (subtree, rest)
| otherwise -> Left "group must contain alternation"
_ -> Left "structural mismatch for <group>"
) . dropCWsp)
>>= \(altSubtree, rest) -> (tryDropRightParens . dropCWsp $ rest)
>>= \case
[] -> Alternation.fromTree altSubtree <&> Model.Group
_ -> Left "structural mismatch for <group>"
where tryDropLeftParens nodes =
case nodes of
(Tree.StringNode bs):rest | bs == Ascii.stringAsBytesUnsafe "(" -> Right rest
| otherwise -> Left "structural mismatch for <group>"
_ -> Left "structural mismatch for <group>"
dropCWsp = dropWhile (`Tree.isRefOf` CWsp.ref)
tryDropRightParens nodes =
case nodes of
(Tree.StringNode bs):rest | bs == Ascii.stringAsBytesUnsafe ")" -> Right rest
| otherwise -> Left "structural mismatch for <group>"
_ -> Left "structural mismatch for <group>"