{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-} -- Module : Text.EDE.Internal.AST -- Copyright : (c) 2013-2015 Brendan Hay -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or -- you can obtain it at http://mozilla.org/MPL/2.0/. -- Maintainer : Brendan Hay -- Stability : experimental -- Portability : non-portable (GHC extensions) -- | AST smart constructors. module Text.EDE.Internal.AST where import Control.Comonad import Control.Comonad.Cofree import Data.Aeson.Types import Data.Foldable import Data.List.NonEmpty (NonEmpty(..)) import Data.Maybe import Data.Monoid (mempty) import Text.EDE.Internal.Types newtype Mu f = Mu (f (Mu f)) cofree :: Functor f => a -> Mu f -> Cofree f a cofree x = go where go (Mu f) = x :< fmap go f var :: Id -> Var var = Var . (:| []) eapp :: a -> [Exp a] -> Exp a eapp x [] = cofree x blank eapp _ [e] = e eapp _ (e:es) = foldl' (\x y -> extract x :< EApp x y) e es efun :: Id -> Exp a -> Exp a efun i e = let x = extract e in x :< EApp (x :< EFun i) e efilter :: Exp a -> (Id, [Exp a]) -> Exp a efilter e (i, ps) = let x = extract e in eapp x ((x :< EFun i) : e : ps) elet :: Maybe (Id, Exp a) -> Exp a -> Exp a elet m e = maybe e (\(i, b) -> extract b :< ELet i b e) m ecase :: Exp a -> [Alt (Exp a)] -> Maybe (Exp a) -> Exp a ecase p ws f = extract p :< ECase p (ws ++ maybe [] ((:[]) . wild) f) eif :: (Exp a, Exp a) -> [(Exp a, Exp a)] -> Maybe (Exp a) -> Exp a eif t ts f = foldr' c (fromMaybe (extract (fst t) `cofree` blank) f) (t:ts) where c (p, w) e = extract p :< ECase p [true w, false e] eempty :: Exp a -> Exp a -> Maybe (Exp a) -> Exp a eempty v e = maybe e (eif (efun "!" (efun "empty" v), e) [] . Just) true, false, wild :: Exp a -> Alt (Exp a) true = (PLit (Bool True),) false = (PLit (Bool False),) wild = (PWild,) blank :: Mu ExpF blank = Mu (ELit (String mempty))