retrie-1.2.2: A powerful, easy-to-use codemodding tool for Haskell.

Safe Haskell | Safe-Inferred
Language | Haskell2010

Retrie.Types

Contents

- Queries and Matchers
- Rewrites and Rewriters
  - Functions on Rewrites
- Internal

Synopsis

- data Direction
  - = LeftToRight
  - | RightToLeft
- data Query ast v = Query {
  - qQuantifiers :: Quantifiers
  - qPattern :: Annotated ast
  - qResult :: v
  }
- newtype Matcher a = Matcher (IntMap (UMap a))
- mkMatcher :: Matchable ast => Query ast v -> Matcher v
- mkLocalMatcher :: Matchable ast => AlphaEnv -> Query ast v -> Matcher v
- runMatcher :: (Matchable ast, MonadIO m) => Context -> Matcher v -> ast -> TransformT m [(Substitution, v)]
- type Rewrite ast = Query ast (Template ast, MatchResultTransformer)
- mkRewrite :: Quantifiers -> Annotated ast -> Annotated ast -> Rewrite ast
- type Rewriter = Matcher (RewriterResult Universe)
- mkRewriter :: Matchable ast => Rewrite ast -> Rewriter
- mkLocalRewriter :: Matchable ast => AlphaEnv -> Rewrite ast -> Rewriter
- runRewriter :: forall ast m. (Matchable ast, MonadIO m) => (RewriterResult Universe -> RewriterResult Universe) -> Context -> Rewriter -> ast -> TransformT m (MatchResult ast)
- data MatchResult ast
  - = MatchResult Substitution (Template ast)
  - | NoMatch
- data Template ast = Template {
  - tTemplate :: Annotated ast
  - tImports :: AnnotatedImports
  - tDependents :: Maybe [Rewrite Universe]
  }
- type MatchResultTransformer = Context -> MatchResult Universe -> IO (MatchResult Universe)
- defaultTransformer :: MatchResultTransformer
- addRewriteImports :: AnnotatedImports -> Rewrite ast -> Rewrite ast
- setRewriteTransformer :: MatchResultTransformer -> Rewrite ast -> Rewrite ast
- toURewrite :: Matchable ast => Rewrite ast -> Rewrite Universe
- fromURewrite :: Matchable ast => Rewrite Universe -> Rewrite ast
- ppRewrite :: Rewrite Universe -> String
- rewritesWithDependents :: [Rewrite ast] -> [Rewrite ast]
- data RewriterResult ast = RewriterResult {
  - rrOrigin :: SrcSpan
  - rrQuantifiers :: Quantifiers
  - rrTransformer :: MatchResultTransformer
  - rrTemplate :: Template ast
  }
- data ParentPrec
  - = HasPrec Fixity
  - | IsLhs
  - | IsHsAppsTy
  - | NeverParen
- data Context = Context {
  - ctxtBinders :: [RdrName]
  - ctxtDependents :: Rewriter
  - ctxtFixityEnv :: FixityEnv
  - ctxtInScope :: AlphaEnv
  - ctxtParentPrec :: ParentPrec
  - ctxtRewriter :: Rewriter
  - ctxtSubst :: Maybe Substitution
  }

# Documentation

data Direction #

Constructors

LeftToRight |
RightToLeft |

#### Instances

Instances details

Eq Direction # |
Instance details Defined in Retrie.Types Methods (==) :: Direction -> Direction -> Bool (/=) :: Direction -> Direction -> Bool

# Queries and Matchers

data Query ast v #

`Query` is the primitive way to specify a matchable pattern (quantifiers and expression). Whenever the pattern is matched, the associated result will be returned.

Constructors

Query |

Fields

- qQuantifiers :: Quantifiers
- qPattern :: Annotated ast
- qResult :: v

#### Instances

Instances details

Bifunctor Query # |
Instance details Defined in Retrie.Types Methods bimap :: (a -> b) -> (c -> d) -> Query a c -> Query b d # first :: (a -> b) -> Query a c -> Query b c # second :: (b -> c) -> Query a b -> Query a c #
Functor (Query ast) # |
Instance details Defined in Retrie.Types Methods fmap :: (a -> b) -> Query ast a -> Query ast b # (<$) :: a -> Query ast b -> Query ast a #
(Data (Annotated ast), Show ast, Show v) => Show (Query ast v) # |
Instance details Defined in Retrie.Types Methods showsPrec :: Int -> Query ast v -> ShowS show :: Query ast v -> String showList :: [Query ast v] -> ShowS

