funcons-tools-0.1.0.0: src/Funcons/Parser.hs
{-# LANGUAGE OverloadedStrings #-}
module Funcons.Parser (Funcons.Parser.parse, Funcons.Parser.parser, pFuncons, pValues) where
import Text.ParserCombinators.Parsec
import Control.Applicative hiding ((<|>))
import Data.Char (isDigit)
import Data.Text (pack)
import Numeric
import Funcons.Lexer
import Funcons.Types
data Suffix = SuffixOp SeqSortOp
| SuffixSort Funcons
| SuffixBar Funcons
| NoSuffix
pFuncons = applySuffix <$> pFuncons0 <*> mSuffix
where mSuffix :: Parser Suffix
mSuffix = SuffixOp <$> pOp
<|> SuffixSort <$ doubleArrow <*> pFuncons
<|> try (SuffixBar <$ bar <*> pFuncons) -- necessary for builtin maps
<|> return NoSuffix
applySuffix f NoSuffix = f
applySuffix f (SuffixOp op) = FSortSeq f op
applySuffix f (SuffixSort f2) = FSortComputesFrom f f2
applySuffix f (SuffixBar f2) = FSortUnion f f2
-- introduced to bottom-out left-recursion
pFuncons0 :: Parser Funcons
pFuncons0 =
FList <$> brackets (commaSep pFuncons)
<|> try (FMap <$> braces (commaSep1 pKeyValue))
<|> FSet <$> braces (commaSep pFuncons)
<|> FTuple <$> parens (commaSep pFuncons)
<|> FSortComputes <$ doubleArrow <*> pFuncons
<|> maybe_apply . pack <$> identifier <*> optionMaybe pFuncons
<|> FValue <$> pValues
where pKeyValue :: Parser Funcons
pKeyValue = (\x y -> FTuple [x,y]) <$> pFuncons <* barredArrow <*> pFuncons
maybe_apply :: Name -> Maybe Funcons -> Funcons
maybe_apply nm mf = case mf of
Nothing -> FName nm
Just arg -> FApp nm arg
pOp :: Parser SeqSortOp
pOp = StarOp <$ reserved "*"
<|> PlusOp <$ reserved "+"
<|> QuestionMarkOp <$ reserved "?"
pValues :: Parser Values
pValues =
Char <$ char '\'' <*> anyChar <* char '\''
<|> String <$> stringLiteral
<|> EmptyTuple <$ reserved "void"
<|> List [] <$ reserved "nil"
<|> String "\n" <$ reserved "newline"
<|> (\(FValue v) -> v) . int_ . (0-) . readInt <$ char '-' <*> (many1 digit)
<|> (\(FValue v) -> v) . nat_ . readInt <$> (many1 digit)
<|> Atom <$ reserved "atom" <*> parens stringLiteral
<|> mk_rationals . readRational
<$> ((\m l -> m ++ "." ++ l) <$> many1 (satisfy isDigit) <* period <*>
many1 (satisfy isDigit))
where readInt :: String -> Int
readInt = read
{-
ComputationTypes and Types should really be parsed as arbitrary terms,
then evaluated to ComputationType/Type.
However, computation types can currently not be parsed because of left-recursion (see above).
pComputationType :: Parser ComputationTypes
pComputationType = Type <$> pTypes
<|> ComputesType <$ reserved "=>" <*> pTypes
<|> ComputesFromType <$> pTypes <* reserved "=>" <*> pTypes
pTypes :: Parser Types
pTypes =
Atoms <$ reserved "atoms"
<|> AsciiCharacters <$ reserved "ascii-characters"
<|> reserved "bounded-integers" *>
parens (BoundedIntegers <$> natural <* comma <*> natural)
<|> ComputationTypes <$ reserved "computation-types"
<|> EmptyType <$ reserved "empty-type"
<|> UnicodeCharacters <$ reserved "unicode-characters"
<|> Integers <$ reserved "integers"
<|> Strings <$ reserved "strings"
<|> Values <$ reserved "values"
<|> reserved "maps" *> parens (Maps <$> pTypes <* comma <*> pTypes)
<|> Types <$ reserved "types"
<|> ADTs <$ reserved "algebraic-datatypes"
-- <|> ADT
<|> reserved "bits" *> parens (Bits . fromInteger <$> natural)
<|> IEEEFloats <$ reserved "ieee-floats" <*> parens pIEEEFormat
<|> Lists <$ reserved "lists" <*> parens pTypes
<|> Multisets <$ reserved "multisets" <*> parens pTypes
<|> Naturals <$ reserved "naturals"
<|> Rationals <$ reserved "rationals"
<|> Thunks <$ reserved "thunks" <*> parens pComputationType
<|> Sets <$ reserved "sets" <*> parens pTypes
<|> Vectors <$ reserved "vectors" <*> parens pTypes
-- <|> Tuples <$ reserved "tuples" <*> parens (commaSep pTypes)
-- <|> parens (Union <$> pTypes <* reserved "|" <*> pTypes)
-}
pIEEEFormat :: Parser IEEEFormats
pIEEEFormat = Binary32 <$ reserved "binary32"
<|> Binary64 <$ reserved "binary64"
readRational :: String -> Rational
readRational = fst . head . readFloat
--------
parse :: FilePath -> String -> Funcons
parse = parser (whiteSpace *> pFuncons <* whiteSpace)
parser :: Parser a -> FilePath -> String -> a
parser p fp str = case Text.ParserCombinators.Parsec.parse p fp str of
Left err -> error (show err)
Right a -> a
reader :: Parser a -> FilePath -> String -> [(a, String)]
reader p fp str = [(parser p fp str, "")]
instance Read Funcons where
readsPrec d str = reader pFuncons "" str
instance Read Values where
readsPrec d str = reader pValues "" str