module Parser.Expression where

import Text.Parsec
import Text.Parsec.String
import Text.Parsec.Char

import Types
import Parser.Common

-- CALL --

call :: Parser Call
call = do
  pos <- getPosition
  name <- identifier
  openParen
  args <- expr `sepBy` (char ',')
  closeParen
  return $ Call pos name args

-- EXPRESSION --

expr :: Parser Expr
expr = do
  spaces
  intLit <|> charLit <|> boolLit <|> (try callExpr) <|> var

callExpr :: Parser Expr
callExpr = do
  c <- call
  return $ CallExpr c

var :: Parser Expr
var = do
  pos <- getPosition
  name <- identifier
  return $ ExprVar $ Var pos name

intLit :: Parser Expr
intLit = do
  pos <- getPosition
  str <- (string "0") <|> do
    a <- satisfy $ \c -> c `elem` ['1' .. '9']
    b <- many digit
    return $ a:b
  let val = (read str) :: Int
  return $ IntLitExpr $ IntLit pos val

charLit :: Parser Expr
charLit = do
  pos <- getPosition
  char '\''
  c <- newLineChar <|> anyChar
  char '\''
  return $ CharLitExpr $ CharLit pos c

newLineChar :: Parser Char
newLineChar = do
  char '\\'
  char 'n'
  return '\n'

boolLit :: Parser Expr
boolLit = do
  spaces
  pos <- getPosition
  stringValue <- (string "true") <|> (string "false")
  let value = stringValue == "true"
  return $ BoolLitExpr $ BoolLit pos value