newtype Matcher a #

`Matcher` is a compiled `Query`. Several queries can be compiled and then merged into a single compiled `Matcher` via `Semigroup`/`Monoid`.

Constructors

Matcher (IntMap (UMap a)) |

#### Instances

Instances details

Functor Matcher # |
Instance details Defined in Retrie.Types Methods fmap :: (a -> b) -> Matcher a -> Matcher b # (<$) :: a -> Matcher b -> Matcher a #
Monoid (Matcher a) # |
Instance details Defined in Retrie.Types Methods mempty :: Matcher a mappend :: Matcher a -> Matcher a -> Matcher a # mconcat :: [Matcher a] -> Matcher a
Semigroup (Matcher a) # |
Instance details Defined in Retrie.Types Methods (<>) :: Matcher a -> Matcher a -> Matcher a # sconcat :: NonEmpty (Matcher a) -> Matcher a stimes :: Integral b => b -> Matcher a -> Matcher a

mkMatcher :: Matchable ast => Query ast v -> Matcher v #

Compile a `Query` into a `Matcher`.

mkLocalMatcher :: Matchable ast => AlphaEnv -> Query ast v -> Matcher v #

Compile a `Query` into a `Matcher` within a given local scope. Useful for introducing local matchers which only match within a given local scope.

runMatcher :: (Matchable ast, MonadIO m) => Context -> Matcher v -> ast -> TransformT m [(Substitution, v)] #

Run a `Matcher` on an expression in the given `AlphaEnv` and return the results from any matches. Results are accompanied by a `Substitution`, which maps `Quantifiers` from the original `Query` to the expressions they unified with.

# Rewrites and Rewriters

type Rewrite ast = Query ast (Template ast, MatchResultTransformer) #

A `Rewrite` is a `Query` specialized to `Template` results, which have all the information necessary to replace one expression with another.

mkRewrite :: Quantifiers -> Annotated ast -> Annotated ast -> Rewrite ast #

Make a `Rewrite` from given quantifiers and left- and right-hand sides.

type Rewriter = Matcher (RewriterResult Universe) #

A `Rewriter` is a complied `Rewrite`, much like a `Matcher` is a compiled `Query`.

mkRewriter :: Matchable ast => Rewrite ast -> Rewriter #

Compile a `Rewrite` into a `Rewriter`.

mkLocalRewriter :: Matchable ast => AlphaEnv -> Rewrite ast -> Rewriter #

Compile a `Rewrite` into a `Rewriter` with a given local scope. Useful for introducing local matchers which only match within a given local scope.

runRewriter :: forall ast m. (Matchable ast, MonadIO m) => (RewriterResult Universe -> RewriterResult Universe) -> Context -> Rewriter -> ast -> TransformT m (MatchResult ast) #

Run a `Rewriter` on an expression in the given `AlphaEnv` and return the `MatchResult`s from any matches. Takes an extra function for rewriting the `RewriterResult`, which is run *before* the `MatchResultTransformer` is run.

data MatchResult ast #

The result of matching the left-hand side of a `Rewrite`.

Constructors

MatchResult Substitution (Template ast) |
NoMatch |

#### Instances

Instances details

Functor MatchResult # |
Instance details Defined in Retrie.Types Methods fmap :: (a -> b) -> MatchResult a -> MatchResult b # (<$) :: a -> MatchResult b -> MatchResult a #

data Template ast #

The right-hand side of a `Rewrite`.

Constructors

Template |

Fields

- tTemplate :: Annotated ast

  The expression for the right-hand side.

- tImports :: AnnotatedImports

  Imports to add whenever a rewrite is successful.

- tDependents :: Maybe [Rewrite Universe]

  Dependent rewrites to introduce whenever a rewrite is successful. See Note [tDependents]

#### Instances

Instances details

