content: 
  {-# LANGUAGE ScopedTypeVariables #-}
  
  -- | 'JSSelector' are used to access fields of Javascript objects.
  module Language.Sunroof.Selector
    ( JSSelector
    , label, index
    , unboxSelector
    , (!)
    ) where
  
  import Data.String ( IsString(..) )
  import Data.Proxy ( Proxy(Proxy) )
  
  import Language.Sunroof.JavaScript ( Expr, E(Dot), ExprE(ExprE) )
  import Language.Sunroof.Classes ( Sunroof(..) )
  import Language.Sunroof.JS.String ( JSString, string )
  import Language.Sunroof.JS.Number ( JSNumber )
  
  -- | A 'JSSelector' selects a field or attribute from a Javascript object.
  --   The phantom type is the type of the selected value. Note the selected
  --   field or attributes may also array entries ('index').
  data JSSelector a = JSSelector Expr
  
  -- | Selectors are also Sunroof objects (they can be passed around).
  instance Sunroof a => Sunroof (JSSelector a) where
    box = JSSelector
    unbox (JSSelector o) = o
  
  -- | Selectors can be created from the name of their attribute.
  instance IsString (JSSelector a) where
    fromString = JSSelector . unbox . string
  
  instance Show (JSSelector a) where
    show (JSSelector ids) = show ids
  
  -- | Create a selector for a named field or attribute.
  --   For type safty it is adivsed to use this with an
  --   accompanying type signature. Example:
  --
  -- > array ! label "length"
  --
  --   See '!' for further information on usage.
  label :: JSString -> JSSelector a
  label = JSSelector . unbox
  
  -- | Create a selector for an indexed value (e.g. array access).
  --   For type safty it is adivsed to use this with an
  --   accompanying type signature. Example:
  --
  -- > array ! index 4
  --
  --   See '!' for further information on usage.
  index :: JSNumber -> JSSelector a
  index = JSSelector . unbox
  
  -- | Provided for internal usage by the compiler. Unwraps the
  --   selector.
  unboxSelector :: JSSelector a -> Expr
  unboxSelector (JSSelector e) = e
  
  ---------------------------------------------------------------
  
  infixl 1 !
  
  -- | Operator to use a selector on a Javascript object. Examples:
  --
  -- > array ! label "length"
  -- > array ! index 4
  (!) :: forall o a . (Sunroof o, Sunroof a) => o -> JSSelector a -> a
  (!) arr (JSSelector idx) = box $ Dot (ExprE $ unbox arr)
                                       (ExprE $ idx)
                                       (typeOf (Proxy :: Proxy a))
  
  
  