packages feed

Eq-1.0: EqManips/InputParser/EqCode.hs

module EqManips.InputParser.EqCode
    ( program  -- if you want to define some definition before
    , expr     -- if you want to evaluate just an expression
    , parseFormula
    , perfectParse 
    , parseProgramm
    ) where


import Control.Applicative( (<$>), (<*) )
import Control.Monad.Identity

import EqManips.Types
import EqManips.Polynome
import EqManips.Linker
import EqManips.Algorithm.Utils

import Text.Parsec.Expr
import Text.Parsec
import Text.Parsec.Language( haskellStyle )
import qualified Text.Parsec.Token as P

-- | Helper function to parse a formula and apply all
-- needed algorithm to be able to apply them
parseFormula :: String -> Either ParseError (Formula ListForm)
parseFormula = either Left (Right . polynomizeFormula) . perfectParse

-- | Parse a formula and doesn't alter it's global form
-- (no polynomization)
perfectParse :: String -> Either ParseError (Formula ListForm)
perfectParse text = case runParser expr () "FromFile" text of
             Left e -> Left e
             Right f -> Right . listifyFormula
                              . linkFormula
                              $ Formula f

-- | Helper function to use to parse a programm.
-- Perform some transformations to get a usable
-- formula.
parseProgramm :: String -> Either ParseError [Formula ListForm]
parseProgramm text = rez
    where parsed = runParser program () "FromFile" text
          rez = case parsed of
                 Left a -> Left a
                 Right f -> Right $ map ( polynomizeFormula
                                        . listifyFormula
                                        . linkFormula
                                        . Formula ) f

-----------------------------------------------------------
--          Lexing defs
-----------------------------------------------------------
float :: Parsed st Double
float = P.float lexer

identifier :: Parsed st String
identifier = P.identifier lexer

reservedOp :: String -> Parsed st ()
reservedOp= P.reservedOp lexer

integer :: Parsed st Integer
integer = P.integer lexer

parens :: ParsecT String u Identity a -> ParsecT String u Identity a
parens = P.parens lexer

braces :: ParsecT String u Identity a -> ParsecT String u Identity a
braces = P.braces lexer

brackets :: ParsecT String u Identity a -> ParsecT String u Identity a
brackets = P.brackets lexer

whiteSpace :: Parsed st ()
whiteSpace = P.whiteSpace lexer

lexer :: P.GenTokenParser String st Identity
lexer  = P.makeTokenParser 
         (haskellStyle { P.reservedOpNames = [ "&", "|", "<", ">"
                                             , "*", "/", "+", "-"
                                             , "^", "=", "!", ":"
                                             , "_"
                                             ]
                       , P.identStart = letter
                       } )

-----------------------------------------------------------
--          Real "grammar"
-----------------------------------------------------------
type Parsed st b = ParsecT String st Identity b

program :: Parsed st [FormulaPrim]
program = sepBy expr (whiteSpace >> char ';' >> whiteSpace) <* whiteSpace
       <?> "program"

-- | Parser for the mini language is defined here
expr :: Parsed st FormulaPrim
expr = whiteSpace >> buildExpressionParser operatorDefs funCall
    <?> "expression"

operatorDefs :: OperatorTable String st Identity FormulaPrim
operatorDefs = 
    [ [postfix "!" (unOp OpFactorial)]
    , [prefix "-" (unOp OpNegate) ]
    , [binary "_" (\a b -> indexes a [b]) AssocLeft]
    , [binary "^" (binop OpPow) AssocLeft]
    , [binary "/" (binop OpDiv) AssocLeft, binary "*" (binop OpMul) AssocLeft]
    , [binary "+" (binop OpAdd) AssocLeft, binary "-" (binop OpSub) AssocLeft]
    , [binary "=" (binop OpEq)  AssocRight, binary "/=" (binop OpNe) AssocLeft
      ,binary "<" (binop OpLt)  AssocLeft,  binary ">"  (binop OpGt) AssocLeft
      ,binary "<=" (binop OpLe) AssocLeft,  binary ">=" (binop OpGe) AssocLeft]
    , [binary "&" (binop OpAnd) AssocLeft, binary "|" (binop OpOr) AssocLeft]
    , [binary "::" (binop OpCons) AssocRight]
    , [ binary ":>" (binop OpLazyAttrib) AssocRight
      , binary ":=" (binop OpAttrib) AssocRight]
    ]

funCall :: Parsed st FormulaPrim
funCall = do
    caller <- term
    (app caller <$> argList) <|> return caller
        where argSeparator = whiteSpace >> char ',' >> whiteSpace
              exprList = sepBy expr argSeparator
              argList = parens (whiteSpace >> (exprList <* whiteSpace))

listParser :: Parsed st FormulaPrim
listParser = do
    lst <- brackets $ sepBy expr (whiteSpace >> char ',' >> whiteSpace) <* whiteSpace
    return $ list lst

variable :: Parsed st FormulaPrim
variable = Variable <$> identifier
        <?> "variable"

term :: Parsed st FormulaPrim
term = try trueConst
    <|> try falseConst
    <|> try nilConst
    <|> variable
    <|> try ellipses
    <|> try (CFloat <$> float)
    <|> CInteger . fromInteger <$> integer
    <|> parens expr
    <|> meta Force <$> braces expr
    <|> listParser
    <?> "Term error"

ellipses :: Parsed st FormulaPrim
ellipses = return (NumEntity Ellipsis) <* (string "..." >> whiteSpace)

nilConst :: Parsed st FormulaPrim
nilConst = return (list []) <* (string "[]" >> whiteSpace)

trueConst :: Parsed st FormulaPrim
trueConst = return (Truth True) <* (string "true" >> whiteSpace)

falseConst :: Parsed st FormulaPrim
falseConst = return (Truth False) <* (string "false" >> whiteSpace)

-----------------------------------------------
----        Little helpers
-----------------------------------------------
binary :: String -> (a -> a -> a) -> Assoc -> Operator String st Identity a
binary name fun = Infix (do{ reservedOp name; return fun })

prefix :: String -> (a -> a) -> Operator String st Identity a
prefix  name fun       = Prefix (do{ reservedOp name; return fun })

postfix :: String -> (a -> a) -> Operator String st Identity a
postfix name fun = Postfix (do{ reservedOp name; return fun })

binop :: BinOperator -> FormulaPrim -> FormulaPrim -> FormulaPrim
binop op left right = binOp op [left, right]