module Analyzer.ConstExpressionConverters where
import Analyzer.AnalyzedAst (Expression (ExprValue), Value (..))
import Analyzer.AnalyzedType (Type (..))
import Data.Either.Extra (mapLeft)
import MaybeVoid (MaybeVoid (..))
import qualified Parser.Ast as Ast
import qualified PrimitiveValue as PV
simplifyConstExpr :: Ast.Expression -> Either Err (MaybeVoid Type, Expression)
simplifyConstExpr :: Expression -> Either Err (MaybeVoid Type, Expression)
simplifyConstExpr Expression
expression = do
PrimitiveValue Integer
constant <- Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
expression
case PrimitiveValue Integer
constant of
PV.PrimNum Integer
c -> do
Int
c' <- Integer -> Either Err Int
convertIntegerToInt Integer
c
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> MaybeVoid a
NonVoid Type
TInt, Value -> Expression
ExprValue forall a b. (a -> b) -> a -> b
$ Int -> Value
ValInt Int
c')
PV.PrimBool Bool
c -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> MaybeVoid a
NonVoid Type
TBool, Value -> Expression
ExprValue forall a b. (a -> b) -> a -> b
$ Bool -> Value
ValBool Bool
c)
PV.PrimString Text
c -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> MaybeVoid a
NonVoid Type
TString, Value -> Expression
ExprValue forall a b. (a -> b) -> a -> b
$ Text -> Value
ValString Text
c)
simplifyConstIntExpr :: Ast.Expression -> Either Err Int
simplifyConstIntExpr :: Expression -> Either Err Int
simplifyConstIntExpr Expression
expression = do
PrimitiveValue Integer
constant <- Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
expression
case PrimitiveValue Integer
constant of
PV.PrimNum Integer
c -> Integer -> Either Err Int
convertIntegerToInt Integer
c
PrimitiveValue Integer
_ -> forall a b. a -> Either a b
Left Err
MismatchedTypes
convertIntegerToInt :: Integer -> Either Err Int
convertIntegerToInt :: Integer -> Either Err Int
convertIntegerToInt Integer
integer =
if forall a. Integral a => a -> Integer
toInteger (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
integer :: Int) forall a. Eq a => a -> a -> Bool
== Integer
integer
then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
integer
else forall a b. a -> Either a b
Left Err
NotInIntBounds
simplifyConstExpr' :: Ast.Expression -> Either Err (PV.PrimitiveValue Integer)
simplifyConstExpr' :: Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
expression = case Expression
expression of
Ast.ExprValue Value
val -> case Value
val of
Ast.ValInt Integer
c -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall num. num -> PrimitiveValue num
PV.PrimNum Integer
c
Ast.ValBool Bool
c -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall num. Bool -> PrimitiveValue num
PV.PrimBool Bool
c
Ast.ValString Text
c -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall num. Text -> PrimitiveValue num
PV.PrimString Text
c
Value
_ -> forall a b. a -> Either a b
Left Err
NotConstExpr
Ast.ExprUnaryOp UnaryOp
unOp Expression
expr -> do
PrimitiveValue Integer
expr' <- Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
expr
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft Err -> Err
mapErr forall a b. (a -> b) -> a -> b
$ forall num.
Integral num =>
UnaryOp -> PrimitiveValue num -> Either Err (PrimitiveValue num)
PV.primitiveUnOpApplication UnaryOp
unOp PrimitiveValue Integer
expr'
Ast.ExprBinaryOp BinaryOp
binOp Expression
lhs Expression
rhs -> do
PrimitiveValue Integer
lhs' <- Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
lhs
PrimitiveValue Integer
rhs' <- Expression -> Either Err (PrimitiveValue Integer)
simplifyConstExpr' Expression
rhs
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft Err -> Err
mapErr forall a b. (a -> b) -> a -> b
$ forall num.
Integral num =>
BinaryOp
-> PrimitiveValue num
-> PrimitiveValue num
-> Either Err (PrimitiveValue num)
PV.primitiveBinOpApplication BinaryOp
binOp PrimitiveValue Integer
lhs' PrimitiveValue Integer
rhs'
Expression
_ -> forall a b. a -> Either a b
Left Err
NotConstExpr
mapErr :: PV.Err -> Err
mapErr :: Err -> Err
mapErr Err
err = case Err
err of
Err
PV.MismatchedTypes -> Err
MismatchedTypes
Err
PV.DivisionByZero -> Err
DivisionByZero
data Err
= MismatchedTypes
| DivisionByZero
| NotInIntBounds
| NotConstExpr