From 3e8c332e2b0dbeaac7aeeff54e2d35fe1db6a07a Mon Sep 17 00:00:00 2001
From: Sean Gillespie <sean@mistersg.net>
Date: Fri, 30 Dec 2016 22:25:07 -0500
Subject: [PATCH] Update System F parser

 * Add type abstraction `\X. body`
 * enforce case for variable names
   * Types begin with a capital
   * Variables begin with a lower
---
 src/Language/SystemF/Expression.hs  |  6 +++---
 src/Language/SystemF/Parser.hs      | 26 +++++++++++++++++++-------
 test/Language/SystemF/ParserSpec.hs |  3 +++
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/src/Language/SystemF/Expression.hs b/src/Language/SystemF/Expression.hs
index 437f0e2..ece7e15 100644
--- a/src/Language/SystemF/Expression.hs
+++ b/src/Language/SystemF/Expression.hs
@@ -9,7 +9,7 @@ data SystemFExpr name ty
   = Var name                                        -- Variable
   | App (SystemFExpr name ty) (SystemFExpr name ty) -- Application
   | Abs name (Ty ty) (SystemFExpr name ty)          -- Abstraction
-  | TyAbs (Ty ty) (SystemFExpr name ty)             -- Type Abstraction
+  | TyAbs ty (SystemFExpr name ty)                  -- Type Abstraction
                                                     -- \X. body
 
   | TyApp (SystemFExpr name ty) (Ty ty)             -- Type Application
@@ -117,7 +117,7 @@ pprTyArrow' space a b = a <> arrow <> b
 -- Pretty print a type abstraction
 pprTAbs :: (PrettyPrint n, PrettyPrint t)
         => PDoc String
-        -> Ty t
+        -> t
         -> SystemFExpr n t
         -> PDoc String
 pprTAbs pdoc ty body = between vars' lambda' ". " (pprExpr pdoc body')
@@ -130,7 +130,7 @@ uncurryAbs name ty = uncurry' [(name, ty)]
   where uncurry' ns (Abs n' t' body') = uncurry' ((n', t'):ns) body'
         uncurry' ns body'             = (reverse ns, body')
 
-uncurryTAbs :: Ty t -> SystemFExpr n t -> ([Ty t], SystemFExpr n t)
+uncurryTAbs :: t -> SystemFExpr n t -> ([t], SystemFExpr n t)
 uncurryTAbs ty = uncurry' [ty]
   where uncurry' ts (TyAbs t' body') = uncurry' (t':ts) body'
         uncurry' ts body'            = (reverse ts, body')
diff --git a/src/Language/SystemF/Parser.hs b/src/Language/SystemF/Parser.hs
index fbcb40a..8a1709f 100644
--- a/src/Language/SystemF/Parser.hs
+++ b/src/Language/SystemF/Parser.hs
@@ -25,18 +25,26 @@ app :: Parser (SystemFExpr String String)
 app = chainl1 term (return App)
 
 term :: Parser (SystemFExpr String String)
-term = abs <|> var <|> parens expr
+term = try abs 
+     <|> tyabs 
+     <|> var 
+     <|> parens expr
 
 var :: Parser (SystemFExpr String String)
-var = Var <$> identifier
+var = Var <$> exprId
 
 abs :: Parser (SystemFExpr String String)
 abs = curry 
     <$> (symbol '\\' *> many1 args <* symbol '.') 
     <*> expr
-  where args = (,) <$> (identifier <* symbol ':') <*> ty
+  where args = (,) <$> (exprId <* symbol ':') <*> ty
         curry = flip . foldr . uncurry $ Abs
 
+tyabs :: Parser (SystemFExpr String String)
+tyabs = curry <$> args <*> expr
+  where args = symbol '\\' *> many1 typeId <* symbol '.'
+        curry = flip (foldr TyAbs)
+
 -- Parse type expressions
 ty :: Parser (Ty String)
 ty = try arrow
@@ -48,16 +56,20 @@ tyterm :: Parser (Ty String)
 tyterm = tyvar <|> parens ty
 
 tyvar :: Parser (Ty String)
-tyvar = TyVar <$> identifier
+tyvar = TyVar <$> typeId
 
 parens :: Parser a -> Parser a
 parens p = symbol '(' *> p <* symbol ')'
 
-identifier :: Parser String
-identifier = lexeme ((:) <$> first <*> many rest)
-  where first = letter <|> char '_'
+identifier :: Parser Char -> Parser String
+identifier firstChar = lexeme ((:) <$> first <*> many rest)
+  where first = firstChar <|> char '_'
         rest = first <|> digit
 
+typeId, exprId :: Parser String
+typeId = identifier upper
+exprId = identifier lower
+
 whitespace :: Parser ()
 whitespace = void . many . oneOf $ " \t"
 
diff --git a/test/Language/SystemF/ParserSpec.hs b/test/Language/SystemF/ParserSpec.hs
index 57160fd..1bcfb04 100644
--- a/test/Language/SystemF/ParserSpec.hs
+++ b/test/Language/SystemF/ParserSpec.hs
@@ -19,6 +19,9 @@ spec = do
     it "parses simple abstractions" $
       parseExpr "\\x:T. x" `shouldBe` Right (Abs "x" (TyVar "T") (Var "x"))
 
+    it "parses simple type abstractions" $
+      parseExpr "\\X. x" `shouldBe` Right (TyAbs "X" (Var "x"))
+
     it "parses nested abstractions" $
       parseExpr "\\a:A b:B. b" 
         `shouldBe` Right (Abs "a" (TyVar "A") (Abs "b" (TyVar "B") (Var "b")))
-- 
GitLab