-- | Utility parser combinators for parsing CSS stylesheets.
module Stylist.Parse.Util(
concatP, capture, skipSpace,
scanBlock, skipBlock, scanInner,
Parser
) where
import Data.CSS.Syntax.Tokens
-- | A simple parser combinator type.
type Parser x = [Token] -> (x, [Token])
-- | Chains two parser combinators together.
concatP :: (a -> b -> c) -> Parser a -> Parser b -> Parser c
concatP join left right tokens = (join x y, remainder)
where
(x, tokens') = left tokens
(y, remainder) = right tokens'
-- | "captures" the token being parsed into the returned output.
capture :: Parser [Token] -> Parser [Token]
capture cb (token:tokens) = (token:captured, tokens')
where (captured, tokens') = cb tokens
capture _ [] = ([], [])
-- | Removes preceding `Whitespace` tokens.
skipSpace :: [Token] -> [Token]
skipSpace (Whitespace:tokens) = skipSpace tokens
skipSpace tokens = tokens
-- | Returns tokens until the next unbalanced closing brace.
scanBlock :: Parser [Token]
-- TODO assert closing tags are correct
-- But what should the error recovery be?
scanBlock (RightCurlyBracket:tokens) = ([RightCurlyBracket], tokens)
scanBlock (RightParen:tokens) = ([RightParen], tokens)
scanBlock (RightSquareBracket:tokens) = ([RightSquareBracket], tokens)
scanBlock tokens@(LeftCurlyBracket:_) = scanInner tokens scanBlock
scanBlock tokens@(LeftParen:_) = scanInner tokens scanBlock
scanBlock tokens@(Function _:_) = scanInner tokens scanBlock
scanBlock tokens@(LeftSquareBracket:_) = scanInner tokens scanBlock
scanBlock tokens = capture scanBlock tokens
-- | Returns tokens after the next unbalanced closing brace.
skipBlock :: [Token] -> [Token]
skipBlock tokens = snd $ scanBlock tokens
-- | Parses a block followed by the given combinator, returning the tokens the matched.
scanInner :: [Token] -> Parser [Token] -> ([Token], [Token])
scanInner (token:tokens) cb = concatP gather scanBlock cb tokens
where gather x y = token : x ++ y
scanInner [] _ = error "Expected a token to capture."