diff options
Diffstat (limited to 'scaffolder/src/Text/Edifact/Scaffolder/Segments')
5 files changed, 220 insertions, 0 deletions
diff --git a/scaffolder/src/Text/Edifact/Scaffolder/Segments/Dependencies.hs b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Dependencies.hs new file mode 100644 index 0000000..acb9ea8 --- /dev/null +++ b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Dependencies.hs | |||
@@ -0,0 +1,47 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | |||
3 | module Text.Edifact.Scaffolder.Segments.Dependencies | ||
4 | ( -- * | ||
5 | mkDependenciesHaddock | ||
6 | , mkDependenciesImports | ||
7 | , mkDependenciesReexports | ||
8 | ) where | ||
9 | |||
10 | import Text.Edifact.Scaffolder.Commons | ||
11 | import Text.Edifact.Scaffolder.Segments.Types | ||
12 | |||
13 | import Data.List.NonEmpty as NE (nonEmpty, toList) | ||
14 | import Data.Maybe (catMaybes, mapMaybe) | ||
15 | import Formatting as F | ||
16 | |||
17 | mkDependenciesReexports :: NonEmpty Element -> Scaffolding [Export] | ||
18 | mkDependenciesReexports = reexportDependencies fElementFunction | ||
19 | |||
20 | mkDependenciesImports :: NonEmpty Element -> Scaffolding [ImportGroup] | ||
21 | mkDependenciesImports elements = | ||
22 | let filterElements optic = mapMaybe optic . NE.toList | ||
23 | in maybe [] (pure . ImportGroup) . nonEmpty . catMaybes <$> | ||
24 | sequence | ||
25 | [ mkCompositeDependenciesImports (filterElements getComposite elements) | ||
26 | , mkSimpleDependenciesImports (filterElements getSimple elements) | ||
27 | ] | ||
28 | |||
29 | mkSimpleDependenciesImports :: [SimpleCode] -> Scaffolding (Maybe Import) | ||
30 | mkSimpleDependenciesImports = | ||
31 | ifNonEmpty (importDependencies "Simples" fSimpleParserFunction) | ||
32 | |||
33 | mkCompositeDependenciesImports :: [CompositeCode] -> Scaffolding (Maybe Import) | ||
34 | mkCompositeDependenciesImports = | ||
35 | ifNonEmpty (importDependencies "Composites" fCompositeParserFunction) | ||
36 | |||
37 | ifNonEmpty :: Applicative f => (NonEmpty input -> f output) -> [input] -> f (Maybe output) | ||
38 | ifNonEmpty f = traverse f . nonEmpty | ||
39 | |||
40 | mkDependenciesHaddock :: NonEmpty Element -> Scaffolding [Text] | ||
41 | mkDependenciesHaddock = haddockDependencies fElementFunction | ||
42 | |||
43 | fElementFunction :: Format r (Element -> r) | ||
44 | fElementFunction = | ||
45 | let buildElementFunction (Simple code _ _ _ _) = bprint fSimpleParserFunction code | ||
46 | buildElementFunction (Composite code _ _) = bprint fCompositeParserFunction code | ||
47 | in later buildElementFunction | ||
diff --git a/scaffolder/src/Text/Edifact/Scaffolder/Segments/Elements.hs b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Elements.hs new file mode 100644 index 0000000..4e8b39c --- /dev/null +++ b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Elements.hs | |||
@@ -0,0 +1,26 @@ | |||
1 | module Text.Edifact.Scaffolder.Segments.Elements | ||
2 | ( listSegments | ||
3 | ) where | ||
4 | |||
5 | import Text.Edifact.Scaffolder.Commons | ||
6 | |||
7 | import Data.Char (isLower, toUpper) | ||
8 | import Text.Parsec (eof, lower, satisfy, string, | ||
9 | (<?>)) | ||
10 | import Text.Parsec.String (Parser) | ||
11 | |||
12 | listSegments :: Scaffolding [ElementWithDefinition SegmentCode] | ||
13 | listSegments = listElements "segments" segmentCodeParser | ||
14 | |||
15 | segmentCodeParser :: Parser SegmentCode | ||
16 | segmentCodeParser = do | ||
17 | c1 <- lowerExceptU | ||
18 | c2 <- lower | ||
19 | c3 <- lower | ||
20 | let code = SegmentCode (toUpper <$> [c1,c2,c3]) | ||
21 | code <$ string ".txt" | ||
22 | <* eof | ||
23 | <?> "SegmentCode" | ||
24 | |||
25 | lowerExceptU :: Parser Char | ||
26 | lowerExceptU = satisfy (\ c -> isLower c && c /= 'u') | ||
diff --git a/scaffolder/src/Text/Edifact/Scaffolder/Segments/Implementation.hs b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Implementation.hs new file mode 100644 index 0000000..8535a17 --- /dev/null +++ b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Implementation.hs | |||
@@ -0,0 +1,21 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | |||
3 | module Text.Edifact.Scaffolder.Segments.Implementation | ||
4 | ( -- * | ||
5 | toImplementation | ||
6 | ) where | ||
7 | |||
8 | import Text.Edifact.Scaffolder.Commons | ||
9 | import Text.Edifact.Scaffolder.Segments.Types | ||
10 | |||
11 | import Data.List.NonEmpty as NE (toList) | ||
12 | import Formatting | ||
13 | |||
14 | toImplementation :: NonEmpty Dependency -> [Text] | ||
15 | toImplementation = haskellList . fmap callDependency . NE.toList | ||
16 | |||
17 | callDependency :: Dependency -> Text | ||
18 | callDependency (Dependency pos (Simple code _ presence _ _)) = | ||
19 | sformat ( quoted fPosition % " .@ " % fPresence % " simple" % fSimpleCode) pos presence code | ||
20 | callDependency (Dependency pos (Composite code _ presence)) = | ||
21 | sformat ( quoted fPosition % " .@ " % fPresence % " composite" % fCompositeCode) pos presence code | ||
diff --git a/scaffolder/src/Text/Edifact/Scaffolder/Segments/Specification.hs b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Specification.hs new file mode 100644 index 0000000..39a7ad4 --- /dev/null +++ b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Specification.hs | |||
@@ -0,0 +1,99 @@ | |||
1 | module Text.Edifact.Scaffolder.Segments.Specification | ||
2 | ( -- * | ||
3 | specificationParser | ||
4 | , listCompositesAndSimples | ||
5 | ) where | ||
6 | |||
7 | import Text.Edifact.Scaffolder.Commons | ||
8 | import Text.Edifact.Scaffolder.Segments.Types | ||
9 | |||
10 | import Text.Parsec as P (anyChar, choice, | ||
11 | count, digit, | ||
12 | endOfLine, many, | ||
13 | many1, manyTill, | ||
14 | oneOf, skipMany, | ||
15 | string, try, | ||
16 | upper, (<?>)) | ||
17 | import Text.Parsec.String (Parser) | ||
18 | |||
19 | specificationParser :: Parser ((SegmentCode, SegmentName), [Dependency]) | ||
20 | specificationParser = do | ||
21 | segmentInfo <- scanUntil [ segmentParser ] | ||
22 | dependencies <- scan [ inLine dependencyParser ] <?> "Segments specification" | ||
23 | pure (segmentInfo, dependencies) | ||
24 | |||
25 | listCompositesAndSimples :: Parser (SegmentCode, [Element]) | ||
26 | listCompositesAndSimples = do | ||
27 | parsed <- specificationParser | ||
28 | pure (fst $ fst parsed, dependencyElement <$> snd parsed) | ||
29 | |||
30 | segmentParser :: Parser (SegmentCode, SegmentName) | ||
31 | segmentParser = do | ||
32 | _ <- count 6 (oneOf "+*#|X ") | ||
33 | skipMany (string " ") | ||
34 | code <- SegmentCode <$> count 3 upper | ||
35 | _ <- count 2 (string " ") | ||
36 | skipMany (string " ") | ||
37 | name <- SegmentName <$> manyTill anyChar (() <$ try endOfLine) | ||
38 | pure (code, name) | ||
39 | |||
40 | dependencyParser :: Parser Dependency | ||
41 | dependencyParser = | ||
42 | Dependency <$> positionParser | ||
43 | <* many1 (oneOf "+*#|-X ") | ||
44 | <*> elementParser | ||
45 | <?> "Dependency" | ||
46 | |||
47 | inLine :: Parser a -> Parser [a] | ||
48 | inLine p = single (many (string " ") *> p) | ||
49 | |||
50 | positionParser :: Parser Position | ||
51 | positionParser = | ||
52 | fromString <$> count 3 digit | ||
53 | <?> "Position" | ||
54 | |||
55 | elementParser :: Parser Element | ||
56 | elementParser = | ||
57 | choice [ compositeParser | ||
58 | , simpleParser | ||
59 | ] | ||
60 | <?> "Element" | ||
61 | |||
62 | compositeParser :: Parser Element | ||
63 | compositeParser = Composite <$> compositeCodeParser | ||
64 | <* many (string " ") | ||
65 | <*> stringToPresenceParser | ||
66 | <* many1 (string " ") | ||
67 | <*> presenceParser | ||
68 | <* string " " | ||
69 | <* many (oneOf " 0123456789") | ||
70 | <?> "Composite" | ||
71 | |||
72 | simpleParser :: Parser Element | ||
73 | simpleParser = Simple <$> (fromString <$> count 4 digit) | ||
74 | <* many1 (string " ") | ||
75 | <*> stringToPresenceParser | ||
76 | <* many1 (string " ") | ||
77 | <*> presenceParser | ||
78 | <* string " " | ||
79 | <* many (oneOf " 0123456789") | ||
80 | <*> simpleTypeParser | ||
81 | <*> simpleLengthParser | ||
82 | <?> "Simple" | ||
83 | |||
84 | simpleTypeParser :: Parser SimpleType | ||
85 | simpleTypeParser = choice [ Alphanumeric <$ string "an" | ||
86 | , Alphabetic <$ string "a" | ||
87 | , Numeric <$ string "n" | ||
88 | ] <?> "SimpleType" | ||
89 | |||
90 | simpleLengthParser :: Parser SimpleLength | ||
91 | simpleLengthParser = choice [ UpTo <$> fmap fromString (string ".." >> many1 digit) | ||
92 | , Exactly <$> (fromString <$> many1 digit) | ||
93 | ] <?> "SimpleLength" | ||
94 | |||
95 | compositeCodeParser :: Parser CompositeCode | ||
96 | compositeCodeParser = do | ||
97 | initial <- oneOf "CE" | ||
98 | rest <- count 3 digit | ||
99 | pure (fromString (initial : rest)) | ||
diff --git a/scaffolder/src/Text/Edifact/Scaffolder/Segments/Types.hs b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Types.hs new file mode 100644 index 0000000..6a34cbc --- /dev/null +++ b/scaffolder/src/Text/Edifact/Scaffolder/Segments/Types.hs | |||
@@ -0,0 +1,27 @@ | |||
1 | module Text.Edifact.Scaffolder.Segments.Types where | ||
2 | |||
3 | import Text.Edifact.Scaffolder.Commons | ||
4 | |||
5 | data Dependency = Dependency { dependencyPosition :: Position | ||
6 | , dependencyElement :: Element | ||
7 | } deriving Show | ||
8 | |||
9 | data Element = Composite CompositeCode Text Presence | ||
10 | | Simple SimpleCode Text Presence SimpleType SimpleLength | ||
11 | deriving (Show, Eq, Ord) | ||
12 | |||
13 | data SimpleType = Alphanumeric | Alphabetic | Numeric deriving (Show, Eq, Ord) | ||
14 | |||
15 | data SimpleLength = Exactly Text | UpTo Text deriving (Show, Eq, Ord) | ||
16 | |||
17 | getCode :: Element -> String | ||
18 | getCode (Simple (SimpleCode c) _ _ _ _) = c | ||
19 | getCode (Composite (CompositeCode c) _ _) = c | ||
20 | |||
21 | getSimple :: Element -> Maybe SimpleCode | ||
22 | getSimple (Simple c _ _ _ _) = Just c | ||
23 | getSimple _ = Nothing | ||
24 | |||
25 | getComposite :: Element -> Maybe CompositeCode | ||
26 | getComposite (Composite c _ _) = Just c | ||
27 | getComposite _ = Nothing | ||