2014-12-11 03:48:56 +03:00
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
2014-10-29 22:17:58 +03:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
|
|
|
import Control.Applicative
|
2014-12-11 23:40:39 +03:00
|
|
|
import Control.Category.Structures
|
2014-11-23 15:39:58 +03:00
|
|
|
import Control.Lens.Cons
|
2014-10-30 18:36:55 +03:00
|
|
|
import Control.Lens.SemiIso
|
2014-10-29 22:17:58 +03:00
|
|
|
import Control.Lens.TH
|
2014-12-11 03:48:56 +03:00
|
|
|
import Control.SIArrow
|
2014-11-30 18:37:58 +03:00
|
|
|
import qualified Data.Attoparsec.Text.Lazy as AP
|
2014-10-29 22:17:58 +03:00
|
|
|
import Data.Char
|
2014-11-23 15:39:58 +03:00
|
|
|
import Data.Scientific (Scientific)
|
2014-12-11 23:40:39 +03:00
|
|
|
import Data.Syntax (Seq)
|
2014-10-29 22:17:58 +03:00
|
|
|
import qualified Data.Syntax as S
|
2014-11-30 18:37:58 +03:00
|
|
|
import qualified Data.Syntax.Attoparsec.Text.Lazy as S
|
2014-12-11 03:48:56 +03:00
|
|
|
import Data.Syntax.Char (SyntaxChar, SyntaxText)
|
2014-10-29 22:17:58 +03:00
|
|
|
import qualified Data.Syntax.Char as S
|
2014-10-30 18:36:55 +03:00
|
|
|
import qualified Data.Syntax.Combinator as S
|
2014-11-30 18:37:58 +03:00
|
|
|
import qualified Data.Syntax.Printer.Text as S
|
2014-10-29 22:17:58 +03:00
|
|
|
import Data.Text (Text)
|
2014-11-30 18:37:58 +03:00
|
|
|
import qualified Data.Text.Lazy.Builder as T
|
|
|
|
import qualified Data.Text.Lazy.IO as T
|
2014-10-29 22:17:58 +03:00
|
|
|
|
2014-11-23 17:28:20 +03:00
|
|
|
-- A simple lambda calculus.
|
2014-11-23 15:39:58 +03:00
|
|
|
|
|
|
|
data Literal = LitStr Text
|
|
|
|
| LitNum Scientific
|
|
|
|
deriving (Show)
|
|
|
|
|
|
|
|
$(makePrisms ''Literal)
|
|
|
|
|
2014-10-29 22:17:58 +03:00
|
|
|
data AST = Var Text
|
2014-11-23 15:39:58 +03:00
|
|
|
| Lit Literal
|
2014-10-29 22:17:58 +03:00
|
|
|
| App AST AST
|
|
|
|
| Abs Text AST
|
2014-11-23 15:39:58 +03:00
|
|
|
| Let Text AST AST
|
2014-10-29 22:17:58 +03:00
|
|
|
deriving (Show)
|
|
|
|
|
|
|
|
$(makePrisms ''AST)
|
|
|
|
|
|
|
|
-- | A variable name.
|
2014-12-11 03:48:56 +03:00
|
|
|
name :: SyntaxText syn => syn () Text
|
2014-11-23 15:39:58 +03:00
|
|
|
name = _Cons /$/ S.satisfy isAlpha /*/ S.takeWhile isAlphaNum
|
|
|
|
|
|
|
|
-- | A quoted string.
|
2014-12-11 03:48:56 +03:00
|
|
|
quoted :: SyntaxChar syn => syn () (Seq syn)
|
2014-11-23 15:39:58 +03:00
|
|
|
quoted = S.char '"' */ S.takeTill (=='"') /* S.char '"'
|
2014-10-29 22:17:58 +03:00
|
|
|
|
|
|
|
-- | Encloses a symbol in parentheses.
|
2014-12-11 03:48:56 +03:00
|
|
|
parens :: SyntaxChar syn => syn () a -> syn () a
|
2014-10-29 22:17:58 +03:00
|
|
|
parens m = S.char '(' */ S.spaces_ */ m /* S.spaces_ /* S.char ')'
|
|
|
|
|
2014-11-23 15:39:58 +03:00
|
|
|
-- | A literal.
|
2014-12-11 03:48:56 +03:00
|
|
|
literal :: SyntaxText syn => syn () Literal
|
2014-11-23 15:39:58 +03:00
|
|
|
literal = _LitNum /$/ S.scientific
|
2014-12-11 03:48:56 +03:00
|
|
|
/+/ _LitStr /$/ quoted
|
2014-11-23 15:39:58 +03:00
|
|
|
|
|
|
|
-- | An atom is a variable, literal or an expression in parentheses.
|
2014-12-11 03:48:56 +03:00
|
|
|
atom :: SyntaxText syn => syn () AST
|
2014-11-23 15:39:58 +03:00
|
|
|
atom = _Lit /$/ literal
|
2014-12-11 03:48:56 +03:00
|
|
|
/+/ _Var /$/ name
|
|
|
|
/+/ parens expr
|
2014-10-29 22:17:58 +03:00
|
|
|
|
2014-11-23 15:39:58 +03:00
|
|
|
-- | Parses a list of atoms and folds them with the _App prism.
|
2014-12-11 03:48:56 +03:00
|
|
|
apps :: SyntaxText syn => syn () AST
|
2014-11-23 15:39:58 +03:00
|
|
|
apps = bifoldl1 _App /$/ S.sepBy1 atom S.spaces1
|
2014-10-30 18:36:55 +03:00
|
|
|
|
2014-10-29 22:17:58 +03:00
|
|
|
-- | An expression of our lambda calculus.
|
2014-11-23 15:39:58 +03:00
|
|
|
--
|
|
|
|
-- Thanks to 'tuple-morph' we don't have to worry about /* and */ here.
|
|
|
|
-- Tuples are reassociated and units are removed by the 'morphed'
|
|
|
|
-- isomorphism (applied in /$~ operator).
|
2014-12-11 03:48:56 +03:00
|
|
|
expr :: SyntaxText syn => syn () AST
|
2014-11-23 15:39:58 +03:00
|
|
|
expr = _Abs /$~ S.char '\\' /*/ S.spaces_
|
|
|
|
/*/ name /*/ S.spaces
|
2014-11-29 20:01:08 +03:00
|
|
|
/*/ S.string "->" /*/ S.spaces
|
2014-11-23 15:39:58 +03:00
|
|
|
/*/ expr
|
|
|
|
|
2014-12-11 03:48:56 +03:00
|
|
|
/+/ _Let /$~ S.string "let" /*/ S.spaces1
|
2014-11-23 15:39:58 +03:00
|
|
|
/*/ name /*/ S.spaces
|
|
|
|
/*/ S.char '=' /*/ S.spaces
|
|
|
|
/*/ expr /*/ S.spaces1
|
|
|
|
/*/ S.string "in" /*/ S.spaces1
|
2014-10-30 18:36:55 +03:00
|
|
|
/*/ expr
|
2014-11-23 15:39:58 +03:00
|
|
|
|
2014-12-11 03:48:56 +03:00
|
|
|
/+/ apps
|
2014-10-29 22:17:58 +03:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
|
|
|
-- Load the standard input.
|
|
|
|
t <- T.getContents
|
|
|
|
|
|
|
|
-- Try to parse it.
|
2014-12-11 03:48:56 +03:00
|
|
|
case AP.parse (S.getParser_ expr <* AP.skipSpace <* AP.endOfInput) t of
|
2014-11-30 18:37:58 +03:00
|
|
|
AP.Fail _ _ err -> putStrLn err
|
|
|
|
AP.Done _ ast -> do
|
|
|
|
-- If parsing succeeded print the AST.
|
|
|
|
print ast
|
|
|
|
|
|
|
|
-- Try to pretty print it.
|
|
|
|
-- (Printing cannot really fail in this example)
|
2014-12-11 03:48:56 +03:00
|
|
|
case S.runPrinter_ expr ast of
|
2014-11-30 18:37:58 +03:00
|
|
|
Left err -> putStrLn err
|
|
|
|
Right bld -> T.putStrLn (T.toLazyText bld)
|
2014-10-29 22:28:06 +03:00
|
|
|
|
2014-10-29 22:17:58 +03:00
|
|
|
return ()
|