{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
module Nat (termToInt, intToTerm, parseTerm, pp, s, z) where
import Data.Text
import Text.ParserCombinators.Parsec.Char
import Text.ParserCombinators.Parsec
import Text.Printf
import Data.String
import qualified Data.List as L
import qualified Language.REST.MetaTerm as MT
import Language.REST.Op
import Language.REST.Types
import Language.REST.RuntimeTerm as RT
import Language.REST.Types
s = Op "s"
z = Op "z"
intToTerm :: Int -> RuntimeTerm
intToTerm 0 = App z []
intToTerm n = App s [intToTerm (n - 1)]
termToInt :: (MT.ToMetaTerm a) => a -> Maybe Int
termToInt t = go (MT.toMetaTerm t) where
go (MT.RWApp op []) | op == z = Just 0
go (MT.RWApp op [t1]) | op == s = (1 +) <$> go t1
go _ = Nothing
instance ToRuntimeTerm Int where
toRuntimeTerm = intToTerm
pp :: MT.ToMetaTerm a => a -> String
pp = prettyPrint (PPArgs []
[ ("+", "+")
, ("*", "*")
, ("∪", "∪")
, ("union", "∪")
, ("intersect", "∩")
] showInt)
where
showInt :: MT.MetaTerm -> Maybe Text
showInt t = fmap (pack . show) $ termToInt t
op :: GenParser Char st Op
op = fmap (Op . pack) (many (alphaNum <|> char '\''))
parens p = do
_ <- char '('
r <- p
_ <- char ')'
return r
term = try infixTerm <|> nonInfixTerm
where
nonInfixTerm = try (parens term) <|> try appTerm <|> try numberTerm <|> nullTerm
numberTerm = do
d1 <- digit
n <- many digit
return $ intToTerm (read (d1 : n))
infixOp =
try (string "+")
<|> (try (string "\\/") >> return "∪")
<|> string "*"
infixTerm = do
t1 <- nonInfixTerm
_ <- spaces
op <- infixOp
_ <- spaces
t2 <- nonInfixTerm
return $ App (Op (pack op)) [t1, t2]
nullTerm = do
o <- op
return $ App o []
appTerm = do
o <- op
trms <- parens $ sepBy1 term (char ',' >> spaces)
return $ App o trms
parseTerm :: String -> RuntimeTerm
parseTerm str =
case parse term "" str of
Left err -> error (show err)
Right t -> t
instance IsString RuntimeTerm where
fromString = parseTerm