Functor Template # |
Instance details Defined in Retrie.Types Methods fmap :: (a -> b) -> Template a -> Template b # (<$) :: a -> Template b -> Template a #

type MatchResultTransformer = Context -> MatchResult Universe -> IO (MatchResult Universe) #

A `MatchResultTransformer` allows the user to specify custom logic to modify the result of matching the left-hand side of a rewrite (the `MatchResult`). The `MatchResult` generated by this function is used to effect the resulting AST rewrite.

For example, this transformer looks at the matched expression to build the resulting expression:

    fancyMigration :: MatchResultTransformer
    fancyMigration ctxt matchResult
      | MatchResult sub t <- matchResult
      , HoleExpr e <- lookupSubst sub "x" = do
        e' <- ... some fancy IO computation using 'e' ...
        return $ MatchResult (extendSubst sub "x" (HoleExpr e')) t
      | otherwise = NoMatch

    main :: IO ()
    main = runScript $ \opts -> do
      rrs <- parseRewrites opts [Adhoc "forall x. ... = ..."]
      return $ apply
        [ setRewriteTransformer fancyMigration rr | rr <- rrs ]

Since the `MatchResultTransformer` can also modify the `Template`, you can construct an entirely novel right-hand side, add additional imports, or inject new dependent rewrites.

defaultTransformer :: MatchResultTransformer #

The default transformer. Returns the `MatchResult` unchanged.

## Functions on Rewrites

addRewriteImports :: AnnotatedImports -> Rewrite ast -> Rewrite ast #

Add imports to a `Rewrite`. Whenever the `Rewrite` successfully rewrites an expression, the imports are inserted into the enclosing module.

setRewriteTransformer :: MatchResultTransformer -> Rewrite ast -> Rewrite ast #

Set the `MatchResultTransformer` for a `Rewrite`.

toURewrite :: Matchable ast => Rewrite ast -> Rewrite Universe #

Inject a type-specific rewrite into the universal type.

fromURewrite :: Matchable ast => Rewrite Universe -> Rewrite ast #

Project a type-specific rewrite from the universal type.

ppRewrite :: Rewrite Universe -> String #

Pretty-print a `Rewrite` for debugging.

rewritesWithDependents :: [Rewrite ast] -> [Rewrite ast] #

Filter a list of rewrites for those that introduce dependent rewrites.

# Internal

data RewriterResult ast #

Wrapper that allows us to attach extra derived information to the `Template` supplied by the `Rewrite`. Saves the user from specifying it.

Constructors

RewriterResult |

Fields

- rrOrigin :: SrcSpan
- rrQuantifiers :: Quantifiers
- rrTransformer :: MatchResultTransformer
- rrTemplate :: Template ast

#### Instances

Instances details

Functor RewriterResult # |
Instance details Defined in Retrie.Types Methods fmap :: (a -> b) -> RewriterResult a -> RewriterResult b # (<$) :: a -> RewriterResult b -> RewriterResult a #

data ParentPrec #

Precedence of parent node in the AST.

Constructors

HasPrec Fixity | Parent has precedence info.
IsLhs | We are a pattern in a left-hand-side
IsHsAppsTy | Parent is HsAppsTy
NeverParen | Based on parent, we should never add parentheses.

data Context #

`Context` maintained by AST traversals.

Constructors

Context |

Fields

- ctxtBinders :: [RdrName]

  Stack of bindings of which we are currently in the right-hand side. Used to avoid introducing self-recursion.

- ctxtDependents :: Rewriter

  The rewriter we apply to determine whether to add context-dependent rewrites to `ctxtRewriter`. We keep this separate because most of the time it is empty, and we don't want to match every rewrite twice.

- ctxtFixityEnv :: FixityEnv

  Current FixityEnv.

- ctxtInScope :: AlphaEnv

  In-scope local bindings. Used to detect shadowing.

- ctxtParentPrec :: ParentPrec

  Precedence of parent (app = HasPrec 10, infix op = HasPrec $ op precedence)

- ctxtRewriter :: Rewriter

  The rewriter we should use to mutate the code.

- ctxtSubst :: Maybe Substitution

  If present, update substitution with binder renamings. Used to implement capture-avoiding substitution.