@@ -5,7 +5,7 @@ module Hie.Cabal.Parser where
5
5
import Control.Applicative
6
6
import Control.Monad
7
7
import Data.Attoparsec.Text
8
- import Data.Char ( isSpace )
8
+ import Data.Char
9
9
import Data.Text (Text )
10
10
import qualified Data.Text as T
11
11
@@ -31,117 +31,138 @@ parsePackage' = parseOnly parsePackage
31
31
parsePackage :: Parser Package
32
32
parsePackage =
33
33
( do
34
- n <- field 0 " name"
34
+ n <- field 0 " name" $ const parseString
35
35
(Package _ t) <- parsePackage
36
36
pure $ Package n t
37
37
)
38
38
<|> ( do
39
39
h <- parseComponent 0
40
40
(Package n t) <- parsePackage
41
- pure $ Package n (h : t)
41
+ pure $ Package n (h <> t)
42
42
)
43
43
<|> (skipToNextLine >> parsePackage)
44
44
<|> pure (Package " " [] )
45
45
46
46
componentHeader :: Indent -> Text -> Parser Name
47
47
componentHeader i t = do
48
- indent i
48
+ _ <- indent i
49
49
_ <- asciiCI t
50
50
skipMany tabOrSpace
51
51
n <- parseString <|> pure " "
52
52
skipToNextLine
53
53
pure n
54
54
55
- parseComponent :: Indent -> Parser Component
55
+ parseComponent :: Indent -> Parser [ Component ]
56
56
parseComponent i =
57
57
parseExe i
58
58
<|> parseLib i
59
59
<|> parseBench i
60
60
<|> parseTestSuite i
61
61
62
- parseLib :: Indent -> Parser Component
62
+ parseLib :: Indent -> Parser [ Component ]
63
63
parseLib i = parseSec i " library" $ Comp Lib
64
64
65
- parseTestSuite :: Indent -> Parser Component
65
+ parseTestSuite :: Indent -> Parser [ Component ]
66
66
parseTestSuite i = parseSec i " test-suite" $ Comp Test
67
67
68
- parseExe :: Indent -> Parser Component
68
+ parseExe :: Indent -> Parser [ Component ]
69
69
parseExe = parseSecMain (Comp Exe ) " executable"
70
70
71
- parseBench :: Indent -> Parser Component
71
+ parseBench :: Indent -> Parser [ Component ]
72
72
parseBench = parseSecMain (Comp Bench ) " benchmark"
73
73
74
- parseSecMain :: (Name -> Path -> Component ) -> Text -> Indent -> Parser Component
74
+ parseSecMain :: (Name -> Path -> Component ) -> Text -> Indent -> Parser [ Component ]
75
75
parseSecMain c s i = do
76
76
n <- componentHeader i s
77
- c n <$> pathMain (i + 1 ) " ./" " "
77
+ p <- pathMain (i + 1 ) [" ./" ] " "
78
+ pure $ map (c n) p
78
79
79
80
parseQuoted :: Parser Text
80
81
parseQuoted = do
81
82
q <- char ' "' <|> char ' \' '
82
83
takeTill (== q)
83
84
84
85
parseString :: Parser Name
85
- parseString = parseQuoted <|> takeWhile1 (not . (\ c -> isSpace c || c == ' ,' ))
86
-
87
- pathMain :: Indent -> Text -> Text -> Parser Text
86
+ parseString = parseQuoted <|> unqualName
87
+
88
+ unqualName :: Parser Text
89
+ unqualName = takeWhile1 (\ c -> isAlphaNum c || c `elem` (" -_./" :: String ))
90
+
91
+ parseList :: Indent -> Parser [Text ]
92
+ parseList i = items <|> (emptyOrComLine >> indent i >> items)
93
+ where
94
+ items = do
95
+ skipMany tabOrSpace
96
+ h <- parseString
97
+ skipMany tabOrSpace
98
+ skipMany (char ' ,' )
99
+ t <-
100
+ items
101
+ <|> (skipToNextLine >> indent i >> parseList i)
102
+ <|> pure []
103
+ pure $ h : t
104
+
105
+ pathMain :: Indent -> [Text ] -> Text -> Parser [Text ]
88
106
pathMain i p m =
89
- (field i " hs-source-dirs " >>= (\ p' -> pathMain i p' m))
90
- <|> (field i " main-is" >>= pathMain i p)
107
+ (hsSourceDir i >>= (\ p' -> pathMain i p' m))
108
+ <|> (field i " main-is" ( const parseString) >>= pathMain i p)
91
109
<|> (skipBlockLine i >> pathMain i p m)
92
- <|> pure (p <> " /" <> m)
110
+ <|> pure (map ( <> " /" <> m) p )
93
111
94
- parseSec :: Indent -> Text -> (Name -> Path -> Component ) -> Parser Component
112
+ parseSec :: Indent -> Text -> (Name -> Path -> Component ) -> Parser [ Component ]
95
113
parseSec i compType compCon = do
96
114
n <- componentHeader i compType
97
- compCon n <$> extractPath (i + 1 )
115
+ p <- extractPath (i + 1 ) []
116
+ let p' = if null p then [" ./" ] else p
117
+ pure $ map (compCon n) p'
98
118
99
119
skipToNextLine :: Parser ()
100
120
skipToNextLine = skipWhile (not . isEndOfLine) >> endOfLine
101
121
102
122
skipBlock :: Indent -> Parser ()
103
123
skipBlock i = skipMany $ skipBlockLine i
104
124
125
+ comment :: Parser ()
126
+ comment = skipMany tabOrSpace >> " --" >> skipToNextLine
127
+
105
128
skipBlockLine :: Indent -> Parser ()
106
- skipBlockLine i =
107
- (indent i >> skipToNextLine)
108
- <|> (skipMany tabOrSpace >> endOfLine )
109
- <|> (skipSpace >> " -- " >> skipToNextLine)
129
+ skipBlockLine i = (indent i >> skipToNextLine) <|> emptyOrComLine
130
+
131
+ emptyOrComLine :: Parser ( )
132
+ emptyOrComLine = skipMany tabOrSpace >> endOfLine <|> comment
110
133
111
134
tabOrSpace :: Parser Char
112
135
tabOrSpace = char ' ' <|> char ' \t '
113
136
114
- field :: Indent -> Text -> Parser Text
115
- field i f =
137
+ hsSourceDir :: Indent -> Parser [Text ]
138
+ hsSourceDir i = field i " hs-source-dirs" parseList
139
+
140
+ -- field :: Indent -> Text -> Parser Text
141
+ field ::
142
+ Indent ->
143
+ Text ->
144
+ (Indent -> Parser a ) ->
145
+ Parser a
146
+ field i f p =
116
147
do
117
- indent i
148
+ i' <- indent i
118
149
_ <- asciiCI f
119
150
skipSpace
120
151
_ <- char ' :'
121
152
skipSpace
122
- p <- parseString
153
+ p' <- p $ i' + 1
123
154
skipToNextLine
124
- pure p
155
+ pure p'
125
156
126
- parseMainIs :: Indent -> Parser Path
127
- parseMainIs i =
128
- do
129
- p <- field i " main-is"
130
- skipBlock i
131
- pure p
132
- <?> " hs-source-dirs"
133
-
134
- extractPath :: Indent -> Parser Path
135
- extractPath i =
136
- ( do
137
- p <- field i " hs-source-dirs"
138
- skipBlock i
139
- pure p
140
- )
141
- <|> (skipBlockLine i >> extractPath i <?> " skip line" )
142
- <|> (pure " ./" <?> " not found" ) <?> " extractPath"
157
+ extractPath :: Indent -> [Path ] -> Parser [Path ]
158
+ extractPath i ps =
159
+ (field i " hs-source-dirs" parseList >>= (\ p -> extractPath i $ ps <> p))
160
+ <|> (skipBlockLine i >> extractPath i ps)
161
+ <|> (comment >> extractPath i ps)
162
+ <|> pure ps
143
163
144
164
-- | Skip at least n spaces
145
- indent :: Indent -> Parser ()
146
- indent 0 = skipMany tabOrSpace <?> " indent 0"
147
- indent i = tabOrSpace >> indent (i - 1 ) <?> " indent 0"
165
+ indent :: Indent -> Parser Int
166
+ indent i = do
167
+ c <- length <$> many' tabOrSpace
168
+ if c >= i then pure c else fail " insufficient indent"
0 commit comments