haste-compiler-0.5.3: src/Haste/AST/Constructors.hs
{-# LANGUAGE FlexibleInstances, TupleSections, CPP, OverloadedStrings #-}
#if __GLASGOW_HASKELL__ < 710
{-# LANGUAGE OverlappingInstances #-}
#endif
-- | Smart constructors for Haste's AST.
module Haste.AST.Constructors where
import Haste.AST.Syntax
import Haste.AST.Op
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.UTF8 as BS
-- | Literal types.
class Literal a where
lit :: a -> Exp
instance Literal Lit where
lit = Lit
instance Literal Double where
lit = lit . LNum
instance Literal Integer where
lit = lit . LInt
instance Literal Bool where
lit = lit . LBool
instance Literal BS.ByteString where
lit = lit . LStr
instance Literal [Char] where
lit = lit . BS.fromString
#if __GLASGOW_HASKELL__ < 710
instance Literal a => Literal [a] where
#else
instance {-# OVERLAPPABLE #-} Literal a => Literal [a] where
#endif
lit = Arr . map lit
instance Literal Exp where
lit = id
instance Literal Var where
lit = Var
litN :: Double -> Exp
litN = lit
litS :: BS.ByteString -> Exp
litS = lit
-- | Create a foreign variable. Foreign vars will not be subject to any name
-- mangling.
foreignVar :: BS.ByteString -> Var
foreignVar = Foreign
-- | A regular, internal variable. Subject to name mangling.
internalVar :: Name -> BS.ByteString -> Var
internalVar n c = Internal n c False
-- | A variable serving as a known location, to store return values from
-- expressions that get compiled into statements.
knownLocation :: Name -> BS.ByteString -> Var
knownLocation n c = Internal n c True
-- | Create a name, qualified or not.
name :: BS.ByteString -> Maybe (BS.ByteString, BS.ByteString) -> Name
name = Name
-- | A variable expression, for convenience.
var :: Name -> BS.ByteString -> Exp
var n comment = Var $ internalVar n comment
-- | Turn a Var into an expression.
varExp :: Var -> Exp
varExp = Var
-- | Call to a native method on an object. Always saturated.
callMethod :: Exp -> BS.ByteString -> [Exp] -> Exp
callMethod obj meth args = Call 0 (Method meth) obj args
-- | Foreign function call. Always saturated, never trampolines.
callForeign :: BS.ByteString -> [Exp] -> Exp
callForeign f = Call 0 (Fast False) (Var $ foreignVar f)
-- | A normal function call. May be unsaturated. A saturated call is always
-- turned into a fast call.
call :: Arity -> Exp -> [Exp] -> Exp
call arity f xs = foldApp $ Call (arity - length xs) (Normal True) f xs
callSaturated :: Exp -> [Exp] -> Exp
callSaturated f xs = Call 0 (Fast True) f xs
-- | "Fold" nested function applications into one, turning them into fast calls
-- if they turn out to be saturated.
foldApp :: Exp -> Exp
foldApp (Call arity (Normal tramp) (Call _ (Normal _) f args) args') =
Call arity (Normal tramp) (foldApp f) (args ++ args')
foldApp (Call 0 (Normal tramp) f args) =
Call 0 (Fast tramp) f args
foldApp (Call arity (Normal tramp) f args) | arity > 0 =
Fun newargs $ Return
$ Call arity (Fast tramp) f (args ++ map Var newargs)
where
newargs = newVars "_fa_" arity
foldApp ex =
ex
-- | Introduce n new vars.
newVars :: String -> Int -> [Var]
newVars prefix n =
map nv [1..n]
where
nv i = Internal (Name (BS.fromString $ prefix++show i) Nothing) "" False
-- | Create a thunk.
thunk :: Bool -> Stm -> Exp
thunk = Thunk
-- | Evaluate an expression that may or may not be a thunk.
eval :: Exp -> Exp
eval ex
| definitelyNotThunk ex = ex
| otherwise = Eval ex
-- | Create a tail call.
tailcall :: Exp -> Stm
tailcall = Tailcall
-- | A binary operator.
binOp :: BinOp -> Exp -> Exp -> Exp
binOp = BinOp
-- | Negate an expression.
not_ :: Exp -> Exp
not_ = Not
-- | Index into an array.
index :: Exp -> Exp -> Exp
index = Index
-- | Create a function.
fun :: [Var] -> Stm -> Exp
fun = Fun
-- | Create an array of expressions.
array :: [Exp] -> Exp
array = Arr
-- | Case statement.
-- Takes a scrutinee expression, a default alternative, a list of more
-- specific alternatives, and a continuation statement. The continuation
-- will be explicitly shared among all the alternatives.
case_ :: Exp -> (Stm -> Stm) -> [(Exp, Stm -> Stm)] -> Stm -> Stm
case_ ex def alts = Case ex (def stop) (map (\(e, s) -> (e, s stop)) alts)
-- | Return from a function.
ret :: Exp -> Stm
ret = Return
-- | Return from a thunk.
thunkRet :: Exp -> Stm
thunkRet = ThunkRet
-- | Create a new var with a new value.
newVar :: Reorderable -> Var -> Exp -> Stm -> Stm
newVar r lhs = Assign (NewVar r lhs)
-- | Reuse an old variable.
assignVar :: Reorderable -> Var -> Exp -> Stm -> Stm
assignVar r lhs = Assign (LhsExp r (Var lhs))
-- | Assignment without var. Performed for the side effect, so never
-- reorderable.
sideEffectingAssign :: Exp -> Exp -> Stm -> Stm
sideEffectingAssign lhs = Assign (LhsExp False lhs)
-- | Assignment expression.
assignEx :: Exp -> Exp -> Exp
assignEx = AssignEx
-- | Terminate a statement without doing anything at all.
stop :: Stm
stop = Stop
-- | Data constructor application.
conApp :: Exp -> [Exp] -> Exp
conApp tag = Obj . ((dataConTagField, tag) :) . zip dataConFieldNames
-- | Get the data constructor tag of the given algebraic value.
getTag :: Exp -> Exp
getTag e = e `select` dataConTagField
-- | Get the @n@th field of the given algebraic value.
getField :: Exp -> Int -> Exp
getField e n = e `select` (dataConFieldNames !! n)
-- | Get a member from an object.
select :: Exp -> BS.ByteString -> Exp
select = Member