{-  Exploring Languages with Interpreters and Functional Programming
    ELI Calculator, Imperative Core Languages; Values Module
    Copyright (C) 2017, 2018, H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2017-09-19: Developed for both Expression, Imperative Core languages
2017-09-20: Added toNumType to handle conversion of string to NumType,
            including detecting fixinteger overflow
2018-08-09: Updated for 2018 ELIFP textbook, Expression Language
            renamed ELI Calculator language

The intention of this module is to encapsulate definitions and
functions that know the specific representation of data of type
"ValType". Other modules should use the functions here to enable the
representation to be changed easily

The only type of values supported is integer. The type ValType should
always be used to represent this type.

Boolean values are represented as integers where 0 represents False
and 1 represents True. For some purposes, any nonzero value
represents True.

-}

module Values
    ( NumType, ValType, Name, defaultVal, toNumType,
      falseVal, trueVal, boolToVal, valToBool
    )
where

type Name    = String
type NumType = Int
type ValType = NumType

-- default value for ValType entities (such as variables)
defaultVal :: ValType
defaultVal = 0


{-  Function "toNumType" converts unsigned integer strings to NumType
    values. If that can be reasonably done, it returns the value
    wrapped in a Right. Otherwise, it returns an error message wrapped
    in a Left.

    This version is specific to NumType as Int.
-}

toNumType :: String -> Either String NumType
toNumType num =
    case (read num) :: Integer of
        x | x > maxInt -> Left (num ++ " exceeds Int range!")
        x              -> Right ((fromInteger x) :: Int)

maxInt = toInteger (maxBound :: Int)


{-  Constants "falseVal" and "trueVal" and functions "boolToVal"
    and valToBool encapsulate the representation of Boolean
    values as ImpCore values. 

    Function "boolToVal" takes a Haskell Bool value and returns
    the equivalent ImpCore encoding "falseVal" or "trueVal".

    Function "valToBool" takes a ValType value and returns the
    equivalent Haskell Bool value.

    For ImpCore, any nonzero integer value is considered as "truthy"
    in some circumstances. Only zero is consider as "falsey".
-}

falseVal, trueVal :: ValType
falseVal = 0
trueVal  = 1

boolToVal :: Bool -> ValType
boolToVal True  = trueVal
boolToVal False = falseVal

valToBool :: ValType -> Bool
valToBool x = (x /= falseVal)
