moonlight-pale-0.1.0.0: src-ghc-surface/Moonlight/Pale/Ghc/Expr/Render/Expression.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Moonlight.Pale.Ghc.Expr.Render.Expression
( renderExprWith,
renderClausesExpression,
renderPatternLambda,
renderLambdaCase,
renderLambdaCaseAlt,
renderLambdaCases,
renderLambdaCasesAlt,
renderClauseLhs,
renderClauseArrow,
renderClauseArrowCore,
renderGuardedAlt,
renderOpChain,
renderCaseBranch,
renderCaseExpression,
renderGuardedCaseAlts,
renderGuardedCaseAlt,
renderMultiIf,
renderMultiIfAlt,
renderDoExpression,
renderDoStatement,
renderLetStatement,
renderLetExpression,
renderLetBinding,
renderGuardStatements,
renderGuardStatement,
renderRecordLike,
renderField,
renderRecordExpression,
renderArithSeq
)
where
import Data.List.NonEmpty qualified as NonEmpty
import Moonlight.Pale.Ghc.Expr.Render.Analysis
import Moonlight.Pale.Ghc.Expr.Render.Carrier
import Moonlight.Pale.Ghc.Expr.Render.Document
import Moonlight.Pale.Ghc.Expr.Render.Literal
import Moonlight.Pale.Ghc.Expr.Render.Name
import Moonlight.Pale.Ghc.Expr.Render.Pattern
import Moonlight.Pale.Ghc.Expr.Render.Refusal
import Moonlight.Pale.Ghc.Expr.Syntax
renderExprWith ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
recursive ->
Either RenderRefusal document
renderExprWith renderContext renderMode parentPrecedence expressionTerm = do
expressionValue <- rsProjectNode renderContext expressionTerm
case expressionValue of
VarF variableReference ->
Right (renderVarRefAtom renderContext variableReference)
AppF functionValue argumentValue -> do
functionDoc <- renderExprWith renderContext renderMode 10 functionValue
argumentDoc <- renderExprWith renderContext renderMode 11 argumentValue
Right (wrapParen (parentPrecedence > 10) (functionDoc <> text " " <> argumentDoc))
LamF binderAnn bodyValue -> do
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right (wrapParen (parentPrecedence > 0) (text "\\" <> renderBinderAnn renderContext binderAnn <> text " -> " <> bodyDoc))
LetF _ bindingValues bodyValue ->
renderLetExpression renderContext renderMode parentPrecedence bindingValues bodyValue
OpChainF firstOperand chainTail ->
renderOpChain renderContext renderMode parentPrecedence firstOperand (NonEmpty.toList chainTail)
SectionLF leftValue operatorValue -> do
leftDoc <- renderExprWith renderContext renderMode 0 leftValue
operatorDoc <- renderOperator renderContext operatorValue
Right (text "(" <> leftDoc <> text " " <> operatorDoc <> text ")")
SectionRF operatorValue rightValue -> do
operatorDoc <- renderOperator renderContext operatorValue
rightDoc <- renderExprWith renderContext renderMode 0 rightValue
Right (text "(" <> operatorDoc <> text " " <> rightDoc <> text ")")
ParF innerValue -> do
innerDoc <- renderExprWith renderContext renderMode 0 innerValue
Right (parenthesizeDoc innerDoc)
LitF literalValue ->
Right (text (renderNormalizedLit literalValue))
OverLitF literalValue ->
Right (text (renderNormalizedOverLit literalValue))
IfF conditionValue thenValue elseValue -> do
conditionDoc <- renderExprWith renderContext renderMode 0 conditionValue
thenDoc <- renderExprWith renderContext renderMode 0 thenValue
elseDoc <- renderExprWith renderContext renderMode 0 elseValue
Right (wrapParen (parentPrecedence > 0) (text "if " <> conditionDoc <> text " then " <> thenDoc <> text " else " <> elseDoc))
CaseF scrutineeValue branchValues ->
renderCaseExpression renderContext renderMode parentPrecedence scrutineeValue branchValues
DoF statementValues -> do
renderDoExpression renderContext renderMode parentPrecedence statementValues
NegF innerValue -> do
innerDoc <- renderExprWith renderContext renderMode 10 innerValue
Right (wrapParen (parentPrecedence > 9) (text "-" <> innerDoc))
ExplicitListF valueList -> do
elementDocs <- traverse (renderExprWith renderContext renderMode 0) valueList
Right (text "[" <> intercalateDoc (text ", ") elementDocs <> text "]")
ExplicitTupleF boxity slots -> do
slotDocs <- traverse (traverse (renderExprWith renderContext renderMode 0)) slots
let delimiters =
case boxity of
BoxedTuple -> ("(", ")")
UnboxedTuple -> ("(#", "#)")
Right
( text (fst delimiters)
<> intercalateDoc (text ", ") (fmap (foldMap id) slotDocs)
<> text (snd delimiters)
)
RecordConF constructorValue fieldValues ->
renderRecordLike renderContext renderMode constructorValue fieldValues
RecordUpdF recordValue fieldValues ->
renderRecordLike renderContext renderMode recordValue fieldValues
ArithSeqF arithSeqValue ->
renderArithSeq renderContext renderMode arithSeqValue
GuardedF {} ->
Left RenderGuardedExpression
ClausesF clauseValues ->
renderClausesExpression renderContext renderMode parentPrecedence clauseValues
MultiIfF guardedAlts ->
renderMultiIf renderContext renderMode parentPrecedence guardedAlts
ExprWithTySigF bodyValue typeTextValue -> do
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right (wrapParen (parentPrecedence > 0) (bodyDoc <> text " :: " <> renderTypeText typeTextValue))
AppTypeF functionValue typeTextValue -> do
functionDoc <- renderExprWith renderContext renderMode 10 functionValue
Right (wrapParen (parentPrecedence > 10) (functionDoc <> text " @" <> renderTypeText typeTextValue))
renderClausesExpression ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[([HsPatF], recursive)] ->
Either RenderRefusal document
renderClausesExpression renderContext renderMode parentPrecedence clauseValues = do
validClauses <- validateClauses clauseValues
renderAsPatternLambda <-
case validClauses of
[(patternValues, bodyValue)]
| not (all isLambdaBinderPattern patternValues) ->
not <$> isGuardedBody renderContext bodyValue
_ ->
Right False
if renderAsPatternLambda
then
case validClauses of
[(patternValues, bodyValue)] ->
renderPatternLambda renderContext renderMode parentPrecedence patternValues bodyValue
_ ->
Left RenderClausesShape
else
if all ((== 1) . length . fst) validClauses
then renderLambdaCase renderContext renderMode parentPrecedence validClauses
else renderLambdaCases renderContext renderMode parentPrecedence validClauses
renderPatternLambda ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[HsPatF] ->
recursive ->
Either RenderRefusal document
renderPatternLambda renderContext renderMode parentPrecedence patternValues bodyValue = do
lhsDoc <- renderClausePatterns renderContext patternValues
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right (wrapParen (parentPrecedence > 0) (text "\\" <> lhsDoc <> text " -> " <> bodyDoc))
renderLambdaCase ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[([HsPatF], recursive)] ->
Either RenderRefusal document
renderLambdaCase renderContext renderMode parentPrecedence clauseValues = do
altDocs <- traverse (renderLambdaCaseAlt renderContext renderMode) clauseValues
Right (wrapParen (parentPrecedence > 0) (renderBlock renderMode "\\case" altDocs))
renderLambdaCaseAlt ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
([HsPatF], recursive) ->
Either RenderRefusal document
renderLambdaCaseAlt renderContext renderMode = \case
([patternValue], bodyValue) -> do
patternDoc <- renderPat renderContext False patternValue
renderClauseArrow renderContext renderMode patternDoc bodyValue
_ ->
Left RenderClausesShape
renderLambdaCases ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[([HsPatF], recursive)] ->
Either RenderRefusal document
renderLambdaCases renderContext renderMode parentPrecedence clauseValues = do
altDocs <- traverse (renderLambdaCasesAlt renderContext renderMode) clauseValues
Right (wrapParen (parentPrecedence > 0) (renderBlock renderMode "\\cases" altDocs))
renderLambdaCasesAlt ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
([HsPatF], recursive) ->
Either RenderRefusal document
renderLambdaCasesAlt renderContext renderMode (patternValues, bodyValue) = do
lhsDoc <- renderClausePatterns renderContext patternValues
renderClauseArrow renderContext renderMode lhsDoc bodyValue
renderClauseLhs ::
RenderDocument document =>
RenderSource recursive ->
document ->
[HsPatF] ->
Either RenderRefusal document
renderClauseLhs renderContext headDoc patternValues =
(headDoc <+>) <$> renderClausePatterns renderContext patternValues
renderClauseArrow ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
document ->
recursive ->
Either RenderRefusal document
renderClauseArrow =
renderClauseArrowCore
renderClauseArrowCore ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
document ->
recursive ->
Either RenderRefusal document
renderClauseArrowCore renderContext renderMode lhsDoc bodyValue = do
bodyNode <- rsProjectNode renderContext bodyValue
case bodyNode of
GuardedF guardedAlts ->
renderGuardedCaseAlts renderContext renderMode lhsDoc guardedAlts
_ -> do
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right (renderDelimitedExpression renderMode lhsDoc "->" bodyDoc)
renderGuardedAlt ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
document ->
String ->
GuardedAltF recursive ->
Either RenderRefusal document
renderGuardedAlt renderContext renderMode prefixDoc delimiter guardedAlt =
case gaGuards guardedAlt of
[] ->
Left RenderGuardedExpression
guardStatements -> do
guardDoc <- renderGuardStatements renderContext renderMode guardStatements
bodyDoc <- renderExprWith renderContext renderMode 0 (gaBody guardedAlt)
Right (prefixDoc <> guardDoc <> text delimiter <> bodyDoc)
renderOpChain ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
recursive ->
[(recursive, recursive)] ->
Either RenderRefusal document
renderOpChain renderContext renderMode parentPrecedence firstOperand chainTail = do
firstDoc <- renderExprWith renderContext renderMode 1 firstOperand
tailDocs <-
traverse
( \(operatorValue, operandValue) ->
(,)
<$> renderOperator renderContext operatorValue
<*> renderExprWith renderContext renderMode 1 operandValue
)
chainTail
let chainDoc =
hsep
( firstDoc
: foldMap
(\(operatorDoc, operandDoc) -> [operatorDoc, operandDoc])
tailDocs
)
Right (wrapParen (parentPrecedence > 0) chainDoc)
renderCaseBranch ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
(HsPatF, recursive) ->
Either RenderRefusal document
renderCaseBranch renderContext renderMode (casePattern, branchValue) = do
patternDoc <- renderPat renderContext False casePattern
renderClauseArrow renderContext renderMode patternDoc branchValue
renderCaseExpression ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
recursive ->
[(HsPatF, recursive)] ->
Either RenderRefusal document
renderCaseExpression renderContext renderMode parentPrecedence scrutineeValue branchValues = do
scrutineeDoc <- renderExprWith renderContext renderMode 0 scrutineeValue
branchDocs <- traverse (renderCaseBranch renderContext renderMode) branchValues
Right
( wrapParen
(parentPrecedence > 0)
( case renderMode of
CompactRender ->
text "case "
<> scrutineeDoc
<> text " of { "
<> intercalateDoc (text "; ") branchDocs
<> text " }"
GeneratedRender ->
vcat
[ text "case " <> scrutineeDoc <> text " of",
nest 2 (vcat branchDocs)
]
)
)
renderGuardedCaseAlts ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
document ->
[GuardedAltF recursive] ->
Either RenderRefusal document
renderGuardedCaseAlts renderContext renderMode patternDoc guardedAlts =
case guardedAlts of
[] ->
Left RenderGuardedExpression
[GuardedAltF [] bodyValue] -> do
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right (patternDoc <> text " -> " <> bodyDoc)
_ -> do
altDocs <- traverse (renderGuardedCaseAlt renderContext renderMode) guardedAlts
Right (patternDoc <> hcat altDocs)
renderGuardedCaseAlt ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
GuardedAltF recursive ->
Either RenderRefusal document
renderGuardedCaseAlt renderContext renderMode =
renderGuardedAlt renderContext renderMode (text " | ") " -> "
renderMultiIf ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[GuardedAltF recursive] ->
Either RenderRefusal document
renderMultiIf renderContext renderMode parentPrecedence guardedAlts =
case guardedAlts of
[] ->
Left RenderGuardedExpression
firstAlt : restAlts -> do
firstDoc <- renderMultiIfAlt renderContext renderMode (text "if ") firstAlt
restDocs <- traverse (renderMultiIfAlt renderContext renderMode (text " ")) restAlts
Right
( wrapParen
(parentPrecedence > 0)
( case renderMode of
CompactRender -> hcat (firstDoc : restDocs)
GeneratedRender -> vcat (firstDoc : restDocs)
)
)
renderMultiIfAlt ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
document ->
GuardedAltF recursive ->
Either RenderRefusal document
renderMultiIfAlt renderContext renderMode prefixDoc =
renderGuardedAlt renderContext renderMode (prefixDoc <> text "| ") " -> "
renderDoExpression ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
[HsStmtF recursive] ->
Either RenderRefusal document
renderDoExpression renderContext renderMode parentPrecedence statementValues = do
statementDocs <- traverse (renderDoStatement renderContext renderMode) statementValues
Right (wrapParen (parentPrecedence > 0) (renderBlock renderMode "do" statementDocs))
renderDoStatement ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
HsStmtF recursive ->
Either RenderRefusal document
renderDoStatement renderContext renderMode = \case
BindStmtF bindPattern rhsValue -> do
patternDoc <- renderPat renderContext False bindPattern
rhsDoc <- renderExprWith renderContext renderMode 0 rhsValue
Right (patternDoc <> text " <- " <> rhsDoc)
BodyStmtF exprValue ->
renderExprWith renderContext renderMode 0 exprValue
LetStmtF _ bindingValues ->
renderLetStatement renderContext renderMode bindingValues
renderLetStatement ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
LocalBindingRows recursive ->
Either RenderRefusal document
renderLetStatement renderContext renderMode bindingValues = do
bindingDocs <- traverse (renderLetBinding renderContext renderMode) bindingValues
Right (renderBlock renderMode "let" bindingDocs)
renderLetExpression ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
Int ->
LocalBindingRows recursive ->
recursive ->
Either RenderRefusal document
renderLetExpression renderContext renderMode parentPrecedence bindingValues bodyValue = do
bindingDocs <- traverse (renderLetBinding renderContext renderMode) bindingValues
bodyDoc <- renderExprWith renderContext renderMode 0 bodyValue
Right $
wrapParen (parentPrecedence > 0) $
case renderMode of
CompactRender ->
text "let " <> intercalateDoc (text "; ") bindingDocs <> text " in " <> bodyDoc
GeneratedRender ->
vcat
[ text "let",
nest 2 (vcat bindingDocs),
text "in " <> bodyDoc
]
renderLetBinding ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
(HsPatF, recursive) ->
Either RenderRefusal document
renderLetBinding renderContext renderMode (bindingPattern, rhsValue) = do
patternDoc <- renderPat renderContext False bindingPattern
rhsDoc <- renderExprWith renderContext renderMode 0 rhsValue
Right
(renderDelimitedExpression renderMode patternDoc "=" rhsDoc)
renderGuardStatements ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
[HsGuardStmtF recursive] ->
Either RenderRefusal document
renderGuardStatements renderContext renderMode guardStatements = do
guardDocs <- traverse (renderGuardStatement renderContext renderMode) guardStatements
Right (intercalateDoc (text ", ") guardDocs)
renderGuardStatement ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
HsGuardStmtF recursive ->
Either RenderRefusal document
renderGuardStatement renderContext renderMode = \case
GuardBoolF exprValue ->
renderExprWith renderContext renderMode 0 exprValue
GuardPatF patternValue rhsValue -> do
patternDoc <- renderPat renderContext False patternValue
rhsDoc <- renderExprWith renderContext renderMode 0 rhsValue
Right (patternDoc <+> text "<-" <+> rhsDoc)
GuardLetF _ bindingValues ->
renderLetStatement renderContext renderMode bindingValues
renderRecordLike ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
recursive ->
[(NormalizedFieldLabel, recursive)] ->
Either RenderRefusal document
renderRecordLike renderContext renderMode headValue fieldValues = do
headDoc <- renderExprWith renderContext renderMode 11 headValue
fieldDocs <- traverse (renderField renderContext renderMode) fieldValues
Right (renderRecordExpression renderMode headDoc fieldDocs)
renderField ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
(NormalizedFieldLabel, recursive) ->
Either RenderRefusal document
renderField renderContext renderMode (fieldLabelValue, fieldValue) = do
fieldDoc <- renderExprWith renderContext renderMode 0 fieldValue
Right (text (nflSelector fieldLabelValue) <> text " = " <> fieldDoc)
renderRecordExpression ::
RenderDocument document =>
RenderMode ->
document ->
[document] ->
document
renderRecordExpression renderMode headDoc fieldDocs =
case (renderMode, fieldDocs) of
(CompactRender, _) ->
headDoc <> text " { " <> intercalateDoc (text ", ") fieldDocs <> text " }"
(GeneratedRender, []) ->
headDoc <> text " {}"
(GeneratedRender, firstField : remainingFields) ->
vcat
[ headDoc,
nest 2
( vcat
( (text "{ " <> firstField)
: fmap (text ", " <>) remainingFields
<> [text "}"]
)
)
]
renderArithSeq ::
RenderDocument document =>
RenderSource recursive ->
RenderMode ->
NormalizedArithSeq recursive ->
Either RenderRefusal document
renderArithSeq renderContext renderMode = \case
ArithSeqFrom fromValue -> do
fromDoc <- renderExprWith renderContext renderMode 0 fromValue
Right (text "[" <> fromDoc <> text " ..]")
ArithSeqFromThen fromValue thenValue -> do
fromDoc <- renderExprWith renderContext renderMode 0 fromValue
thenDoc <- renderExprWith renderContext renderMode 0 thenValue
Right (text "[" <> fromDoc <> text ", " <> thenDoc <> text " ..]")
ArithSeqFromTo fromValue toValue -> do
fromDoc <- renderExprWith renderContext renderMode 0 fromValue
toDoc <- renderExprWith renderContext renderMode 0 toValue
Right (text "[" <> fromDoc <> text " .. " <> toDoc <> text "]")
ArithSeqFromThenTo fromValue thenValue toValue -> do
fromDoc <- renderExprWith renderContext renderMode 0 fromValue
thenDoc <- renderExprWith renderContext renderMode 0 thenValue
toDoc <- renderExprWith renderContext renderMode 0 toValue
Right (text "[" <> fromDoc <> text ", " <> thenDoc <> text " .. " <> toDoc <> text "]")