packages feed

Delta-Lambda-0.3.0.0: source/Parser.hs

module Parser where

import           Control.Applicative
import           Control.Monad.Except
import           Data.Text                   (Text)
import           Data.Text                   (pack, unpack)
import           Data.Word                   (Word64)

import           Language.Preprocessor.Cpphs
import           Text.Megaparsec             hiding (space)
import qualified Text.Megaparsec.Lexer       as Lexer
import           Text.Megaparsec.Text

import           AST

lineComment, blockComment, spaceToken :: Parser ()
lineComment = Lexer.skipLineComment "--" <|> Lexer.skipLineComment "#"

blockComment = Lexer.skipBlockComment "{-" "-}"

spaceToken = Lexer.space (void spaceChar) lineComment blockComment

lexeme :: Parser a -> Parser a
lexeme = Lexer.lexeme spaceToken

symbol :: String -> Parser String
symbol = Lexer.symbol spaceToken

variableToken :: Parser Text
variableToken = lexeme =<<
                return . pack <$> ((:) <$> (letterChar <|> Text.Megaparsec.char '$')
                                       <*> many alphaNumChar)

commaToken, colonToken, typeToken :: Parser ()
commaToken = void (symbol ",")

colonToken = void (symbol ":")

typeToken = void (symbol "type")

parensToken, bracketsToken :: Parser a -> Parser a
parensToken = between (symbol "(") (symbol ")")

bracketsToken = between (symbol "[") (symbol "]")

vector :: Parser [Term SourcePos Text Word64]
vector = sepBy1 term commaToken

telescope :: Parser [([(Text, SourcePos)], Term SourcePos Text Word64)]
telescope = sepBy1
              ((,) <$> sepBy ((,) <$> variableToken <*> getPosition) commaToken
                   <*> (colonToken >> term))
              commaToken

term :: Parser (Term SourcePos Text Word64)
term = (Type <$> (typeToken >> getPosition) <?> "type")
       <|> try (Variable <$> variableToken <*> return 0 <*> getPosition <?> "variable")
       <|> (apply <$> parensToken vector <*> term <?> "application")
       <|> (funct <$> bracketsToken telescope <*> term <?> "abstraction")

apply :: [Term SourcePos v i] -> Term SourcePos v i -> Term SourcePos v i
apply = flip $ foldl (\f a -> Application (getNodeMetadata (Term a)) a f)

funct :: [([(Text, SourcePos)], Term SourcePos Text Word64)] -> Term SourcePos Text Word64 -> Term SourcePos Text Word64
funct = flip $ foldr $ \(ns, typ) bod ->
  foldr (\(n, p) -> Abstraction n p typ . bindTerm n 1) bod ns

parseString :: String -> Text -> Either String (Term SourcePos Text Word64)
parseString filename' input =
  case parse term filename' input of
    Left err  -> Left $ show err
    Right val -> Right val

parseInput :: Text -> Either String (Term SourcePos Text Word64)
parseInput = parseString "stdin"

preprocessor :: [String] -> FilePath -> Text -> IO (Either String Text)
preprocessor options filename fileContents =
  case Language.Preprocessor.Cpphs.parseOptions options of
    Left err -> return $ Left err
    Right cpphsOpts -> do
      fileContents' <- runCpphs cpphsOpts filename (unpack fileContents)
      return $ Right $ pack fileContents'