packages feed

ZipperAG-1.0.0: src/Language/ZipperAG.hs

{-|
Module      : ZipperAG
Description : Zipper-based Attribute Grammars in Haskell 
Copyright   : (c) Pedro Martins, 2013
                  José Nuno Macedo, 2020
License     : BSD3
Maintainer  : José Nuno Macedo <zenunomacedo@gmail.com>
Stability   : Experimental
Portability : Portable
-}
module Language.ZipperAG where

import Data.Generics.Zipper
import Data.Generics.Aliases (mkQ)
import Data.Maybe
import Data.Data (Data)

-- |Navigate to the n'th child
(.$) :: Zipper a -> Int -> Zipper a
z .$ 1 = fromJust (down' z)
z .$ n = fromJust (right ( z.$(n-1) ))

-- |Navigate to the parent node
parent = fromJust.up

-- |Tests if z is the n'th sibling
(.|) :: Zipper a -> Int -> Bool
z .| 1 = case left z of
  Nothing -> False
  _ -> True
z .| n = case left z of
  Nothing -> False
  Just x ->  x .| (n-1)

-- |Move N positions to the right on the zipper
(.$>) :: Zipper a -> Int -> Zipper a
zipper .$> n = let current = arity zipper
               in  (parent zipper).$(current+n)

-- |Move N positions to the left on the zipper
(.$<) :: Zipper a -> Int -> Zipper a
zipper .$< n = let current = arity zipper
               in  (parent zipper).$(current-n)

-- |Computes the arity of a zipper node. 
-- Arity refers to its position amongst its siblings. 
-- For example, the first sibling, with no nodes to the left, has arity 1. Move to the right once with @.$>1@ and its arity is now 2. 
arity :: Zipper a -> Int 
arity m = arity' m 1
 where arity' :: Zipper a -> Int -> Int
       arity' m n = case left m of
                     Nothing  -> n                     
                     Just m'  -> arity' m' (n+1)

-- |Prepare data for Attribute-Grammar manipulation. Alias for 'toZipper'. 
mkAG :: Data x => x -> Zipper x
mkAG = toZipper

-- |compute attribute __f__ of parent of zipper __z__ 
(.^) :: (Zipper a -> b) -> Zipper a -> b 
(.^) f z = f $ parent z 

-- |compute attribute __f__ at the root of zipper __z__ 
(.^^) :: (Zipper a -> b) -> Zipper a -> b
(.^^) f z = moveQ up (f z) (f.^^) z

-- |compute attribute __f__ of node navigating upwards in zipper __z__. Traverses upwards in the zipper and queries the first node that satisfies __p__
inherit :: Data n => (n -> Bool) -> (Zipper a -> b) -> Zipper a -> b 
inherit p f z = if query (mkQ False p) z then f z else (inherit p f).^ z