packages feed

camfort-0.700: source.lhs

> {-# LANGUAGE TypeSynonymInstances #-}
> {-# LANGUAGE FlexibleInstances #-}

> import Text.ParserCombinators.Parsec
> import Text.ParserCombinators.Parsec.Expr
> import Text.Parsec.Char
> import qualified Text.ParserCombinators.Parsec.Token

> import Debug.Trace

> import Control.Comonad

> data Expr a = Plus a (Expr a) (Expr a) | Num a Int deriving Show

> instance Comonad Expr where
>     extract (Plus x _ _) = x
>     extract (Num x _)    = x 

> tagRoot :: Expr a -> a -> Expr a
> tagRoot (Plus _ e1 e2) x = Plus x e1 e2
> tagRoot (Num _ n)      x = Num x n

> instance Functor Expr where
>     fmap f (Plus x e1 e2) = Plus (f x) (fmap f e1) (fmap f e2)
>     fmap f (Num x n) = Num (f x) n

> data ExprZ a = ExprZ (Path a) (Expr a) deriving Show
> data Path a = L a (Path a) (Expr a) | R a (Path a) (Expr a) | Top deriving Show

> left (ExprZ p (Plus n l r)) = ExprZ (L n p r) l 
> left (ExprZ p (Num a n))    = ExprZ p (Num a n)

> right (ExprZ p (Plus n l r)) = ExprZ (R n p l) r
> right (ExprZ p (Num a n))    = ExprZ p (Num a n)

> up (ExprZ (L a p r) l) = ExprZ p (Plus a l r)
> up (ExprZ (R a p l) r) = ExprZ p (Plus a l r)
> up (ExprZ Top e)       = ExprZ Top e

> isTop (ExprZ Top _) = True
> isTop _             = False

> isLeaf (ExprZ _ (Num _ _)) = True
> isLeaf _                   = False

> insertP :: FlipFlag a => ExprZ a -> Expr a -> ExprZ a
> insertP (ExprZ p e) e' = ExprZ p (tagRoot e' (flipFlag $ extract e))

> class FlipFlag t where
>     flipFlag :: t -> t

> instance FlipFlag Annotation where
>     flipFlag (ps, flag) = (ps, not flag)

> instance Functor Path where
>     fmap f Top = Top
>     fmap f (L x p t) = L (f x) (fmap f p) (fmap f t)
>     fmap f (R x p t) = R (f x) (fmap f p) (fmap f t)

> instance Functor ExprZ where
>     fmap f (ExprZ p t) = ExprZ (fmap f p) (fmap f t)

> instance Comonad ExprZ where
>     extract (ExprZ p (Num x n)) = x
>     extract (ExprZ p (Plus x _ _)) = x

>     extend k tz = fmap k (ExprZ (cjoinP tz) (cjoinT tz))

> cjoinT :: ExprZ t -> Expr (ExprZ t)
> cjoinT t@(ExprZ p (Num x n)) = Num t n
> cjoinT t = Plus t (cjoinT . left $ t) (cjoinT . right $ t)

> cjoinP :: ExprZ t -> Path (ExprZ t)
> cjoinP (ExprZ Top t) = Top
> cjoinP z@(ExprZ (L _ _ _) _) = L (up z) (cjoinP (up z)) (cjoinT (right . up $ z)) 
> cjoinP z@(ExprZ (R _ _ _) _) = R (up z) (cjoinP (up z)) (cjoinT (left . up $ z)) 

> type Annotation =  (((Line, Column), (Line, Column)), Bool)

> tagPos p = do pos  <- getPosition
>               x    <- p 
>               pos' <- getPosition
>               return $ tagRoot x ((((sourceLine pos, sourceColumn pos), 
>                                           (sourceLine pos', sourceColumn pos')), False))

> expr = tagPos $ (try exprNum) <|> exprPlus

> exprPlus = do string "("
>               spaces
>               e1 <- expr
>               spaces
>               string "+"
>               spaces
>               e2 <- expr
>               spaces
>               string ")"
>               return $ Plus undefined e1 e2 

> exprNum = do n <- many1 digit
>              return $ Num undefined (read n)

         
> doParse :: String -> Expr Annotation
> doParse input = let p = do { e <- expr; eof; return e }
>                 in case (runParser p () "" input) of
>                      Left err  -> error (show err)
>                      Right x   -> x
>                 

> ppr (Plus _ e1 e2) = "(" ++ ppr e1 ++ " + " ++ ppr e2 ++ ")"
> ppr (Num _ n)      = show n

> inBounds x (l, u) = x >= l && x < u

> takeBounds ((ll, lc), (ul, uc)) inp = takeBounds' ((ll, lc), (ul, uc)) [] inp

> takeBounds' ((ll, lc), (ul, uc)) tk inp =
>     if (ll == ul && lc == uc) then (reverse tk, inp)
>     else case inp of []             -> (reverse tk, inp)
>                      ([]:ys)        -> takeBounds' ((ll+1, 0), (ul, uc)) ('\n':tk) ys
>                      ((x:xs):ys)    -> takeBounds' ((ll, lc+1), (ul, uc)) (x:tk) (xs:ys)


> pprint input z = pprint' (1, 1) (lines input) z

> pprint' :: (Int, Int) -> [String] -> ExprZ Annotation -> String
> pprint' (l, c) []      _ = ""
> pprint' (l, c) ([]:[]) z = ""
> pprint' (l, c) ([]:xs) z = pprint' (l+1, 0) xs z ++ "\n"
> pprint' (l, c) inp z@(ExprZ p e)
>      | (inBounds (l, c) (fst $ extract z)) = 
>                    if (snd $ extract z) then ppr e
>                    else 
>                         case e of 
>                           Num ((lb, ub), _) _ -> let (tk, rest) = takeBounds (lb, ub) inp
>                                                  in tk
>                           Plus ((lb, ub), _) _ _ ->
>                                                   let lfb = fst $ extract $ left z
>                                                       rfb = fst $ extract $ right z
>                                                       (p1, rest1) = takeBounds (lb, fst $ lfb) inp
>                                                       p2 = pprint' (fst $ lfb) rest1 (left z)
>                                                       (_, inp') = takeBounds (fst $ lfb, snd $ lfb) rest1
>                                                       (p3, rest2) = takeBounds (snd $ lfb, fst $ rfb) inp'
>                                                       p4 = pprint' (fst $ rfb) rest2 (right z)
>                                                       (_, inp'') = takeBounds (fst $ rfb, snd $ rfb) rest2
>                                                       (p5, rest3) = takeBounds (snd $ rfb, ub) inp''
>                                                   in p1 ++ p2 ++ p3 ++ p4 ++ p5
>      | otherwise = pprint' (l, c) inp (up z)

> foo = let input = "((1 +   2) +  3  )"
>           x = ExprZ Top $ doParse input
>           x' = right x
>           y = doParse "(3 + 4)"
>           z = insertP x' y 
>           w = doParse "(9 + (4 + 3))"
>           z' = insertP (left $ up $ z) w
>           z'' = up $ z'
>       in pprint input z''

 instance (Num a, Num b) => Num (a, b) where
     (a, b) + (x, y) = (a + x, b + y)
     (a, b) * (x, y) = (a * x, b * y)
     (a, b) - (x, y) = (a - x, b - y)