content: {-# language DataKinds #-}
  {-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
  {-# language FunctionalDependencies, MultiParamTypeClasses #-}
  {-# language LambdaCase #-}
  {-# language TemplateHaskell #-}
  
  {-|
  Module      : Language.Python.Internal.Syntax.IR
  Copyright   : (C) CSIRO 2017-2019
  License     : BSD3
  Maintainer  : Isaac Elliott <isaace71295@gmail.com>
  Stability   : experimental
  Portability : non-portable
  
  This module only exists as our current best solution to decoupling parts of the
  concrete syntax from abstract syntax. You won't need to care about its existence
  and hopefully it will be deleted soon.
  
  -}
  
  module Language.Python.Internal.Syntax.IR where
  
  import Control.Lens.Fold (foldMapOf, folded)
  import Control.Lens.Getter ((^.))
  import Control.Lens.Lens (Lens', lens)
  import Control.Lens.Prism (Prism')
  import Control.Lens.Review ((#))
  import Control.Lens.Setter (over, mapped)
  import Control.Lens.TH (makeLenses)
  import Control.Lens.Traversal (traverseOf)
  import Control.Lens.Tuple (_1, _2, _3)
  import Data.Bifoldable (bifoldMap)
  import Data.Bifunctor (bimap)
  import Data.Bitraversable (bitraverse)
  import Data.List.NonEmpty (NonEmpty)
  import Data.Monoid ((<>))
  import Data.Validation (Validation(..))
  
  import Language.Python.Syntax.Ann
  import Language.Python.Syntax.AugAssign
  import Language.Python.Syntax.CommaSep
  import Language.Python.Syntax.Comment
  import Language.Python.Syntax.Ident
  import Language.Python.Syntax.Import
  import Language.Python.Syntax.ModuleNames
  import Language.Python.Syntax.Numbers
  import Language.Python.Syntax.Operator.Binary
  import Language.Python.Syntax.Operator.Unary
  import Language.Python.Syntax.Punctuation
  import Language.Python.Syntax.Strings
  import Language.Python.Syntax.Whitespace
  
  import qualified Language.Python.Syntax.Module as Syntax
  import qualified Language.Python.Syntax.Expr as Syntax
  import qualified Language.Python.Syntax.Statement as Syntax
  
  class AsIRError s a | s -> a where
    _InvalidUnpacking :: Prism' s a
  
  data IRError a
    -- | Unpacking ( @*value@ ) was used in an invalid position
    = InvalidUnpacking a
    deriving (Eq, Show)
  
  fromIRError :: AsIRError s a => IRError a -> s
  fromIRError (InvalidUnpacking a) = _InvalidUnpacking # a
  
  data SmallStatement a
    = MkSmallStatement
        (SimpleStatement a)
        [(Semicolon a, SimpleStatement a)]
        (Maybe (Semicolon a))
        (Maybe (Comment a))
        (Maybe Newline)
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Statement a
    = SmallStatement (Indents a) (SmallStatement a)
    | CompoundStatement (CompoundStatement a)
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data CompoundStatement a
    = Fundef
    { _csAnn :: a
    , _unsafeCsFundefDecorators :: [Decorator a]
    , _csIndents :: Indents a
    , _unsafeCsFundefAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
    , _unsafeCsFundefDef :: NonEmpty Whitespace -- ^ @\'def\' \<spaces\>@
    , _unsafeCsFundefName :: Ident '[] a -- ^ @\<ident\>@
    , _unsafeCsFundefLeftParen :: [Whitespace] -- ^ @\'(\' \<spaces\>@
    , _unsafeCsFundefParameters :: CommaSep (Param a) -- ^ @\<parameters\>@
    , _unsafeCsFundefRightParen :: [Whitespace] -- ^ @\')\' \<spaces\>@
    , _unsafeCsFundefReturnType :: Maybe ([Whitespace], Expr a) -- ^ @[\'->\' \<spaces\> \<expr\>]@
    , _unsafeCsFundefBody :: Suite a -- ^ @\<suite\>@
    }
    | If
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsIfIf :: [Whitespace] -- ^ @\'if\' \<spaces\>@
    , _unsafeCsIfCond :: Expr a -- ^ @\<expr\>@
    , _unsafeCsIfBody :: Suite a -- ^ @\<suite\>@
    , _unsafeCsIfElifs :: [(Indents a, [Whitespace], Expr a, Suite a)] -- ^ @(\'elif\' \<spaces\> \<expr\> \<suite\>)*@
    , _unsafeCsIfElse :: Maybe (Indents a, [Whitespace], Suite a) -- ^ @[\'else\' \<spaces\> \<suite\>]@
    }
    | While
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsWhileWhile :: [Whitespace] -- ^ @\'while\' \<spaces\>@
    , _unsafeCsWhileCond :: Expr a -- ^ @\<expr\>@
    , _unsafeCsWhileBody :: Suite a -- ^ @\<suite\>@
    , _unsafeCsWhileElse
      :: Maybe (Indents a, [Whitespace], Suite a) -- ^ @[\'else\' \<spaces\> \<suite\>]@
    }
    | TryExcept
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsTryExceptTry :: [Whitespace] -- ^ @\'try\' \<spaces\>@
    , _unsafeCsTryExceptBody :: Suite a -- ^ @\<suite\>@
    , _unsafeCsTryExceptExcepts :: NonEmpty (Indents a, [Whitespace], Maybe (ExceptAs a), Suite a) -- ^ @(\'except\' \<spaces\> \<except_as\> \<suite\>)+@
    , _unsafeCsTryExceptElse :: Maybe (Indents a, [Whitespace], Suite a) -- ^ @[\'else\' \<spaces\> \<suite\>]@
    , _unsafeCsTryExceptFinally :: Maybe (Indents a, [Whitespace], Suite a) -- ^ @[\'finally\' \<spaces\> \<suite\>]@
    }
    | TryFinally
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsTryFinallyTry :: [Whitespace] -- ^ @\'try\' \<spaces\>@
    , _unsafeCsTryFinallyTryBody :: Suite a -- ^ @\<suite\>@
    , _unsafeCsTryFinallyFinallyIndents :: Indents a
    , _unsafeCsTryFinallyFinally :: [Whitespace] -- ^ @\'finally\' \<spaces\>@
    , _unsafeCsTryFinallyFinallyBody :: Suite a -- ^ @\<suite\>@
    }
    | For
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsForAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
    , _unsafeCsForFor :: [Whitespace] -- ^ @\'for\' \<spaces\>@
    , _unsafeCsForBinder :: Expr a -- ^ @\<expr\>@
    , _unsafeCsForIn :: [Whitespace] -- ^ @\'in\' \<spaces\>@
    , _unsafeCsForCollection :: CommaSep1' (Expr a) -- ^ @\<exprs\>@
    , _unsafeCsForBody :: Suite a -- ^ @\<suite\>@
    , _unsafeCsForElse :: Maybe (Indents a, [Whitespace], Suite a) -- ^ @[\'else\' \<spaces\> \<suite\>]@
    }
    | ClassDef
    { _csAnn :: a
    , _unsafeCsClassDefDecorators :: [Decorator a]
    , _csIndents :: Indents a
    , _unsafeCsClassDefClass :: NonEmpty Whitespace -- ^ @\'class\' \<spaces\>@
    , _unsafeCsClassDefName :: Ident '[] a -- ^ @\<ident\>@
    , _unsafeCsClassDefArguments :: Maybe ([Whitespace], Maybe (CommaSep1' (Arg a)), [Whitespace]) -- ^ @[\'(\' \<spaces\> [\<args\>] \')\' \<spaces\>]@
    , _unsafeCsClassDefBody :: Suite a -- ^ @\<suite\>@
    }
    | With
    { _csAnn :: a
    , _csIndents :: Indents a
    , _unsafeCsWithAsync :: Maybe (NonEmpty Whitespace) -- ^ @[\'async\' \<spaces\>]@
    , _unsafeCsWithWith :: [Whitespace] -- ^ @\'with\' \<spaces\>@
    , _unsafeCsWithItems :: CommaSep1 (WithItem a) -- ^ @\<with_items\>@
    , _unsafeCsWithBody :: Suite a -- ^ @\<suite\>@
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data SimpleStatement a
    = Return a [Whitespace] (Maybe (Expr a))
    | Expr a (Expr a)
    | Assign a (Expr a) (NonEmpty (Equals, Expr a))
    | AugAssign a (Expr a) (AugAssign a) (Expr a)
    | Pass a [Whitespace]
    | Break a [Whitespace]
    | Continue a [Whitespace]
    | Global a (NonEmpty Whitespace) (CommaSep1 (Ident '[] a))
    | Nonlocal a (NonEmpty Whitespace) (CommaSep1 (Ident '[] a))
    | Del a [Whitespace] (CommaSep1' (Expr a))
    | Import
        a
        (NonEmpty Whitespace)
        (CommaSep1 (ImportAs ModuleName '[] a))
    | From
        a
        [Whitespace]
        (RelativeModuleName '[] a)
        [Whitespace]
        (ImportTargets '[] a)
    | Raise a
        [Whitespace]
        (Maybe (Expr a, Maybe ([Whitespace], Expr a)))
    | Assert a
        [Whitespace]
        (Expr a)
        (Maybe (Comma, Expr a))
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Param a
    = PositionalParam
    { _paramAnn :: a
    , _paramName :: Ident '[] a
    , _paramType :: Maybe (Colon, Expr a)
    }
    | KeywordParam
    { _paramAnn :: a
    , _paramName :: Ident '[] a
    -- ':' spaces <expr>
    , _paramType :: Maybe (Colon, Expr a)
    -- = spaces
    , _unsafeKeywordParamWhitespaceRight :: [Whitespace]
    , _unsafeKeywordParamExpr :: Expr a
    }
    | StarParam
    { _paramAnn :: a
    -- '*' spaces
    , _unsafeStarParamWhitespace :: [Whitespace]
    , _unsafeStarParamName :: Ident '[] a
    , _paramType :: Maybe (Colon, Expr a)
    }
    | UnnamedStarParam
    { _paramAnn :: a
    -- '*' spaces
    , _unsafeUnnamedStarParamWhitespace :: [Whitespace]
    }
    | DoubleStarParam
    { _paramAnn :: a
    -- '**' spaces
    , _unsafeDoubleStarParamWhitespace :: [Whitespace]
    , _paramName :: Ident '[] a
    , _paramType :: Maybe (Colon, Expr a)
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data CompIf a
    = CompIf a [Whitespace] (Expr a) -- ^ 'if' <any_spaces> <expr>
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data CompFor a
    = CompFor a [Whitespace] (Expr a) [Whitespace] (Expr a) -- ^ 'for' <any_spaces> <targets> 'in' <any_spaces> <expr>
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Comprehension e a
    = Comprehension a (e a) (CompFor a) [Either (CompFor a) (CompIf a)] -- ^ <expr> <comp_for> (comp_for | comp_if)*
    deriving (Eq, Show)
  
  instance Functor e => Functor (Comprehension e) where
    fmap f (Comprehension a b c d) =
      Comprehension (f a) (fmap f b) (fmap f c) (fmap (bimap (fmap f) (fmap f)) d)
  
  instance Foldable e => Foldable (Comprehension e) where
    foldMap f (Comprehension a b c d) =
      f a <> foldMap f b <> foldMap f c <> foldMap (bifoldMap (foldMap f) (foldMap f)) d
  
  instance Traversable e => Traversable (Comprehension e) where
    traverse f (Comprehension a b c d) =
      Comprehension <$>
      f a <*>
      traverse f b <*>
      traverse f c <*>
      traverse (bitraverse (traverse f) (traverse f)) d
  
  data Subscript a
    = SubscriptExpr (Expr a)
    | SubscriptSlice
        -- [expr]
        (Maybe (Expr a))
        -- ':' <spaces>
        Colon
        -- [expr]
        (Maybe (Expr a))
        -- [':' [expr]]
        (Maybe (Colon, Maybe (Expr a)))
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data DictItem a
    = DictItem
    { _dictItemAnn :: a
    , _unsafeDictItemKey :: Expr a
    , _unsafeDictItemColon :: Colon
    , _unsafeDictItemvalue :: Expr a
    }
    | DictUnpack
    { _dictItemAnn :: a
    , _unsafeDictItemUnpackWhitespace :: [Whitespace]
    , _unsafeDictItemUnpackValue :: Expr a
    } deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Arg a
    = PositionalArg
    { _argAnn :: a
    , _argExpr :: Expr a
    }
    | KeywordArg
    { _argAnn :: a
    , _unsafeKeywordArgName :: Ident '[] a
    , _unsafeKeywordArgWhitespaceRight :: [Whitespace]
    , _argExpr :: Expr a
    }
    | StarArg
    { _argAnn :: a
    , _unsafeStarArgWhitespace :: [Whitespace]
    , _argExpr :: Expr a
    }
    | DoubleStarArg
    { _argAnn :: a
    , _unsafeDoubleStarArgWhitespace :: [Whitespace]
    , _argExpr :: Expr a
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Expr a
    = StarExpr
    { _exprAnn :: a
    , _unsafeStarExprWhitespace :: [Whitespace]
    , _unsafeStarExprValue :: Expr a
    }
    | Unit
    { _exprAnn :: a
    , _unsafeUnitWhitespaceInner :: [Whitespace]
    , _unsafeUnitWhitespaceRight :: [Whitespace]
    }
    | Lambda
    { _exprAnn :: a
    , _unsafeLambdaWhitespace :: [Whitespace]
    , _unsafeLambdaArgs :: CommaSep (Param a)
    , _unsafeLambdaColon :: Colon
    , _unsafeLambdaBody :: Expr a
    }
    | Yield
    { _exprAnn :: a
    , _unsafeYieldWhitespace :: [Whitespace]
    , _unsafeYieldValue :: CommaSep (Expr a)
    }
    | YieldFrom
    { _exprAnn :: a
    , _unsafeYieldWhitespace :: [Whitespace]
    , _unsafeFromWhitespace :: [Whitespace]
    , _unsafeYieldFromValue :: Expr a
    }
    | Ternary
    { _exprAnn :: a
    -- expr
    , _unsafeTernaryValue :: Expr a
    -- 'if' spaces
    , _unsafeTernaryWhitespaceIf :: [Whitespace]
    -- expr
    , _unsafeTernaryCond :: Expr a
    -- 'else' spaces
    , _unsafeTernaryWhitespaceElse :: [Whitespace]
    -- expr
    , _unsafeTernaryElse :: Expr a
    }
    | ListComp
    { _exprAnn :: a
    -- [ spaces
    , _unsafeListCompWhitespaceLeft :: [Whitespace]
    -- comprehension
    , _unsafeListCompValue :: Comprehension Expr a
    -- ] spaces
    , _unsafeListCompWhitespaceRight :: [Whitespace]
    }
    | List
    { _exprAnn :: a
    -- [ spaces
    , _unsafeListWhitespaceLeft :: [Whitespace]
    -- exprs
    , _unsafeListValues :: Maybe (CommaSep1' (Expr a))
    -- ] spaces
    , _unsafeListWhitespaceRight :: [Whitespace]
    }
    | DictComp
    { _exprAnn :: a
    -- { spaces
    , _unsafeDictCompWhitespaceLeft :: [Whitespace]
    -- comprehension
    , _unsafeDictCompValue :: Comprehension DictItem a
    -- } spaces
    , _unsafeDictCompWhitespaceRight :: [Whitespace]
    }
    | Dict
    { _exprAnn :: a
    , _unsafeDictWhitespaceLeft :: [Whitespace]
    , _unsafeDictValues :: Maybe (CommaSep1' (DictItem a))
    , _unsafeDictWhitespaceRight :: [Whitespace]
    }
    | SetComp
    { _exprAnn :: a
    -- { spaces
    , _unsafeSetCompWhitespaceLeft :: [Whitespace]
    -- comprehension
    , _unsafeSetCompValue :: Comprehension Expr a
    -- } spaces
    , _unsafeSetCompWhitespaceRight :: [Whitespace]
    }
    | Set
    { _exprAnn :: a
    , _unsafeSetWhitespaceLeft :: [Whitespace]
    , _unsafeSetValues :: CommaSep1' (Expr a)
    , _unsafeSetWhitespaceRight :: [Whitespace]
    }
    | Deref
    { _exprAnn :: a
    -- expr
    , _unsafeDerefValueLeft :: Expr a
    -- . spaces
    , _unsafeDerefWhitespaceLeft :: [Whitespace]
    -- ident
    , _unsafeDerefValueRight :: Ident '[] a
    }
    | Subscript
    { _exprAnn :: a
    -- expr
    , _unsafeSubscriptValueLeft :: Expr a
    -- [ spaces
    , _unsafeSubscriptWhitespaceLeft :: [Whitespace]
    -- expr
    , _unsafeSubscriptValueRight :: CommaSep1' (Subscript a)
    -- ] spaces
    , _unsafeSubscriptWhitespaceRight :: [Whitespace]
    }
    | Call
    { _exprAnn :: a
    -- expr
    , _unsafeCallFunction :: Expr a
    -- ( spaces
    , _unsafeCallWhitespaceLeft :: [Whitespace]
    -- exprs
    , _unsafeCallArguments :: Maybe (CommaSep1' (Arg a))
    -- ) spaces
    , _unsafeCallWhitespaceRight :: [Whitespace]
    }
    | None
    { _exprAnn :: a
    , _unsafeNoneWhitespace :: [Whitespace]
    }
    | Ellipsis
    { _exprAnn :: a
    , _unsafeEllipsisWhitespace :: [Whitespace]
    }
    | BinOp
    { _exprAnn :: a
    , _unsafeBinOpExprLeft :: Expr a
    , _unsafeBinOpOp :: BinOp a
    , _unsafeBinOpExprRight :: Expr a
    }
    | UnOp
    { _exprAnn :: a
    , _unsafeUnOpOp :: UnOp a
    , _unsafeUnOpValue :: Expr a
    }
    | Parens
    { _exprAnn :: a
    -- ( spaces
    , _unsafeParensWhitespaceLeft :: [Whitespace]
    -- expr
    , _unsafeParensValue :: Expr a
    -- ) spaces
    , _unsafeParensWhitespaceAfter :: [Whitespace]
    }
    | Ident
    { _exprAnn :: a
    , _unsafeIdentValue :: Ident '[] a
    }
    | Int
    { _exprAnn :: a
    , _unsafeIntValue :: IntLiteral a
    , _unsafeIntWhitespace :: [Whitespace]
    }
    | Float
    { _exprAnn :: a
    , _unsafeFloatValue :: FloatLiteral a
    , _unsafeFloatWhitespace :: [Whitespace]
    }
    | Imag
    { _exprAnn :: a
    , _unsafeImagValue :: ImagLiteral a
    , _unsafeImagWhitespace :: [Whitespace]
    }
    | Bool
    { _exprAnn :: a
    , _unsafeBoolValue :: Bool
    , _unsafeBoolWhitespace :: [Whitespace]
    }
    | String
    { _exprAnn :: a
    , _unsafeStringLiteralValue :: NonEmpty (StringLiteral a)
    }
    | Tuple
    { _exprAnn :: a
    -- expr
    , _unsafeTupleHead :: Expr a
    -- , spaces
    , _unsafeTupleWhitespace :: Comma
    -- [exprs]
    , _unsafeTupleTail :: Maybe (CommaSep1' (Expr a))
    }
    | Not
    { _exprAnn :: a
    , _unsafeNotWhitespace :: [Whitespace]
    , _unsafeNotValue :: Expr a
    }
    | Generator
    { _exprAnn :: a
    , _generatorValue :: Comprehension Expr a
    }
    | Await
    { _exprAnn :: a
    , _unsafeAwaitWhitespace :: [Whitespace]
    , _unsafeAwaitValue :: Expr a
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  exprAnn :: Lens' (Expr a) a
  exprAnn =
    lens
      (\case
          Unit a _ _ -> a
          StarExpr a _ _ -> a
          Lambda a _ _ _ _ -> a
          Yield a _ _ -> a
          YieldFrom a _ _ _ -> a
          Ternary a _ _ _ _ _ -> a
          None a _ -> a
          Ellipsis a _ -> a
          List a _ _ _ -> a
          ListComp a _ _ _ -> a
          Deref a _ _ _ -> a
          Subscript a _ _ _ _ -> a
          Call a _ _ _ _ -> a
          BinOp a _ _ _ -> a
          UnOp a _ _ -> a
          Parens a _ _ _ -> a
          Ident a _ -> a
          Int a _ _ -> a
          Float a _ _ -> a
          Imag a _ _ -> a
          Bool a _ _ -> a
          String a _ -> a
          Not a _ _ -> a
          Tuple a _ _ _ -> a
          DictComp a _ _ _ -> a
          Dict a _ _ _ -> a
          SetComp a _ _ _ -> a
          Set a _ _ _ -> a
          Generator a _ -> a
          Await a _ _ -> a)
      (\e ann ->
        case e of
          Unit _ a b -> Unit ann a b
          StarExpr _ a b -> StarExpr ann a b
          Lambda _ a b c d -> Lambda ann a b c d
          Yield _ a b -> Yield ann a b
          YieldFrom ann a b c -> YieldFrom ann a b c
          Ternary ann a b c d e -> Ternary ann a b c d e
          None _ a -> None ann a
          Ellipsis _ a -> Ellipsis ann a
          List _ a b c -> List ann a b c
          ListComp _ a b c -> ListComp ann a b c
          Deref _ a b c -> Deref ann a b c
          Subscript _ a b c d -> Subscript ann a b c d
          Call _ a b c d -> Call ann a b c d
          BinOp _ a b c -> BinOp ann a b c
          UnOp _ a b -> UnOp ann a b
          Parens _ a b c -> Parens ann a b c
          Ident _ b -> Ident ann b
          Int _ a b -> Int ann a b
          Float _ a b -> Float ann a b
          Imag _ a b -> Imag ann a b
          Bool _ a b -> Bool ann a b
          String _ a -> String ann a
          Not _ a b -> Not ann a b
          Tuple _ a b c -> Tuple ann a b c
          DictComp _ a b c -> DictComp ann a b c
          Dict _ a b c -> Dict ann a b c
          SetComp _ a b c -> SetComp ann a b c
          Set _ a b c -> Set ann a b c
          Generator _ a -> Generator ann a
          Await _ a b -> Not ann a b)
  
  data Suite a
    -- ':' <space> smallStatement
    = SuiteOne a Colon (SmallStatement a)
    | SuiteMany a
        -- ':' <spaces> [comment] <newline>
        Colon (Maybe (Comment a)) Newline
        -- <block>
        (Block a)
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Block a
    = Block
    { _blockBlankLines :: [(Blank a, Newline)]
    , _blockHead :: Statement a
    , _blockTail :: [Either (Blank a, Newline) (Statement a)]
    } deriving (Eq, Show)
  
  instance Functor Block where
    fmap f (Block a b c) =
      Block
        (over (mapped._1.mapped) f a)
        (fmap f b)
        (bimap (over (_1.mapped) f) (fmap f) <$> c)
  
  instance Foldable Block where
    foldMap f (Block a b c) =
      foldMapOf (folded._1.folded) f a <>
      foldMap f b <>
      foldMap (bifoldMap (foldMapOf (_1.folded) f) (foldMap f)) c
  
  instance Traversable Block where
    traverse f (Block a b c) =
      Block <$>
      traverseOf (traverse._1.traverse) f a <*>
      traverse f b <*>
      traverse (bitraverse (traverseOf (_1.traverse) f) (traverse f)) c
  
  data WithItem a
    = WithItem
    { _withItemAnn :: a
    , _withItemValue :: Expr a
    , _withItemBinder :: Maybe ([Whitespace], Expr a)
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Decorator a
    = Decorator
    { _decoratorAnn :: a
    , _decoratorIndents :: Indents a
    , _decoratorAt :: At
    , _decoratorExpr :: Expr a
    , _decoratorComment :: Maybe (Comment a)
    , _decoratorNewline :: Newline
    , _decoratorBlankLines :: [(Blank a, Newline)]
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data ExceptAs a
    = ExceptAs
    { _exceptAsAnn :: a
    , _exceptAsExpr :: Expr a
    , _exceptAsName :: Maybe ([Whitespace], Ident '[] a)
    }
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data Module a
    = ModuleEmpty
    | ModuleBlankFinal (Blank a)
    | ModuleBlank (Blank a) Newline (Module a)
    | ModuleStatement (Statement a) (Module a)
    deriving (Eq, Show, Functor, Foldable, Traversable)
  
  data FromIRContext
    = FromIRContext
    { _allowStarred :: Bool
    }
  
  makeLenses ''FromIRContext
  
  fromIR_expr
    :: AsIRError e a
    => Expr a
    -> Validation (NonEmpty e) (Syntax.Expr '[] a)
  fromIR_expr ex =
    case ex of
      StarExpr{} -> Failure $ pure (_InvalidUnpacking # (ex ^. exprAnn))
      Unit a b c -> pure $ Syntax.Unit (Ann a) b c
      Lambda a b c d e ->
        (\c' -> Syntax.Lambda (Ann a) b c' d) <$>
        traverse fromIR_param c <*>
        fromIR_expr e
      Yield a b c -> Syntax.Yield (Ann a) b <$> traverse fromIR_expr c
      YieldFrom a b c d -> Syntax.YieldFrom (Ann a) b c <$> fromIR_expr d
      Ternary a b c d e f ->
        (\b' d' -> Syntax.Ternary (Ann a) b' c d' e) <$>
        fromIR_expr b <*>
        fromIR_expr d <*>
        fromIR_expr f
      ListComp a b c d ->
        (\c' -> Syntax.ListComp (Ann a) b c' d) <$>
        fromIR_comprehension fromIR_expr c
      List a b c d ->
        (\c' -> Syntax.List (Ann a) b c' d) <$>
        traverseOf (traverse.traverse) fromIR_listItem c
      DictComp a b c d ->
        (\c' -> Syntax.DictComp (Ann a) b c' d) <$>
        fromIR_comprehension fromIR_dictItem c
      Dict a b c d ->
        (\c' -> Syntax.Dict (Ann a) b c' d) <$>
        traverseOf (traverse.traverse) fromIR_dictItem c
      SetComp a b c d ->
        (\c' -> Syntax.SetComp (Ann a) b c' d) <$>
        fromIR_comprehension fromIR_setItem c
      Set a b c d ->
        (\c' -> Syntax.Set (Ann a) b c' d) <$>
        traverse fromIR_setItem c
      Deref a b c d ->
        (\b' -> Syntax.Deref (Ann a) b' c d) <$>
        fromIR_expr b
      Subscript a b c d e ->
        (\b' d' -> Syntax.Subscript (Ann a) b' c d' e) <$>
        fromIR_expr b <*>
        traverse fromIR_subscript d
      Call a b c d e ->
        (\b' d' -> Syntax.Call (Ann a) b' c d' e) <$>
        fromIR_expr b <*>
        traverseOf (traverse.traverse) fromIR_arg d
      None a b -> pure $ Syntax.None (Ann a) b
      Ellipsis a b -> pure $ Syntax.Ellipsis (Ann a) b
      BinOp a b c d ->
        (\b' d' -> Syntax.BinOp (Ann a) b' c d') <$>
        fromIR_expr b <*>
        fromIR_expr d
      UnOp a b c ->
        Syntax.UnOp (Ann a) b <$> fromIR_expr c
      Parens a b c d ->
        (\c' -> Syntax.Parens (Ann a) b c' d) <$>
        fromIR_expr c
      Ident a b -> pure $ Syntax.Ident (Ann a) b
      Int a b c -> pure $ Syntax.Int (Ann a) b c
      Float a b c -> pure $ Syntax.Float (Ann a) b c
      Imag a b c -> pure $ Syntax.Imag (Ann a) b c
      Bool a b c -> pure $ Syntax.Bool (Ann a) b c
      String a b -> pure $ Syntax.String (Ann a) b
      Tuple a b c d ->
        (\b' -> Syntax.Tuple (Ann a) b' c) <$>
        fromIR_tupleItem b <*>
        traverseOf (traverse.traverse) fromIR_tupleItem d
      Not a b c -> Syntax.Not (Ann a) b <$> fromIR_expr c
      Generator a b -> Syntax.Generator (Ann a) <$> fromIR_comprehension fromIR_expr b
      Await a b c -> Syntax.Await (Ann a) b <$> fromIR_expr c
  
  fromIR_suite
    :: AsIRError e a
    => Suite a
    -> Validation (NonEmpty e) (Syntax.Suite '[] a)
  fromIR_suite s =
    case s of
      SuiteOne a b c ->
        Syntax.SuiteOne (Ann a) b <$> fromIR_smallStatement c
      SuiteMany a b c d e ->
        Syntax.SuiteMany (Ann a) b c d <$> fromIR_block e
  
  fromIR_param
    :: AsIRError e a
    => Param a
    -> Validation (NonEmpty e) (Syntax.Param '[] a)
  fromIR_param p =
    case p of
      PositionalParam a b c ->
        Syntax.PositionalParam (Ann a) b <$> traverseOf (traverse._2) fromIR_expr c
      KeywordParam a b c d e ->
        Syntax.KeywordParam (Ann a) b <$>
        traverseOf (traverse._2) fromIR_expr c <*>
        pure d <*>
        fromIR_expr e
      StarParam a b c d ->
        Syntax.StarParam (Ann a) b c <$> traverseOf (traverse._2) fromIR_expr d
      UnnamedStarParam a b -> pure $ Syntax.UnnamedStarParam (Ann a) b
      DoubleStarParam a b c d ->
        Syntax.DoubleStarParam (Ann a) b c <$> traverseOf (traverse._2) fromIR_expr d
  
  fromIR_arg
    :: AsIRError e a
    => Arg a
    -> Validation (NonEmpty e) (Syntax.Arg '[] a)
  fromIR_arg a =
    case a of
      PositionalArg a b -> Syntax.PositionalArg (Ann a) <$> fromIR_expr b
      KeywordArg a b c d -> Syntax.KeywordArg (Ann a) b c <$> fromIR_expr d
      StarArg a b c -> Syntax.StarArg (Ann a) b <$> fromIR_expr c
      DoubleStarArg a b c -> Syntax.DoubleStarArg (Ann a) b <$> fromIR_expr c
  
  fromIR_decorator
    :: AsIRError e a
    => Decorator a
    -> Validation (NonEmpty e) (Syntax.Decorator '[] a)
  fromIR_decorator (Decorator a b c d e f g) =
    (\d' -> Syntax.Decorator (Ann a) b c d' e f g) <$>
    fromIR_expr d
  
  fromIR_exceptAs
    :: AsIRError e a
    => ExceptAs a
    -> Validation (NonEmpty e) (Syntax.ExceptAs '[] a)
  fromIR_exceptAs (ExceptAs a b c) =
    (\b' -> Syntax.ExceptAs (Ann a) b' c) <$>
    fromIR_expr b
  
  fromIR_withItem
    :: AsIRError e a
    => WithItem a
    -> Validation (NonEmpty e) (Syntax.WithItem '[] a)
  fromIR_withItem (WithItem a b c) =
    Syntax.WithItem (Ann a) <$>
    fromIR_expr b <*>
    traverseOf (traverse._2) fromIR_expr c
  
  fromIR_comprehension
    :: AsIRError e a
    => (ex a -> Validation (NonEmpty e) (ex' '[] a))
    -> Comprehension ex a
    -> Validation (NonEmpty e) (Syntax.Comprehension ex' '[] a)
  fromIR_comprehension f (Comprehension a b c d) =
    Syntax.Comprehension (Ann a) <$>
    f b <*>
    fromIR_compFor c <*>
    traverse (bitraverse fromIR_compFor fromIR_compIf) d
  
  fromIR_dictItem
    :: AsIRError e a
    => DictItem a
    -> Validation (NonEmpty e) (Syntax.DictItem '[] a)
  fromIR_dictItem di =
    case di of
      DictItem a b c d ->
        (\b' -> Syntax.DictItem (Ann a) b' c) <$>
        fromIR_expr b <*>
        fromIR_expr d
      DictUnpack a b c ->
        Syntax.DictUnpack (Ann a) b <$> fromIR_expr c
  
  fromIR_subscript
    :: AsIRError e a
    => Subscript a
    -> Validation (NonEmpty e) (Syntax.Subscript '[] a)
  fromIR_subscript s =
    case s of
      SubscriptExpr a -> Syntax.SubscriptExpr <$> fromIR_expr a
      SubscriptSlice a b c d ->
        (\a' -> Syntax.SubscriptSlice a' b) <$>
        traverse fromIR_expr a <*>
        traverse fromIR_expr c <*>
        traverseOf (traverse._2.traverse) fromIR_expr d
  
  fromIR_block
    :: AsIRError e a
    => Block a
    -> Validation (NonEmpty e) (Syntax.Block '[] a)
  fromIR_block (Block a b c) =
    Syntax.Block a <$>
    fromIR_statement b <*>
    traverseOf (traverse.traverse) fromIR_statement c
  
  fromIR_compFor
    :: AsIRError e a
    => CompFor a
    -> Validation (NonEmpty e) (Syntax.CompFor '[] a)
  fromIR_compFor (CompFor a b c d e) =
    (\c' -> Syntax.CompFor (Ann a) b c' d) <$>
    fromIR_expr c <*>
    fromIR_expr e
  
  fromIR_compIf
    :: AsIRError e a
    => CompIf a
    -> Validation (NonEmpty e) (Syntax.CompIf '[] a)
  fromIR_compIf (CompIf a b c) =
    Syntax.CompIf (Ann a) b <$> fromIR_expr c
  
  fromIR_smallStatement
    :: AsIRError e a
    => SmallStatement a
    -> Validation (NonEmpty e) (Syntax.SmallStatement '[] a)
  fromIR_smallStatement (MkSmallStatement b c d e f) =
    (\b' c' -> Syntax.MkSmallStatement b' c' d e f) <$>
    fromIR_SimpleStatement b <*>
    traverseOf (traverse._2) fromIR_SimpleStatement c
  
  fromIR_statement
    :: AsIRError e a
    => Statement a
    -> Validation (NonEmpty e) (Syntax.Statement '[] a)
  fromIR_statement ex =
    case ex of
      SmallStatement i a ->
        Syntax.SmallStatement i <$> fromIR_smallStatement a
      CompoundStatement a ->
        Syntax.CompoundStatement <$> fromIR_compoundStatement a
  
  fromIR_SimpleStatement
    :: AsIRError e a
    => SimpleStatement a
    -> Validation (NonEmpty e) (Syntax.SimpleStatement '[] a)
  fromIR_SimpleStatement ex =
    case ex of
      Assign a b c ->
        Syntax.Assign (Ann a) <$>
        fromIR_expr b <*>
        traverseOf (traverse._2) fromIR_expr c
      Return a b c -> Syntax.Return (Ann a) b <$> traverse fromIR_expr c
      Expr a b -> Syntax.Expr (Ann a) <$> fromIR_expr b
      AugAssign a b c d ->
        (\b' d' -> Syntax.AugAssign (Ann a) b' c d') <$>
        fromIR_expr b <*>
        fromIR_expr d
      Pass a ws -> pure $ Syntax.Pass (Ann a) ws
      Break a ws -> pure $ Syntax.Break (Ann a) ws
      Continue a ws -> pure $ Syntax.Continue (Ann a) ws
      Global a b c -> pure $ Syntax.Global (Ann a) b c
      Nonlocal a b c -> pure $ Syntax.Nonlocal (Ann a) b c
      Del a b c -> Syntax.Del (Ann a) b <$> traverse fromIR_expr c
      Import a b c -> pure $ Syntax.Import (Ann a) b c
      From a b c d e -> pure $ Syntax.From (Ann a) b c d e
      Raise a b c ->
        Syntax.Raise (Ann a) b <$>
        traverse
          (\(a, b) -> (,) <$>
            fromIR_expr a <*>
            traverseOf (traverse._2) fromIR_expr b)
          c
      Assert a b c d ->
        Syntax.Assert (Ann a) b <$>
        fromIR_expr c <*>
        traverseOf (traverse._2) fromIR_expr d
  
  fromIR_compoundStatement
    :: AsIRError e a
    => CompoundStatement a
    -> Validation (NonEmpty e) (Syntax.CompoundStatement '[] a)
  fromIR_compoundStatement st =
    case st of
      Fundef a b asyncWs c d e f g h i j ->
        (\b' g' i' -> Syntax.Fundef (Ann a) b' asyncWs c d e f g' h i') <$>
        traverse fromIR_decorator b <*>
        traverse fromIR_param g <*>
        traverseOf (traverse._2) fromIR_expr i <*>
        fromIR_suite j
      If a b c d e f g ->
        Syntax.If (Ann a) b c <$>
        fromIR_expr d <*>
        fromIR_suite e <*>
        traverse (\(a, b, c, d) -> (,,,) a b <$> fromIR_expr c <*> fromIR_suite d) f <*>
        traverseOf (traverse._3) fromIR_suite g
      While a b c d e f ->
        Syntax.While (Ann a) b c <$>
        fromIR_expr d <*>
        fromIR_suite e <*>
        traverseOf (traverse._3) fromIR_suite f
      TryExcept a b c d e f g ->
        Syntax.TryExcept (Ann a) b c <$>
        fromIR_suite d <*>
        traverse
          (\(a, b, c, d) -> (,,,) a b <$> traverse fromIR_exceptAs c <*> fromIR_suite d)
          e <*>
        traverseOf (traverse._3) fromIR_suite f <*>
        traverseOf (traverse._3) fromIR_suite g
      TryFinally a b c d e f g ->
        (\d' -> Syntax.TryFinally (Ann a) b c d' e f) <$> fromIR_suite d <*> fromIR_suite g
      For a b asyncWs c d e f g h ->
        (\d' -> Syntax.For (Ann a) b asyncWs c d' e) <$>
        fromIR_expr d <*>
        traverse fromIR_expr f <*>
        fromIR_suite g <*>
        traverseOf (traverse._3) fromIR_suite h
      ClassDef a b c d e f g ->
        (\b' -> Syntax.ClassDef (Ann a) b' c d e) <$>
        traverse fromIR_decorator b <*>
        traverseOf (traverse._2.traverse.traverse) fromIR_arg f <*>
        fromIR_suite g
      With a b asyncWs c d e ->
        Syntax.With (Ann a) b asyncWs c <$>
        traverse fromIR_withItem d <*>
        fromIR_suite e
  
  fromIR_listItem
    :: AsIRError e a
    => Expr a
    -> Validation (NonEmpty e) (Syntax.ListItem '[] a)
  fromIR_listItem (StarExpr a b c) =
    Syntax.ListUnpack (Ann a) [] b <$> fromIR_expr c
  fromIR_listItem (Parens a b c d) =
    (\case
        Syntax.ListUnpack w x y z -> Syntax.ListUnpack w ((b, d) : x) y z
        Syntax.ListItem x y -> Syntax.ListItem (Ann a) (Syntax.Parens x b y d)) <$>
    fromIR_listItem c
  fromIR_listItem e = (\x -> Syntax.ListItem (x ^. annot) x) <$> fromIR_expr e
  
  fromIR_tupleItem
    :: AsIRError e a
    => Expr a
    -> Validation (NonEmpty e) (Syntax.TupleItem '[] a)
  fromIR_tupleItem (StarExpr a b c) =
    Syntax.TupleUnpack (Ann a) [] b <$> fromIR_expr c
  fromIR_tupleItem (Parens a b c d) =
    (\case
        Syntax.TupleUnpack w x y z -> Syntax.TupleUnpack w ((b, d) : x) y z
        Syntax.TupleItem x y -> Syntax.TupleItem (Ann a) (Syntax.Parens x b y d)) <$>
    fromIR_tupleItem c
  fromIR_tupleItem e =
    (\x -> Syntax.TupleItem (x ^. annot) x) <$> fromIR_expr e
  
  fromIR_setItem
    :: AsIRError e a
    => Expr a
    -> Validation (NonEmpty e) (Syntax.SetItem '[] a)
  fromIR_setItem (StarExpr a b c) =
    Syntax.SetUnpack (Ann a) [] b <$> fromIR_expr c
  fromIR_setItem (Parens a b c d) =
    (\case
        Syntax.SetUnpack w x y z -> Syntax.SetUnpack w ((b, d) : x) y z
        Syntax.SetItem x y -> Syntax.SetItem (Ann a) (Syntax.Parens x b y d)) <$>
    fromIR_setItem c
  fromIR_setItem e = (\x -> Syntax.SetItem (x ^. annot) x) <$> fromIR_expr e
  
  fromIR
    :: AsIRError e a
    => Module a
    -> Validation (NonEmpty e) (Syntax.Module '[] a)
  fromIR ModuleEmpty = pure Syntax.ModuleEmpty
  fromIR (ModuleBlankFinal a) = pure $ Syntax.ModuleBlankFinal a
  fromIR (ModuleBlank a b c) = Syntax.ModuleBlank a b <$> fromIR c
  fromIR (ModuleStatement a b) = Syntax.ModuleStatement <$> fromIR_statement a <*> fromIR b
  