polyglot-0.1.1.0: src/SyntaxTrees/Purescript/FnDef.hs
module SyntaxTrees.Purescript.FnDef where
import Data.List (intercalate)
import SyntaxTrees.Purescript.Common (Literal, QCtor, QCtorOp, QVar, QVarOp,
Var, VarOp)
import SyntaxTrees.Purescript.Pattern (Pattern, showPatternNested)
import SyntaxTrees.Purescript.Type (Type)
import Utils.List (mix)
import Utils.String (Wrapper (Wrapper), joinWords, str,
wrapBlock, wrapContext, wrapCsv,
wrapCurlyCsv, wrapParens, wrapParensCsv,
wrapSpaces, wrapSquareCsv, (+++))
data FnSig
= FnSig
{ name :: Var
, type' :: Type
}
data FnDef
= FnDef
{ names :: [Var]
, args :: [Pattern]
, body :: MaybeGuardedFnBody
}
data InfixFnDef
= InfixFnDef
{ associativity :: Associativity
, precedence :: Integer
, fnName :: Var
, opName :: VarOp
}
data FnDefOrSig
= Def FnDef
| Sig FnSig
data FnBody
= FnApply
{ fn :: FnBody
, args :: [FnBody]
}
| InfixFnApply
{ fnOps :: [FnOp]
, args :: [FnBody]
}
| LeftOpSection
{ fnOp :: FnOp
, arg :: FnBody
}
| RightOpSection
{ arg :: FnBody
, fnOp :: FnOp
}
| LambdaExpr
{ patterns :: [Pattern]
, body :: FnBody
}
| LetExpr
{ fnBindings :: [FnDefOrSig]
, body :: FnBody
}
| WhereExpr
{ body :: FnBody
, fnBindings :: [FnDefOrSig]
}
| IfExpr
{ cond :: FnBody
, ifBranch :: FnBody
, elseBranch :: FnBody
}
| MultiWayIfExpr
{ whenExprs :: [GuardedFnBody]
}
| DoExpr
{ steps :: [DoStep]
}
| CaseOfExpr
{ matchee :: FnBody
, cases :: [CaseBinding]
}
| LambdaCaseExpr
{ cases :: [CaseBinding]
}
| RecordCreate
{ ctor :: FnBody
, namedFields :: [(Var, FnBody)]
}
| RecordUpdate
{ var :: FnBody
, namedFields :: [(Var, FnBody)]
}
| TypeAnnotation FnBody Type
| ArrayRange FnBody FnBody
| Tuple [FnBody]
| Array [FnBody]
| FnOp' FnOp
| FnVar' FnVar
| Literal' Literal
data FnVar
= Selector Var
| Selection QVar [Var]
| Var' QVar
| Ctor' QCtor
data FnOp
= VarOp' QVarOp
| CtorOp' QCtorOp
data DoStep
= DoBinding [Var] FnBody
| LetBinding [FnDefOrSig]
| Body FnBody
data CaseBinding
= CaseBinding Pattern MaybeGuardedFnBody
data MaybeGuardedFnBody
= Guarded [GuardedFnBody]
| Standard FnBody
data GuardedFnBody
= GuardedFnBody
{ guard :: Guard
, body :: FnBody
}
data Guard
= Guard [PatternGuard]
| Otherwise
data PatternGuard
= PatternGuard Pattern FnBody
| SimpleGuard FnBody
data Associativity
= LAssoc
| RAssoc
instance Show FnSig where
show (FnSig x y) =
joinWords [show x,
"::",
show y]
instance Show FnDef where
show (FnDef x y z) =
joinWords [wrapCsv x,
intercalate " " (showPatternNested <$> y),
showMaybeGuardedFnBody "=" z]
instance Show InfixFnDef where
show (InfixFnDef x y z t) =
joinWords [show x,
show y,
show z,
"as",
show t]
instance Show FnDefOrSig where
show (Def x) = show x
show (Sig x) = show x
instance Show FnBody where
show (FnApply fn args) =
joinWords [showNestedFnBody fn,
intercalate " " $ showNestedFnBody <$> args]
show (InfixFnApply fnOps args) =
intercalate "" $ mix (showNestedInfixFnBody <$> args)
(wrapSpaces . show <$> fnOps)
show (LeftOpSection x y) =
joinWords ["_",
show x,
showNestedFnBody y]
show (RightOpSection x y) =
joinWords [showNestedFnBody x,
show y,
"_"]
show (LambdaExpr x y) =
joinWords ["\\" ++ intercalate " " (showPatternNested <$> x),
"->",
show y]
show (LetExpr x y) =
"\n" ++ wrapContext ("let" ++ wrapBlock x ++ "in" ++ "\n" ++ show y)
show (WhereExpr x y) =
show x ++ "\n" ++ wrapContext ("where" ++ wrapBlock y)
show (IfExpr x y z) =
"if" +++ show x +++
"then" ++ wrapBlock [y] ++ "\n" ++
"else" ++ wrapBlock [z]
show (MultiWayIfExpr x) =
"if" ++ wrapBlock (Wrapper . ("|" ++) .
showGuardedFnBody "->" <$> x)
show (DoExpr x) =
"do" ++ wrapBlock x
show (CaseOfExpr x y) =
joinWords ["case",
show x,
"of",
wrapBlock y]
show (LambdaCaseExpr x) =
"\\case" ++ wrapBlock x
show (RecordCreate x y) =
joinWords [show x,
wrapCurlyCsv $ Wrapper . format <$> y]
where
format (z, t) = show z ++ ":" +++ show t
show (RecordUpdate x y) =
joinWords [show x,
wrapCurlyCsv $ Wrapper . format <$> y]
where
format (z, t) = show z +++ "=" +++ show t
show (TypeAnnotation x y) = joinWords [show x, "::", show y]
show (ArrayRange x y) = joinWords [show x, "..", show y]
show (Tuple x) = wrapParensCsv x
show (Array x) = wrapSquareCsv x
show (FnOp' x) = wrapParens $ show x
show (FnVar' x) = show x
show (Literal' x) = show x
instance Show FnVar where
show (Selector x) = "." ++ show x
show (Selection x y) = intercalate "." (show x : (show <$> y))
show (Var' x) = show x
show (Ctor' x) = show x
instance Show FnOp where
show (VarOp' x) = show x
show (CtorOp' x) = show x
instance Show DoStep where
show (DoBinding x y) =
joinWords [wrapCsv x,
"<-",
show y]
show (LetBinding x) = "let" ++ wrapBlock x
show (Body x) = show x
instance Show CaseBinding where
show (CaseBinding x y) =
joinWords [show x,
showMaybeGuardedFnBody "->" y]
instance Show Guard where
show (Guard x) = str ("\n" ++ ",") x
show (Otherwise) = "otherwise"
instance Show PatternGuard where
show (PatternGuard x y) =
joinWords [show x,
"<-",
show y]
show (SimpleGuard x) = show x
instance Show Associativity where
show LAssoc = "infixl"
show RAssoc = "infixr"
showMaybeGuardedFnBody :: String -> MaybeGuardedFnBody -> String
showMaybeGuardedFnBody op (Guarded x) =
wrapBlock $ Wrapper . ("|" ++) . showGuardedFnBody op <$> x
showMaybeGuardedFnBody op (Standard x) = op +++ show x
showGuardedFnBody :: String -> GuardedFnBody -> String
showGuardedFnBody op (GuardedFnBody x y) =
joinWords [show x,
op,
show y]
showNestedFnBody :: FnBody -> String
showNestedFnBody x = transformFn $ show x
where
transformFn = if shouldWrap then wrapParens else id
shouldWrap = case x of
FnApply _ _ -> True
InfixFnApply _ _ -> True
LeftOpSection _ _ -> True
RightOpSection _ _ -> True
LambdaExpr _ _ -> True
LetExpr _ _ -> True
WhereExpr _ _ -> True
RecordCreate _ _ -> True
RecordUpdate _ _ -> True
ArrayRange _ _ -> True
TypeAnnotation _ _ -> True
_ -> False
showNestedInfixFnBody :: FnBody -> String
showNestedInfixFnBody x = transformFn $ show x
where
transformFn = if shouldWrap then wrapParens else id
shouldWrap = case x of
InfixFnApply _ _ -> True
LeftOpSection _ _ -> True
RightOpSection _ _ -> True
LambdaExpr _ _ -> True
LetExpr _ _ -> True
WhereExpr _ _ -> True
RecordCreate _ _ -> True
RecordUpdate _ _ -> True
ArrayRange _ _ -> True
TypeAnnotation _ _ -> True
_ -> False