packages feed

moonlight-pale-0.1.0.0: src-ghc-surface/Moonlight/Pale/Ghc/Expr/Render/Pattern.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Moonlight.Pale.Ghc.Expr.Render.Pattern
  ( renderClausePatterns,
    renderPat,
    renderRecordPattern,
    renderRecordPatternItem
  )
where

import GHC.Types.Name.Occurrence (isSymOcc)
import GHC.Types.Name.Reader (RdrName, rdrNameOcc)
import Moonlight.Pale.Ghc.Expr.NameRender (renderRdrName)
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.Refusal
import Moonlight.Pale.Ghc.Expr.Syntax

renderClausePatterns ::
  RenderDocument document =>
  RenderSource recursive ->
  [HsPatF] ->
  Either RenderRefusal document
renderClausePatterns renderContext patternValues = do
  patternDocs <- traverse (renderPat renderContext True) patternValues
  Right (intercalateDoc (text " ") patternDocs)

renderPat ::
  RenderDocument document =>
  RenderSource recursive ->
  Bool ->
  HsPatF ->
  Either RenderRefusal document
renderPat renderContext atomicContext = \case
  PVarP binderAnn ->
    Right (renderBinderAnn renderContext binderAnn)
  PWildP ->
    Right (text "_")
  PConP conName subPatterns ->
    case subPatterns of
      [] ->
        Right (renderConName conName)
      [leftPattern, rightPattern]
        | isSymOcc (rdrNameOcc conName) -> do
            leftDoc <- renderPat renderContext True leftPattern
            rightDoc <- renderPat renderContext True rightPattern
            Right (wrapParen atomicContext (leftDoc <> text (" " <> renderRdrName conName <> " ") <> rightDoc))
      _ -> do
        argDocs <- traverse (renderPat renderContext True) subPatterns
        Right (wrapParen atomicContext (intercalateDoc (text " ") (renderConName conName : argDocs)))
  PTupleP boxity subPatterns -> do
    componentDocs <- traverse (renderPat renderContext False) subPatterns
    let delimiters =
          case boxity of
            BoxedTuple -> ("(", ")")
            UnboxedTuple -> ("(#", "#)")
    Right (text (fst delimiters) <> intercalateDoc (text ", ") componentDocs <> text (snd delimiters))
  PListP subPatterns -> do
    componentDocs <- traverse (renderPat renderContext False) subPatterns
    Right (text "[" <> intercalateDoc (text ", ") componentDocs <> text "]")
  PLitP literalValue ->
    Right (text (renderNormalizedLit literalValue))
  POverLitP literalValue ->
    Right (text (renderNormalizedOverLit literalValue))
  PAsP binderAnn subPattern -> do
    subDoc <- renderPat renderContext True subPattern
    Right (renderBinderAnn renderContext binderAnn <> text "@" <> subDoc)
  PBangP subPattern -> do
    subDoc <- renderPat renderContext True subPattern
    Right (text "!" <> subDoc)
  PLazyP subPattern -> do
    subDoc <- renderPat renderContext True subPattern
    Right (text "~" <> subDoc)
  PParP subPattern -> do
    subDoc <- renderPat renderContext False subPattern
    Right (parenthesizeDoc subDoc)
  PRecP conName fieldPatterns ->
    renderRecordPattern renderContext conName fieldPatterns

renderRecordPattern ::
  RenderDocument document =>
  RenderSource recursive ->
  RdrName ->
  [HsRecPatItem] ->
  Either RenderRefusal document
renderRecordPattern renderContext conName recordItems =
  case recordItems of
    [] ->
      Right (renderConName conName <> text " {}")
    _ -> do
      itemDocuments <-
        traverse (renderRecordPatternItem renderContext) recordItems
      Right
        ( renderConName conName
            <> text " {"
            <> intercalateDoc (text ", ") itemDocuments
            <> text "}"
        )

renderRecordPatternItem ::
  RenderDocument document =>
  RenderSource recursive ->
  HsRecPatItem ->
  Either RenderRefusal document
renderRecordPatternItem renderContext = \case
  HsRecPatField fieldName (HsRecPatExplicit fieldPattern) -> do
    fieldDocument <- renderPat renderContext False fieldPattern
    Right
      ( text (renderRdrName fieldName)
          <> text " = "
          <> fieldDocument
      )
  HsRecPatField fieldName (HsRecPatPun _) ->
    Right (text (renderRdrName fieldName))
  HsRecPatWildcard _ _ ->
    Right (text "..")