| 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 |
)
|