Fakultas Ilmu Komputer UI

Commit a35e8d0a authored by Sean Gillespie's avatar Sean Gillespie
Browse files

Add support for let expressions in parser and pretty printer

parent 0aa1b1db
......@@ -9,6 +9,7 @@ data LambdaExpr name
= Var name
| App (LambdaExpr name) (LambdaExpr name)
| Abs name (LambdaExpr name)
| Let name (LambdaExpr name)
deriving (Eq, Show)
-- Pretty printing
......@@ -20,6 +21,7 @@ pprExpr :: PrettyPrint n => PDoc String -> LambdaExpr n -> PDoc String
pprExpr pdoc (Var n) = prettyPrint n `add` pdoc
pprExpr pdoc (Abs n body) = pprAbs pdoc n body
pprExpr pdoc (App e1 e2) = pprApp pdoc e1 e2
pprExpr pdoc (Let n expr) = pprLet pdoc n expr
-- Pretty print an abstraction
pprAbs :: PrettyPrint n => PDoc String -> n -> LambdaExpr n -> PDoc String
......@@ -45,6 +47,15 @@ pprApp pdoc e1@(Abs _ _) e2 = betweenParens (pprExpr pdoc e1) pdoc
pprApp pdoc e1 e2
= pprExpr pdoc e1 `mappend` addSpace (pprExpr pdoc e2)
pprLet :: PrettyPrint n
=> PDoc String
-> n
-> LambdaExpr n
-> PDoc String
pprLet pdoc name expr
= intercalate ss " " pdoc
where ss = ["let", prettyPrint name, "=", prettyPrint expr]
uncurry :: n -> LambdaExpr n -> ([n], LambdaExpr n)
uncurry n = uncurry' [n]
where uncurry' ns (Abs n' body') = uncurry' (n':ns) body'
......
......@@ -15,7 +15,7 @@ expr :: Parser (LambdaExpr String)
expr = try app <|> term
term :: Parser (LambdaExpr String)
term = abs <|> var <|> parens
term = let' <|> abs <|> var <|> parens
var :: Parser (LambdaExpr String)
var = Var <$> identifier
......@@ -28,6 +28,10 @@ abs = curry <$> idents <*> expr
app :: Parser (LambdaExpr String)
app = chainl1 term (return App)
let' :: Parser (LambdaExpr String)
let' = Let <$> ident <*> expr
where ident = keyword "let" *> identifier <* symbol '='
parens :: Parser (LambdaExpr String)
parens = symbol '(' *> expr <* symbol ')'
......@@ -44,3 +48,6 @@ identifier = lexeme ((:) <$> first <*> many rest)
symbol :: Char -> Parser ()
symbol = void . lexeme . char
keyword :: String -> Parser ()
keyword = void . lexeme . string
......@@ -17,6 +17,9 @@ spec = describe "prettyPrint" $ do
prettyPrint (App (Var "a") (Var "b"))
`shouldBe` "a b"
it "prints simple let expressions" $
prettyPrint (Let "x" (Var "y")) `shouldBe` "let x = y"
it "prints nested abstractions" $
prettyPrint (Abs "f" (Abs "x" (Var "x")))
`shouldBe` "λf x. x"
......@@ -37,3 +40,7 @@ spec = describe "prettyPrint" $ do
prettyPrint (App (Abs "f" (Var "f")) (Abs "g" (Var "g")))
`shouldBe` "(λf. f) (λg. g)"
it "prints complex let expressions" $
prettyPrint (Let "x" (Abs "a" (Abs "b" (App (Var "a") (Var "b")))))
`shouldBe` "let x = λa b. a b"
......@@ -27,13 +27,17 @@ spec = describe "parseExpr" $ do
it "parses chained applications" $
parseExpr "f x y" `shouldBe` Right (App (App (Var "f") (Var "x")) (Var "y"))
it "parses simple let expressions" $
parseExpr "let x = z" `shouldBe` Right (Let "x" (Var "z"))
it "parses complex expressions" $ do
let exprs = [
"\\f x. f x",
"(\\p x y. y) (\\p x y. x)",
"f (\\x. x)",
"(\\x . f x) g y",
"(\\f . (\\ x y. f x y) f x y) w x y"
"(\\f . (\\ x y. f x y) f x y) w x y",
"let x = \\f x. f x"
]
mapM_ (flip shouldSatisfy isRight . parseExpr) exprs
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment