module Picologic.Parser (
  parseFile,
  parseExpr,
  readExpr,
) where

import Text.Parsec hiding (State)
import qualified Text.Parsec.Expr as Ex

import Picologic.AST
import Picologic.Lexer

infixOp :: String -> (a -> a -> a) -> Ex.Assoc -> Op a
infixOp x f = Ex.Infix (reservedOp x >> return f)

prefixOp :: String -> (a -> a) -> Op a
prefixOp x f = Ex.Prefix (reservedOp x >> return f)

operators :: [[Op Expr]]
operators = [
    [ prefixOp "~" Neg ],
    [
      infixOp "&" Conj Ex.AssocLeft,
      infixOp "|" Disj Ex.AssocLeft,
      infixOp "->" Implies Ex.AssocLeft,
      infixOp "<->" Iff Ex.AssocLeft
    ]
  ]

var :: Parser Expr
var = do
  x <- identifier
  return $ Var (Ident x)

constant :: Parser Expr
constant = (reserved "1" >> return Top)
       <|> (reserved "0" >> return Bottom)

cexpr :: Parser Expr
cexpr =  Ex.buildExpressionParser operators cfactor

cfactor :: Parser Expr
cfactor =  constant
       <|> var
       <|> parens cexpr

parseExpr :: String -> Either ParseError Expr
parseExpr = parse (contents cexpr) "<stdin>"

readExpr :: String -> Expr
readExpr s = case parseExpr s of
  Left err -> error (show err)
  Right expr -> expr

parseFile :: FilePath -> IO (Either ParseError Expr)
parseFile fname = do
  fcontents <- readFile fname
  return $ parse (contents cexpr) fname fcontents