summaryrefslogtreecommitdiff
path: root/src/Language/Fiddle/Ast/Internal/Instances.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Language/Fiddle/Ast/Internal/Instances.hs')
-rw-r--r--src/Language/Fiddle/Ast/Internal/Instances.hs336
1 files changed, 279 insertions, 57 deletions
diff --git a/src/Language/Fiddle/Ast/Internal/Instances.hs b/src/Language/Fiddle/Ast/Internal/Instances.hs
index c8c606c..2f3707e 100644
--- a/src/Language/Fiddle/Ast/Internal/Instances.hs
+++ b/src/Language/Fiddle/Ast/Internal/Instances.hs
@@ -15,27 +15,6 @@ import GHC.TypeError as TypeError
import Language.Fiddle.Ast.Internal.Kinds
import Language.Fiddle.Ast.Internal.Stage
--- Type class to easily switch between stages if there is no difference in the
--- syntax tree structure between these stages. Can make things much cleaner and
--- avoids the boilerplate and bugprone-ness of needing to rote copy everything.
-class
- (Functor f) =>
- EasySwitchStage
- (t :: Stage -> SynTree)
- (f :: Type -> Type)
- (fromStage :: Stage)
- (toStage :: Stage)
- where
- switchStage :: t fromStage f a -> t toStage f a
- default switchStage ::
- ( Generic (t fromStage f a),
- Generic (t toStage f a),
- GEasySwitchStage (Rep (t fromStage f a)) (Rep (t toStage f a))
- ) =>
- t fromStage f a ->
- t toStage f a
- switchStage t = to $ gSwitchStage (from t)
-
-- Class for walking a syntax tree under the context of a monad and modifying
-- the different parts of the SynTree type..
class Alter (t :: SynTree) where
@@ -63,6 +42,154 @@ class Alter (t :: SynTree) where
m (t f2 a2)
alter ffn fn t = to <$> galter (proxyOf t) ffn fn (from t)
+-- | 'CompilationStage' is a type class representing a stage in the compiler
+-- pipeline. Each 'stage' has associated types that define how it transforms
+-- syntax trees, manages state, and handles annotations.
+--
+-- This class requires:
+-- * A 'StageMonad' for handling monadic actions during the compilation process.
+-- * A 'StageFunctor' for traversing the syntax tree.
+-- * A 'StageState' to represent local state information during traversal.
+class
+ (Monad (StageMonad stage), Traversable (StageFunctor stage)) =>
+ CompilationStage stage
+ where
+ -- | The next stage in the compilation pipeline.
+ type StageAfter stage :: Stage
+
+ -- | The monadic context for this stage (e.g., 'Compile' or 'Either').
+ type StageMonad stage :: Type -> Type
+
+ -- | The state type associated with this stage. This state is designed to be
+ -- used as a 'local state', meaning any modifications to this state are
+ -- only visible to child nodes during the traversal. To share state across
+ -- sibling nodes, use the 'StageMonad'.
+ type StageState stage :: Type
+
+ -- | The functor used for traversing the syntax tree during this stage.
+ type StageFunctor stage :: Type -> Type
+
+ -- | The type of annotations associated with nodes in the syntax tree.
+ type StageAnnotation stage :: Type
+
+-- | Utility type that captures the structure of a syntax tree node for a given
+-- stage. This type alias simplifies references to the full tree structure in
+-- other parts of the code.
+type TreeType (t :: StagedSynTree) (s :: Stage) =
+ t s (StageFunctor s) (StageAnnotation s)
+
+-- | 'AdvanceStage' defines how to transform an Abstract Syntax Tree (AST) node
+-- from one stage to the next in the compiler pipeline. This transformation
+-- can be customized per node type, or a default generic implementation can be
+-- used.
+class
+ (CompilationStage stage) =>
+ AdvanceStage (stage :: Stage) (t :: StagedSynTree)
+ where
+ -- | 'advanceStage' transitions a syntax tree node from the current stage to
+ -- the next stage ('StageAfter stage'). It takes the current local state
+ -- ('StageState') and the syntax tree node ('TreeType') as input and returns
+ -- a monadic action that produces the transformed node for the next stage.
+ --
+ -- This function typically performs tree transformations, checks, or other
+ -- modifications necessary for the compilation process.
+ --
+ -- Parameters:
+ -- * 'StageState stage' - The local state for this stage of the compiler.
+ -- This state is only visible to child nodes. Any changes do not affect
+ -- sibling nodes.
+ -- * 'TreeType t stage' - The syntax tree node at the current stage.
+ --
+ -- Returns: A monadic action that produces the transformed syntax tree node
+ -- at the next stage.
+ advanceStage ::
+ StageState stage -> -- Local state for the current stage
+ TreeType t stage -> -- Syntax tree node at the current stage
+ StageMonad
+ stage
+ ( t
+ (StageAfter stage) -- The next stage in the pipeline
+ (StageFunctor stage) -- The functor associated with the next stage
+ (StageAnnotation stage) -- Annotation type for the next stage
+ )
+
+ -- | Default implementation of 'advanceStage' using generics. This leverages
+ -- 'GAdvanceStage' to automatically traverse and transform the syntax tree.
+ -- If an AST type derives 'Generic', this default can be used to reduce
+ -- boilerplate code.
+ --
+ -- Before performing the generic transformation with 'gAdvanceStage', the
+ -- 'modifyState' function is called to potentially alter the local state
+ -- based on the current node.
+ --
+ -- This implementation is useful for cases where the tree structure remains
+ -- mostly unchanged between stages, and only the state or annotations need
+ -- to be adjusted.
+ default advanceStage ::
+ ( GAdvanceStage
+ (StageState stage) -- The local state for this stage
+ (StageMonad stage) -- The monadic context of this stage
+ (Rep (TreeType t stage)) -- Generic representation of the current tree type
+ (Rep (t (StageAfter stage) (StageFunctor stage) (StageAnnotation stage))), -- Generic representation of the next stage's tree type
+ Generic (TreeType t stage), -- The current tree type must be an instance of 'Generic'
+ Generic
+ ( t
+ (StageAfter stage) -- The tree type at the next stage
+ (StageFunctor stage) -- The functor for the next stage
+ (StageAnnotation stage) -- The annotation type for the next stage
+ )
+ ) =>
+ StageState stage -> -- Local state for the current stage
+ TreeType t stage -> -- Syntax tree node at the current stage
+ StageMonad
+ stage
+ ( t
+ (StageAfter stage) -- The tree type for the next stage
+ (StageFunctor stage) -- The functor for the next stage
+ (StageAnnotation stage) -- The annotation type for the next stage
+ )
+ advanceStage s t = do
+ -- Modify the local state for this node before performing the transformation
+ s' <- modifyState t s
+ -- Perform the generic transformation using 'gAdvanceStage'
+ to <$> gAdvanceStage s' (from t)
+
+ -- | 'modifyState' allows for changes to the local state ('StageState') before
+ -- transforming the syntax tree node. This is called on each node during the
+ -- traversal, allowing the state to be adjusted based on the current node's
+ -- information.
+ --
+ -- The default implementation simply returns the unchanged state, but it can
+ -- be overridden to implement custom state modifications.
+ --
+ -- Note: This state modification is local to the current node and its
+ -- children. Changes to this state are not visible to sibling nodes. If
+ -- information needs to be shared across siblings, consider using the
+ -- 'StageMonad' for that purpose.
+ --
+ -- 'modifyState' is only called by the default implementation of
+ -- advanceStage. If 'advaceStage' is overridden, then overriding this
+ -- function is superfluous.
+ --
+ -- Parameters:
+ -- * 'TreeType t stage' - The syntax tree node at the current stage.
+ -- * 'StageState stage' - The local state for this stage.
+ --
+ -- Returns: A monadic action that produces the (potentially modified) state.
+ modifyState ::
+ TreeType t stage -> -- Syntax tree node at the current stage
+ StageState stage -> -- Local state for the current stage
+ StageMonad stage (StageState stage) -- The modified local state
+ modifyState _ = return
+
+-- | 'GAdvanceStage' is a helper type class that performs the transformation
+-- of the generic representation of a syntax tree node. It is used by the
+-- default implementation of 'advanceStage' to traverse and modify nodes
+-- automatically.
+class GAdvanceStage s m from to where
+ gAdvanceStage :: s -> from x -> m (to x)
+
+
-- A syntax tree object is annotated if it has an annotation 'a' as the last
-- element.
class Annotated (t :: SynTree) where
@@ -170,59 +297,154 @@ instance (GAnnot a r, GAnnot a l) => GAnnot a (l :+: r) where
instance (GAnnot a r) => GAnnot a (M1 i c r) where
gannot (M1 a) = gannot a
+-- instance
+-- (GEasySwitchStage s1 s2) =>
+-- GEasySwitchStage (M1 i c s1) (M1 i c s2)
+-- where
+-- gSwitchStage (M1 a) = M1 (gSwitchStage a)
+--
+-- instance
+-- (GEasySwitchStage l1 l2, GEasySwitchStage r1 r2) =>
+-- GEasySwitchStage (l1 :+: r1) (l2 :+: r2)
+-- where
+-- gSwitchStage (R1 r) = R1 $ gSwitchStage r
+-- gSwitchStage (L1 l) = L1 $ gSwitchStage l
+--
+-- instance
+-- (GEasySwitchStage l1 l2, GEasySwitchStage r1 r2) =>
+-- (GEasySwitchStage (l1 :*: r1) (l2 :*: r2))
+-- where
+-- gSwitchStage (l :*: r) = gSwitchStage l :*: gSwitchStage r
+--
+-- instance
+-- (EasySwitchStage t f fs ts) =>
+-- (GEasySwitchStage (Rec0 (t fs f a)) (Rec0 (t ts f a)))
+-- where
+-- gSwitchStage (K1 val) = K1 (switchStage val)
+--
+-- instance
+-- ( EasySwitchStage t f fs ts,
+-- Functor func
+-- ) =>
+-- (GEasySwitchStage (Rec0 (func (t fs f a))) (Rec0 (func (t ts f a))))
+-- where
+-- gSwitchStage (K1 val) = K1 (switchStage <$> val)
+--
+-- instance (GEasySwitchStage (Rec0 a) (Rec0 a)) where
+-- gSwitchStage = id
+--
+-- instance
+-- ( TypeError
+-- ( TypeError.Text "Unable to match type "
+-- :<>: TypeError.ShowType a
+-- :<>: TypeError.Text " with "
+-- :<>: TypeError.ShowType b
+-- )
+-- ) =>
+-- (GEasySwitchStage (Rec0 a) (Rec0 b))
+-- where
+-- gSwitchStage = error "Cannot be called"
+
+-- class GEasySwitchStage r1 r2 where
+-- gSwitchStage :: r1 x -> r2 x
+
+proxyOf :: t f a -> Proxy t
+proxyOf _ = Proxy
+
+instance (Alter t, Traversable f) => Functor (t f) where
+ fmap f t = runIdentity (alter return (return . f) t)
+
+-- | 'GAdvanceStage' instance for metadata wrappers ('M1').
+-- This instance allows advancing the stage of a metadata node in a generic
+-- representation. The metadata node ('M1') wraps another node ('s1'), which
+-- is recursively advanced to the next stage using 'gAdvanceStage'.
instance
- (GEasySwitchStage s1 s2) =>
- GEasySwitchStage (M1 i c s1) (M1 i c s2)
+ (Monad m, GAdvanceStage s m s1 s2) =>
+ GAdvanceStage s m (M1 i c s1) (M1 i c s2)
where
- gSwitchStage (M1 a) = M1 (gSwitchStage a)
+ gAdvanceStage s (M1 a) = M1 <$> gAdvanceStage s a
+-- | 'GAdvanceStage' instance for sum types (':+:'). This handles the case
+-- where the generic representation of a type is a sum (i.e., an 'Either'-like
+-- choice between two alternatives). The sum type can be either 'L1' (left)
+-- or 'R1' (right), and 'gAdvanceStage' is called recursively on the selected
+-- branch.
instance
- (GEasySwitchStage l1 l2, GEasySwitchStage r1 r2) =>
- GEasySwitchStage (l1 :+: r1) (l2 :+: r2)
+ (Monad m, GAdvanceStage s m l1 l2, GAdvanceStage s m r1 r2) =>
+ GAdvanceStage s m (l1 :+: r1) (l2 :+: r2)
where
- gSwitchStage (R1 r) = R1 $ gSwitchStage r
- gSwitchStage (L1 l) = L1 $ gSwitchStage l
+ gAdvanceStage s (R1 r) = R1 <$> gAdvanceStage s r
+ gAdvanceStage s (L1 l) = L1 <$> gAdvanceStage s l
+-- | 'GAdvanceStage' instance for product types (':*:'). This handles cases
+-- where the generic representation of a type is a product (i.e., a tuple of
+-- multiple components). It recursively advances each component ('l' and 'r')
+-- to the next stage.
instance
- (GEasySwitchStage l1 l2, GEasySwitchStage r1 r2) =>
- (GEasySwitchStage (l1 :*: r1) (l2 :*: r2))
+ (Monad m, GAdvanceStage s m l1 l2, GAdvanceStage s m r1 r2) =>
+ GAdvanceStage s m (l1 :*: r1) (l2 :*: r2)
where
- gSwitchStage (l :*: r) = gSwitchStage l :*: gSwitchStage r
+ gAdvanceStage s (l :*: r) =
+ (:*:) <$> gAdvanceStage s l <*> gAdvanceStage s r
+-- | 'GAdvanceStage' instance for record fields ('Rec0') containing a single
+-- AST element ('t') to be advanced. This instance covers the case where the
+-- field is an individual AST node that implements 'AdvanceStage'.
+-- It advances this node using 'advanceStage'.
instance
- (EasySwitchStage t f fs ts) =>
- (GEasySwitchStage (Rec0 (t fs f a)) (Rec0 (t ts f a)))
+ ( Monad m,
+ AdvanceStage stage t',
+ Traversable f,
+ StageAfter stage ~ stage',
+ StageMonad stage ~ m,
+ StageState stage ~ s,
+ StageFunctor stage ~ f,
+ StageAnnotation stage ~ a
+ ) =>
+ GAdvanceStage s m (Rec0 (t' stage f a)) (Rec0 (t' stage' f a))
where
- gSwitchStage (K1 val) = K1 (switchStage val)
+ gAdvanceStage st (K1 val) = K1 <$> advanceStage st val
+-- | 'GAdvanceStage' instance for record fields ('Rec0') containing a functor
+-- ('func') of AST elements ('t'). This handles cases where the field is a
+-- container (e.g., list, 'Maybe') of AST nodes that need to be advanced.
+-- Each node in the container is transformed using 'advanceStage'.
instance
- ( EasySwitchStage t f fs ts,
- Functor func
+ ( Monad m,
+ AdvanceStage stage t',
+ Traversable f,
+ StageAfter stage ~ stage',
+ StageMonad stage ~ m,
+ StageState stage ~ s,
+ StageFunctor stage ~ f,
+ StageAnnotation stage ~ a,
+ Traversable func
) =>
- (GEasySwitchStage (Rec0 (func (t fs f a))) (Rec0 (func (t ts f a))))
+ GAdvanceStage s m (Rec0 (func (t' stage f a))) (Rec0 (func (t' stage' f a)))
where
- gSwitchStage (K1 val) = K1 (switchStage <$> val)
-
-instance (GEasySwitchStage (Rec0 a) (Rec0 a)) where
- gSwitchStage = id
+ gAdvanceStage st (K1 val) = K1 <$> mapM (advanceStage st) val
+-- | 'GAdvanceStage' instance for record fields ('Rec0') containing a
+-- functor ('f') wrapping an AST element. This handles cases where the field
+-- is a container ('f') of AST nodes that need to be advanced. Each node in
+-- the container is transformed using 'advanceStage'.
instance
- ( TypeError
- ( TypeError.Text "Unable to match type "
- :<>: TypeError.ShowType a
- :<>: TypeError.Text " with "
- :<>: TypeError.ShowType b
- )
+ ( Monad m,
+ AdvanceStage stage t',
+ Traversable f,
+ StageAfter stage ~ stage',
+ StageMonad stage ~ m,
+ StageState stage ~ s,
+ StageFunctor stage ~ f,
+ StageAnnotation stage ~ a
) =>
- (GEasySwitchStage (Rec0 a) (Rec0 b))
+ GAdvanceStage s m (Rec0 (f (t' stage f a))) (Rec0 (f (t' stage' f a)))
where
- gSwitchStage = error "Cannot be called"
-
-class GEasySwitchStage r1 r2 where
- gSwitchStage :: r1 x -> r2 x
+ gAdvanceStage st (K1 val) = K1 <$> mapM (advanceStage st) val
-proxyOf :: t f a -> Proxy t
-proxyOf _ = Proxy
-
-instance (Alter t, Traversable f) => Functor (t f) where
- fmap f t = runIdentity (alter return (return . f) t)
+-- | 'GAdvanceStage' instance for simple record fields ('Rec0') that do not
+-- need to change between stages. This is used for fields that are not AST
+-- nodes and remain the same when advancing the stage (e.g., primitive
+-- types like 'Int', 'Bool', etc.).
+instance (Monad m) => GAdvanceStage s m (Rec0 a) (Rec0 a) where
+ gAdvanceStage _ (K1 val) = return (K1 val)