laborantin-hs-0.1.1.3: Laborantin/Query/Parse.hs
{-# LANGUAGE TupleSections #-}
module Laborantin.Query.Parse (expr, parseUExpr) where
import Laborantin.Types (UExpr (..))
import Control.Applicative ((<$>),(<*>),(*>),(<*))
import qualified Data.Text as T
import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.Combinator
import Data.Maybe (fromJust)
parseUExpr :: String -> Either ParseError UExpr
parseUExpr = parse expr ""
expr :: Parsec String u UExpr
expr = foldl chainl1 term [try inclOp, try mulOp, try addOp, try compOp, try boolOp]
where term = expr' <|> negated <|> ary <|> literal <|> special
where expr' = char '(' *> expr <* char ')'
negated :: Parsec String u UExpr
negated = UNot <$> (spaces *> char '!' *> spaces *> expr)
ary :: Parsec String u UExpr
ary = UL <$> (char '[' *> (expr `sepBy` (spaces >> char ',' >> spaces)) <* char ']')
binOp xs = do
spaces
val <- foldl1 (<|>) (map (try . string . fst) xs)
spaces
return $ fromJust (lookup val xs)
addOp = binOp [("+",UPlus),("-",UMinus)]
mulOp = binOp [("*",UTimes),("/",UDiv)]
boolOp = binOp [("and",UAnd),("or",UOr)]
compOp = binOp [(">=",UGte),(">",UGt),("==",UEq),("<=",ULte),("<",ULt)]
inclOp = binOp [("in",UContains), ("~>",UContains)]
literal :: Parsec String u UExpr
literal = bool <|> (UN <$> number) <|> (US . T.pack <$> quotedString)
special :: Parsec String u UExpr
special = try scname <|> try scstatus <|> scparam
scname,scstatus,scparam :: Parsec String u UExpr
scname = string "@sc.name" *> return UScName
scstatus = string "@sc.status" *> return UScStatus
scparam = UScParam . T.pack <$> (syntax1 <|> syntax2)
where syntax1 = string "@sc.param" *> spaces *> quotedString
syntax2 = char ':' *> plainString
quotedString :: Parsec String u String
quotedString = char '"' *> many (noneOf "\"") <* char '"'
plainString :: Parsec String u String
plainString = many (noneOf " ")
number :: Parsec String u (Rational)
number = do
(dec,frac) <- (try decFrac) <|> (try dec)
return $ read (dec ++ frac ++ " % 1" ++ (map snd $ zip frac (repeat '0')))
dec,decFrac :: Parsec String u (String,String)
dec = (,"") <$> many1 digit
decFrac = do a <- many1 digit
char '.'
b <- many1 digit
return (a,b)
bool :: Parsec String u UExpr
bool = true <|> false <|> fail "bool"
where true = string "true" >> return (UB True)
false = string "false" >> return (UB False)