config-value-0.1: src/Config/Tokens.hs
-- | This module provides the token type used in the lexer and
-- parser and provides the extra pass to insert layout tokens.
module Config.Tokens
( Token(..)
, PosToken(..)
, layoutPass
) where
import Data.Text (Text)
-- | A 'PosToken' is a 'Token' annotated with its line and column.
data PosToken = PosToken
{ posLine :: Int
, posColumn :: Int
, posToken :: Token
}
deriving (Show)
-- | The token type used by "Config.Lexer" and "Config.Parser"
data Token
= Section Text
| String Text
| Bullet
| Comma
| Number Int Integer
| OpenList
| CloseList
| OpenMap
| CloseMap
| Yes
| No
| Error
-- "Virtual" tokens used by the subsequent layout processor
| LayoutSep
| LayoutEnd
| EOF
deriving (Show)
-- | Process a list of position-annotated tokens inserting
-- layout end tokens as appropriate.
layoutPass ::
[PosToken] {- ^ tokens without layout markers -} ->
[PosToken] {- ^ tokens with layout markers -}
layoutPass toks = foldr step (\_ -> []) toks [-1]
-- | Single step of the layout pass
step :: PosToken -> ([Int] -> [PosToken]) -> ([Int] -> [PosToken])
-- start blocks must be indented
-- tokens before the current layout end the current layout
step t next (col:cols)
| usesLayout t && posColumn t > col = t : next (posColumn t:col:cols)
| usesLayout t && posColumn t == col = t{posToken=LayoutSep}
: t : next (col:cols)
| posColumn t <= col = t{posToken=LayoutEnd} : step t next cols
step t next cols = t : next cols
-- | Return True when a token starts a layout scope.
usesLayout :: PosToken -> Bool
usesLayout t
| Section{} <- posToken t = True
| Bullet <- posToken t = True
| otherwise = False