{-# LANGUAGE CPP                #-}
{-# LANGUAGE DeriveDataTypeable #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Language.Haskell.Syntax
-- Copyright   :  (c) The GHC Team, 1997-2000
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  experimental
-- Portability :  portable
--
-- A suite of datatypes describing the abstract syntax of
-- <http://www.haskell.org/onlinereport/ Haskell 98> plus a few extensions:
--
--   * multi-parameter type classes
--
--   * parameters of type class assertions are unrestricted
--
-- This module has been changed so that show is a real show.
-- For GHC, we also derive Typeable and Data for all types.

-----------------------------------------------------------------------------

module Language.Haskell.Syntax (
    -- * Modules
    HsModule(..), HsExportSpec(..),
    HsImportDecl(..), HsImportSpec(..), HsAssoc(..),
    -- * Declarations
    HsDecl(..), HsConDecl(..), HsBangType(..),
    HsMatch(..), HsRhs(..), HsGuardedRhs(..),
    HsSafety(..),
    -- * Class Assertions and Contexts
    HsQualType(..), HsContext, HsAsst,
    -- * Types
    HsType(..),
    -- * Expressions
    HsExp(..), HsStmt(..), HsFieldUpdate(..),
    HsAlt(..), HsGuardedAlts(..), HsGuardedAlt(..),
    -- * Patterns
    HsPat(..), HsPatField(..),
    -- * Literals
    HsLiteral(..),
    -- * Variables, Constructors and Operators
    Module(..), HsQName(..), HsName(..), HsQOp(..), HsOp(..),
    HsSpecialCon(..), HsCName(..),

    -- * Builtin names

    -- ** Modules
    prelude_mod, main_mod,
    -- ** Main function of a program
    main_name,
    -- ** Constructors
    unit_con_name, tuple_con_name, list_cons_name,
    unit_con, tuple_con,
    -- ** Type constructors
    unit_tycon_name, fun_tycon_name, list_tycon_name, tuple_tycon_name,
    unit_tycon, fun_tycon, list_tycon, tuple_tycon,

    -- * Source coordinates
    SrcLoc(..),
  ) where


#ifdef __GLASGOW_HASKELL__
import           Data.Generics.Basics
import           Data.Generics.Instances ()
#endif

-- | A position in the source.
data SrcLoc = SrcLoc {
                srcFilename :: String,
                srcLine     :: Int,
                srcColumn   :: Int
                }
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | The name of a Haskell module.
newtype Module = Module String
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | Constructors with special syntax.
-- These names are never qualified, and always refer to builtin type or
-- data constructors.

data HsSpecialCon
        = HsUnitCon             -- ^ unit type and data constructor @()@
        | HsListCon             -- ^ list type constructor @[]@
        | HsFunCon              -- ^ function type constructor @->@
        | HsTupleCon Int        -- ^ /n/-ary tuple type and data
                                --   constructors @(,)@ etc
        | HsCons                -- ^ list data constructor @(:)@
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | This type is used to represent qualified variables, and also
-- qualified constructors.
data HsQName
        = Qual Module HsName    -- ^ name qualified with a module name
        | UnQual HsName         -- ^ unqualified name
        | Special HsSpecialCon  -- ^ built-in constructor with special syntax
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | This type is used to represent variables, and also constructors.
data HsName
        = HsIdent String        -- ^ /varid/ or /conid/
        | HsSymbol String       -- ^ /varsym/ or /consym/
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | Possibly qualified infix operators (/qop/), appearing in expressions.
data HsQOp
        = HsQVarOp HsQName      -- ^ variable operator (/qvarop/)
        | HsQConOp HsQName      -- ^ constructor operator (/qconop/)
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | Operators, appearing in @infix@ declarations.
data HsOp
        = HsVarOp HsName        -- ^ variable operator (/varop/)
        | HsConOp HsName        -- ^ constructor operator (/conop/)
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | A name (/cname/) of a component of a class or data type in an @import@
-- or export specification.
data HsCName
        = HsVarName HsName      -- ^ name of a method or field
        | HsConName HsName      -- ^ name of a data constructor
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | A Haskell source module.
data HsModule = HsModule SrcLoc Module (Maybe [HsExportSpec])
                         [HsImportDecl] [HsDecl]
#ifdef __GLASGOW_HASKELL__
  deriving (Show,Typeable,Data)
#else
  deriving (Show)
#endif

-- | Export specification.
data HsExportSpec
         = HsEVar HsQName                       -- ^ variable
         | HsEAbs HsQName                       -- ^ @T@:
                        -- a class or datatype exported abstractly,
                        -- or a type synonym.
         | HsEThingAll HsQName                  -- ^ @T(..)@:
                        -- a class exported with all of its methods, or
                        -- a datatype exported with all of its constructors.
         | HsEThingWith HsQName [HsCName]       -- ^ @T(C_1,...,C_n)@:
                        -- a class exported with some of its methods, or
                        -- a datatype exported with some of its constructors.
         | HsEModuleContents Module             -- ^ @module M@:
                        -- re-export a module.
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Import declaration.
data HsImportDecl = HsImportDecl
        { importLoc       :: SrcLoc           -- ^ position of the @import@ keyword.
        , importModule    :: Module        -- ^ name of the module imported.
        , importQualified :: Bool       -- ^ imported @qualified@?
        , importAs        :: Maybe Module      -- ^ optional alias name in an
                                        -- @as@ clause.
        , importSpecs     :: Maybe (Bool,[HsImportSpec])
                        -- ^ optional list of import specifications.
                        -- The 'Bool' is 'True' if the names are excluded
                        -- by @hiding@.
        }
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Import specification.
data HsImportSpec
         = HsIVar HsName                        -- ^ variable
         | HsIAbs HsName                        -- ^ @T@:
                        -- the name of a class, datatype or type synonym.
         | HsIThingAll HsName                   -- ^ @T(..)@:
                        -- a class imported with all of its methods, or
                        -- a datatype imported with all of its constructors.
         | HsIThingWith HsName [HsCName]        -- ^ @T(C_1,...,C_n)@:
                        -- a class imported with some of its methods, or
                        -- a datatype imported with some of its constructors.
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Associativity of an operator.
data HsAssoc
         = HsAssocNone  -- ^ non-associative operator (declared with @infix@)
         | HsAssocLeft  -- ^ left-associative operator (declared with @infixl@).
         | HsAssocRight -- ^ right-associative operator (declared with @infixr@)
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

data HsDecl
         = HsTypeDecl    SrcLoc HsName [HsName] HsType
         | HsDataDecl    SrcLoc HsContext HsName [HsName] [HsConDecl] [HsQName]
         | HsInfixDecl   SrcLoc HsAssoc Int [HsOp]
         | HsNewTypeDecl SrcLoc HsContext HsName [HsName] HsConDecl [HsQName]
         | HsClassDecl   SrcLoc HsContext HsName [HsName] [HsDecl]
         | HsInstDecl    SrcLoc HsContext HsQName [HsType] [HsDecl]
         | HsDefaultDecl SrcLoc [HsType]
         | HsTypeSig     SrcLoc [HsName] HsQualType
         | HsFunBind     [HsMatch]
         | HsPatBind     SrcLoc HsPat HsRhs {-where-} [HsDecl]
         | HsForeignImport SrcLoc String HsSafety String HsName HsType
         | HsForeignExport SrcLoc String String HsName HsType
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Clauses of a function binding.
data HsMatch
         = HsMatch SrcLoc HsName [HsPat] HsRhs {-where-} [HsDecl]
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Declaration of a data constructor.
data HsConDecl
         = HsConDecl SrcLoc HsName [HsBangType]
                                -- ^ ordinary data constructor
         | HsRecDecl SrcLoc HsName [([HsName],HsBangType)]
                                -- ^ record constructor
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | The type of a constructor argument or field, optionally including
-- a strictness annotation.
data HsBangType
         = HsBangedTy   HsType  -- ^ strict component, marked with \"@!@\"
         | HsUnBangedTy HsType  -- ^ non-strict component
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | The right hand side of a function or pattern binding.
data HsRhs
         = HsUnGuardedRhs HsExp -- ^ unguarded right hand side (/exp/)
         | HsGuardedRhss  [HsGuardedRhs]
                                -- ^ guarded right hand side (/gdrhs/)
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | A guarded right hand side @|@ /exp/ @=@ /exp/.
-- The first expression will be Boolean-valued.
data HsGuardedRhs
         = HsGuardedRhs SrcLoc HsExp HsExp
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Safety level for invoking a foreign entity
data HsSafety
        = HsSafe        -- ^ call may generate callbacks
        | HsUnsafe      -- ^ call will not generate callbacks
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Ord,Show,Typeable,Data)
#else
  deriving (Eq,Ord,Show)
#endif

-- | A type qualified with a context.
--   An unqualified type has an empty context.
data HsQualType
         = HsQualType HsContext HsType
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Haskell types and type constructors.
data HsType
         = HsTyFun   HsType HsType      -- ^ function type
         | HsTyTuple [HsType]           -- ^ tuple type
         | HsTyApp   HsType HsType      -- ^ application of a type constructor
         | HsTyVar   HsName             -- ^ type variable
         | HsTyCon   HsQName            -- ^ named type or type constructor
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

type HsContext = [HsAsst]

-- | Class assertions.
--   In Haskell 98, the argument would be a /tyvar/, but this definition
--   allows multiple parameters, and allows them to be /type/s.
type HsAsst    = (HsQName,[HsType])

-- | /literal/.
-- Values of this type hold the abstract value of the literal, not the
-- precise string representation used.  For example, @10@, @0o12@ and @0xa@
-- have the same representation.
data HsLiteral
        = HsChar        Char            -- ^ character literal
        | HsString      String          -- ^ string literal
        | HsInt         Integer         -- ^ integer literal
        | HsFrac        Rational        -- ^ floating point literal
        | HsCharPrim    Char            -- ^ GHC unboxed character literal
        | HsStringPrim  String          -- ^ GHC unboxed string literal
        | HsIntPrim     Integer         -- ^ GHC unboxed integer literal
        | HsFloatPrim   Rational        -- ^ GHC unboxed float literal
        | HsDoublePrim  Rational        -- ^ GHC unboxed double literal
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | Haskell expressions.
--
-- /Notes:/
--
-- * Because it is difficult for parsers to distinguish patterns from
--   expressions, they typically parse them in the same way and then check
--   that they have the appropriate form.  Hence the expression type
--   includes some forms that are found only in patterns.  After these
--   checks, these constructors should not be used.
--
-- * The parser does not take precedence and associativity into account,
--   so it will leave 'HsInfixApp's associated to the left.
--
-- * The 'Language.Haskell.Pretty.Pretty' instance for 'HsExp' does not
--   add parentheses in printing.

data HsExp
        = HsVar HsQName                 -- ^ variable
        | HsCon HsQName                 -- ^ data constructor
        | HsLit HsLiteral               -- ^ literal constant
        | HsInfixApp HsExp HsQOp HsExp  -- ^ infix application
        | HsApp HsExp HsExp             -- ^ ordinary application
        | HsNegApp HsExp                -- ^ negation expression @-@ /exp/
        | HsLambda SrcLoc [HsPat] HsExp -- ^ lambda expression
        | HsLet [HsDecl] HsExp          -- ^ local declarations with @let@
        | HsIf HsExp HsExp HsExp        -- ^ @if@ /exp/ @then@ /exp/ @else@ /exp/
        | HsCase HsExp [HsAlt]          -- ^ @case@ /exp/ @of@ /alts/
        | HsDo [HsStmt]                 -- ^ @do@-expression:
                                        -- the last statement in the list
                                        -- should be an expression.
        | HsTuple [HsExp]               -- ^ tuple expression
        | HsList [HsExp]                -- ^ list expression
        | HsParen HsExp                 -- ^ parenthesized expression
        | HsLeftSection HsExp HsQOp     -- ^ left section @(@/exp/ /qop/@)@
        | HsRightSection HsQOp HsExp    -- ^ right section @(@/qop/ /exp/@)@
        | HsRecConstr HsQName [HsFieldUpdate]
                                        -- ^ record construction expression
        | HsRecUpdate HsExp [HsFieldUpdate]
                                        -- ^ record update expression
        | HsEnumFrom HsExp              -- ^ unbounded arithmetic sequence,
                                        -- incrementing by 1
        | HsEnumFromTo HsExp HsExp      -- ^ bounded arithmetic sequence,
                                        -- incrementing by 1
        | HsEnumFromThen HsExp HsExp    -- ^ unbounded arithmetic sequence,
                                        -- with first two elements given
        | HsEnumFromThenTo HsExp HsExp HsExp
                                        -- ^ bounded arithmetic sequence,
                                        -- with first two elements given
        | HsListComp HsExp [HsStmt]     -- ^ list comprehension
        | HsExpTypeSig SrcLoc HsExp HsQualType
                                        -- ^ expression type signature
        | HsAsPat HsName HsExp          -- ^ patterns only
        | HsWildCard                    -- ^ patterns only
        | HsIrrPat HsExp                -- ^ patterns only
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | A pattern, to be matched against a value.
data HsPat
        = HsPVar HsName                 -- ^ variable
        | HsPLit HsLiteral              -- ^ literal constant
        | HsPNeg HsPat                  -- ^ negated pattern
        | HsPInfixApp HsPat HsQName HsPat
                                        -- ^ pattern with infix data constructor
        | HsPApp HsQName [HsPat]        -- ^ data constructor and argument
                                        -- patterns
        | HsPTuple [HsPat]              -- ^ tuple pattern
        | HsPList [HsPat]               -- ^ list pattern
        | HsPParen HsPat                -- ^ parenthesized pattern
        | HsPRec HsQName [HsPatField]   -- ^ labelled pattern
        | HsPAsPat HsName HsPat         -- ^ @\@@-pattern
        | HsPWildCard                   -- ^ wildcard pattern (@_@)
        | HsPIrrPat HsPat               -- ^ irrefutable pattern (@~@)
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | An /fpat/ in a labeled record pattern.
data HsPatField
        = HsPFieldPat HsQName HsPat
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | This type represents both /stmt/ in a @do@-expression,
--   and /qual/ in a list comprehension.
data HsStmt
        = HsGenerator SrcLoc HsPat HsExp
                                -- ^ a generator /pat/ @<-@ /exp/
        | HsQualifier HsExp     -- ^ an /exp/ by itself: in a @do@-expression,
                                -- an action whose result is discarded;
                                -- in a list comprehension, a guard expression
        | HsLetStmt [HsDecl]    -- ^ local bindings
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | An /fbind/ in a labeled record construction or update expression.
data HsFieldUpdate
        = HsFieldUpdate HsQName HsExp
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | An /alt/ in a @case@ expression.
data HsAlt
        = HsAlt SrcLoc HsPat HsGuardedAlts [HsDecl]
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

data HsGuardedAlts
        = HsUnGuardedAlt HsExp          -- ^ @->@ /exp/
        | HsGuardedAlts  [HsGuardedAlt] -- ^ /gdpat/
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-- | A guarded alternative @|@ /exp/ @->@ /exp/.
-- The first expression will be Boolean-valued.
data HsGuardedAlt
        = HsGuardedAlt SrcLoc HsExp HsExp
#ifdef __GLASGOW_HASKELL__
  deriving (Eq,Show,Typeable,Data)
#else
  deriving (Eq,Show)
#endif

-----------------------------------------------------------------------------
-- Builtin names.

prelude_mod, main_mod :: Module
prelude_mod           = Module "Prelude"
main_mod              = Module "Main"

main_name :: HsName
main_name             = HsIdent "main"

unit_con_name :: HsQName
unit_con_name         = Special HsUnitCon

tuple_con_name :: Int -> HsQName
tuple_con_name i      = Special (HsTupleCon (i+1))

list_cons_name :: HsQName
list_cons_name        = Special HsCons

unit_con :: HsExp
unit_con              = HsCon unit_con_name

tuple_con :: Int -> HsExp
tuple_con i           = HsCon (tuple_con_name i)

unit_tycon_name, fun_tycon_name, list_tycon_name :: HsQName
unit_tycon_name       = unit_con_name
fun_tycon_name        = Special HsFunCon
list_tycon_name       = Special HsListCon

tuple_tycon_name :: Int -> HsQName
tuple_tycon_name i    = tuple_con_name i

unit_tycon, fun_tycon, list_tycon :: HsType
unit_tycon            = HsTyCon unit_tycon_name
fun_tycon             = HsTyCon fun_tycon_name
list_tycon            = HsTyCon list_tycon_name

tuple_tycon :: Int -> HsType
tuple_tycon i         = HsTyCon (tuple_tycon_name i)