module Megaparsec (runSexp, runLongws, runNumcsv, runTm) where import Control.Applicative import qualified Data.ByteString as B import Text.Megaparsec import Text.Megaparsec.Byte.Lexer import Data.Char import Common type Parser = Parsec () B.ByteString isLatinLetter :: Char -> Bool isLatinLetter c = ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') char8 :: Char -> Parser () char8 c = () <$ single (fromIntegral (ord c)) {-# inline skipWhile #-} skipWhile :: (Char -> Bool) -> Parser () skipWhile f = () <$ takeWhileP Nothing (f . chr . fromIntegral) {-# inline skipWhile1 #-} skipWhile1 :: (Char -> Bool) -> Parser () skipWhile1 f = () <$ takeWhile1P Nothing (f . chr . fromIntegral) {-# inline takeWhile1 #-} takeWhile1 :: (Char -> Bool) -> Parser B.ByteString takeWhile1 f = takeWhile1P Nothing (f . chr . fromIntegral) ws, open, close, ident, sexp :: Parser () ws = skipWhile (\c -> c == ' ' || c == '\n') open = char8 '(' >> ws close = char8 ')' >> ws ident = skipWhile1 isLatinLetter <* ws sexp = (open *> skipSome sexp <* close) <|> ident runSexp = runParser sexp "" longw, longws :: Parser () longw = () <$ chunk "thisisalongkeyword" longws = skipSome (longw *> ws) <* eof runLongws = runParser longws "" numeral, comma, numcsv :: Parser () numeral = skipWhile1 (\c -> '0' <= c && c <= '9') >> ws comma = single (fromIntegral (ord ',')) >> ws numcsv = numeral >> skipSome (comma >> numeral) >> eof runNumcsv = runParser numcsv "" -------------------------------------------------------------------------------- ident' :: Parser B.ByteString ident' = takeWhile1 (\c -> isLatinLetter c || isDigit c) <* ws equal = char8 '=' >> ws semi = char8 ';' >> ws dot = char8 '.' >> ws addOp = char8 '+' >> ws mulOp = char8 '*' >> ws parl = char8 '(' >> ws parr = char8 ')' >> ws chainl :: (b -> a -> b) -> Parser b -> Parser a -> Parser b chainl f start elem = start >>= go where go b = do {!a <- elem; go $! f b a} <|> pure b {-# inline chainl #-} add :: Parser Tm add = chainl Add mul (addOp *> mul) mul :: Parser Tm mul = chainl Mul spine (mulOp *> spine) spine :: Parser Tm spine = chainl App atom atom atom :: Parser Tm atom = (Int <$> (decimal <* ws)) <|> (Var <$> ident') <|> (parl *> tm <* parr) tm :: Parser Tm tm = (do {_ <- chunk "fun"; ws; x <- ident'; dot; t <- tm; pure (Lam x t)}) <|> (do {_ <- chunk "let"; ws; x <- ident'; equal; t <- tm; semi; u <- tm; pure (Let x t u)}) <|> add runTm = runParser (ws *> tm <* eof) ""