{----
 - String.hs - String parsing specialization of PosParse
 ----
 - Author: Jesse Rudolph <jesse.rudolph@gmail.com>
 - See LICENSE for licensing details
 ----------------------------------------------------------------- -}

module Language.Noodle.Parsing.String
    ( module Language.Noodle.Parsing.String
    , module Language.Noodle.Parsing.Positional ) where

import qualified Language.Noodle.Parsing.Positional as P (getTok,getTokIf)
import Language.Noodle.Parsing.Positional hiding (getTok,getTokIf)
    -- we hide these to make it hard to break automatic position update


{-- since the type of our tokens is known to be an instance of Show,
 -  we can make primative error messages a little more descriptive --}

{-- INVARIANT: all parsers based on combinators and primative parsers,
 -  exported from CharParser should correctly update position automatically --}


-- a specialization of the PosParser type that fills in the token type as Char
type Parser st res = PosParser st Char res



-- parse one character and return it if it matches c
char :: Char -> Parser st Char
char c = satisfy (== c) <|> fail ("expected " ++ show c)


-- parse one character and return it if predicate succeeds
satisfy :: (Char -> Bool) -> Parser st Char
satisfy f = do c <- P.getTokIf f
               case c of
                '\n' -> incLine
                _    -> incPos
               return c


-- parse the first character in the list
oneOf :: [Char] -> Parser st Char
oneOf [] = error "violated invariant: 'oneOf []' is undefined"
oneOf cs = choice (map char cs)


-- parse string matching s and return it
string :: String -> Parser st String
string s = mapM (char) s


-- parse one of either a space, tab, newline, or carriage return, and return it
whiteChar :: Parser st Char
whiteChar = char ' ' <|> char '\t' <|> char '\n' <|> char '\r'


-- parse zero or more occurances of whiteChar
whiteSpace :: Parser st String
whiteSpace = many whiteChar


-- parse lowercase aphabetical characters
alphaLower :: Parser st Char
alphaLower = oneOf ['a'..'z']


-- parse uppercase alphabetical characters
alphaUpper :: Parser st Char
alphaUpper = oneOf ['A'..'Z']


-- parse numberical characters
digit      :: Parser st Char
digit = oneOf ['0'..'9']