packages feed

atomo-0.4: src/Atomo/Parser/Base.hs

{-# OPTIONS -fno-warn-name-shadowing #-}
module Atomo.Parser.Base where

import Control.Monad.Identity
import Text.Parsec

import Atomo.Lexer.Base (TaggedToken(..), Token(..))
import Atomo.Types (Expr(..), ParserState(..), Value(..), Option(..))
import Atomo.Pretty
import qualified Atomo.Types as T


-- | A headless dispatch segment.
--
-- Used for both single dispatch chains and particles.
data Chained
    = CSingle String [Option Expr]
    | CKeyword [String] [Expr] [Option Expr]
    deriving Show

type ParserOf a = ParsecT a ParserState Identity
type Parser = ParserOf [TaggedToken]


showToken :: Token -> String
showToken TokEnd = "ending"
showToken t = show (pretty t)

withToken :: (Token -> Maybe a) -> Parser a
withToken f =
    tokenPrim
        (showToken . tToken)
        (\_ t _ -> tLocation t)
        (f . tToken)

someToken :: Parser Token
someToken = withToken Just

endOfFile :: Parser ()
endOfFile = try $ choice
    [ do
        t <- someToken
        unexpected (showToken t)
    , return ()
    ]

keyword :: Parser String
keyword = withToken $ \t ->
    case t of
        TokKeyword n -> Just n
        _ -> Nothing

optionalKeyword :: Parser String
optionalKeyword = withToken $ \t ->
    case t of
        TokOptional n -> Just n
        _ -> Nothing

optionalFlag :: Parser String
optionalFlag = withToken $ \t ->
    case t of
        TokOptionalFlag n -> Just n
        _ -> Nothing

operator :: Parser String
operator = withToken $ \t ->
    case t of
        TokOperator n -> Just n
        _ -> Nothing

identifier :: Parser String
identifier = withToken $ \t ->
    case t of
        TokIdentifier n ->
            Just n
        _ -> Nothing

particle :: Parser Chained
particle = withToken $ \t ->
    case t of
        TokParticle ns ->
            Just (CKeyword ns (replicate (length ns) wildcard) [])
        _ -> Nothing
  where
    wildcard = EDispatch Nothing (T.single "_" (ETop Nothing))

primitive :: Parser Value
primitive = withToken $ \t ->
    case t of
        TokPrimitive v -> Just v
        _ -> Nothing

macroQuote :: Parser (String, String, [Char])
macroQuote = withToken $ \t ->
    case t of
        TokMacroQuote n r fs -> Just (n, r, fs)
        _ -> Nothing

punctuation :: Char -> Parser ()
punctuation p = withToken $ \t ->
    case t of
        TokPunctuation c | c == p -> Just ()
        TokOpen c | c == p -> Just ()
        TokClose c | c == p -> Just ()
        _ -> Nothing

reserved :: String -> Parser ()
reserved r = withToken $ \t ->
    case t of
        TokReserved n | n == r -> Just ()
        _ -> Nothing

anyReserved :: Parser String
anyReserved = withToken $ \t ->
    case t of
        TokReserved n -> Just n
        _ -> Nothing

end :: Parser ()
end = withToken $ \t ->
    case t of
        TokEnd -> Just ()
        _ -> Nothing

symbol :: String -> Parser ()
symbol s = withToken $ \t ->
    case t of
        TokIdentifier n | n == s -> Just ()
        _ -> Nothing

integer :: Parser Integer
integer = withToken $ \t ->
    case t of
        TokPrimitive (Integer i) -> Just i
        _ -> Nothing

parens :: Parser a -> Parser a
parens p = do
    punctuation '('
    r <- p
    optional end
    punctuation ')'
    return r

brackets :: Parser a -> Parser a
brackets p = do
    punctuation '['
    r <- p
    punctuation ']'
    return r

braces :: Parser a -> Parser a
braces p = do
    punctuation '{'
    r <- p
    punctuation '}'
    return r

blockOf :: Parser a -> Parser [a]
blockOf p = sepEndBy p end

blockOf1 :: Parser a -> Parser [a]
blockOf1 p = sepEndBy1 p end

keywordSegment :: Parser a -> Parser (String, a)
keywordSegment p = do
    name <- keyword
    target <- p
    return (name, target)

optionSegment :: Parser a -> Parser (String, a)
optionSegment p = do
    name <- optionalKeyword
    target <- p
    return (name, target)

optionFlag :: Parser (String, Expr)
optionFlag = do
    name <- optionalFlag
    return (name, EPrimitive Nothing (Boolean True))

tagged :: Parser Expr -> Parser Expr
tagged p = do
    pos <- getPosition
    r <- p
    return r { eLocation = Just pos }

followedBy :: Parser a -> Parser Bool
followedBy p = choice
    [ lookAhead (try p) >> return True
    , return False
    ]