Reputation: 7129
I have a following programming language grammar:
data Expr = ...
data Stmt = SExpr Expr | SBlock Block | SLet Fundef | ...
data Block = Block [Stmt]
data Fundef = Fundef String [String] Block
data TopDef = TopFun Fundef
With following example syntax:
function long_function_name () = {
let g() = {
{
h()
};
3
}
}
I am trying to use HughesPJ pretty
library to create a pretty printer for this language. My attempts so far look like:
instance Pretty Stmt where
pPrint = \case
SExpr e -> pPrint e
SBlock b -> pPrint b
SLet f -> text "let" <+> pPrint f
instance Pretty Block where
pPrint (Block stmts) = lbrace $+$
nest 2 (vcat (punctuate semi (map pPrint stmts))) $+$
rbrace
instance Pretty Fundef where
pPrint (Fundef name args body) = pPrint name <> parens (...) <+> text "=" <+> pPrint body
instance Prettty TopDef where
pPrint (TopFun f) = text "function" <+> pPrint f
The problem is, I want to have {
in the same line as the function declaration, but it always makes the indentation of the following lines relative to the column of the bracket instead of being absolute. Should be visible in the pretty print of the example above;
function long_function_name () = {
let g() = {
{
h()
};
3
}
}
Why does it happen and how should I tackle this problem? I would like to avoid as much code duplication as possible.
Upvotes: 2
Views: 106
Reputation: 54981
You’re writing <+>
before the body, so the $+$
vertical concatenation is entirely within that horizontal concatenation of the function
line, hence it’s all indented. I believe the way to do what you want with pretty
is to explicitly match on the block, since it’s part of the vertical layout, i.e.:
pPrint (Fundef name args (Block stmts)) = vcat
[ pPrint name <> parens (...) <+> text "=" <+> lbrace
, nest 2 (vcat (punctuate semi (map pPrint stmts)))
, rbrace
]
The more modern pretty-printing libraries like prettyprinter
make this a little easier: nest
(or indent
, or hang
) handles the indentation of lines following the first line in a vertical layout, so you can put the nest
around the opening brace and body, and the closing brace outside the nesting, like so:
"prefix" <+> vcat
[ nest 4 $ vcat
[ "{"
, "body"
]
, "}"
]
⇓
prefix {
body
}
(NB. you can use OverloadedStrings
like this instead of wrapping literals in text
.)
But that won’t work with pretty
, which seems to be designed to align the heck out of everything.
I also recommend prettyprinter
for its other advantages, for example, a group
function that allows you to express “put this on one line if it fits”, which is extremely helpful for making formatting robust & responsive to different rendering contexts.
Upvotes: 1