content: {-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-}
  {-# language DataKinds #-}
  {-# language InstanceSigs, ScopedTypeVariables, TypeApplications #-}
  {-# language LambdaCase #-}
  
  {-|
  Module      : Language.Python.Syntax.Import
  Copyright   : (C) CSIRO 2017-2019
  License     : BSD3
  Maintainer  : Isaac Elliott <isaace71295@gmail.com>
  Stability   : experimental
  Portability : non-portable
  
  Syntax used in import statements
  
  https://docs.python.org/3.5/reference/simple_stmts.html#the-import-statement
  -}
  
  module Language.Python.Syntax.Import
    ( ImportAs(..)
    , ImportTargets(..)
      -- * Lenses
    , importAsAnn
    , importAsName
    , importAsQual
    )
  where
  
  import Control.Lens.Getter ((^.), getting, to)
  import Control.Lens.Lens (Lens, Lens', lens)
  import Control.Lens.Prism (_Just)
  import Control.Lens.Setter ((.~))
  import Control.Lens.Tuple (_2)
  import Data.Function ((&))
  import Data.List.NonEmpty (NonEmpty)
  import Data.Generics.Product.Typed (typed)
  import GHC.Generics (Generic)
  import Unsafe.Coerce (unsafeCoerce)
  
  import Language.Python.Optics.Validated
  import Language.Python.Syntax.Ann
  import Language.Python.Syntax.CommaSep
  import Language.Python.Syntax.Ident
  import Language.Python.Syntax.Whitespace
  
  -- | Some data optionally followed by @as <ident>@
  --
  -- Used in:
  --
  -- @import a as b@
  --
  -- @from a import b as c, d as e@
  --
  -- @from a import (b as c, d as e)@
  data ImportAs e v a
    = ImportAs
    { _importAsAnn :: Ann a
    , _importAsName :: e v a
    , _importAsQual :: Maybe (NonEmpty Whitespace, Ident v a)
    }
    deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
  
  instance HasAnn (ImportAs e v) where
    annot :: forall a. Lens' (ImportAs e v a) (Ann a)
    annot = typed @(Ann a)
  
  instance Validated e => Validated (ImportAs e) where
    unvalidated = to unsafeCoerce
  
  importAsAnn :: Lens' (ImportAs e v a) a
  importAsAnn = annot_
  
  importAsName :: Validated e => Lens (ImportAs e v a) (ImportAs e' '[] a) (e v a) (e' '[] a)
  importAsName = lens _importAsName (\s a -> (s ^. unvalidated) { _importAsName = a })
  
  importAsQual
    :: Validated e
    => Lens
         (ImportAs e v a)
         (ImportAs e '[] a)
         (Maybe (NonEmpty Whitespace, Ident v a))
         (Maybe (NonEmpty Whitespace, Ident '[] a))
  importAsQual = lens _importAsQual (\s a -> (s ^. unvalidated) { _importAsQual = a })
  
  instance HasTrailingWhitespace (e v a) => HasTrailingWhitespace (ImportAs e v a) where
    trailingWhitespace =
      lens
        (\(ImportAs _ a b) ->
           maybe (a ^. getting trailingWhitespace) (^. _2.trailingWhitespace) b)
        (\(ImportAs x a b) ws ->
           ImportAs
             x
             (maybe (a & trailingWhitespace .~ ws) (const a) b)
             (b & _Just._2.trailingWhitespace .~ ws))
  
  -- | The targets of a @from ... import ...@ statement
  data ImportTargets v a
    -- | @from x import *@
    = ImportAll (Ann a) [Whitespace]
    -- | @from x import a, b, c@
    | ImportSome (Ann a) (CommaSep1 (ImportAs Ident v a))
    -- | @from x import (a, b, c)@
    | ImportSomeParens
        (Ann a)
        -- ( spaces
        [Whitespace]
        -- imports as
        (CommaSep1' (ImportAs Ident v a))
        -- ) spaces
        [Whitespace]
    deriving (Eq, Show, Functor, Foldable, Traversable, Generic)
  
  instance HasAnn (ImportTargets v) where
    annot :: forall a. Lens' (ImportTargets v a) (Ann a)
    annot = typed @(Ann a)
  
  instance HasTrailingWhitespace (ImportTargets v a) where
    trailingWhitespace =
      lens
        (\case
            ImportAll _ ws -> ws
            ImportSome _ cs -> cs ^. trailingWhitespace
            ImportSomeParens _ _ _ ws -> ws)
        (\ts ws ->
           case ts of
             ImportAll a _ -> ImportAll a ws
             ImportSome a cs -> ImportSome a (cs & trailingWhitespace .~ ws)
             ImportSomeParens x a b _ -> ImportSomeParens x a b ws)