jsmw-0.1: Language/JSMW/Cond.hs
------------------------------------------------------------------
-- |
-- Module : Language.JSMW.Cond
-- Copyright : (c) Dmitry Golubovsky, 2009
-- License : BSD-style
--
-- Maintainer : golubovsky@gmail.com
-- Stability : experimental
-- Portability : portable
--
--
--
-- Encoding of Javascript conditionals.
------------------------------------------------------------------
module Language.JSMW.Cond (
-- * Switch
-- $switch
switch
,(-->)
,none
) where
import Control.Monad
import Control.Monad.RWS
import Control.Monad.Writer
import BrownPLT.JavaScript
import BrownPLT.JavaScript.PrettyPrint
import Data.DOM
import Data.DOM.Dom
import Language.JSMW.Monad
#ifdef __HADDOCK__
import Data.DOM.JSMWExt
import Language.JSMW.Arith
#endif
class Switchable a b where
toSwitch :: a -> Expression b
instance (Integral a) => Switchable a Double where
toSwitch = number
instance Switchable Bool Bool where
toSwitch = bool
instance Switchable String String where
toSwitch = string
-- Switch with labels of type s, scrutinee of type r, defined on container c,
-- with case branches returning expressions of type e.
type Switch s r c e a = Writer [(s, Maybe (Expression r), JSMW c (Expression e))] a
-- $switch The following functions help encode the Javascript @switch@ and @case@ statements.
-- The @Switchable@ class seen in the type signatures, and its necessary instances are
-- defined internally by this module. The @switch@ statement can be encoded for numeric,
-- boolean, and string scrutinees.
--
-- Unlike Javascript @switch@, a value can be returned from JSMW 'switch' (see
-- the second example). All expressions matching case labels must return values of the same
-- type.
--
-- Below are examples of @switch@ statements encoded in JSMW.
--
-- @
-- let p = 'number' 5 - ('number' 1 - 'number' 4)
-- 'switch' p $ do
-- 5 '-->' 'alert' ('string' \"This is Five\")
-- 8 '-->' 'alert' ('string' \"This is Eight\")
-- 'none' $ 'toString' p >>= 'alert'
-- ...
-- n2 <- 'switch' ctrl $ do
-- True '-->' return (n - 'number' 1)
-- False '-->' return (n + 'number' 1)
-- @
-- | Encode a @switch@ statement.
switch :: (Switchable s r, CElement c)
=> Expression r -> Switch s r c e a -> JSMW c (Expression e)
switch scrut sw = do
sv <- once =<< return scrut
let ccst = execWriter sw
rt = undefined :: e
ccs <- mapM (\(_, cex, cjsmw) -> do
st <- get
curc <- once =<< ask
let (finx, fins, stms) = runJSMWWith curc st cjsmw
blk = getBlock (finx, fins, stms)
bstms = unBlock blk
unBlock (BlockStmt a bss) = bss
unBlock s = [s]
put fins
let constr = case cex of
Just cex -> CaseClause rt (cex /\ rt)
Nothing -> CaseDefault rt
return (constr bstms)) ccst
let swstmt = BlockStmt rt [SwitchStmt rt (sv /\ rt) ccs
, ThrowStmt rt (StringLit rt nmmsg)]
nmmsg = "No match in switch statement, scrutinee: " ++ show (expr scrut)
fun = FuncExpr rt [] swstmt
fv <- mkNewVar
writeStmt (ExprStmt () (AssignExpr () OpAssign (VarRef () (Id () fv)) (fun /\ ())))
once =<< return (CallExpr rt (VarRef rt (Id rt fv)) [])
-- | Encode a case label. The first (left) argument is a literal describing
-- the value of the label. Note that the left argument must be a Haskell
-- literal, not a Javascript expression. In other words, for boolean labels,
-- use 'True' rather than 'true'. The second (right) argument is a JSMW monadic
-- expression matching the label. @Break@ statements are inserted automatically
-- (that is, fall-through case labels are not permitted).
(-->) :: (Switchable s r, CElement c) => s -> JSMW c (Expression e) -> Switch s r c e ()
x --> y = tell [(x, Just $ toSwitch x, y)]
-- | Encode a @default:@ case label, that is, what action should be taken if none
-- of the case labels matches the scrutinee.
--
-- In both 'none' and '-->', JSMW monadic expression should be of the same type.
-- Also note that if no case label matches the scrutinee value, and no default
-- label has been defined, an exception will be thrown showing the scrutinee
-- name that did not match.
none :: (Switchable s r, CElement c) => JSMW c (Expression e) -> Switch s r c e ()
none y = tell [(undefined, Nothing, y)]