moonlight-pale-0.1.0.0: src-ghc-surface/Moonlight/Pale/Ghc/Expr/Syntax.hs
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeFamilies #-}
module Moonlight.Pale.Ghc.Expr.Syntax
( HsVarRef (..),
BinderAnn (..),
HsOpaqueTag (..),
HsPatOpaqueTag (..),
HsRecPatFieldValue (..),
HsRecPatItem (..),
HsPatF (..),
patBinders,
traversePatBinders,
LetRecursion (..),
BindingComponent (..),
BindingComponentRecursion (..),
FixityAssociativity (..),
FixityDeclaration (..),
TypeSignature (..),
ExactIntegral,
exactIntegralSource,
exactIntegralNegative,
exactIntegralValue,
exactIntegralToInteger,
exactIntegralFromInteger,
ExactFractional,
exactFractionalSource,
exactFractionalNegative,
exactFractionalSignificand,
exactFractionalExponent,
exactFractionalBase,
exactFractionalToRational,
exactFractionalFromRational,
NormalizedLit (..),
normalizeHsLit,
NormalizedOverLit (..),
normalizeHsOverLit,
NormalizedFieldLabel (..),
normalizeFieldLabel,
NormalizedTypeText (..),
NormalizedArithSeq (..),
TupleBoxity (..),
TupleSlot (..),
SourceRegion (..),
SourceCharRange,
SourceEndConvention (..),
SourceRangeFailure (..),
sourceRegionFromSrcSpan,
sourceRegionFromRealSrcSpan,
sourceCharRangeStart,
sourceCharRangeEnd,
sourceCharRangeFromOffsets,
sourceRegionCharRange,
sourceRegionCharRangeWith,
sourceCharRangeRegion,
sourceCharRangeRegionWith,
sourceCharRangeText,
HsExprF (..),
HsStmtF (..),
HsGuardStmtF (..),
GuardedAltF (..),
Expr (..),
eraseExpr,
HsExprTag (..),
TagSignature (..),
tagSignatureFromTag,
tagSignatureMember,
)
where
import Data.Bits (bit, testBit, (.|.))
import Data.ByteString (ByteString)
import Data.Kind (Type)
import Data.List.NonEmpty (NonEmpty)
import Data.Word (Word64)
import GHC.Data.FastString (unpackFS)
import GHC.Hs (GhcPs, HsLit (..), HsOverLit (..), OverLitVal (..))
import GHC.Types.FieldLabel
( DuplicateRecordFields (..),
FieldLabel,
FieldSelectors (..),
flHasDuplicateRecordFields,
flHasFieldSelector,
flSelector,
)
import GHC.Types.Name (nameOccName)
import GHC.Types.Name.Occurrence (occNameString)
import GHC.Types.Name.Reader (RdrName, rdrNameOcc)
import GHC.Types.SourceText (FractionalExponentBase (..), FractionalLit (..), IntegralLit (..), SourceText (..))
import GHC.Types.SrcLoc
( RealSrcSpan,
SrcSpan (..),
srcSpanEndCol,
srcSpanEndLine,
srcSpanStartCol,
srcSpanStartLine,
)
import Moonlight.Core (BinderId, HasConstructorTag (..), Pattern (..), ZipMatch (..), zipSameNodeShape)
import Moonlight.Pale.Ghc.Expr.Opaque (HsOpaqueTag (..), HsPatOpaqueTag (..))
import Moonlight.Pale.Ghc.Expr.Scope (FreeScopeSummary, ScopeId)
type HsVarRef :: Type
data HsVarRef
= GlobalName !RdrName
| LocalName !BinderAnn
deriving stock (Eq, Ord)
type BinderAnn :: Type
data BinderAnn = BinderAnn
{ baId :: !BinderId,
baName :: !RdrName
}
deriving stock (Eq, Ord)
instance Show HsVarRef where
show = \case
GlobalName rdrName -> "GlobalName " <> occNameString (rdrNameOcc rdrName)
LocalName binderAnn -> "LocalName " <> show binderAnn
instance Show BinderAnn where
show binderAnn =
"BinderAnn { baId = " <> show (baId binderAnn) <> ", baName = " <> occNameString (rdrNameOcc (baName binderAnn)) <> " }"
type HsRecPatFieldValue :: Type
data HsRecPatFieldValue
= HsRecPatExplicit !HsPatF
| HsRecPatPun !BinderAnn
deriving stock (Eq, Ord)
instance Show HsRecPatFieldValue where
show = \case
HsRecPatExplicit fieldPattern ->
"HsRecPatExplicit (" <> show fieldPattern <> ")"
HsRecPatPun binderAnn ->
"HsRecPatPun (" <> show binderAnn <> ")"
type HsRecPatItem :: Type
data HsRecPatItem
= HsRecPatField !RdrName !HsRecPatFieldValue
| HsRecPatWildcard !SourceRegion ![BinderAnn]
deriving stock (Eq, Ord)
instance Show HsRecPatItem where
show = \case
HsRecPatField fieldName fieldValue ->
"HsRecPatField "
<> occNameString (rdrNameOcc fieldName)
<> " ("
<> show fieldValue
<> ")"
HsRecPatWildcard wildcardRegion wildcardBinders ->
"HsRecPatWildcard "
<> show wildcardRegion
<> " "
<> show wildcardBinders
type HsPatF :: Type
data HsPatF
= PVarP !BinderAnn
| PWildP
| PConP !RdrName ![HsPatF]
| PTupleP !TupleBoxity ![HsPatF]
| PListP ![HsPatF]
| PLitP !NormalizedLit
| POverLitP !NormalizedOverLit
| PAsP !BinderAnn !HsPatF
| PBangP !HsPatF
| PLazyP !HsPatF
| PParP !HsPatF
| PRecP !RdrName ![HsRecPatItem]
deriving stock (Eq, Ord)
instance Show HsPatF where
show = \case
PVarP binderAnn -> "PVarP (" <> show binderAnn <> ")"
PWildP -> "PWildP"
PConP conName subPatterns -> "PConP " <> occNameString (rdrNameOcc conName) <> " " <> show subPatterns
PTupleP boxity subPatterns -> "PTupleP " <> show boxity <> " " <> show subPatterns
PListP subPatterns -> "PListP " <> show subPatterns
PLitP literalValue -> "PLitP (" <> show literalValue <> ")"
POverLitP literalValue -> "POverLitP (" <> show literalValue <> ")"
PAsP binderAnn subPattern -> "PAsP (" <> show binderAnn <> ") (" <> show subPattern <> ")"
PBangP subPattern -> "PBangP (" <> show subPattern <> ")"
PLazyP subPattern -> "PLazyP (" <> show subPattern <> ")"
PParP subPattern -> "PParP (" <> show subPattern <> ")"
PRecP conName recordItems -> "PRecP " <> occNameString (rdrNameOcc conName) <> " " <> show recordItems
patBinders :: HsPatF -> [BinderAnn]
patBinders = \case
PVarP binderAnn -> [binderAnn]
PWildP -> []
PConP _ subPatterns -> foldMap patBinders subPatterns
PTupleP _ subPatterns -> foldMap patBinders subPatterns
PListP subPatterns -> foldMap patBinders subPatterns
PLitP _ -> []
POverLitP _ -> []
PAsP binderAnn subPattern -> binderAnn : patBinders subPattern
PBangP subPattern -> patBinders subPattern
PLazyP subPattern -> patBinders subPattern
PParP subPattern -> patBinders subPattern
PRecP _ recordItems -> foldMap recordItemBinders recordItems
traversePatBinders :: Applicative f => (BinderAnn -> f BinderAnn) -> HsPatF -> f HsPatF
traversePatBinders onBinder = go
where
go = \case
PVarP binderAnn -> PVarP <$> onBinder binderAnn
PWildP -> pure PWildP
PConP conName subPatterns -> PConP conName <$> traverse go subPatterns
PTupleP boxity subPatterns -> PTupleP boxity <$> traverse go subPatterns
PListP subPatterns -> PListP <$> traverse go subPatterns
PLitP literalValue -> pure (PLitP literalValue)
POverLitP literalValue -> pure (POverLitP literalValue)
PAsP binderAnn subPattern -> PAsP <$> onBinder binderAnn <*> go subPattern
PBangP subPattern -> PBangP <$> go subPattern
PLazyP subPattern -> PLazyP <$> go subPattern
PParP subPattern -> PParP <$> go subPattern
PRecP conName recordItems ->
PRecP conName <$> traverse (traverseRecordItemBinders onBinder) recordItems
recordItemBinders :: HsRecPatItem -> [BinderAnn]
recordItemBinders = \case
HsRecPatField _ (HsRecPatExplicit fieldPattern) ->
patBinders fieldPattern
HsRecPatField _ (HsRecPatPun binderAnn) ->
[binderAnn]
HsRecPatWildcard _ wildcardBinders ->
wildcardBinders
traverseRecordItemBinders ::
Applicative f =>
(BinderAnn -> f BinderAnn) ->
HsRecPatItem ->
f HsRecPatItem
traverseRecordItemBinders onBinder = \case
HsRecPatField fieldName (HsRecPatExplicit fieldPattern) ->
HsRecPatField fieldName . HsRecPatExplicit
<$> traversePatBinders onBinder fieldPattern
HsRecPatField fieldName (HsRecPatPun binderAnn) ->
HsRecPatField fieldName . HsRecPatPun
<$> onBinder binderAnn
HsRecPatWildcard wildcardRegion wildcardBinders ->
HsRecPatWildcard wildcardRegion
<$> traverse onBinder wildcardBinders
type LetRecursion :: Type
data LetRecursion
= NonRecursiveBinds
| AcyclicDependentBinds
| RecursiveBinds
deriving stock (Eq, Ord, Show)
type BindingComponent :: Type
data BindingComponent = BindingComponent
{ bindingComponentRows :: !(NonEmpty Int),
bindingComponentBinders :: ![BinderId],
bindingComponentDependencies :: ![BinderId],
bindingComponentRecursion :: !BindingComponentRecursion
}
deriving stock (Eq, Ord, Show)
type BindingComponentRecursion :: Type
data BindingComponentRecursion
= AcyclicBindingComponent
| RecursiveBindingComponent
deriving stock (Eq, Ord, Show)
type FixityAssociativity :: Type
data FixityAssociativity
= FixityLeft
| FixityRight
| FixityNone
deriving stock (Eq, Ord, Show)
type FixityDeclaration :: Type
data FixityDeclaration = FixityDeclaration
{ fixityAssociativity :: !FixityAssociativity,
fixityPrecedence :: !Int,
fixityOperators :: !(NonEmpty RdrName)
}
deriving stock (Eq, Ord)
instance Show FixityDeclaration where
show declaration =
"FixityDeclaration "
<> show (fixityAssociativity declaration)
<> " "
<> show (fixityPrecedence declaration)
<> " "
<> show (fmap (occNameString . rdrNameOcc) (fixityOperators declaration))
type TypeSignature :: Type
data TypeSignature = TypeSignature
{ typeSignatureNames :: !(NonEmpty RdrName),
typeSignatureType :: !NormalizedTypeText
}
deriving stock (Eq, Ord)
instance Show TypeSignature where
show signature =
"TypeSignature "
<> show (fmap (occNameString . rdrNameOcc) (typeSignatureNames signature))
<> " "
<> show (typeSignatureType signature)
type NormalizedLit :: Type
data NormalizedLit
= NormalizedChar !Char
| NormalizedCharPrim !Char
| NormalizedString !String
| NormalizedMultilineString !String
| NormalizedStringPrim !ByteString
| NormalizedInt !ExactIntegral
| NormalizedIntPrim !ExactIntegral
| NormalizedWordPrim !ExactIntegral
| NormalizedInt8Prim !ExactIntegral
| NormalizedInt16Prim !ExactIntegral
| NormalizedInt32Prim !ExactIntegral
| NormalizedInt64Prim !ExactIntegral
| NormalizedWord8Prim !ExactIntegral
| NormalizedWord16Prim !ExactIntegral
| NormalizedWord32Prim !ExactIntegral
| NormalizedWord64Prim !ExactIntegral
| NormalizedFloatPrim !ExactFractional
| NormalizedDoublePrim !ExactFractional
deriving stock (Eq, Ord, Show)
type NormalizedOverLit :: Type
data NormalizedOverLit
= NormalizedIntegralOverLit !ExactIntegral
| NormalizedFractionalOverLit !ExactFractional
| NormalizedStringOverLit !String
deriving stock (Eq, Ord, Show)
type NormalizedTypeText :: Type
newtype NormalizedTypeText = NormalizedTypeText
{ nttText :: String
}
deriving stock (Eq, Ord, Show)
type NormalizedFieldLabel :: Type
data NormalizedFieldLabel = NormalizedFieldLabel
{ nflSelector :: !String,
nflAllowsDuplicateRecordFields :: !Bool,
nflHasSelector :: !Bool
}
deriving stock (Eq, Ord, Show)
type NormalizedArithSeq :: Type -> Type
data NormalizedArithSeq r
= ArithSeqFrom !r
| ArithSeqFromThen !r !r
| ArithSeqFromTo !r !r
| ArithSeqFromThenTo !r !r !r
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type ExactIntegral :: Type
data ExactIntegral = ExactIntegral
{ exactIntegralSource :: !(Maybe String),
exactIntegralNegative :: !Bool,
exactIntegralValue :: !Integer
}
deriving stock (Eq, Ord, Show)
type ExactFractional :: Type
data ExactFractional = ExactFractional
{ exactFractionalSource :: !(Maybe String),
exactFractionalNegative :: !Bool,
exactFractionalSignificand :: !Rational,
exactFractionalExponent :: !Integer,
exactFractionalBase :: !FractionalExponentBase
}
deriving stock (Eq, Ord, Show)
exactIntegralToInteger :: ExactIntegral -> Integer
exactIntegralToInteger exactValue =
(if exactIntegralNegative exactValue then negate else id)
(exactIntegralValue exactValue)
exactIntegralFromInteger :: Integer -> ExactIntegral
exactIntegralFromInteger value =
ExactIntegral
{ exactIntegralSource = Nothing,
exactIntegralNegative = value < 0,
exactIntegralValue = abs value
}
exactFractionalToRational :: ExactFractional -> Rational
exactFractionalToRational exactValue =
let exponentFactor =
case exactFractionalBase exactValue of
Base10 -> rationalPower 10 (exactFractionalExponent exactValue)
Base2 -> rationalPower 2 (exactFractionalExponent exactValue)
unsignedValue =
exactFractionalSignificand exactValue * exponentFactor
in (if exactFractionalNegative exactValue then negate else id) unsignedValue
exactFractionalFromRational :: Rational -> ExactFractional
exactFractionalFromRational value =
ExactFractional
{ exactFractionalSource = Nothing,
exactFractionalNegative = value < 0,
exactFractionalSignificand = abs value,
exactFractionalExponent = 0,
exactFractionalBase = Base10
}
rationalPower :: Integer -> Integer -> Rational
rationalPower baseValue exponentValue
| exponentValue < 0 =
1 / fromInteger (baseValue ^ negate exponentValue)
| otherwise =
fromInteger (baseValue ^ exponentValue)
type TupleSlot :: Type -> Type
data TupleSlot r
= TuplePresent !r
| TupleMissing
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type TupleBoxity :: Type
data TupleBoxity
= BoxedTuple
| UnboxedTuple
deriving stock (Eq, Ord, Show)
type SourceRegion :: Type
data SourceRegion = SourceRegion
{ srStartLine :: !Int,
srStartCol :: !Int,
srEndLine :: !Int,
srEndCol :: !Int
}
deriving stock (Eq, Ord, Show)
type SourceCharRange :: Type
data SourceCharRange = SourceCharRange
{ sourceCharRangeStart :: !Int,
sourceCharRangeEnd :: !Int
}
deriving stock (Eq, Ord, Show)
type SourceEndConvention :: Type
data SourceEndConvention
= SourceEndHalfOpen
| SourceEndInclusive
deriving stock (Eq, Ord, Show)
type SourceRangeFailure :: Type
data SourceRangeFailure
= SourceRangePositionOutsideSource !Int !Int
| SourceRangePositionInsideTab !Int !Int
| SourceRangeEndsBeforeStart !SourceRegion
| SourceRangeOffsetsInvalid !Int !Int
| SourceRangeInvalidTabStop !Int
| SourceRangeCarriageReturnUnsupported
deriving stock (Eq, Ord, Show)
sourceRegionFromSrcSpan :: SrcSpan -> Maybe SourceRegion
sourceRegionFromSrcSpan = \case
RealSrcSpan realSpan _ ->
Just (sourceRegionFromRealSrcSpan realSpan)
UnhelpfulSpan _ ->
Nothing
sourceRegionFromRealSrcSpan :: RealSrcSpan -> SourceRegion
sourceRegionFromRealSrcSpan realSpan =
SourceRegion
{ srStartLine = srcSpanStartLine realSpan,
srStartCol = srcSpanStartCol realSpan,
srEndLine = srcSpanEndLine realSpan,
srEndCol = srcSpanEndCol realSpan
}
sourceCharRangeFromOffsets :: Int -> Int -> Either SourceRangeFailure SourceCharRange
sourceCharRangeFromOffsets startOffset endOffset
| startOffset < 0 || endOffset < startOffset =
Left (SourceRangeOffsetsInvalid startOffset endOffset)
| otherwise =
Right (SourceCharRange startOffset endOffset)
sourceRegionCharRange :: String -> SourceRegion -> Either SourceRangeFailure SourceCharRange
sourceRegionCharRange = sourceRegionCharRangeWith 8 SourceEndHalfOpen
sourceRegionCharRangeWith :: Int -> SourceEndConvention -> String -> SourceRegion -> Either SourceRangeFailure SourceCharRange
sourceRegionCharRangeWith tabStop endConvention source region = do
if tabStop > 0
then Right ()
else Left (SourceRangeInvalidTabStop tabStop)
if '\r' `elem` source
then Left SourceRangeCarriageReturnUnsupported
else Right ()
startOffset <- sourcePositionOffset tabStop source (srStartLine region) (srStartCol region)
endOffset <-
case endConvention of
SourceEndHalfOpen -> sourcePositionOffset tabStop source (srEndLine region) (srEndCol region)
SourceEndInclusive -> sourceInclusivePositionEndOffset tabStop source (srEndLine region) (srEndCol region)
if startOffset <= endOffset
then Right (SourceCharRange startOffset endOffset)
else Left (SourceRangeEndsBeforeStart region)
sourceCharRangeRegion :: String -> SourceCharRange -> Either SourceRangeFailure SourceRegion
sourceCharRangeRegion = sourceCharRangeRegionWith 8
sourceCharRangeRegionWith :: Int -> String -> SourceCharRange -> Either SourceRangeFailure SourceRegion
sourceCharRangeRegionWith tabStop source sourceRange@(SourceCharRange startOffset endOffset) = do
if tabStop > 0
then Right ()
else Left (SourceRangeInvalidTabStop tabStop)
if '\r' `elem` source
then Left SourceRangeCarriageReturnUnsupported
else Right ()
_ <- sourceCharRangeText source sourceRange
(startLine, startColumn) <- sourcePositionAtOffset tabStop source startOffset
(endLine, endColumn) <- sourcePositionAtOffset tabStop source endOffset
Right
SourceRegion
{ srStartLine = startLine,
srStartCol = startColumn,
srEndLine = endLine,
srEndCol = endColumn
}
sourceCharRangeText :: String -> SourceCharRange -> Either SourceRangeFailure String
sourceCharRangeText source (SourceCharRange startOffset endOffset)
| startOffset >= 0 && startOffset <= endOffset && endOffset <= length source =
Right (take (endOffset - startOffset) (drop startOffset source))
| otherwise =
Left (SourceRangeOffsetsInvalid startOffset endOffset)
sourcePositionOffset :: Int -> String -> Int -> Int -> Either SourceRangeFailure Int
sourcePositionOffset tabStop source lineNumber columnNumber = do
(lineStart, lineText) <- sourceLineAt source lineNumber columnNumber
localOffset <- sourceLineBoundaryOffset tabStop lineNumber columnNumber lineText
Right (lineStart + localOffset)
sourceInclusivePositionEndOffset :: Int -> String -> Int -> Int -> Either SourceRangeFailure Int
sourceInclusivePositionEndOffset tabStop source lineNumber columnNumber = do
(lineStart, lineText) <- sourceLineAt source lineNumber columnNumber
localOffset <- sourceLineBoundaryOffset tabStop lineNumber columnNumber lineText
if localOffset < length lineText
then Right (lineStart + localOffset + 1)
else Left (SourceRangePositionOutsideSource lineNumber columnNumber)
sourceLineAt :: String -> Int -> Int -> Either SourceRangeFailure (Int, String)
sourceLineAt source lineNumber columnNumber =
case drop (lineNumber - 1) (sourceLineRows source) of
lineRow : _
| lineNumber >= 1 && columnNumber >= 1 -> Right lineRow
_ -> Left (SourceRangePositionOutsideSource lineNumber columnNumber)
sourceLineRows :: String -> [(Int, String)]
sourceLineRows source =
let lineTexts = splitCanonicalLines source
lineStarts = scanl (\lineStart lineText -> lineStart + length lineText + 1) 0 lineTexts
in zip lineStarts lineTexts
sourcePositionAtOffset :: Int -> String -> Int -> Either SourceRangeFailure (Int, Int)
sourcePositionAtOffset tabStop source sourceOffset =
case containingLine of
Nothing -> Left (SourceRangeOffsetsInvalid sourceOffset sourceOffset)
Just (lineNumber, lineStart, lineText) ->
let localOffset = sourceOffset - lineStart
visualColumn = foldl (advanceVisualColumn tabStop) 1 (take localOffset lineText)
in if localOffset <= length lineText
then Right (lineNumber, visualColumn)
else Left (SourceRangeOffsetsInvalid sourceOffset sourceOffset)
where
containingLine =
foldl
(\selected row -> if lineStartOf row <= sourceOffset then Just row else selected)
Nothing
(zipWith toNumberedLine [1 ..] (sourceLineRows source))
toNumberedLine :: Int -> (Int, String) -> (Int, Int, String)
toNumberedLine lineNumber (lineStart, lineText) = (lineNumber, lineStart, lineText)
lineStartOf :: (Int, Int, String) -> Int
lineStartOf (_, lineStart, _) = lineStart
splitCanonicalLines :: String -> [String]
splitCanonicalLines source =
case break (== '\n') source of
(lineText, []) -> [lineText]
(lineText, _ : remaining) -> lineText : splitCanonicalLines remaining
sourceLineBoundaryOffset :: Int -> Int -> Int -> String -> Either SourceRangeFailure Int
sourceLineBoundaryOffset tabStop lineNumber targetColumn = resolve 0 1
where
resolve localOffset visualColumn remaining
| targetColumn == visualColumn = Right localOffset
| otherwise =
case remaining of
[] -> Left (SourceRangePositionOutsideSource lineNumber targetColumn)
character : rest ->
let nextVisualColumn = advanceVisualColumn tabStop visualColumn character
in if targetColumn > visualColumn && targetColumn < nextVisualColumn
then Left (SourceRangePositionInsideTab lineNumber targetColumn)
else resolve (localOffset + 1) nextVisualColumn rest
advanceVisualColumn :: Int -> Int -> Char -> Int
advanceVisualColumn tabStop visualColumn character
| character == '\t' = ((visualColumn - 1) `div` tabStop + 1) * tabStop + 1
| otherwise = visualColumn + 1
type HsExprF :: Type -> Type
data HsExprF r
= VarF !HsVarRef
| AppF !r !r
| LamF !BinderAnn !r
| LetF !LetRecursion ![(HsPatF, r)] !r
| OpChainF !r !(NonEmpty (r, r))
| SectionLF !r !r
| SectionRF !r !r
| ParF !r
| LitF !NormalizedLit
| OverLitF !NormalizedOverLit
| IfF !r !r !r
| CaseF !r ![(HsPatF, r)]
| DoF ![HsStmtF r]
| NegF !r
| ExplicitListF ![r]
| ExplicitTupleF !TupleBoxity ![TupleSlot r]
| RecordConF !r ![(NormalizedFieldLabel, r)]
| RecordUpdF !r ![(NormalizedFieldLabel, r)]
| ArithSeqF !(NormalizedArithSeq r)
| GuardedF ![GuardedAltF r]
| ClausesF ![([HsPatF], r)]
| MultiIfF ![GuardedAltF r]
| ExprWithTySigF !r !NormalizedTypeText
| AppTypeF !r !NormalizedTypeText
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type HsGuardStmtF :: Type -> Type
data HsGuardStmtF r
= GuardBoolF !r
| GuardPatF !HsPatF !r
| GuardLetF !LetRecursion ![(HsPatF, r)]
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type GuardedAltF :: Type -> Type
data GuardedAltF r = GuardedAltF
{ gaGuards :: ![HsGuardStmtF r],
gaBody :: !r
}
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type HsStmtF :: Type -> Type
data HsStmtF r
= BindStmtF !HsPatF !r
| BodyStmtF !r
| LetStmtF !LetRecursion ![(HsPatF, r)]
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)
type Expr :: Type
data Expr = Expr
{ exprRegion :: !(Maybe SourceRegion),
exprScope :: !ScopeId,
exprFreeScopes :: !FreeScopeSummary,
exprNode :: !(HsExprF Expr)
}
deriving stock (Eq, Ord, Show)
type HsExprTag :: Type
data HsExprTag
= VarTag
| AppTag
| LamTag
| LetTag
| OpChainTag
| SectionLTag
| SectionRTag
| ParTag
| LitTag
| OverLitTag
| IfTag
| CaseTag
| DoTag
| NegTag
| ExplicitListTag
| ExplicitTupleTag
| RecordConTag
| RecordUpdTag
| ArithSeqTag
| GuardedTag
| ClausesTag
| MultiIfTag
| ExprWithTySigTag
| AppTypeTag
deriving stock (Eq, Ord, Show, Enum, Bounded)
type TagSignature :: Type
newtype TagSignature = TagSignature Word64
deriving stock (Eq, Ord, Show)
tagSignatureFromTag :: HsExprTag -> TagSignature
tagSignatureFromTag tag =
TagSignature (bit (fromEnum tag))
tagSignatureMember :: HsExprTag -> TagSignature -> Bool
tagSignatureMember tag (TagSignature signature) =
testBit signature (fromEnum tag)
instance Semigroup TagSignature where
TagSignature left <> TagSignature right =
TagSignature (left .|. right)
instance Monoid TagSignature where
mempty =
TagSignature 0
instance HasConstructorTag HsExprF where
type ConstructorTag HsExprF = HsExprTag
constructorTag = \case
VarF {} -> VarTag
AppF {} -> AppTag
LamF {} -> LamTag
LetF {} -> LetTag
OpChainF {} -> OpChainTag
SectionLF {} -> SectionLTag
SectionRF {} -> SectionRTag
ParF {} -> ParTag
LitF {} -> LitTag
OverLitF {} -> OverLitTag
IfF {} -> IfTag
CaseF {} -> CaseTag
DoF {} -> DoTag
NegF {} -> NegTag
ExplicitListF {} -> ExplicitListTag
ExplicitTupleF {} -> ExplicitTupleTag
RecordConF {} -> RecordConTag
RecordUpdF {} -> RecordUpdTag
ArithSeqF {} -> ArithSeqTag
GuardedF {} -> GuardedTag
ClausesF {} -> ClausesTag
MultiIfF {} -> MultiIfTag
ExprWithTySigF {} -> ExprWithTySigTag
AppTypeF {} -> AppTypeTag
instance ZipMatch HsExprF where
zipMatch =
zipSameNodeShape
normalizeHsLit :: HsLit GhcPs -> NormalizedLit
normalizeHsLit = \case
HsChar _ value -> NormalizedChar value
HsCharPrim _ value -> NormalizedCharPrim value
HsString _ value -> NormalizedString (unpackFS value)
HsMultilineString _ value -> NormalizedMultilineString (unpackFS value)
HsStringPrim _ value -> NormalizedStringPrim value
HsInt _ value -> NormalizedInt (exactIntegral value)
HsIntPrim sourceText value -> NormalizedIntPrim (primitiveIntegral sourceText value)
HsWordPrim sourceText value -> NormalizedWordPrim (primitiveIntegral sourceText value)
HsInt8Prim sourceText value -> NormalizedInt8Prim (primitiveIntegral sourceText value)
HsInt16Prim sourceText value -> NormalizedInt16Prim (primitiveIntegral sourceText value)
HsInt32Prim sourceText value -> NormalizedInt32Prim (primitiveIntegral sourceText value)
HsInt64Prim sourceText value -> NormalizedInt64Prim (primitiveIntegral sourceText value)
HsWord8Prim sourceText value -> NormalizedWord8Prim (primitiveIntegral sourceText value)
HsWord16Prim sourceText value -> NormalizedWord16Prim (primitiveIntegral sourceText value)
HsWord32Prim sourceText value -> NormalizedWord32Prim (primitiveIntegral sourceText value)
HsWord64Prim sourceText value -> NormalizedWord64Prim (primitiveIntegral sourceText value)
HsFloatPrim _ value -> NormalizedFloatPrim (exactFractional value)
HsDoublePrim _ value -> NormalizedDoublePrim (exactFractional value)
normalizeHsOverLit :: HsOverLit GhcPs -> NormalizedOverLit
normalizeHsOverLit = \case
OverLit {ol_val = value} -> normalizeOverLitVal value
normalizeFieldLabel :: FieldLabel -> NormalizedFieldLabel
normalizeFieldLabel fieldLabelValue =
NormalizedFieldLabel
{ nflSelector = occNameString (nameOccName (flSelector fieldLabelValue)),
nflAllowsDuplicateRecordFields = duplicateFieldFlag (flHasDuplicateRecordFields fieldLabelValue),
nflHasSelector = selectorFieldFlag (flHasFieldSelector fieldLabelValue)
}
eraseExpr :: Expr -> Pattern HsExprF
eraseExpr expressionValue =
PatternNode (fmap eraseExpr (exprNode expressionValue))
normalizeOverLitVal :: OverLitVal -> NormalizedOverLit
normalizeOverLitVal = \case
HsIntegral value -> NormalizedIntegralOverLit (exactIntegral value)
HsFractional value -> NormalizedFractionalOverLit (exactFractional value)
HsIsString _ value -> NormalizedStringOverLit (unpackFS value)
exactIntegral :: IntegralLit -> ExactIntegral
exactIntegral (IL sourceText isNegative value) =
ExactIntegral
{ exactIntegralSource = sourceTextString sourceText,
exactIntegralNegative = isNegative,
exactIntegralValue = value
}
primitiveIntegral :: SourceText -> Integer -> ExactIntegral
primitiveIntegral sourceText value =
ExactIntegral
{ exactIntegralSource = sourceTextString sourceText,
exactIntegralNegative = value < 0,
exactIntegralValue = abs value
}
exactFractional :: FractionalLit -> ExactFractional
exactFractional fractionalLit =
ExactFractional
{ exactFractionalSource = sourceTextString (fl_text fractionalLit),
exactFractionalNegative = fl_neg fractionalLit,
exactFractionalSignificand = fl_signi fractionalLit,
exactFractionalExponent = fl_exp fractionalLit,
exactFractionalBase = fl_exp_base fractionalLit
}
sourceTextString :: SourceText -> Maybe String
sourceTextString = \case
SourceText sourceText -> Just (unpackFS sourceText)
NoSourceText -> Nothing
duplicateFieldFlag :: DuplicateRecordFields -> Bool
duplicateFieldFlag = \case
DuplicateRecordFields -> True
NoDuplicateRecordFields -> False
selectorFieldFlag :: FieldSelectors -> Bool
selectorFieldFlag = \case
FieldSelectors -> True
NoFieldSelectors -> False