packages feed

peg-matching-0.1.0.0: src/Match/Rewrite.hs

{-|
Module      : Match.Rewrite
Description : Functions for rewriting syntax trees based on patterns.
Copyright   : (c) Guilherme Drummond, Rodrigo Ribeiro, 2025
License     : BSD-3-Clause
Maintainer  : rodrigo.ribeiro@ufop.edu.br
Stability   : experimental
Portability : POSIX

This module provides functions to rewrite ASTs ('ParsedTree')
based on patterns ('Pattern'). It uses pattern matching to replace
subtrees with new structures.
-}
module Match.Rewrite
    ( replace
    , rewrite
    ) where

import Syntax.Pattern (Pattern(..))
import Syntax.ParsedTree (ParsedTree(..))
import Match.Capture (capture)
import Data.Generics (mkT, everywhere)
import Syntax.Peg (Grammar)

{-|
Substitui uma subárvore em uma AST ('ParsedTree') com base em uma variável ('PatVar').

The 'replace' function checks if a subtree matches a variable and, if so,
replaces the corresponding subtree with the provided subtree.

@since 1.0.0
-}
replace :: Pattern -> ParsedTree -> (Pattern, ParsedTree) -> ParsedTree
replace (PatVar _ name)  t (PatVar _ name', t') = if name == name' then t' else t
replace (PatNT nt p)     (ParsedNT nt' t) subst = if nt == nt'
                                                    then ParsedNT nt' (replace p t subst)
                                                    else ParsedNT nt' t
replace (PatSeq p1 p2)   (ParsedSeq t1 t2)     subst = ParsedSeq (replace p1 t1 subst) (replace p2 t2 subst)
-- TODO: The following line was added to try and fix a problem of duplicating the 
-- contents of a variable during rewriting. As such, it may not be fully correct
replace (PatSeq p1 p2@(PatVar _ _)) (ParsedIndent t1 t2)  subst = ParsedIndent (replace p1 t1 subst) [replace p2 (ParsedStar t2) subst]
replace (PatSeq p1 p2)   (ParsedIndent t1 t2)  subst = ParsedIndent (replace p1 t1 subst) $ map (\ x -> replace p2 x subst) t2
replace (PatChoice p1 _) (ParsedChoiceLeft t)  subst = ParsedChoiceLeft $ replace p1 t subst
replace (PatChoice _ p2) (ParsedChoiceRight t) subst = ParsedChoiceRight $ replace p2 t subst
replace (PatStar p)      (ParsedStar ts)       subst = ParsedStar $ map (\ x -> replace p x subst) ts
replace _                t                     _     = t

{-|
Rewrites an AST ('ParsedTree') by replacing subtrees that match
a variable ('PatVar') with another pattern.

@since 1.0.0
-}
rewrite :: Grammar -> Pattern -> Pattern -> ParsedTree -> ParsedTree
rewrite g p p' = everywhere $ mkT (\x -> foldr ((flip . replace) p') x (concat (capture g p x)))