content: -- |ECMAScript 3 syntax. /Spec/ refers to the ECMA-262 specification,
  -- 3rd edition.
  {-# LANGUAGE DeriveDataTypeable #-}
  {-# LANGUAGE DeriveFoldable     #-}
  {-# LANGUAGE DeriveFunctor      #-}
  {-# LANGUAGE DeriveGeneric      #-}
  {-# LANGUAGE DeriveTraversable  #-}
  {-# LANGUAGE FlexibleInstances  #-}
  {-# LANGUAGE OverloadedStrings  #-}
  
  module Language.Rsc.AST.Syntax (
      JavaScript(..)
    , unJavaScript
    , Statement(..)
    , ClassElt(..)
    , isIterationStmt
    , isStaticClassElt
    , CaseClause(..)
    , CatchClause(..)
    , ForInit(..)
    , ForInInit(..)
    , VarDecl(..)
    , Expression(..)
    , InfixOp(..)
    , AssignOp(..)
    , unId
    , PrefixOp(..)
    , Prop(..)
    , UnaryAssignOp(..)
    , LValue (..)
    , EnumElt(..)
    , BuiltinOp(..)
    , SyntaxKind (..)
  
    , Consumable(..)
    , Consume
    , onlyCtxTyped
  
    , undefinedVar
  
    , mapStmtM
    , mapExprM
  
    ) where
  
  import           Data.Default
  import           Data.Generics          (Data, Typeable)
  import qualified Data.Traversable       as T
  import           GHC.Generics
  import           Language.Rsc.Locations
  import           Language.Rsc.Names
  
  data JavaScript a   -- | A script in \<script\> ... \</script\> tags.
    = Script a [Statement a]
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  instance Default a => Default (JavaScript a) where
    def = Script def []
  
  -- | extracts statements from a JavaScript type
  unJavaScript :: JavaScript a -> [Statement a]
  unJavaScript (Script _ stmts) = stmts
  
  -- | Infix operators: see spec 11.5-11.11
  data InfixOp = OpLT         -- ^ @<@
               | OpLEq        -- ^ @<=@
               | OpGT         -- ^ @>@
               | OpGEq        -- ^ @>=@
               | OpIn         -- ^ @in@
               | OpInstanceof -- ^ @instanceof@
               | OpEq         -- ^ @==@
               | OpNEq        -- ^ @!=@
               | OpStrictEq   -- ^ @===@
               | OpStrictNEq  -- ^ @!===@
               | OpLAnd       -- ^ @&&@
               | OpLOr        -- ^ @||@
               | OpMul        -- ^ @*@
               | OpDiv        -- ^ @/@
               | OpMod        -- ^ @%@
               | OpSub        -- ^ @-@
               | OpLShift     -- ^ @<<@
               | OpSpRShift   -- ^ @>>@
               | OpZfRShift   -- ^ @>>>@
               | OpBAnd       -- ^ @&@
               | OpBXor       -- ^ @^@
               | OpBOr        -- ^ @|@
               | OpAdd        -- ^ @+@
      deriving (Show,Data,Typeable,Eq,Ord,Enum,Generic)
  
  -- | Assignment operators: see spec 11.13
  data AssignOp = OpAssign         -- ^ simple assignment, @=@
                | OpAssignAdd      -- ^ @+=@
                | OpAssignSub      -- ^ @-=@
                | OpAssignMul      -- ^ @*=@
                | OpAssignDiv      -- ^ @/=@
                | OpAssignMod      -- ^ @%=@
                | OpAssignLShift   -- ^ @<<=@
                | OpAssignSpRShift -- ^ @>>=@
                | OpAssignZfRShift -- ^ @>>>=@
                | OpAssignBAnd     -- ^ @&=@
                | OpAssignBXor     -- ^ @^=@
                | OpAssignBOr      -- ^ @|=@
    deriving (Show,Data,Typeable,Eq,Ord,Generic)
  
  -- | Unary assignment operators: see spec 11.3, 11.4.4, 11.4.5
  data UnaryAssignOp = PrefixInc  -- ^ @++x@
                     | PrefixDec  -- ^ @--x@
                     | PostfixInc -- ^ @x++@
                     | PostfixDec -- ^ @x-- @
    deriving (Show, Data, Typeable, Eq, Ord, Generic)
  
  -- | Prefix operators: see spec 11.4 (excluding 11.4.4, 11.4.5)
  data PrefixOp = PrefixLNot   -- ^ @!@
                | PrefixBNot   -- ^ @~@
                | PrefixPlus   -- ^ @+@
                | PrefixMinus  -- ^ @-@
                | PrefixTypeof -- ^ @typeof@
                | PrefixVoid   -- ^ @void@
                | PrefixDelete -- ^ @delete@
    deriving (Show,Data,Typeable,Eq,Ord,Generic)
  
  -- | Property names in an object initializer: see spec 11.1.5
  data Prop a = PropId a (Id a)     -- ^ property name is an identifier, @foo@
              | PropString a String -- ^ property name is a string, @\"foo\"@
              | PropNum a Integer   -- ^ property name is an integer, @42@
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | Left-hand side expressions: see spec 11.2
  data LValue a
    = LVar a String -- ^ variable reference, @foo@
    | LDot a (Expression a) String -- ^ @foo.bar@
    | LBracket a (Expression a) (Expression a) -- ^ @foo[bar]@
    deriving (Show, Eq, Ord, Data, Typeable, Functor,Foldable,Traversable,Generic)
  
  -- | Expressions, see spec 11
  data Expression a
    = StringLit a String                        -- ^ @\"foo\"@, spec 11.1.3, 7.8
    | RegexpLit a String Bool Bool
                                                -- ^ @RegexpLit a regexp global?  case_insensitive?@
                                                --   (regular expression, see spec 11.1.3, 7.8)
    | NumLit a Double                           -- ^ @41.99999@, spec 11.1.3, 7.8
    | IntLit a Int                              -- ^ @42@, spec 11.1.3, 7.8
    | BoolLit a Bool                            -- ^ @true@, spec 11.1.3, 7.8
    | NullLit a                                 -- ^ @null@, spec 11.1.3, 7.8
    | ArrayLit a [Expression a]                 -- ^ @[1,2,3]@, spec 11.1.4
    | ObjectLit a [(Prop a, Expression a)]      -- ^ @{foo:\"bar\", baz: 42}@, spec 11.1.5
  
    | HexLit a String                           -- ^ RefScript Hex literal (Used as BitVector)
  
    | ThisRef a                                 -- ^ @this@, spec 11.1.1
    | VarRef a (Id a)                           -- ^ @foo@, spec 11.1.2
    | DotRef a (Expression a) (Id a)            -- ^ @foo.bar@, spec 11.2.1
    | BracketRef a (Expression a)
                   (Expression a)
                                                -- ^ @foo[bar]@, spec 11.2.1
    | NewExpr a (Expression a)
                [Expression a]
                                                -- ^ @new foo(bar)@, spec 11.2.2
    | PrefixExpr a PrefixOp (Expression a)
                                                -- ^ @\@e@, spec 11.4 (excluding 11.4.4, 111.4.5)
    | UnaryAssignExpr a UnaryAssignOp
                        (LValue a)
                                                -- ^ @++x@, @x-- @ etc., spec 11.3, 11.4.4, 11.4.5
    | InfixExpr a InfixOp (Expression a)
                          (Expression a)
                                                -- ^ @e1\@e2@, spec 11.5, 11.6, 11.7, 11.8, 11.9, 11.10, 11.11
    | CondExpr a (Expression a)
        (Expression a) (Expression a)
                                                -- ^ @e1 ? e2 : e3@, spec 11.12
    | AssignExpr a AssignOp (LValue a)
                            (Expression a)
                                                -- ^ @e1 \@=e2@, spec 11.13
    | ListExpr a [Expression a]                 -- ^ @e1, e2@, spec 11.14
    | CallExpr a (Expression a) [Expression a]  -- ^ @f(x,y,z)@, spec 11.2.3
    | SuperRef a                                -- ^ @super@, TS spec
                                                -- funcexprs are optionally named
    | FuncExpr a (Maybe (Id a)) [Id a]
                 [Statement a]
                                                -- ^ @function f (x,y,z) {...}@, spec 11.2.5, 13
  
    --
    -- RefScript Cast expressions
    --
    | Cast  a (Expression a)                    -- ^ User inserted cast
    | Cast_ a (Expression a)                    -- ^ Implicitly created cast
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable,Generic)
  
  -- | Case clauses, spec 12.11
  data CaseClause a = CaseClause a (Expression a) [Statement a]
                      -- ^ @case e: stmts;@
                    | CaseDefault a [Statement a]
                      -- ^ @default: stmts;@
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | Catch clause, spec 12.14
  data CatchClause a = CatchClause a (Id a) (Statement a)
                       -- ^ @catch (x) {...}@
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | A variable declaration, spec 12.2
  data VarDecl a = VarDecl a (Id a) (Maybe (Expression a))
                   -- ^ @var x = e;@
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | for initializer, spec 12.6
  data ForInit a = NoInit                   -- ^ empty
                 | VarInit [VarDecl a]      -- ^ @var x, y=42@
                 | ExprInit (Expression a)  -- ^ @expr@
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | for..in initializer, spec 12.6
  data ForInInit a = ForInVar (Id a)        -- ^ @var x@
                   | ForInLVal (LValue a)   -- ^ @foo.baz@, @foo[bar]@, @z@
   deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable, Generic)
  
  -- | Statements, spec 12.
  data Statement a
    = BlockStmt a [Statement a] -- ^ @{stmts}@, spec 12.1
    | EmptyStmt a -- ^ @;@, spec 12.3
    | ExprStmt a (Expression a) -- ^ @expr;@, spec 12.4
    | IfStmt a (Expression a) (Statement a) (Statement a)
      -- ^ @if (e) stmt@, spec 12.5
    | IfSingleStmt a (Expression a) (Statement a)
      -- ^ @if (e) stmt1 else stmt2@, spec 12.5
    | SwitchStmt a (Expression a) [CaseClause a]
      -- ^ @switch (e) clauses@, spec 12.11
    | WhileStmt a (Expression a) (Statement a)
      -- ^ @while (e) do stmt@, spec 12.6
    | DoWhileStmt a (Statement a) (Expression a)
      -- ^ @do stmt while (e);@, spec 12.6
    | BreakStmt a (Maybe (Id a)) -- ^ @break lab;@, spec 12.8
    | ContinueStmt a (Maybe (Id a)) -- ^ @continue lab;@, spec 12.7
    | LabelledStmt a (Id a) (Statement a) -- ^ @lab: stmt@, spec 12.12
    | ForInStmt a (ForInInit a) (Expression a) (Statement a)
      -- ^ @for (x in o) stmt@, spec 12.6
    | ForStmt a (ForInit a) (Maybe (Expression a)) (Maybe (Expression a)) (Statement a)
      -- ^ @ForStmt a init test increment body@, @for (init; test, increment) body@, spec 12.6
    | TryStmt a (Statement a) (Maybe (CatchClause a)) (Maybe (Statement a))
      -- ^ @try stmt catch(x) stmt finally stmt@, spec 12.14
    | ThrowStmt a (Expression a)
      -- ^ @throw expr;@, spec 12.13
    | ReturnStmt a (Maybe (Expression a))
      -- ^ @return expr;@, spec 12.9
    | WithStmt a (Expression a) (Statement a)
      -- ^ @with (o) stmt@, spec 12.10
    | VarDeclStmt a [VarDecl a]
      -- ^ @var x, y=42;@, spec 12.2
    | FunctionStmt a (Id a) [Id a] (Maybe [Statement a])
      -- ^ @function f(x, y, z) [{...}]@, spec 13
    | ClassStmt a (Id a) [ClassElt a]
      -- ^ @class C<V> extends C'<T> {...}@
    | ModuleStmt a (Id a) [Statement a]
      -- ^ @module M {...}@
    | InterfaceStmt a (Id a)
      -- ^ @interface A {...}@ -- Placeholder for interface annotations
    | EnumStmt a (Id a) [EnumElt a]
  
    deriving (Show,Data,Typeable,Eq,Ord,Functor,Foldable,Traversable,Generic)
  
  -- | Class Elements
  data ClassElt a   -- Class element, spec 8.1.2
    = Constructor a [Id a] [Statement a]
    | MemberVarDecl a Bool {-static-} (Id a) (Maybe (Expression a))
    | MemberMethDecl a Bool {-static-} (Id a) [Id a] [Statement a]
    deriving (Show, Data, Typeable, Eq, Ord, Functor, Foldable, Traversable, Generic)
  
  -- | Enumeration Elements
  data EnumElt a = EnumElt a (Id a) (Expression a)
    deriving (Show, Data, Typeable, Eq, Ord, Functor, Foldable, Traversable, Generic)
  
  
  -- data Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async
  --   deriving (Show, Data, Typeable, Eq, Ord, Generic)
  
  -- | Returns 'True' if the statement is an /IterationStatement/
  -- according to spec 12.6.
  isIterationStmt :: Statement a -> Bool
  isIterationStmt s = case s of
    WhileStmt {}   -> True
    DoWhileStmt {} -> True
    ForStmt {}     -> True
    ForInStmt {}   -> True
    _              -> False
  
  
  isStaticClassElt :: ClassElt a -> Bool
  isStaticClassElt (Constructor _ _ _)        = False
  isStaticClassElt (MemberVarDecl _ s _ _)    = s
  isStaticClassElt (MemberMethDecl _ s _ _ _) = s
  
  -----------------------------------------------------------------------
  -- | Operators
  -----------------------------------------------------------------------
  
  data BuiltinOp = BIUndefined
                 | BIBracketRef
                 | BIBracketAssign
                 | BIImmArrayLit
                 | BIArrayLit
                 | BICallExpr
                 | BIDotRefCallExpr
                 | BIAnonymousFun
                 | BIFieldInit
                 | BIExprT
                 | BIUniqueArrayLit
                 | BIObjectLit
                 | BINumArgs
                 | BITruthy
                 | BISetProp
                 | BICondExpr
                 | BICastExpr
                 | BISuper
                 | BISuperVar
                 | BIForInKeys
                 | BICtorExit
                 | BICtor
                 | BIGetLength
                 | BIThis
                 deriving (Eq, Ord, Show)
  
  
  
  data SyntaxKind = FuncDeclKind | MethDeclKind | FieldDeclKind | CtorDeclKind | VarDeclKind
                  | ClassDeclKind | ModuleDeclKind | EnumDeclKind deriving ( Eq )
  
  
  -- | `consume`
  --
  
  type Consume = Bool
  
  class Consumable a where
    consumable :: a -> Bool
  
  instance Consumable (Expression a) where
    consumable (ObjectLit _ _ ) = True
    consumable (ArrayLit _ _  ) = True
    consumable (NewExpr _ _ _ ) = True
    consumable (CallExpr _ _ _) = True
    consumable (Cast_ _ e     ) = consumable e
    consumable _                = False
  
  instance Consumable (Statement a) where
    consumable (ReturnStmt _ _) = True
    consumable _                = False
  
  
  
  onlyCtxTyped :: Expression t -> Bool
  onlyCtxTyped FuncExpr{} = True
  onlyCtxTyped _          = False
  
  undefinedVar    = VarRef (srcPos dummySpan) undefinedId
  
  
  mapStmtM :: Monad m => (a -> m b) -> Statement a -> m (Statement b)
  mapStmtM = T.mapM
  
  mapExprM :: Monad m => (a -> m b) -> Expression a -> m (Expression b)
  mapExprM = T.mapM
  
  