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)