sunroof-compiler-0.2: Language/Sunroof/JS/Array.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Provides a more specific type for arrays in Javascript
-- (together with basic operations on them).
module Language.Sunroof.JS.Array
( JSArray
, array, newArray
, length'
, lookup'
, insert'
, push, pop
, shift, unshift
, forEach
, empty
) where
import Prelude hiding ( lookup, length )
import Data.List ( intercalate )
import Data.Boolean ( BooleanOf, IfB(..) )
import Language.Sunroof.JavaScript ( Expr, showExpr, literal )
import Language.Sunroof.Types
import Language.Sunroof.Classes ( Sunroof(..), SunroofValue(..), SunroofArgument(..) )
import Language.Sunroof.Selector ( JSSelector, index, (!) )
import Language.Sunroof.JS.Bool ( JSBool, jsIfB )
import Language.Sunroof.JS.Number ( JSNumber )
-- -------------------------------------------------------------
-- JSArray Type
-- -------------------------------------------------------------
-- | Type if arrays in Javascript. The type parameter
-- given the entry type.
data JSArray a = JSArray Expr
-- | Show the Javascript.
instance Show (JSArray a) where
show (JSArray v) = showExpr False v
-- | Arrays are first-class Javascript values.
instance (Sunroof a) => Sunroof (JSArray a) where
box = JSArray
unbox (JSArray o) = o
-- | The boolean of arrays are 'JSBool'.
type instance BooleanOf (JSArray a) = JSBool
-- | You can write branches that return arrays.
instance (Sunroof a) => IfB (JSArray a) where
ifB = jsIfB
-- -------------------------------------------------------------
-- JSArray Combinators
-- -------------------------------------------------------------
-- | Create a literal array from a Haskell list.
array :: (SunroofValue a, Sunroof (ValueOf a)) => [a] -> JS t (JSArray (ValueOf a))
array l = evaluate $ box $ literal $ "[" ++ intercalate "," (fmap (showExpr False . unbox . js) l) ++ "]"
-- | Create a new array object containing the given values.
newArray :: (SunroofArgument args, Sunroof a) => args -> JS t (JSArray a)
newArray args = cast `fmap` new "Array" args
-- | The empty array.
empty :: (Sunroof a) => JS t (JSArray a)
empty = evaluate $ box $ literal "[]"
-- | The @length@ property of arrays.
length' :: JSSelector JSNumber
length' = attr "length"
-- | A type-safe version of array lookup.
lookup' :: (Sunroof a) => JSNumber -> JSArray a -> a
lookup' n e = e ! index n
-- | A type-safe version of array insert.
insert' :: (Sunroof a) => JSNumber -> a -> JSArray a -> JS t ()
insert' n a e = e # index n := a
-- | Push a element into the array as if it was a stack.
-- Returns nothing instead of the new length.
-- See <http://www.w3schools.com/jsref/jsref_push.asp>.
push :: (SunroofArgument a, Sunroof a) => a -> JSArray a -> JS t ()
push a = invoke "push" a
-- | Adds a new element to the beginning of the array (queue).
-- Returns nothing instead of the new length.
-- See <http://www.w3schools.com/jsref/jsref_unshift.asp>.
unshift :: (SunroofArgument a, Sunroof a) => a -> JSArray a -> JS t ()
unshift a = invoke "unshift" a
-- | Pop a element from the array as if it was a stack.
-- See <http://www.w3schools.com/jsref/jsref_pop.asp>.
pop :: (Sunroof a) => JSArray a -> JS t a
pop = invoke "pop" ()
-- | Removes and return the first element of an array (dequeue).
-- See <http://www.w3schools.com/jsref/jsref_shift.asp>.
shift :: (Sunroof a) => JSArray a -> JS t a
shift = invoke "shift" ()
-- | Foreach iteration method provided by most browsers.
-- Execute the given action on each element of the array.
-- See
-- <https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach>,
-- <http://msdn.microsoft.com/en-us/library/ie/ff679980.aspx>.
forEach :: (Sunroof a, SunroofArgument a) => (a -> JS A ()) -> JSArray a -> JS t ()
forEach body arr = do
f <- function body
arr # invoke "forEach" f :: JS t ()
return ()