34 | 34 |
-- * Section-Level Parsing
|
35 | 35 |
-- $sections
|
36 | 36 |
, section
|
| 37 |
, allOptional
|
37 | 38 |
|
38 | 39 |
-- * Field-Level Parsing
|
39 | 40 |
-- $fields
|
|
44 | 45 |
, flag
|
45 | 46 |
, comment
|
46 | 47 |
, placeholderValue
|
47 | |
, skipIfMissing
|
| 48 |
, optional
|
48 | 49 |
|
49 | 50 |
-- * FieldValues
|
50 | 51 |
-- $fieldvalues
|
|
65 | 66 |
) where
|
66 | 67 |
|
67 | 68 |
import Control.Monad.Trans.State.Strict (State, runState, modify)
|
| 69 |
import qualified Control.Monad.Trans.State.Strict as State
|
68 | 70 |
import qualified Data.Foldable as F
|
69 | 71 |
#if __GLASGOW_HASKELL__ >= 710
|
70 | 72 |
import Data.Function ((&))
|
71 | 73 |
#endif
|
72 | 74 |
import Data.Monoid ((<>))
|
73 | |
import Data.Sequence ((<|), Seq, ViewL(..))
|
| 75 |
import Data.Sequence ((<|), Seq, ViewL(..), ViewR(..))
|
74 | 76 |
import qualified Data.Sequence as Seq
|
75 | 77 |
import Data.Text (Text)
|
76 | 78 |
import qualified Data.Text as T
|
|
242 | 244 |
section :: Text -> SectionSpec s () -> IniSpec s ()
|
243 | 245 |
section name (SectionSpec mote) = IniSpec $ do
|
244 | 246 |
let fields = runBidirM mote
|
245 | |
modify (Seq.|> Section (normalize name) fields (allOptional fields))
|
246 | |
|
247 | |
allOptional :: (Seq (Field s)) -> Bool
|
248 | |
allOptional = all isOptional
|
| 247 |
modify (Seq.|> Section (normalize name) fields (allFieldsOptional fields))
|
| 248 |
|
| 249 |
allFieldsOptional :: (Seq (Field s)) -> Bool
|
| 250 |
allFieldsOptional = all isOptional
|
249 | 251 |
where isOptional (Field _ fd) = fdSkipIfMissing fd
|
250 | 252 |
isOptional (FieldMb _ _) = True
|
| 253 |
|
| 254 |
allOptional
|
| 255 |
:: (SectionSpec s () -> IniSpec s ())
|
| 256 |
-> (SectionSpec s () -> IniSpec s ())
|
| 257 |
allOptional k spec = IniSpec $ do
|
| 258 |
let IniSpec comp = k spec
|
| 259 |
comp
|
| 260 |
modify (\ s -> case Seq.viewr s of
|
| 261 |
EmptyR -> s
|
| 262 |
rs :> Section name fields _ ->
|
| 263 |
rs Seq.|> Section name (fmap makeOptional fields) True)
|
| 264 |
|
| 265 |
makeOptional :: Field s -> Field s
|
| 266 |
makeOptional (Field l d) = Field l d { fdSkipIfMissing = True }
|
| 267 |
makeOptional (FieldMb l d) = FieldMb l d { fdSkipIfMissing = True }
|
251 | 268 |
|
252 | 269 |
data Section s = Section NormalizedText (Seq (Field s)) Bool
|
253 | 270 |
|
|
339 | 356 |
|
340 | 357 |
-- | If the field is not found in parsing, simply skip instead of
|
341 | 358 |
-- raising an error or setting anything.
|
342 | |
skipIfMissing :: FieldDescription t -> FieldDescription t
|
343 | |
skipIfMissing fd = fd { fdSkipIfMissing = True }
|
| 359 |
optional :: FieldDescription t -> FieldDescription t
|
| 360 |
optional fd = fd { fdSkipIfMissing = True }
|
344 | 361 |
|
345 | 362 |
infixr 0 .=
|
346 | 363 |
infixr 0 .=?
|
|
456 | 473 |
s' <- parseFields s (Seq.viewl fs) v
|
457 | 474 |
parseSections s' (Seq.viewl rest) i
|
458 | 475 |
| opt = parseSections s (Seq.viewl rest) i
|
459 | |
| otherwise = Left ("Unable to find section " ++ show name)
|
| 476 |
| otherwise = Left ("Unable to find section " ++
|
| 477 |
show (normalizedText name))
|
460 | 478 |
|
461 | 479 |
-- Now that we've got 'set', we can walk the field descriptions and
|
462 | 480 |
-- find them. There's some fiddly logic, but the high-level idea is
|
|
472 | 490 |
parseFields (set l value s) (Seq.viewl fs) sect
|
473 | 491 |
| fdSkipIfMissing descr =
|
474 | 492 |
parseFields s (Seq.viewl fs) sect
|
475 | |
| otherwise = Left ("Unable to find field " ++ show (fdName descr))
|
| 493 |
| otherwise = Left ("Unable to find field " ++
|
| 494 |
show (normalizedText (fdName descr)))
|
476 | 495 |
parseFields s (FieldMb l descr Seq.:< fs) sect
|
477 | 496 |
| Just v <- lkp (fdName descr) (isVals sect) = do
|
478 | 497 |
value <- fvParse (fdValue descr) (T.strip (vValue v))
|
|
499 | 518 |
, isStartLine = 0
|
500 | 519 |
, isEndLine = 0
|
501 | 520 |
, isComments = Seq.empty
|
502 | |
} where mkIniValue val descr optional =
|
| 521 |
} where mkIniValue val descr opt =
|
503 | 522 |
( fdName descr
|
504 | 523 |
, IniValue
|
505 | 524 |
{ vLineNo = 0
|
506 | 525 |
, vName = actualText (fdName descr)
|
507 | 526 |
, vValue = val
|
508 | 527 |
, vComments = mkComments (fdComment descr)
|
509 | |
, vCommentedOut = optional
|
| 528 |
, vCommentedOut = opt
|
510 | 529 |
, vDelimiter = '='
|
511 | 530 |
}
|
512 | 531 |
)
|