1 {-# LANGUAGE OverloadedStrings #-}
3 module Text.Edifact.Scaffolder.Messages.Implementation
8 import Text.Edifact.Scaffolder.Commons
9 import Text.Edifact.Scaffolder.Messages.Types
11 import Control.Monad.State.Strict (State, evalState, gets,
13 import Data.List.NonEmpty as NE (NonEmpty (..),
18 toImplementation :: MessageCode -> NonEmpty Dependency -> [Text]
20 let closeList deps = deps <> [ "]" ]
21 in closeList . render . fmap concat . traverse callDependency . NE.toList
23 render :: Rendering a -> a
25 let initialState = RenderingContext 0 0 :| []
26 in evalState r initialState
30 data RenderingContext = RenderingContext { listPosition :: Int
34 type Rendering = State (Trail RenderingContext)
36 callDependency :: Dependency -> Rendering [Text]
37 callDependency (Dependency element) = renderElement element
39 increment :: Rendering ()
41 let mapHead f (v :| t) = f v :| t
42 in modify (mapHead (\ ctx -> ctx { listPosition = listPosition ctx + 1 }))
44 pushIndent :: Rendering ()
46 let indentState t@(previous :| _) = RenderingContext 0 (indentLevel previous + 2) <| t
49 popIndent :: Rendering ()
51 let pop (_ :| []) = error "Incoherent state: can't unindent anymore (this shouldn't happen)"
52 pop (_ :| up) = NE.fromList up
55 getCurrentIndex :: Rendering Int
56 getCurrentIndex = gets (listPosition . NE.head)
58 getCurrentIndentation :: Rendering Int
59 getCurrentIndentation = gets (indentLevel . NE.head)
61 renderElement :: Element -> Rendering [Text]
62 renderElement (Segment code positional) =
63 let output index indentation =
64 [ sformat (fIndentation % fIndex % " " % fPositional % " " % fSegmentParserFunction) indentation index positional code
66 in output <$> getCurrentIndex
67 <*> getCurrentIndentation
69 renderElement (GroupStart code positional) =
70 let output index indentation =
71 [ sformat (fIndentation % fIndex % " " % fPositional % " (") indentation index positional
72 , sformat (fIndentation % fSegmentGroupFunction) (indentation + 1) code
74 in output <$> getCurrentIndex
75 <*> getCurrentIndentation
78 renderElement (GroupEnd _) =
79 let output indentation =
80 [ sformat (fIndentation % "]") indentation
81 , sformat (fIndentation % ")") (indentation - 1)
83 in output <$> getCurrentIndentation
86 fIndentation :: Format r (Int -> r)
88 let buildIndentation n = fromString (replicate (n * 2) ' ')
89 in later buildIndentation
91 fIndex :: Format r (Int -> r)
93 let buildIndex 0 = "["
97 fPositional :: Format r (Positional -> r)
99 let buildPositional (Positional p r) = bprint (quoted fPosition % " .@ " % fRepetition) p r
100 in later buildPositional
102 fSegmentGroupFunction :: Format r (GroupCode -> r)
103 fSegmentGroupFunction = "segmentGroup " % quoted fGroupCode
105 fRepetition :: Format r (Repetition -> r)
107 let buildRepetition (Repetition Mandatory 1) = bprint "once"
108 buildRepetition (Repetition Optional 1) = bprint "maybeOnce"
109 buildRepetition (Repetition Mandatory c) = bprint ("repeatedAtLeastOnce" % " " % fCardinality) c
110 buildRepetition (Repetition Optional c) = bprint ("repeated" % " " % fCardinality) c
111 in later buildRepetition
113 fCardinality :: Format r (Cardinality -> r)
114 fCardinality = mapf getCardinality int