on master help sign in
Start using the PrettyPrint library to show expressions, literals, and patterns.
f2b3ed7Evan Czaplicki
compiler/Parse/Expression.hs+28−27
@@ -1,4 +1,4 @@
1−module Parse.Expression (def,term) where
1+module Parse.Expression {-(def,term)-} where
2
2
3import Control.Applicative ((<$>), (<*>))
3import Control.Applicative ((<$>), (<*>))
4import Data.List (foldl')
4import Data.List (foldl')
@@ -12,6 +12,7 @@ import qualified Parse.Type as Type
12import Parse.Binop
12import Parse.Binop
13import Parse.Literal
13import Parse.Literal
14
14
15+import SourceSyntax.PrettyPrint
15import SourceSyntax.Location as Location
16import SourceSyntax.Location as Location
16import SourceSyntax.Pattern hiding (tuple,list)
17import SourceSyntax.Pattern hiding (tuple,list)
17import qualified SourceSyntax.Literal as Literal
18import qualified SourceSyntax.Literal as Literal
@@ -21,14 +22,13 @@ import SourceSyntax.Declaration (Declaration(Definition))
21import Unique
22import Unique
22import Types.Types (Type (VarT), Scheme (Forall))
23import Types.Types (Type (VarT), Scheme (Forall))
23
24
24−import System.IO.Unsafe
25−
26
25
27-------- Basic Terms --------
26-------- Basic Terms --------
28
27
29varTerm :: IParser (Expr t v)
28varTerm :: IParser (Expr t v)
30varTerm = toVar <$> var <?> "variable"
29varTerm = toVar <$> var <?> "variable"
31
30
31+toVar :: String -> Expr t v
32toVar v = case v of "True" -> Literal (Literal.Boolean True)
32toVar v = case v of "True" -> Literal (Literal.Boolean True)
33 "False" -> Literal (Literal.Boolean False)
33 "False" -> Literal (Literal.Boolean False)
34 _ -> Var v
34 _ -> Var v
@@ -39,7 +39,7 @@ accessor = do
39 lbl <- try (string "." >> rLabel)
39 lbl <- try (string "." >> rLabel)
40 end <- getPosition
40 end <- getPosition
41 let loc e = Location.add ("." ++ lbl) (Location.at start end e)
41 let loc e = Location.add ("." ++ lbl) (Location.at start end e)
42− return (Lambda "_" (loc $ Access (loc $ Var "_") lbl))
42+ return (Lambda (PVar "_") (loc $ Access (loc $ Var "_") lbl))
43
43
44
44
45-------- Complex Terms --------
45-------- Complex Terms --------
@@ -61,7 +61,7 @@ parensTerm = parens $ choice
61 op <- try anyOp
61 op <- try anyOp
62 end <- getPosition
62 end <- getPosition
63 let loc = Location.at start end
63 let loc = Location.at start end
64− return . loc . Lambda "x" . loc . Lambda "y" . loc $
64+ return . loc . Lambda (PVar "x") . loc . Lambda (PVar "y") . loc $
65 Binop op (loc $ Var "x") (loc $ Var "y")
65 Binop op (loc $ Var "x") (loc $ Var "y")
66 , do start <- getPosition
66 , do start <- getPosition
67 let comma = char ',' <?> "comma ','"
67 let comma = char ',' <?> "comma ','"
@@ -70,7 +70,7 @@ parensTerm = parens $ choice
70 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
70 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
71 loc = Location.at start end
71 loc = Location.at start end
72 return $ foldr (\x e -> loc $ Lambda x e)
72 return $ foldr (\x e -> loc $ Lambda x e)
73− (loc . tuple $ map (loc . Var) vars) vars
73+ (loc . tuple $ map (loc . Var) vars) (map PVar vars)
74 , do start <- getPosition
74 , do start <- getPosition
75 es <- commaSep expr
75 es <- commaSep expr
76 end <- getPosition
76 end <- getPosition
@@ -83,14 +83,11 @@ recordTerm = brackets $ choice [ misc, addLocation record ]
83 where field = do
83 where field = do
84 label <- rLabel
84 label <- rLabel
85 patterns <- spacePrefix Pattern.term
85 patterns <- spacePrefix Pattern.term
86− whitespace
87− e <- string "=" >> whitespace >> expr
86+ whitespace >> string "=" >> whitespace
87+ body <- expr
88− return (label, foldr Lambda e patterns)
88+ return (label, makeFunction patterns body)
89
89
90− extract [ Def f args exp ] = return (f,args,exp)
91− extract _ = fail "Improperly formed record field."
92−
93− record = Record <$> (mapM extract =<< commaSep field)
90+ record = Record <$> commaSep field
94
91
95 change = do
92 change = do
96 lbl <- rLabel
93 lbl <- rLabel
@@ -156,13 +153,13 @@ ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
156lambdaExpr :: IParser (LExpr t v)
153lambdaExpr :: IParser (LExpr t v)
157lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
154lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
158 whitespace
155 whitespace
159− pats <- spaceSep1 Pattern.term
156+ args <- spaceSep1 Pattern.term
160 whitespace ; arrow ; whitespace
157 whitespace ; arrow ; whitespace
161− e <- expr
158+ body <- expr
162− return (foldr Lambda pats e)
159+ return (makeFunction args body)
163
160
164defSet :: IParser [Def t v]
161defSet :: IParser [Def t v]
165−defSet = concat <$> block (do d <- anyDef ; whitespace ; return d)
162+defSet = block (do d <- anyDef ; whitespace ; return d)
166
163
167letExpr :: IParser (Expr t v)
164letExpr :: IParser (Expr t v)
168letExpr = do
165letExpr = do
@@ -197,19 +194,23 @@ funcDef = try (do p1 <- try Pattern.term ; infics p1 <|> func p1)
197 return $ if o == '`' then [ PVar $ takeWhile (/='`') p, p1, p2 ]
194 return $ if o == '`' then [ PVar $ takeWhile (/='`') p, p1, p2 ]
198 else [ PVar (o:p), p1, p2 ]
195 else [ PVar (o:p), p1, p2 ]
199
196
197+makeFunction :: [Pattern] -> LExpr t v -> LExpr t v
198+makeFunction args body@(L a b _) =
199+ let pos = L a b in
200+ foldr (\arg body' -> pos $ Lambda arg body') body args
201+
200−assignExpr :: IParser [Def t v]
202+assignExpr :: IParser (Def t v)
201assignExpr = withPos $ do
203assignExpr = withPos $ do
202− fDefs <- funcDef
204+ (name:args) <- funcDef
203− whitespace
204− e <- string "=" >> whitespace >> expr
205+ whitespace >> string "=" >> whitespace
205− n <- sourceLine <$> getPosition
206+ body <- expr
206− runAt (1000 * n) $ Pattern.flatten fDefs e
207+ return . Def name $ makeFunction args body
207
208
208−anyDef =
209+anyDef :: IParser (Def t v)
209− ((\d -> [d]) <$> Type.annotation) <|>
210+anyDef = Type.annotation <|> assignExpr
210− assignExpr
211
211
212+def :: IParser (Declaration t v)
212−def = map Definition <$> anyDef
213+def = Definition <$> anyDef
213
214
214parseDef str =
215parseDef str =
215 case iParse def "" str of
216 case iParse def "" str of
compiler/Parse/Type.hs+3−3
@@ -85,9 +85,9 @@ typeAlias = do
85 Right t -> return (TypeAlias alias [1..n] t : ctor)
85 Right t -> return (TypeAlias alias [1..n] t : ctor)
86 where ctor = case tipe of
86 where ctor = case tipe of
87 RecordPT extension kvs ->
87 RecordPT extension kvs ->
88− [toConstructor start end alias extension kvs]
88+ [] --toConstructor start end alias extension kvs]
89 _ -> []
89 _ -> []
90−
90+{--
91toConstructor start end alias Nothing kvs =
91toConstructor start end alias Nothing kvs =
92 Definition (Def alias args (loc (Record rec)))
92 Definition (Def alias args (loc (Record rec)))
93 where
93 where
@@ -102,7 +102,7 @@ toConstructor start end alias (Just _) kvs =
102 args = map fst kvs
102 args = map fst kvs
103 rec = foldl insert (Var "_ext_") (zip args (map (loc . Var) args))
103 rec = foldl insert (Var "_ext_") (zip args (map (loc . Var) args))
104 insert e (k,v) = Insert (loc e) k v
104 insert e (k,v) = Insert (loc e) k v
105−
105+--}
106annotation :: IParser (Def t v)
106annotation :: IParser (Def t v)
107annotation = TypeAnnotation <$> try start <*> (toType <$> typeExpr)
107annotation = TypeAnnotation <$> try start <*> (toType <$> typeExpr)
108 where start = do v <- lowVar <|> parens symOp
108 where start = do v <- lowVar <|> parens symOp
compiler/SourceSyntax/Declaration.hs+2−2
@@ -12,7 +12,7 @@ data Declaration tipe var
12 | ImportEvent String (Expr.LExpr tipe var) String Type
12 | ImportEvent String (Expr.LExpr tipe var) String Type
13 | ExportEvent String String Type
13 | ExportEvent String String Type
14 | Fixity Assoc Int String
14 | Fixity Assoc Int String
15− deriving (Eq, Show, Data, Typeable)
15+ deriving (Eq, Show, Data, Typeable, Show)
16
16
17data Assoc = L | N | R
17data Assoc = L | N | R
18− deriving (Eq, Show, Data, Typeable)
18+ deriving (Eq, Show, Data, Typeable, Show)
compiler/SourceSyntax/Everything.hs+1−1
@@ -12,7 +12,7 @@ module SourceSyntax.Everything
12import SourceSyntax.Helpers
12import SourceSyntax.Helpers
13import SourceSyntax.Location
13import SourceSyntax.Location
14import SourceSyntax.Literal
14import SourceSyntax.Literal
15−import SourceSyntax.Pattern hiding (tuple, list, cons, nil)
15+import SourceSyntax.Pattern hiding (tuple, list, cons, nil, prettyParens)
16import SourceSyntax.Expression
16import SourceSyntax.Expression
17import SourceSyntax.Declaration hiding (Assoc(..))
17import SourceSyntax.Declaration hiding (Assoc(..))
18import SourceSyntax.Module
18import SourceSyntax.Module
compiler/SourceSyntax/Expression.hs+78−52
@@ -4,6 +4,8 @@ module SourceSyntax.Expression where
4import Data.Data
4import Data.Data
5import Data.List (intercalate)
5import Data.List (intercalate)
6import qualified Text.Pandoc as Pandoc
6import qualified Text.Pandoc as Pandoc
7+import SourceSyntax.PrettyPrint
8+import Text.PrettyPrint as PP
7import qualified SourceSyntax.Helpers as Help
9import qualified SourceSyntax.Helpers as Help
8import qualified SourceSyntax.Location as Location
10import qualified SourceSyntax.Location as Location
9import qualified SourceSyntax.Pattern as Pattern
11import qualified SourceSyntax.Pattern as Pattern
@@ -29,70 +31,94 @@ data Expr t v
29 | Modify (LExpr t v) [(String, LExpr t v)]
31 | Modify (LExpr t v) [(String, LExpr t v)]
30 | Record [(String, LExpr t v)]
32 | Record [(String, LExpr t v)]
31 | Markdown Pandoc.Pandoc
33 | Markdown Pandoc.Pandoc
32− deriving (Eq, Data, Typeable)
34+ deriving (Eq, Data, Typeable, Show)
33
35
34data Def tipe var
36data Def tipe var
35 = Def Pattern.Pattern (LExpr tipe var)
37 = Def Pattern.Pattern (LExpr tipe var)
36 | TypeAnnotation String Type
38 | TypeAnnotation String Type
37− deriving (Eq, Data, Typeable)
39+ deriving (Eq, Data, Typeable, Show)
38
40
39tuple es = Data ("Tuple" ++ show (length es)) es
41tuple es = Data ("Tuple" ++ show (length es)) es
40
42
41delist (Location.L _ _ (Data "::" [h,t])) = h : delist t
43delist (Location.L _ _ (Data "::" [h,t])) = h : delist t
42delist _ = []
44delist _ = []
43
45
44−
45−instance Show (Expr t v) where
46+instance Pretty (Expr t v) where
46− show e =
47+ pretty expr =
47− let show' (Location.L _ _ e) = Help.parensIf (needsParens e) (show e) in
48+ case expr of
48− case e of
49+ Literal lit -> pretty lit
49− Literal lit -> show lit
50+ Var x@(c:_) -> parensIf (Help.isOp c) (PP.text x)
50− Range e1 e2 -> "[" ++ show e1 ++ ".." ++ show e2 ++ "]"
51+ Range e1 e2 -> PP.brackets (pretty e1 <> PP.text ".." <> pretty e2)
51− ExplicitList es -> "[" ++ intercalate "," (map show es) ++ "]"
52+ ExplicitList es -> PP.brackets (commaCat (map pretty es))
52− Binop op e1 e2 -> show' e1 ++ " " ++ op ++ " " ++ show' e2
53+ Binop op e1 e2 -> PP.sep [ prettyParens e1 <+> PP.text op, prettyParens e2 ]
53− Lambda x e -> let (xs,e') = getLambdas (Location.none $ Lambda x e) in
54+ Lambda p e -> let (ps,body) = collectLambdas (Location.none $ Lambda p e)
54− concat [ "\\", intercalate " " xs, " -> ", show e' ]
55+ in PP.text "\\" <> PP.sep ps <+> PP.text "->" <+> pretty body
55− App e1 e2 -> show' e1 ++ " " ++ show' e2
56+ App _ _ -> PP.hang func 2 (PP.sep args)
56− MultiIf (p:ps) -> concat [ "if | ", iff p, sep (map iff ps) ]
57+ where func:args = map prettyParens (collectApps (Location.none expr))
58+ MultiIf branches -> PP.text "if" $$ nest 3 (vcat $ map iff branches)
57− where iff (b,e) = show b ++ " -> " ++ show e
59+ where
58− sep = concatMap ("\n | " ++)
60+ iff (b,e) = PP.text "|" <+> PP.hang (pretty b <+> PP.text "->") 2 (pretty e)
59− Let defs e -> "let { "++intercalate " ; " (map show defs)++" } in "++show e
61+ Let defs e ->
60− Var (c:cs) -> if Help.isOp c then Help.parens (c:cs) else c:cs
62+ PP.sep [ PP.hang (PP.text "let") 4 (PP.vcat (map pretty defs))
61− Case e pats -> "case "++ show e ++" of " ++ Help.brkt (intercalate " ; " pats')
63+ , PP.text "in" <+> pretty e ]
62− where pats' = map (\(p,e) -> show p ++ " -> " ++ show e) pats
64+ Case e pats ->
63− Data "::" [h,t] -> show h ++ " :: " ++ show t
65+ PP.hang pexpr 2 (PP.vcat (map pretty' pats))
66+ where
67+ pexpr = PP.sep [ PP.text "case" <+> pretty e, PP.text "of" ]
68+ pretty' (p,e) = pretty p <+> PP.text "->" <+> pretty e
69+ Data "::" [hd,tl] -> pretty hd <+> PP.text "::" <+> pretty tl
64− Data "[]" [] -> "[]"
70+ Data "[]" [] -> PP.text "[]"
65− Data name es -> name ++ " " ++ intercalate " " (map show' es)
71+ Data name es -> PP.hang (PP.text name) 2 (PP.sep (map prettyParens es))
66− Access e x -> show' e ++ "." ++ x
72+ Access e x -> prettyParens e <> PP.text "." <> PP.text x
67− Remove e x -> Help.brkt (show e ++ " - " ++ x)
73+ Remove e x -> PP.braces (pretty e <+> PP.text "-" <+> PP.text x)
68 Insert (Location.L _ _ (Remove e y)) x v ->
74 Insert (Location.L _ _ (Remove e y)) x v ->
69− Help.brkt (show e ++ " - " ++ y ++ " | " ++ x ++ " = " ++ show v)
75+ PP.braces (pretty e <+> PP.text "-" <+> PP.text y <+> PP.text "|" <+> PP.text x <+> PP.text "=" <+> pretty v)
70− Insert e x v -> Help.brkt (show e ++ " | " ++ x ++ " = " ++ show v)
76+ Insert e x v ->
71− Modify e fs -> Help.brkt (show e ++" | "++ intercalate ", " (map field fs))
77+ PP.braces (pretty e <+> PP.text "|" <+> PP.text x <+> PP.text "=" <+> pretty v)
78+
79+ Modify e fs ->
80+ PP.braces $ PP.hang (pretty e <+> PP.text "|")
81+ 4
82+ (PP.sep . PP.punctuate PP.comma $ map field fs)
83+ where
72− where field (x,e) = x ++ " <- " ++ show e
84+ field (x,e) = PP.text x <+> PP.text "<-" <+> pretty e
73− Record r -> Help.brkt (intercalate ", " (map fields r))
85+
86+ Record fs ->
87+ PP.braces $ PP.nest 2 (PP.sep . PP.punctuate PP.comma $ map field fs)
74− where fields (f,e) = f ++ " = " ++ show e
88+ where
89+ field (x,e) = PP.text x <+> PP.text "=" <+> pretty e
90+
75− Markdown _ -> "[markdown| ... |]"
91+ Markdown _ -> PP.text "[markdown| ... |]"
76
92
93+instance Pretty (Def t v) where
94+ pretty def =
95+ case def of
96+ TypeAnnotation name tipe ->
97+ PP.text name <+> PP.text ":" <+> PP.text (show tipe)
98+ Def pattern expr ->
99+ pretty pattern <+> PP.text "=" <+> pretty expr
77
100
78−instance Show (Def t v) where
101+collectApps lexpr@(Location.L _ _ expr) =
79− show e =
80− case e of
102+ case expr of
81− TypeAnnotation n t -> n ++ " : " ++ show t
103+ App a b -> collectApps a ++ [b]
82− Def pattern e ->
104+ _ -> [lexpr]
83− show pattern ++ " = " ++ show e
84
105
85−getLambdas (Location.L _ _ (Lambda x e)) = (show x:xs,e')
106+collectLambdas lexpr@(Location.L _ _ expr) =
86− where (xs,e') = getLambdas e
107+ case expr of
87−getLambdas e = ([],e)
108+ Lambda pattern body ->
109+ let (ps, body') = collectLambdas body
110+ in (pretty pattern : ps, body')
111+ _ -> ([], lexpr)
88
112
89−needsParens e =
113+prettyParens (Location.L _ _ expr) = parensIf needed (pretty expr)
114+ where
115+ needed =
90− case e of
116+ case expr of
91− Binop _ _ _ -> True
117+ Binop _ _ _ -> True
92− Lambda _ _ -> True
118+ Lambda _ _ -> True
93− App _ _ -> True
119+ App _ _ -> True
94− MultiIf _ -> True
120+ MultiIf _ -> True
95− Let _ _ -> True
121+ Let _ _ -> True
96− Case _ _ -> True
122+ Case _ _ -> True
97− Data name (x:xs) -> name /= "::"
123+ Data name (x:xs) -> name /= "::"
98− _ -> False
124+ _ -> False
compiler/SourceSyntax/Helpers.hs+5−4
@@ -1,11 +1,12 @@
1
1
2module SourceSyntax.Helpers where
2module SourceSyntax.Helpers where
3
3
4−import Data.Char (isSymbol)
4+import Data.Char (isSymbol,isDigit)
5
5
6brkt s = "{ " ++ s ++ " }"
6brkt s = "{ " ++ s ++ " }"
7
7
8−parens s = "(" ++ s ++ ")"
8+isTuple name =
9−parensIf b s = if b then parens s else s
9+ take 5 name == "Tuple" && all isDigit (drop 5 name)
10
10
11+isOp c =
11−isOp c = isSymbol c || elem c "+-/*=.$<>:&|^?%#@~!"
12+ isSymbol c || elem c "+-/*=.$<>:&|^?%#@~!"
compiler/SourceSyntax/Literal.hs+11−10
@@ -2,20 +2,21 @@
2module SourceSyntax.Literal where
2module SourceSyntax.Literal where
3
3
4import Data.Data
4import Data.Data
5+import SourceSyntax.PrettyPrint
6+import qualified Text.PrettyPrint as PP
5
7
6data Literal = IntNum Int
8data Literal = IntNum Int
7 | FloatNum Float
9 | FloatNum Float
8 | Chr Char
10 | Chr Char
9 | Str String
11 | Str String
10 | Boolean Bool
12 | Boolean Bool
11− deriving (Eq, Ord, Data, Typeable)
13+ deriving (Eq, Ord, Data, Typeable, Show)
12
14
13−
14−instance Show Literal where
15+instance Pretty Literal where
15− show e =
16+ pretty literal =
16− case e of
17+ case literal of
17− IntNum n -> show n
18+ IntNum n -> PP.int n
18− FloatNum n -> show n
19+ FloatNum n -> PP.float n
19− Chr c -> show c
20+ Chr c -> PP.char c
20− Str s -> show s
21+ Str s -> PP.text (show s)
21− Boolean b -> show b
22+ Boolean bool -> PP.text (show bool)
compiler/SourceSyntax/Pattern.hs+27−18
@@ -1,11 +1,12 @@
1{-# LANGUAGE DeriveDataTypeable #-}
1{-# LANGUAGE DeriveDataTypeable #-}
2module SourceSyntax.Pattern where
2module SourceSyntax.Pattern where
3
3
4−import Data.Char (isDigit)
5import Data.List (intercalate)
4import Data.List (intercalate)
6import Data.Data
5import Data.Data
7import SourceSyntax.Helpers
6import SourceSyntax.Helpers
7+import SourceSyntax.PrettyPrint
8+import Text.PrettyPrint as PP
8−import qualified SourceSyntax.Literal as Literal
9+import SourceSyntax.Literal as Literal
9
10
10data Pattern = PData String [Pattern]
11data Pattern = PData String [Pattern]
11 | PRecord [String]
12 | PRecord [String]
@@ -13,7 +14,7 @@ data Pattern = PData String [Pattern]
13 | PVar String
14 | PVar String
14 | PAnything
15 | PAnything
15 | PLiteral Literal.Literal
16 | PLiteral Literal.Literal
16− deriving (Eq, Ord, Data, Typeable)
17+ deriving (Eq, Ord, Data, Typeable, Show)
17
18
18cons h t = PData "::" [h,t]
19cons h t = PData "::" [h,t]
19nil = PData "[]" []
20nil = PData "[]" []
@@ -21,19 +22,27 @@ list = foldr cons nil
21tuple es = PData ("Tuple" ++ show (length es)) es
22tuple es = PData ("Tuple" ++ show (length es)) es
22
23
23
24
24−instance Show Pattern where
25+instance Pretty Pattern where
25− show p =
26+ pretty pattern =
26− case p of
27+ case pattern of
27− PVar x -> x
28+ PVar x -> PP.text x
28− PLiteral lit -> show lit
29+ PLiteral lit -> pretty lit
29− PRecord fs -> brkt (intercalate ", " fs)
30+ PRecord fs -> PP.braces (commaCat $ map PP.text fs)
30− PAlias x p -> show p ++ " as " ++ x
31+ PAlias x p -> prettyParens p <+> PP.text "as" <+> PP.text x
31− PAnything -> "_"
32+ PAnything -> PP.text "_"
32− PData "::" [hd@(PData "::" _),tl] ->
33+ PData "::" [hd,tl] -> parensIf isCons (pretty hd) <+> PP.text "::" <+> pretty tl
33− parens (show hd) ++ " :: " ++ show tl
34+ where isCons = case hd of
34− PData "::" [hd,tl] -> show hd ++ " :: " ++ show tl
35+ PData "::" _ -> True
35− PData "[]" [] -> "[]"
36+ _ -> False
36 PData name ps ->
37 PData name ps ->
37− if take 5 name == "Tuple" && all isDigit (drop 5 name) then
38+ if isTuple name then
38− parens . intercalate ", " $ map show ps
39+ PP.parens . commaCat $ map pretty ps
39− else parensIf (not (null ps)) $ unwords (name : map show ps)
40+ else sep (PP.text name : map prettyParens ps)
41+
42+prettyParens pattern = parensIf needsThem (pretty pattern)
43+ where
44+ needsThem =
45+ case pattern of
46+ PData name (_:_) | not (isTuple name) -> True
47+ PAlias _ _ -> True
48+ _ -> False
compiler/SourceSyntax/PrettyPrint.hsnew file+15
@@ -0,0 +1,15 @@
1+
2+module SourceSyntax.PrettyPrint where
3+
4+import Text.PrettyPrint
5+import SourceSyntax.Location
6+
7+class Pretty a where
8+ pretty :: a -> Doc
9+
10+instance Pretty a => Pretty (Located a) where
11+ pretty (L _ _ e) = pretty e
12+
13+commaCat docs = cat (punctuate comma docs)
14+
15+parensIf bool doc = if bool then parens doc else doc