{- - The Lambda Shell, an interactive environment for evaluating pure untyped lambda terms. - Copyright (C) 2005-2007, Robert Dockins - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -} -- | This module defines parsers for lambda terms -- and for \"let\" bound definitions. module LambdaParser ( nameParser , lambdaParser , definitionFileParser , stripComments , Statement (..) , statementParser , statementsParser , LamParseState (..) , LamParser ) where import Data.List import qualified Data.Map as Map import Text.ParserCombinators.Parsec import Lambda import CPS -- | A type representing "statements". A statement is -- either a lambda form to reduce, a let binding, -- a confluence test, a cps transform, -- or the empty statement. data Statement = Stmt_eval (PureLambda () String) | Stmt_let String (PureLambda () String) | Stmt_isEq (PureLambda () String) (PureLambda () String) | Stmt_empty data LamParseState = LamParseState { cpsTransform :: CPS LamParser , extendedSyntax :: Bool } type LamParser = GenParser Char LamParseState -- | Parser for an identifier. An identifier is -- a letter followed by zero or more alphanumeric characters (or underscores). nameParser :: LamParser String nameParser = do a <- letter as <- many (char '_' <|> alphaNum) return (a:as) -- | Parser for a lambda term. Function application is left associative. -- -- @ -- lambda -\> name -- lambda -\> \'(\' lambda \')\' -- lambda -\> lambda lambda -- lambda -\> \'\\\' {name} \'.\' lambda -- @ lambdaParser :: Bindings () String -> LamParser (PureLambda () String) lambdaParser b = do st <- getState let p = if (extendedSyntax st) then extSyntax else basicSyntax spaces e <- appParser p b [] spaces return e -- | Parser for multiple statements. -- -- @ -- stmts -\> stmt ';' stmts -- stmts -\> -- @ statementsParser :: Bindings () String -> LamParser [Statement] statementsParser b = do spaces; x <- p b; eof; return x where p b = do x <- stmtParser b let b' = case x of (Stmt_let name t) -> Map.insert name t b _ -> b spaces ( do char ';' spaces xs <- p b' return (x:xs)) <|> (return [x]) -- | Parser for a statement. -- -- @ -- stmt -\> \'let\' name \'=\' lambda -- stmt -\> lambda -- @ statementParser :: Bindings () String -> LamParser Statement statementParser b = do spaces x <- stmtParser b spaces eof return x stmtParser :: Bindings () String -> LamParser Statement stmtParser b = try (letDefParser b >>= return . uncurry Stmt_let) <|> try (compParser b >>= return . uncurry Stmt_isEq) <|> (lambdaParser b >>= return . Stmt_eval) <|> (return Stmt_empty) compParser :: Bindings () String -> LamParser (PureLambda () String,PureLambda () String) compParser b = do x <- lambdaParser b spaces string "==" spaces y <- lambdaParser b spaces return (x,y) letDefParser :: Bindings () String -> LamParser (String,PureLambda () String) letDefParser b = do string "let" many1 space n <- nameParser spaces char '=' e <- lambdaParser b return (n,e) stripComments :: String -> String stripComments (x:xs) | x == '#' = stripComments (dropWhile (/= '\n') xs) | otherwise = x : stripComments xs stripComments [] = [] -- | Parser a file of definitions. Each definition takes the form -- -- @ -- def -\> \'let\' name \'=\' lambda \';\' -- @ definitionFileParser :: Bindings () String -> LamParser (Bindings () String) definitionFileParser b = (do spaces (n,t) <- definitionParser b spaces let b' = Map.insert n t b definitionFileParser b' ) <|> (eof >> return b) definitionParser :: Bindings () String -> LamParser (String,PureLambda () String) definitionParser b = do n <- nameParser spaces char '=' e <- lambdaParser b char ';' return (n,e) type P = Bindings () String -> [String] -> LamParser (PureLambda () String) cpsParser :: P -> P cpsParser p b l = do string "[[" spaces x <- (appParser p) b l spaces string "]]" st <- getState cpsTransform st b x parensParser :: P -> P parensParser p b l = do char '(' spaces e <- (appParser p) b l spaces char ')' return e varParser :: P varParser b labels = do var <- nameParser let i = elemIndex var labels case i of Just i -> return (Var () i) Nothing -> if Map.member var b then return (Binding () var) else fail ("variable '"++var++"' not in scope") absParser :: P -> P absParser p b labels = do char '\\' spaces vars <- sepEndBy1 nameParser spaces char '.' spaces let labels' = foldr (:) labels (reverse vars) exp <- (appParser p) b labels' let expr = foldr (Lam ()) exp vars return expr appParser :: P -> P appParser p b l = do exprs <- sepEndBy1 (p b l) (many1 space) return (foldl1 (App ()) exprs) basicSyntax :: P basicSyntax b l = parensParser basicSyntax b l <|> absParser basicSyntax b l <|> varParser b l extSyntax :: P extSyntax b l = parensParser extSyntax b l <|> absParser extSyntax b l <|> cpsParser extSyntax b l <|> varParser b l