babynf-0.1.0.2: lib/Data/BAByNF/ABNF/Rules/HexVal.hs
{-# LANGUAGE LambdaCase #-}
module Data.BAByNF.ABNF.Rules.HexVal
( ref
, rule
, fromTree
) where
import Data.List qualified as List
import Data.ByteString qualified as ByteString
import Data.BAByNF.ABNF.Core qualified as Core
import Data.BAByNF.Core.Tree (Tree)
import Data.BAByNF.Core.Tree qualified as Tree
import Data.BAByNF.Util.Ascii qualified as Ascii
import Data.BAByNF.Util.List qualified as Util.List
import Data.BAByNF.Util.Hex qualified as Hex
import Data.BAByNF.ABNF.Model qualified as Model
ref :: Model.Rulename
ref = Model.Rulename (Ascii.stringAsBytesUnsafe "hex-val")
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 "x"
, Model.Repetition (Model.RangedRepeat (Model.FixedBound 1) Model.UnBound) (Model.RulenameElement Core.hexdigRef)
, Model.Repetition Model.NoRepeat
$ Model.OptionElement
. Model.Option
. Model.Alternation
$
[ Model.Concatenation
. List.singleton
. Model.Repetition (Model.RangedRepeat (Model.FixedBound 1) Model.UnBound)
. Model.GroupElement
. Model.Group
. 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.FixedBound 1) Model.UnBound) (Model.RulenameElement Core.hexdigRef)
]
, Model.Concatenation
. List.singleton
. Model.Repetition Model.NoRepeat
. Model.GroupElement
. Model.Group
. 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.FixedBound 1) Model.UnBound) (Model.RulenameElement Core.hexdigRef)
]
]
]
fromTree :: Tree Model.Rulename -> Either String Model.HexVal
fromTree tree =
let nodes = Tree.nodes tree
in (case List.uncons nodes of
Just (h, rest) ->
if isB h
then Right rest
else Left "hex-val must start with x | X"
_ -> Left "structural mismatch for <hex-val>")
>>= takeHexSeq
>>= \(firstSeq, rest) ->
case List.uncons rest of
Nothing -> Right (Model.SeqHexVal [firstSeq])
Just (c, rest') | isDash c -> takeHexSeq rest' >>= \(secondSeq, end) ->
case end of
[] -> Right (Model.RangeHexVal firstSeq secondSeq)
_ -> Left "structural mismatch for <hex-val>"
| isDot c -> let takeSeq x = takeHexSeq x >>= (\(nextSeq, rest'') -> case rest'' of
[] -> Right [nextSeq]
c':rest''' -> if isDot c'
then takeSeq rest''' >>= \seqs -> Right (nextSeq : seqs)
else Left "structural mismatch for <hex-val>")
in takeSeq rest' >>= \seqs -> Right (Model.SeqHexVal $ firstSeq : seqs)
| otherwise -> Left "structural mismatch for <hex-val>"
where takeHexSeq :: [Tree.Node Model.Rulename] -> Either String (Hex.Seq, [Tree.Node Model.Rulename])
takeHexSeq nodes = case Util.List.lsplitWhenNot nodes isHexDig of
(hexno@(_:_), rest) ->
case Ascii.toHexSeq $ ByteString.concat (map Tree.stringifyNode hexno) of
Just hexseq -> Right (hexseq, rest)
Nothing -> Left "invalid hex digits in <hex-val>"
_ -> Left "structural mismatch for <hex-val>"
isB node = Tree.isStringEq node (Ascii.bs 'x') || Tree.isStringEq node (Ascii.bs 'X')
isHexDig node = Tree.isRefOf node Core.hexdigRef
isDot node = Tree.isStringEq node (Ascii.stringAsBytesUnsafe ".")
isDash node = Tree.isStringEq node (Ascii.stringAsBytesUnsafe "-")