egison-5.1.0: hs-src/Language/Egison/PrettyMath/AST.hs
{-# LANGUAGE FlexibleInstances #-}
{- |
Module : Language.Egison.PrettyMath.AST
Licence : MIT
-}
module Language.Egison.PrettyMath.AST
( MathValue(..)
, MathIndex(..)
, ToMathValue(..)
, isSub
, parseExpr
) where
import Data.Foldable (toList)
import Text.ParserCombinators.Parsec hiding (spaces)
import qualified Language.Egison.Data as E
import qualified Language.Egison.IExpr as E
import qualified Language.Egison.Math.CAS as CAS
data MathValue
= Atom String [MathIndex]
| NegativeAtom String
| Plus [MathValue]
| Multiply [MathValue]
| Div MathValue MathValue
| Power MathValue MathValue
| Func MathValue [MathValue]
| Tensor [MathValue] [MathIndex]
| Tuple [MathValue]
| Collection [MathValue]
| Quote MathValue
| Partial MathValue [MathValue]
deriving (Eq, Show)
data MathIndex
= Super MathValue
| Sub MathValue
deriving (Eq, Show)
isSub :: MathIndex -> Bool
isSub (Sub _) = True
isSub _ = False
class ToMathValue a where
toMathValue :: a -> MathValue
instance ToMathValue E.EgisonValue where
toMathValue (E.CASData cv) = toMathValue cv
toMathValue (E.Tuple es) = Tuple (map toMathValue es)
toMathValue (E.Collection es) = Collection (map toMathValue (toList es))
toMathValue (E.TensorData t) = toMathValue t
toMathValue e = Atom (show e) []
instance ToMathValue a => ToMathValue (E.Tensor a) where
toMathValue (E.Scalar _) = undefined
toMathValue (E.Tensor [_] xs js) = Tensor (map toMathValue (toList xs)) (map toMathIndex js)
toMathValue (E.Tensor [_, n] xs js) = Tensor (f (fromIntegral n) (map toMathValue (toList xs))) (map toMathIndex js)
where
f _ [] = []
f n xs = Tensor (take n xs) [] : f n (drop n xs)
toMathValue (E.Tensor _ _ _) = undefined
-- CASValue instances
instance ToMathValue CAS.CASValue where
toMathValue (CAS.CASInteger n) = toMathValue n
toMathValue (CAS.CASFactor sym) = toMathValue sym
toMathValue (CAS.CASPoly []) = Atom "0" []
toMathValue (CAS.CASPoly [t]) = toMathValue t
toMathValue (CAS.CASPoly ts) = Plus (map toMathValue ts)
toMathValue (CAS.CASFrac num (CAS.CASInteger 1)) = toMathValue num
toMathValue (CAS.CASFrac num (CAS.CASPoly [CAS.CASTerm (CAS.CASInteger 1) []])) = toMathValue num
toMathValue (CAS.CASFrac num denom) = Div (toMathValue num) (toMathValue denom)
instance ToMathValue CAS.CASTerm where
toMathValue (CAS.CASTerm coeff []) = toMathValue coeff
toMathValue (CAS.CASTerm (CAS.CASInteger 1) [x]) = toMathValue x
toMathValue (CAS.CASTerm (CAS.CASInteger 1) xs) = Multiply (map toMathValue xs)
toMathValue (CAS.CASTerm coeff xs) = Multiply (toMathValue coeff : map toMathValue xs)
instance ToMathValue Integer where
toMathValue n | n < 0 = NegativeAtom (show (-n))
toMathValue n = Atom (show n) []
instance {-# OVERLAPPING #-} ToMathValue (CAS.SymbolExpr, Integer) where
toMathValue (x, 1) = toMathValue x
toMathValue (x, n) = Power (toMathValue x) (toMathValue n)
instance ToMathValue CAS.SymbolExpr where
toMathValue (CAS.Symbol _ (':':':':':':_) []) = Atom "#" []
toMathValue (CAS.Symbol _ s js) = toMathValue' js (Atom s [])
where
toMathValue' [] acc = acc
toMathValue' (E.User x:js) (Partial e ps) =
toMathValue' js (Partial e (ps ++ [toMathValue x]))
toMathValue' (E.User x:js) e@Atom{} =
toMathValue' js (Partial e [toMathValue x])
toMathValue' (j:js) (Atom e is) =
toMathValue' js (Atom e (is ++ [toMathIndex j]))
toMathValue' _ _ = undefined -- TODO
toMathValue (CAS.Apply1 fn a1) =
case toMathValue fn of
Atom "^" [] -> Power (toMathValue fn) (toMathValue a1)
_ -> Func (toMathValue fn) [toMathValue a1]
toMathValue (CAS.Apply2 fn a1 a2) =
case toMathValue fn of
Atom "^" [] -> Power (toMathValue a1) (toMathValue a2)
_ -> Func (toMathValue fn) [toMathValue a1, toMathValue a2]
toMathValue (CAS.Apply3 fn a1 a2 a3) =
Func (toMathValue fn) [toMathValue a1, toMathValue a2, toMathValue a3]
toMathValue (CAS.Apply4 fn a1 a2 a3 a4) =
Func (toMathValue fn) [toMathValue a1, toMathValue a2, toMathValue a3, toMathValue a4]
toMathValue (CAS.Quote mExpr) = Quote (toMathValue mExpr)
toMathValue (CAS.QuoteFunction whnf) =
case E.prettyFunctionName whnf of
Just name -> Atom name []
Nothing -> Atom "f" []
toMathValue (CAS.FunctionData (CAS.CASPoly [CAS.CASTerm (CAS.CASInteger 1) [(CAS.Symbol _ s js, 1)]]) _) = toMathValue' js (Atom s [])
where
toMathValue' [] acc = acc
toMathValue' (E.User x:js) (Partial e ps) =
toMathValue' js (Partial e (ps ++ [toMathValue x]))
toMathValue' (E.User x:js) e@Atom{} =
toMathValue' js (Partial e [toMathValue x])
toMathValue' (j:js) (Atom e is) =
toMathValue' js (Atom e (is ++ [toMathIndex j]))
toMathValue' _ _ = undefined -- TODO
toMathValue (CAS.FunctionData name _) = toMathValue name
toMathIndex :: ToMathValue a => E.Index a -> MathIndex
toMathIndex (E.Sub x) = Sub (toMathValue x)
toMathIndex (E.Sup x) = Super (toMathValue x)
toMathIndex _ = undefined -- TODO
--
-- Parser
--
spaces :: Parser ()
spaces = skipMany1 space
spaces0 :: Parser ()
spaces0 = skipMany space
symbol :: Parser Char
symbol = oneOf "!$%&*+-/:<=>?@#"
parseAtom :: Parser MathValue
parseAtom = Atom <$> ((:) <$> (letter <|> symbol <|> digit) <*> many (letter <|> digit <|> symbol)) <*> many parseScript
parseAtom' :: Parser MathValue
parseAtom' = flip Atom [] <$> ((:) <$> (letter <|> symbol <|> digit) <*> many (letter <|> digit <|> symbol))
parsePartial :: Parser MathValue
parsePartial = Partial <$> parseAtom <*> many1 (char '|' >> parseAtom)
parseNegativeAtom :: Parser MathValue
parseNegativeAtom = char '-' >> NegativeAtom <$> ((:) <$> (letter <|> symbol <|> digit) <*> many (letter <|> digit <|> symbol))
parseList :: Parser [MathValue]
parseList = sepEndBy parseExpr spaces
parseScript :: Parser MathIndex
parseScript = Sub <$> (char '_' >> parseAtom')
<|> Super <$> (char '~' >> parseAtom')
parsePlus :: Parser MathValue
parsePlus = try (string "(+") >> spaces >> Plus <$> parseList <* char ')'
parseMultiply :: Parser MathValue
parseMultiply = try (string "(*") >> spaces >> Multiply <$> parseList <* char ')'
parseDiv :: Parser MathValue
parseDiv = try (string "(/") >> spaces >> Div <$> parseExpr <*> (spaces >> parseExpr) <* char ')'
parseFunction :: Parser MathValue
parseFunction = char '(' >> Func <$> parseAtom <* spaces <*> parseList <* char ')'
parseTensor :: Parser MathValue
parseTensor = string "[|" >> spaces0 >> Tensor <$> parseList <* spaces0 <* string "|]" <*> many parseScript
parseTuple :: Parser MathValue
parseTuple = char '[' >> Tuple <$> parseList <* char ']'
parseCollection :: Parser MathValue
parseCollection = char '{' >> Collection <$> parseList <* char '}'
parseQuote :: Parser MathValue
parseQuote = char '\'' >> Quote <$> parseExpr'
parseExpr' :: Parser MathValue
parseExpr' = parseNegativeAtom
<|> try parsePartial
<|> parseAtom
<|> parseQuote
<|> parsePlus
<|> parseMultiply
<|> parseDiv
<|> try parseFunction
<|> try parseTensor
<|> try parseTuple
<|> try parseCollection
parseExpr :: Parser MathValue
parseExpr = do
x <- parseExpr'
option x $ Power x <$> try (char '^' >> parseExpr')