{-
Copyright(C) 1999 Erik Meijer and Arjan van Yzendoorn
-}
module SimpleMondrianPrinter where
import Mondrian
import Pretty
import Utils
mondrianIndent :: Int
mondrianIndent = 2
compilationUnit :: CompilationUnit -> Doc
compilationUnit = \m ->
case m of
{ Package n ds -> package m (name n) (decls ds)
}
package = \(Package n' ds') -> \n -> \ds ->
case null ds' of
{ True -> text "package" <+> n <+> row ds
; False -> text "package" <+> n <-> nest (-mondrianIndent) (column ds)
}
decls = \ds -> [ decl d | d <- ds ]
decl = \d ->
case d of
{ ImportDecl ns -> importDecl d (name ns)
; ClassDecl n xs ds -> classDecl d (name n) (extends xs) (decls ds)
; SigDecl n t -> sigDecl (name n) (expr t)
; VarDecl v (Lambda ns e) -> varDecl d (name v) (lambdas ns) (expr e)
; VarDecl v e -> decl (VarDecl v (Lambda [] e))
}
extends = \xs ->
case xs of
{ [] -> empty
; [x] -> text "extends" <+> name x <+> empty
; xs -> text "multiple inheritance not supported" <+> row [name x | x <- xs]
}
classDecl = \(ClassDecl n' xs' ds') -> \n -> \xs -> \ds ->
case ds' of
{ [] -> text "class" <+> n <+> xs
; otherwise -> text "class" <+> n <+> xs <-> column ds
}
sigDecl = \n -> \t -> n <+> text "::" <+> t
importDecl = \d -> \n -> text "import" <+> n
varDecl = \(VarDecl v' (Lambda ns' e')) -> \v -> \ns -> \e ->
if isSimpleExpr e'
then v <+> text "=" <+> ns <|> e
else v <+> text "=" <+> ns <-> nest mondrianIndent e
names = \ns -> horizontal (text " ") [ name n | n <- ns ]
name = \ns -> horizontal (text ".") [text n | n <- ns]
lambdas = \ns ->
case ns of
{ [] -> empty
; [n] -> text "\\" <|> name n <+> text "->" <+> empty
; n:ns -> text "\\" <|> name n <+> text "->" <+> lambdas ns
}
expr = \e ->
case e of
{ Lit l -> lit l
; Var n -> name n
; App f a -> application (expr f) (expr a)
; Lambda ns b -> lambdaExpr e (lambdas ns) (expr b)
; New n ds -> newExpr e (name n) (decls ds)
; Case e1 as -> caseExpr e (expr e1) (arms as)
; Let ds e1 -> letExpr e (decls ds) (expr e1)
; Chain e1 oes -> chain e1 oes
}
application = \f -> \a -> text "(" <|> f <+> a <|> text ")"
newExpr = \(New n' ds') -> \n -> \ds ->
case ds' of
{ [] -> text "new" <+> n
; otherwise ->
if isSimpleDecls ds'
then text "new" <+> n <+> row ds
else text "new" <+> n <-> column ds
}
lambdaExpr = \(Lambda ns' e') -> \ns -> \e ->
if isSimpleExpr e'
then ns <|> e
else ns <-> nest mondrianIndent e
caseExpr :: Expr -> Doc -> [Doc] -> Doc
caseExpr = \(Case e' as') -> \e -> \as ->
case (isSimpleExpr e', isSimpleArms as') of
{ (True, True) -> text "case" <+> e <+> text "of" <+> row as
; (True, False)-> text "case" <+> e <+> text "of" <-> column as
; (False, True) -> text "case" <-> nest mondrianIndent e <-> text "of" <+> row as
; (False, False) -> text "case" <-> nest mondrianIndent e <-> text "of" <-> column as
}
letExpr = \(Let ds' e') -> \ds -> \e ->
case (length ds' == 1 && isSimpleDecls ds', isSimpleExpr e') of
{ (True, True) -> text "let" <+> row ds <+> text "in" <+> e
; (True, False) -> text "let" <+> row ds <-> text "in" <-> nest mondrianIndent e
; (False, True) -> text "let" <-> column ds <-> text "in" <+> e
; (False, False) -> text "let" <-> column ds <-> text "in" <-> nest mondrianIndent e
}
arms = \as -> [ arm (p,e) (pattern p) (expr e) | (p,e) <- as ]
arm = \(p',e') -> \p -> \e ->
if isSimplePattern p' && isSimpleExpr e'
then p <+> text "->" <+> e
else p <+> text "->" <-> nest mondrianIndent e
-- This is a dirty hack!
chain = \e -> \oes ->
case oes of
{ [] -> bracket e
; ([""],f):oes -> if (isSimpleExpr f)
then (bracket e) <+> chain f oes
else (bracket e) <-> nest 2 (chain f oes)
; (o,f):oes -> if (isSimpleExpr f)
then (bracket e) <+> name o <+> chain f oes
else (bracket e) <-> name o <+> chain f oes
}
pattern = \p ->
case p of
{ Pattern n ds ->
case ds of
{ [] -> name n
; otherwise -> name n <+> row (decls ds)
}
; Default -> text "default"
}
lit = \l ->
case l of
{ IntLit i -> text (show i)
; CharLit c -> text (show c)
; StringLit s -> text (show s)
}
bracket = \e ->
case e of
{ Lit l -> expr e
; Var n -> expr e
; e -> par (expr e)
}
par = \e -> text "(" <|> e <|> text ")"
column = \ds -> nest mondrianIndent (block (text "{ ", text ";" <+> empty, text "}") ds)
row = \ds -> text "{" <|> horizontal (text ";" <+> empty) ds <|> text "}"