```-- |
-- Module      :  Language.C.Smart
-- Copyright   :  (c) Harvard University 2010-2011
--                (c) Geoffrey Mainland 2011-2013
-- Maintainer  :  mainland@eecs.harvard.edu

{-# LANGUAGE CPP #-}
{-# LANGUAGE QuasiQuotes #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Language.C.Smart where

import Language.C.Quote.C
import Language.C.Syntax as C

import qualified Data.Loc
import qualified Data.Symbol
import qualified Language.C.Syntax

instance Enum Exp where
toEnum n = [cexp|\$int:n|]

error "fromEnum: non-integer constant C expressions"

instance Num C.Exp where
e1 + e2       = [cexp|\$exp:e1 + \$exp:e2|]
e1 * e2       = [cexp|\$exp:e1 * \$exp:e2|]
e1 - e2       = [cexp|\$exp:e1 - \$exp:e2|]
negate e      = [cexp|-\$exp:e|]
abs e         = [cexp|abs(\$exp:e)|]
signum e      = [cexp|\$exp:e > 0 ? 1 : (\$exp:e < 0 ? -1 : 0)|]
fromInteger n = [cexp|\$int:n|]

instance Real C.Exp where
toRational [cexp|\$float:n|]   = n
toRational [cexp|\$double:n|]  = n
toRational [cexp|\$ldouble:n|] = n

toRational _ =
error "fromEnum: non-rational constant C expressions"

instance Integral C.Exp where
e1 `quotRem` e2 = ([cexp|\$exp:e1 / \$exp:e2|], [cexp|\$exp:e1 % \$exp:e2|])

toInteger [cexp|\$int:n|]   = n
toInteger [cexp|\$uint:n|]  = n
toInteger [cexp|\$lint:n|]  = n
toInteger [cexp|\$ulint:n|] = n

toInteger _ =
error "fromInteger: non-integer constant C expressions"

instance Fractional C.Exp where
e1 / e2 = [cexp|\$exp:e1 / \$exp:e2|]
recip e = [cexp|1 / \$exp:e|]

fromRational n = [cexp|\$double:n|]

instance Floating C.Exp where
pi            = [cexp|3.141592653589793238|]
exp e         = [cexp|exp(\$exp:e)|]
sqrt e        = [cexp|sqrt(\$exp:e)|]
log e         = [cexp|log(\$exp:e)|]
e1 ** e2      = [cexp|pow(\$exp:e1, \$exp:e2)|]
logBase e1 e2 = [cexp|log(\$exp:e2)/log(\$exp:e1)|]
sin e         = [cexp|sin(\$exp:e)|]
tan e         = [cexp|tan(\$exp:e)|]
cos e         = [cexp|cos(\$exp:e)|]
asin e        = [cexp|asin(\$exp:e)|]
atan e        = [cexp|atan(\$exp:e)|]
acos e        = [cexp|acos(\$exp:e)|]
sinh e        = [cexp|sinh(\$exp:e)|]
tanh e        = [cexp|tanh(\$exp:e)|]
cosh e        = [cexp|cosh(\$exp:e)|]
asinh e       = [cexp|asinh(\$exp:e)|]
atanh e       = [cexp|atanh(\$exp:e)|]
acosh e       = [cexp|acosh(\$exp:e)|]

infix 4 ===
(===) :: C.Exp -> C.Exp -> C.Stm
e1 === e2 = [cstm|\$exp:e1 = \$exp:e2;|]

infix 4 +=
(+=) :: C.Exp -> C.Exp -> C.Stm
e1 += e2 = [cstm|\$exp:e1 += \$exp:e2;|]
```