{-# language LambdaCase #-} {-# language DataKinds, KindSignatures #-} {-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveGeneric #-} {-# language ExistentialQuantification #-} {-# language InstanceSigs, TypeApplications #-} {-# language MultiParamTypeClasses, FlexibleInstances #-} {-# language ScopedTypeVariables #-} {-| Module : Language.Python.Syntax.Expr Copyright : (C) CSIRO 2017-2019 License : BSD3 Maintainer : Isaac Elliott Stability : experimental Portability : non-portable -} module Language.Python.Syntax.Expr ( -- * Expressions Expr(..), HasExprs(..), shouldGroupLeft, shouldGroupRight -- * Parameters and arguments , Param(..), paramAnn, paramType_, paramType, paramName , Arg(..), argExpr -- * Comprehension expressions -- | https://docs.python.org/3/reference/expressions.html#grammar-token-comprehension , Comprehension(..), CompIf(..), CompFor(..) -- * Collection items , DictItem(..), ListItem(..), SetItem(..), TupleItem(..) -- * Subscripts , Subscript(..) ) where import Control.Lens.Cons (_last) import Control.Lens.Fold ((^?), (^?!)) import Control.Lens.Getter ((^.), getting, to, view) import Control.Lens.Lens (Lens, Lens', lens) import Control.Lens.Plated (Plated(..)) import Control.Lens.Prism (_Just, _Left, _Right) import Control.Lens.Setter ((.~), mapped, over) import Control.Lens.Traversal (Traversal, failing, traverseOf) import Control.Lens.Tuple (_2) import Data.Bifunctor (bimap) import Data.Bifoldable (bifoldMap) import Data.Bitraversable (bitraverse) import Data.Coerce (coerce) import Data.Digit.Integral (integralDecDigits) import Data.Function ((&)) import Data.Generics.Product.Typed (typed) import Data.List.NonEmpty (NonEmpty) import Data.Maybe (isNothing) import Data.Monoid ((<>)) import Data.String (IsString(..)) import GHC.Generics (Generic) import Unsafe.Coerce (unsafeCoerce) import Language.Python.Optics.Validated (Validated(..)) import Language.Python.Syntax.Ann import Language.Python.Syntax.CommaSep import Language.Python.Syntax.Ident 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 {- [unsafeCoerce Validation] We can't 'coerce' 'Expr's because the @v@ parameter is considered to have a nominal role, due to datatypes like 'Comprehension'. We only ever use @v@ in as a phantom in 'Expr', so 'unsafeCoerce :: Expr v a -> Expr '[] a' is safe. -} instance Validated Expr where; unvalidated = to unsafeCoerce instance Validated Param where; unvalidated = to unsafeCoerce instance Validated Arg where; unvalidated = to unsafeCoerce instance Validated DictItem where; unvalidated = to unsafeCoerce instance Validated SetItem where; unvalidated = to unsafeCoerce instance Validated TupleItem where; unvalidated = to unsafeCoerce instance Validated ListItem where; unvalidated = to unsafeCoerce -- | 'Control.Lens.Traversal.Traversal' over all the expressions in a term class HasExprs s where _Exprs :: Traversal (s v a) (s '[] a) (Expr v a) (Expr '[] a) -- | Formal parameters for functions -- -- See data Param (v :: [*]) a -- | @def foo(a):@ = PositionalParam { _paramAnn :: Ann a , _paramName :: Ident v a , _paramType :: Maybe (Colon, Expr v a) } -- | @def foo(bar=None):@ | KeywordParam { _paramAnn :: Ann a , _paramName :: Ident v a -- ':' spaces , _paramType :: Maybe (Colon, Expr v a) -- = spaces , _unsafeKeywordParamWhitespaceRight :: [Whitespace] , _unsafeKeywordParamExpr :: Expr v a } -- | @def foo(*xs):@ | StarParam { _paramAnn :: Ann a -- '*' spaces , _unsafeStarParamWhitespace :: [Whitespace] , _unsafeStarParamName :: Ident v a -- ':' spaces , _paramType :: Maybe (Colon, Expr v a) } -- | @def foo(*):@ | UnnamedStarParam { _paramAnn :: Ann a -- '*' spaces , _unsafeUnnamedStarParamWhitespace :: [Whitespace] } -- | @def foo(**dict):@ | DoubleStarParam { _paramAnn :: Ann a -- '**' spaces , _unsafeDoubleStarParamWhitespace :: [Whitespace] , _paramName :: Ident v a -- ':' spaces , _paramType :: Maybe (Colon, Expr v a) } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (Param v) where annot :: forall a. Lens' (Param v a) (Ann a) annot = typed @(Ann a) instance IsString (Param '[] ()) where fromString a = PositionalParam (Ann ()) (fromString a) Nothing instance HasTrailingWhitespace (Param v a) where trailingWhitespace = lens (\case PositionalParam _ a b -> maybe (a ^. trailingWhitespace) (^. _2.trailingWhitespace) b KeywordParam _ _ _ _ a -> a ^. trailingWhitespace UnnamedStarParam _ a -> a StarParam _ _ b c -> maybe (b ^. trailingWhitespace) (^. _2.trailingWhitespace) c DoubleStarParam _ _ a b -> maybe (a ^. trailingWhitespace) (^. _2.trailingWhitespace) b) (\p ws -> case p of PositionalParam a b c -> PositionalParam a (if isNothing c then b & trailingWhitespace .~ ws else b) (c & _Just._2.trailingWhitespace .~ ws) KeywordParam a b c d e -> KeywordParam a b c d $ e & trailingWhitespace .~ ws UnnamedStarParam a _ -> UnnamedStarParam a ws StarParam a b c d -> StarParam a b (if isNothing d then c & trailingWhitespace .~ ws else c) (d & _Just._2.trailingWhitespace .~ ws) DoubleStarParam a b c d -> DoubleStarParam a b (if isNothing d then c & trailingWhitespace .~ ws else c) (d & _Just._2.trailingWhitespace .~ ws)) -- | Lens on the syntrax tree annotation on a parameter paramAnn :: Lens' (Param v a) a paramAnn = lens (getAnn . _paramAnn) (\s a -> s { _paramAnn = Ann a}) -- | A faux-lens on the optional Python type annotation which may follow a parameter -- -- This is not a lawful 'Lens' because setting an 'UnnamedStarParam''s type won't -- have any effect. -- -- This optic, like many others in hpython, loses validation information -- (the @v@ type parameter) -- -- The following is an example, where @int@ is the paramtype: -- -- @ -- def foo(x: int): -- @ paramType_ :: Functor f => (Maybe (Colon, Expr v a) -> f (Maybe (Colon, Expr '[] a))) -> Param v a -> f (Param '[] a) paramType_ = lens (\case UnnamedStarParam{} -> Nothing a -> _paramType a) (\s ty -> case s ^. unvalidated of PositionalParam a b _ -> PositionalParam a b ty KeywordParam a b _ c d -> KeywordParam a b ty c d StarParam a b c _ -> StarParam a b c ty UnnamedStarParam a b -> UnnamedStarParam a b DoubleStarParam a b c _ -> DoubleStarParam a b c ty) -- | 'Traversal' targeting the Python type annotations which may follow a parameter paramType :: Traversal (Param v a) (Param '[] a) (Colon, Expr v a) (Colon, Expr '[] a) paramType = paramType_._Just -- | (affine) 'Control.Lens.Traversal.Traversal' on the name of a parameter -- -- The name is @x@ in the following examples: -- -- @ -- def foo(x): -- def foo(x=None): -- def foo(*x): -- def foo(**x): -- @ -- -- But the following example does not have a 'paramName': -- -- @ -- def foo(*): -- @ paramName :: Traversal (Param v a) (Param '[] a) (Ident v a) (Ident '[] a) paramName f (PositionalParam a b c) = PositionalParam a <$> f b <*> pure (over (mapped._2) (view unvalidated) c) paramName f (KeywordParam a b c d e) = (\b' -> KeywordParam a b' (over (mapped._2) (view unvalidated) c) d (e ^. unvalidated)) <$> f b paramName f (StarParam a b c d) = (\c' -> StarParam a b c' (over (mapped._2) (view unvalidated) d)) <$> f c paramName _ (UnnamedStarParam a b) = pure $ UnnamedStarParam a b paramName f (DoubleStarParam a b c d) = (\c' -> DoubleStarParam a b c' (over (mapped._2) (view unvalidated) d)) <$> f c instance HasExprs Param where _Exprs f (KeywordParam a name ty ws2 expr) = KeywordParam a (coerce name) <$> traverseOf (traverse._2) f ty <*> pure ws2 <*> f expr _Exprs f (PositionalParam a b c) = PositionalParam a (coerce b) <$> traverseOf (traverse._2) f c _Exprs f (StarParam a b c d) = StarParam a b (coerce c) <$> traverseOf (traverse._2) f d _Exprs _ (UnnamedStarParam a b) = pure $ UnnamedStarParam a b _Exprs f (DoubleStarParam a b c d) = DoubleStarParam a b (coerce c) <$> traverseOf (traverse._2) f d -- | Actual parameters for functions -- -- In the following examples, @x@ is an actual parameter. -- -- @ -- y = foo(x) -- y = bar(quux=x) -- y = baz(*x) -- y = flux(**x) -- @ data Arg (v :: [*]) a = PositionalArg { _argAnn :: Ann a , _argExpr :: Expr v a } | KeywordArg { _argAnn :: Ann a , _unsafeKeywordArgName :: Ident v a , _unsafeKeywordArgWhitespaceRight :: [Whitespace] , _argExpr :: Expr v a } | StarArg { _argAnn :: Ann a , _unsafeStarArgWhitespace :: [Whitespace] , _argExpr :: Expr v a } | DoubleStarArg { _argAnn :: Ann a , _unsafeDoubleStarArgWhitespace :: [Whitespace] , _argExpr :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (Arg v) where annot :: forall a. Lens' (Arg v a) (Ann a) annot = typed @(Ann a) instance IsString (Arg '[] ()) where fromString = PositionalArg (Ann ()) . fromString -- | Lens on the Python expression which is passed as the argument argExpr :: Lens (Arg v a) (Arg '[] a) (Expr v a) (Expr '[] a) argExpr = lens _argExpr (\s a -> (s ^. unvalidated) { _argExpr = a }) instance HasExprs Arg where _Exprs f (KeywordArg a name ws2 expr) = KeywordArg a (coerce name) ws2 <$> f expr _Exprs f (PositionalArg a expr) = PositionalArg a <$> f expr _Exprs f (StarArg a ws expr) = StarArg a ws <$> f expr _Exprs f (DoubleStarArg a ws expr) = StarArg a ws <$> f expr -- | A Python for comprehension, such as -- -- @ -- x for y in z -- @ data Comprehension e (v :: [*]) a = Comprehension (Ann a) (e v a) (CompFor v a) [Either (CompFor v a) (CompIf v a)] -- ^ (comp_for | comp_if)* deriving (Eq, Show, Generic) instance HasAnn (Comprehension e v) where annot :: forall a. Lens' (Comprehension e v a) (Ann a) annot = typed @(Ann a) instance HasTrailingWhitespace (Comprehension e v a) where trailingWhitespace = lens (\(Comprehension _ _ a b) -> case b of [] -> a ^. trailingWhitespace _ -> b ^?! _last.failing (_Left.trailingWhitespace) (_Right.trailingWhitespace)) (\(Comprehension a b c d) ws -> case d of [] -> Comprehension a b (c & trailingWhitespace .~ ws) d _ -> Comprehension a b c (d & _last.failing (_Left.trailingWhitespace) (_Right.trailingWhitespace) .~ ws)) instance Functor (e v) => Functor (Comprehension e v) 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 v) => Foldable (Comprehension e v) where foldMap f (Comprehension a b c d) = foldMap f a <> foldMap f b <> foldMap f c <> foldMap (bifoldMap (foldMap f) (foldMap f)) d instance Traversable (e v) => Traversable (Comprehension e v) where traverse f (Comprehension a b c d) = Comprehension <$> traverse f a <*> traverse f b <*> traverse f c <*> traverse (bitraverse (traverse f) (traverse f)) d -- | A condition inside a comprehension, e.g. @[x for x in xs if even(x)]@ data CompIf (v :: [*]) a = CompIf (Ann a) [Whitespace] (Expr v a) deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (CompIf v) where annot :: forall a. Lens' (CompIf v a) (Ann a) annot = typed @(Ann a) instance HasTrailingWhitespace (CompIf v a) where trailingWhitespace = lens (\(CompIf _ _ a) -> a ^. trailingWhitespace) (\(CompIf a b c) ws -> CompIf a b $ c & trailingWhitespace .~ ws) -- | A nested comprehesion, e.g. @[(x, y) for x in xs for y in ys]@ data CompFor (v :: [*]) a = CompFor (Ann a) [Whitespace] (Expr v a) [Whitespace] (Expr v a) deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (CompFor v) where annot :: forall a. Lens' (CompFor v a) (Ann a) annot = typed @(Ann a) instance HasTrailingWhitespace (CompFor v a) where trailingWhitespace = lens (\(CompFor _ _ _ _ a) -> a ^. trailingWhitespace) (\(CompFor a b c d e) ws -> CompFor a b c d $ e & trailingWhitespace .~ ws) -- | @a : b@ or @**a@ -- -- Used to construct dictionaries, e.g. @{ 1: a, 2: b, **c }@ -- -- https://docs.python.org/3/reference/expressions.html#dictionary-displays data DictItem (v :: [*]) a = DictItem { _dictItemAnn :: Ann a , _unsafeDictItemKey :: Expr v a , _unsafeDictItemColon :: Colon , _unsafeDictItemValue :: Expr v a } | DictUnpack { _dictItemAnn :: Ann a , _unsafeDictItemUnpackWhitespace :: [Whitespace] , _unsafeDictItemUnpackValue :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (DictItem v) where annot :: forall a. Lens' (DictItem v a) (Ann a) annot = typed @(Ann a) instance HasTrailingWhitespace (DictItem v a) where trailingWhitespace = lens (\(DictItem _ _ _ a) -> a ^. trailingWhitespace) (\(DictItem a b c d) ws -> DictItem a b c (d & trailingWhitespace .~ ws)) -- | Syntax for things that can be used as subscripts (inside the square brackets) -- -- e.g. -- -- @a[b]@ -- -- @a[:]@ -- -- @a[b:]@ -- -- @a[:b]@ -- -- @a[b:c]@ -- -- @a[b:c:d]@ -- -- https://docs.python.org/3/reference/expressions.html#subscriptions data Subscript (v :: [*]) a = SubscriptExpr (Expr v a) | SubscriptSlice -- [expr] (Maybe (Expr v a)) -- ':' Colon -- [expr] (Maybe (Expr v a)) -- [':' [expr]] (Maybe (Colon, Maybe (Expr v a))) deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasTrailingWhitespace (Subscript v a) where trailingWhitespace = lens (\case SubscriptExpr e -> e ^. trailingWhitespace SubscriptSlice _ b c d -> case d of Nothing -> case c of Nothing -> b ^. trailingWhitespace Just e -> e ^. trailingWhitespace Just (e, f) -> case f of Nothing -> e ^. trailingWhitespace Just g -> g ^. trailingWhitespace) (\x ws -> case x of SubscriptExpr e -> SubscriptExpr $ e & trailingWhitespace .~ ws SubscriptSlice a b c d -> (\(b', c', d') -> SubscriptSlice a b' c' d') $ case d of Nothing -> case c of Nothing -> (MkColon ws, c, d) Just e -> (b, Just $ e & trailingWhitespace .~ ws, d) Just (e, f) -> case f of Nothing -> (b, c, Just (MkColon ws, f)) Just g -> (b, c, Just (e, Just $ g & trailingWhitespace .~ ws))) -- | @a@ or @*a@ -- -- Used to construct lists, e.g. @[ 1, 'x', **c ]@ -- -- https://docs.python.org/3/reference/expressions.html#list-displays data ListItem (v :: [*]) a = ListItem { _listItemAnn :: Ann a , _unsafeListItemValue :: Expr v a } | ListUnpack { _listItemAnn :: Ann a , _unsafeListUnpackParens :: [([Whitespace], [Whitespace])] , _unsafeListUnpackWhitespace :: [Whitespace] , _unsafeListUnpackValue :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (ListItem v) where annot :: forall a. Lens' (ListItem v a) (Ann a) annot = typed @(Ann a) instance HasExprs ListItem where _Exprs f (ListItem a b) = ListItem a <$> f b _Exprs f (ListUnpack a b c d) = ListUnpack a b c <$> f d instance HasTrailingWhitespace (ListItem v a) where trailingWhitespace = lens (\case ListItem _ a -> a ^. trailingWhitespace ListUnpack _ [] _ a -> a ^. trailingWhitespace ListUnpack _ ((_, ws) : _) _ _ -> ws) (\a ws -> case a of ListItem b c -> ListItem b $ c & trailingWhitespace .~ ws ListUnpack b [] d e -> ListUnpack b [] d $ e & trailingWhitespace .~ ws ListUnpack b ((c, _) : rest) e f -> ListUnpack b ((c, ws) : rest) e f) -- | @a@ or @*a@ -- -- Used to construct sets, e.g. @{ 1, 'x', **c }@ -- -- https://docs.python.org/3/reference/expressions.html#set-displays data SetItem (v :: [*]) a = SetItem { _setItemAnn :: Ann a , _unsafeSetItemValue :: Expr v a } | SetUnpack { _setItemAnn :: Ann a , _unsafeSetUnpackParens :: [([Whitespace], [Whitespace])] , _unsafeSetUnpackWhitespace :: [Whitespace] , _unsafeSetUnpackValue :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (SetItem v) where annot :: forall a. Lens' (SetItem v a) (Ann a) annot = typed @(Ann a) instance HasExprs SetItem where _Exprs f (SetItem a b) = SetItem a <$> f b _Exprs f (SetUnpack a b c d) = SetUnpack a b c <$> f d instance HasTrailingWhitespace (SetItem v a) where trailingWhitespace = lens (\case SetItem _ a -> a ^. trailingWhitespace SetUnpack _ [] _ a -> a ^. trailingWhitespace SetUnpack _ ((_, ws) : _) _ _ -> ws) (\a ws -> case a of SetItem b c -> SetItem b $ c & trailingWhitespace .~ ws SetUnpack b [] d e -> SetUnpack b [] d $ e & trailingWhitespace .~ ws SetUnpack b ((c, _) : rest) e f -> SetUnpack b ((c, ws) : rest) e f) -- | @a@ or @*a@ -- -- Used to construct tuples, e.g. @(1, 'x', **c)@ data TupleItem (v :: [*]) a = TupleItem { _tupleItemAnn :: Ann a , _unsafeTupleItemValue :: Expr v a } | TupleUnpack { _tupleItemAnn :: Ann a , _unsafeTupleUnpackParens :: [([Whitespace], [Whitespace])] , _unsafeTupleUnpackWhitespace :: [Whitespace] , _unsafeTupleUnpackValue :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (TupleItem v) where annot :: forall a. Lens' (TupleItem v a) (Ann a) annot = typed @(Ann a) instance HasExprs TupleItem where _Exprs f (TupleItem a b) = TupleItem a <$> f b _Exprs f (TupleUnpack a b c d) = TupleUnpack a b c <$> f d instance HasTrailingWhitespace (TupleItem v a) where trailingWhitespace = lens (\case TupleItem _ a -> a ^. trailingWhitespace TupleUnpack _ [] _ a -> a ^. trailingWhitespace TupleUnpack _ ((_, ws) : _) _ _ -> ws) (\a ws -> case a of TupleItem b c -> TupleItem b $ c & trailingWhitespace .~ ws TupleUnpack b [] d e -> TupleUnpack b [] d $ e & trailingWhitespace .~ ws TupleUnpack b ((c, _) : rest) e f -> TupleUnpack b ((c, ws) : rest) e f) -- | This large sum type covers all valid Python /expressions/ data Expr (v :: [*]) a -- | @()@ -- -- https://docs.python.org/3/reference/expressions.html#parenthesized-forms = Unit { _unsafeExprAnn :: Ann a , _unsafeUnitWhitespaceInner :: [Whitespace] , _unsafeUnitWhitespaceRight :: [Whitespace] } -- | @lambda x, y: x@ -- -- https://docs.python.org/3/reference/expressions.html#lambda | Lambda { _unsafeExprAnn :: Ann a , _unsafeLambdaWhitespace :: [Whitespace] , _unsafeLambdaArgs :: CommaSep (Param v a) , _unsafeLambdaColon :: Colon , _unsafeLambdaBody :: Expr v a } -- | @yield@ -- -- @yield a@ -- -- @yield a, b@ -- -- https://docs.python.org/3/reference/expressions.html#yield-expressions | Yield { _unsafeExprAnn :: Ann a , _unsafeYieldWhitespace :: [Whitespace] , _unsafeYieldValue :: CommaSep (Expr v a) } -- | @yield from a@ -- -- https://docs.python.org/3/reference/expressions.html#yield-expressions | YieldFrom { _unsafeExprAnn :: Ann a , _unsafeYieldWhitespace :: [Whitespace] , _unsafeFromWhitespace :: [Whitespace] , _unsafeYieldFromValue :: Expr v a } -- | @a if b else c@ -- -- https://docs.python.org/3/reference/expressions.html#conditional-expressions | Ternary { _unsafeExprAnn :: Ann a -- expr , _unsafeTernaryValue :: Expr v a -- 'if' spaces , _unsafeTernaryWhitespaceIf :: [Whitespace] -- expr , _unsafeTernaryCond :: Expr v a -- 'else' spaces , _unsafeTernaryWhitespaceElse :: [Whitespace] -- expr , _unsafeTernaryElse :: Expr v a } -- | @[a for b in c if d]@ -- -- https://docs.python.org/3/reference/expressions.html#list-displays | ListComp { _unsafeExprAnn :: Ann a -- [ spaces , _unsafeListCompWhitespaceLeft :: [Whitespace] -- comprehension , _unsafeListCompValue :: Comprehension Expr v a -- ] spaces , _unsafeListCompWhitespaceRight :: [Whitespace] } -- | @[a, b, c]@ -- -- https://docs.python.org/3/reference/expressions.html#list-displays | List { _unsafeExprAnn :: Ann a -- [ spaces , _unsafeListWhitespaceLeft :: [Whitespace] -- exprs , _unsafeListValues :: Maybe (CommaSep1' (ListItem v a)) -- ] spaces , _unsafeListWhitespaceRight :: [Whitespace] } -- | @{a: b for c in d if e}@ -- -- https://docs.python.org/3/reference/expressions.html#dictionary-displays | DictComp { _unsafeExprAnn :: Ann a -- { spaces , _unsafeDictCompWhitespaceLeft :: [Whitespace] -- comprehension , _unsafeDictCompValue :: Comprehension DictItem v a -- } spaces , _unsafeDictCompWhitespaceRight :: [Whitespace] } -- | @{}@ -- -- @{a: 1, b: 2, c: 3}@ -- -- https://docs.python.org/3/reference/expressions.html#dictionary-displays | Dict { _unsafeExprAnn :: Ann a , _unsafeDictWhitespaceLeft :: [Whitespace] , _unsafeDictValues :: Maybe (CommaSep1' (DictItem v a)) , _unsafeDictWhitespaceRight :: [Whitespace] } -- | @{a for b in c if d}@ -- -- https://docs.python.org/3/reference/expressions.html#set-displays | SetComp { _unsafeExprAnn :: Ann a -- { spaces , _unsafeSetCompWhitespaceLeft :: [Whitespace] -- comprehension , _unsafeSetCompValue :: Comprehension SetItem v a -- } spaces , _unsafeSetCompWhitespaceRight :: [Whitespace] } -- | @{a, b, c}@ -- -- https://docs.python.org/3/reference/expressions.html#set-displays | Set { _unsafeExprAnn :: Ann a , _unsafeSetWhitespaceLeft :: [Whitespace] , _unsafeSetValues :: CommaSep1' (SetItem v a) , _unsafeSetWhitespaceRight :: [Whitespace] } -- | @a.b@ -- -- https://docs.python.org/3/reference/expressions.html#attribute-references | Deref { _unsafeExprAnn :: Ann a -- expr , _unsafeDerefValueLeft :: Expr v a -- . spaces , _unsafeDerefWhitespaceLeft :: [Whitespace] -- ident , _unsafeDerefValueRight :: Ident v a } -- | @a[b]@ -- -- @a[:]@ -- -- @a[:, b:]@ -- -- etc. -- -- https://docs.python.org/3/reference/expressions.html#subscriptions | Subscript { _unsafeExprAnn :: Ann a -- expr , _unsafeSubscriptValueLeft :: Expr v a -- [ spaces , _unsafeSubscriptWhitespaceLeft :: [Whitespace] -- expr , _unsafeSubscriptValueRight :: CommaSep1' (Subscript v a) -- ] spaces , _unsafeSubscriptWhitespaceRight :: [Whitespace] } -- | @f(x)@ -- -- https://docs.python.org/3/reference/expressions.html#calls | Call { _unsafeExprAnn :: Ann a -- expr , _unsafeCallFunction :: Expr v a -- ( spaces , _unsafeCallWhitespaceLeft :: [Whitespace] -- exprs , _unsafeCallArguments :: Maybe (CommaSep1' (Arg v a)) -- ) spaces , _unsafeCallWhitespaceRight :: [Whitespace] } -- | @None@ -- -- https://docs.python.org/3/library/constants.html#None | None { _unsafeExprAnn :: Ann a , _unsafeNoneWhitespace :: [Whitespace] } -- | @...@ -- -- https://docs.python.org/3/library/constants.html#Ellipsis | Ellipsis { _unsafeExprAnn :: Ann a , _unsafeEllipsisWhitespace :: [Whitespace] } -- | @a + b@ -- -- https://docs.python.org/3/reference/expressions.html#the-power-operator -- -- https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations -- -- https://docs.python.org/3/reference/expressions.html#shifting-operations -- -- https://docs.python.org/3/reference/expressions.html#binary-bitwise-operations -- -- https://docs.python.org/3/reference/expressions.html#comparisons -- -- https://docs.python.org/3/reference/expressions.html#membership-test-operations -- -- https://docs.python.org/3/reference/expressions.html#is-not -- -- https://docs.python.org/3/reference/expressions.html#boolean-operations | BinOp { _unsafeExprAnn :: Ann a , _unsafeBinOpExprLeft :: Expr v a , _unsafeBinOpOp :: BinOp a , _unsafeBinOpExprRight :: Expr v a } -- | @-a@ -- -- @~a@ -- -- @+a@ -- -- https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations | UnOp { _exprAnn :: Ann a , _unsafeUnOpOp :: UnOp a , _unsafeUnOpValue :: Expr v a } | Parens { _exprAnn :: Ann a -- ( spaces , _unsafeParensWhitespaceLeft :: [Whitespace] -- expr , _unsafeParensValue :: Expr v a -- ) spaces , _unsafeParensWhitespaceAfter :: [Whitespace] } -- | @a@ -- -- https://docs.python.org/3/reference/expressions.html#atom-identifiers | Ident { _exprAnn :: Ann a , _unsafeIdentValue :: Ident v a } -- | @1@ -- -- @0xF3A -- -- @0o177 -- -- @0b1011@ -- -- https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-integer | Int { _exprAnn :: Ann a , _unsafeIntValue :: IntLiteral a , _unsafeIntWhitespace :: [Whitespace] } -- | @1.@ -- -- @3.14@ -- -- @10e100@ -- -- https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals | Float { _exprAnn :: Ann a , _unsafeFloatValue :: FloatLiteral a , _unsafeFloatWhitespace :: [Whitespace] } -- | @10j@ -- -- @5.j@ -- -- https://docs.python.org/3/reference/lexical_analysis.html#floating-point-literals | Imag { _exprAnn :: Ann a , _unsafeImagValue :: ImagLiteral a , _unsafeImagWhitespace :: [Whitespace] } -- | @True@ -- -- @False@ -- -- https://docs.python.org/3/library/constants.html#True -- -- https://docs.python.org/3/library/constants.html#False | Bool { _exprAnn :: Ann a , _unsafeBoolValue :: Bool , _unsafeBoolWhitespace :: [Whitespace] } -- | @\"asdf\"@ -- -- @b\"asdf\"@ -- -- @\"asdf\" \'asdf\'@ -- -- @\'\'\'asdf\'\'\'@ -- -- https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-stringliteral | String { _exprAnn :: Ann a , _unsafeStringValue :: NonEmpty (StringLiteral a) } -- | @a, b, c@ -- -- @(a, b)@ -- -- @(a,)@ -- -- https://docs.python.org/3/reference/expressions.html#expression-lists | Tuple { _exprAnn :: Ann a -- expr , _unsafeTupleHead :: TupleItem v a -- , spaces , _unsafeTupleWhitespace :: Comma -- [exprs] , _unsafeTupleTail :: Maybe (CommaSep1' (TupleItem v a)) } -- | @not a@ -- -- https://docs.python.org/3/reference/expressions.html#boolean-operations | Not { _exprAnn :: Ann a , _unsafeNotWhitespace :: [Whitespace] , _unsafeNotValue :: Expr v a } -- | @(a for b in c)@ -- -- https://docs.python.org/3/reference/expressions.html#generator-expressions | Generator { _exprAnn :: Ann a , _generatorValue :: Comprehension Expr v a } -- | @await a@ -- -- https://docs.python.org/3/reference/expressions.html#await | Await { _exprAnn :: Ann a , _unsafeAwaitWhitespace :: [Whitespace] , _unsafeAwaitValue :: Expr v a } deriving (Eq, Show, Functor, Foldable, Traversable, Generic) instance HasAnn (Expr v) where annot :: forall a. Lens' (Expr v a) (Ann a) annot = typed @(Ann a) instance HasTrailingWhitespace (Expr v a) where trailingWhitespace = lens (\case Unit _ _ a -> a Lambda _ _ _ _ a -> a ^. trailingWhitespace Yield _ ws CommaSepNone -> ws Yield _ _ e -> e ^?! csTrailingWhitespace YieldFrom _ _ _ e -> e ^. trailingWhitespace Ternary _ _ _ _ _ e -> e ^. trailingWhitespace None _ ws -> ws Ellipsis _ ws -> ws List _ _ _ ws -> ws ListComp _ _ _ ws -> ws Deref _ _ _ a -> a ^. trailingWhitespace Subscript _ _ _ _ ws -> ws Call _ _ _ _ ws -> ws BinOp _ _ _ e -> e ^. trailingWhitespace UnOp _ _ e -> e ^. trailingWhitespace Parens _ _ _ ws -> ws Ident _ a -> a ^. getting trailingWhitespace Int _ _ ws -> ws Float _ _ ws -> ws Imag _ _ ws -> ws Bool _ _ ws -> ws String _ v -> v ^. trailingWhitespace Not _ _ e -> e ^. trailingWhitespace Tuple _ _ (MkComma ws) Nothing -> ws Tuple _ _ _ (Just cs) -> cs ^. trailingWhitespace DictComp _ _ _ ws -> ws Dict _ _ _ ws -> ws SetComp _ _ _ ws -> ws Set _ _ _ ws -> ws Generator _ a -> a ^. trailingWhitespace Await _ _ e -> e ^. trailingWhitespace) (\e ws -> case e of Unit a b _ -> Unit a b ws Lambda a b c d f -> Lambda a b c d (f & trailingWhitespace .~ ws) Yield a _ CommaSepNone -> Yield a ws CommaSepNone Yield a b c -> Yield a b (c & csTrailingWhitespace .~ ws) YieldFrom a b c d -> YieldFrom a b c (d & trailingWhitespace .~ ws) Ternary a b c d e f -> Ternary a b c d e (f & trailingWhitespace .~ ws) None a _ -> None a ws Ellipsis a _ -> Ellipsis a ws List a b c _ -> List a b (coerce c) ws ListComp a b c _ -> ListComp a b (coerce c) ws Deref a b c d -> Deref a (coerce b) c (d & trailingWhitespace .~ ws) Subscript a b c d _ -> Subscript a (coerce b) c d ws Call a b c d _ -> Call a (coerce b) c (coerce d) ws BinOp a b c e -> BinOp a (coerce b) c (e & trailingWhitespace .~ ws) UnOp a b c -> UnOp a b (c & trailingWhitespace .~ ws) Parens a b c _ -> Parens a b (coerce c) ws Ident a b -> Ident a $ b & trailingWhitespace .~ ws Int a b _ -> Int a b ws Float a b _ -> Float a b ws Imag a b _ -> Imag a b ws Bool a b _ -> Bool a b ws String a v -> String a (v & trailingWhitespace .~ ws) Not a b c -> Not a b (c & trailingWhitespace .~ ws) Tuple a b _ Nothing -> Tuple a (coerce b) (MkComma ws) Nothing Tuple a b c (Just cs) -> Tuple a (coerce b) c (Just $ cs & trailingWhitespace .~ ws) DictComp a b c _ -> DictComp a b c ws Dict a b c _ -> Dict a b c ws SetComp a b c _ -> SetComp a b c ws Set a b c _ -> Set a b c ws Generator a b -> Generator a $ b & trailingWhitespace .~ ws Await a b c -> Await a b (c & trailingWhitespace .~ ws)) instance IsString (Expr '[] ()) where fromString s = Ident (Ann ()) $ MkIdent (Ann ()) s [] instance Num (Expr '[] ()) where fromInteger n | n >= 0 = Int (Ann ()) (IntLiteralDec (Ann ()) $ integralDecDigits n ^?! _Right) [] | otherwise = UnOp (Ann ()) (Negate (Ann ()) []) (Int (Ann ()) (IntLiteralDec (Ann ()) $ integralDecDigits (-n) ^?! _Right) []) negate = UnOp (Ann ()) (Negate (Ann ()) []) (+) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Plus (Ann ()) [Space]) (*) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Multiply (Ann ()) [Space]) (-) a = BinOp (Ann ()) (a & trailingWhitespace .~ [Space]) (Minus (Ann ()) [Space]) signum = undefined abs = undefined instance Plated (Expr '[] a) where plate fun e = case e of Unit{} -> pure e Lambda a b c d e -> (\c' -> Lambda a b c' d) <$> (traverse.paramExpr) fun c <*> fun e Yield a b c -> Yield a b <$> traverse fun c YieldFrom a b c d -> YieldFrom a b c <$> fun d Ternary a b c d e f -> (\b' d' -> Ternary a b' c d' e) <$> fun b <*> fun d <*> fun f None{} -> pure e Ellipsis{} -> pure e List a b c d -> (\c' -> List a b c' d) <$> (traverse.traverse.listItemExpr) fun c ListComp a b c d -> (\c' -> ListComp a b c' d) <$> compExpr fun c Deref a b c d -> (\b' -> Deref a b' c d) <$> fun b Subscript a b c d e -> (\b' d' -> Subscript a b' c d' e) <$> fun b <*> (traverse.subscriptExpr) fun d Call a b c d e -> (\b' d' -> Call a b' c d' e) <$> fun b <*> (traverse.traverse.argExpr) fun d BinOp a b c d -> (\b' -> BinOp a b' c) <$> fun b <*> fun d UnOp a b c -> UnOp a b <$> fun c Parens a b c d -> (\c' -> Parens a b c' d) <$> fun c Ident{} -> pure e Int{} -> pure e Float{} -> pure e Imag{} -> pure e Bool{} -> pure e String{} -> pure e Not a b c -> Not a b <$> fun c Tuple a b c d -> (\b' -> Tuple a b' c) <$> tupleItemExpr fun b <*> (traverse.traverse.tupleItemExpr) fun d DictComp a b c d -> (\c' -> DictComp a b c' d) <$> dictCompExpr fun c Dict a b c d -> (\c' -> Dict a b c' d) <$> (traverse.traverse.dictItemExpr) fun c SetComp a b c d -> (\c' -> SetComp a b c' d) <$> setCompExpr fun c Set a b c d -> (\c' -> Set a b c' d) <$> (traverse.setItemExpr) fun c Generator a b -> Generator a <$> compExpr fun b Await a b c -> Await a b <$> fun c where paramExpr fun' p = case p of PositionalParam a b c -> PositionalParam a b <$> (traverse._2) fun' c KeywordParam a b c d e -> (\c' -> KeywordParam a b c' d) <$> (traverse._2) fun' c <*> fun' e UnnamedStarParam{} -> pure p StarParam a b c d -> StarParam a b c <$> (traverse._2) fun' d DoubleStarParam a b c d -> DoubleStarParam a b c <$> (traverse._2) fun' d listItemExpr fun' li = case li of ListItem a b -> ListItem a <$> fun' b ListUnpack a b c d -> ListUnpack a b c <$> fun' d tupleItemExpr fun' ti = case ti of TupleItem a b -> TupleItem a <$> fun' b TupleUnpack a b c d -> TupleUnpack a b c <$> fun' d setItemExpr fun' si = case si of SetItem a b -> SetItem a <$> fun' b SetUnpack a b c d -> SetUnpack a b c <$> fun' d dictItemExpr fun' di = case di of DictItem a b c d -> (\b' -> DictItem a b' c) <$> fun' b <*> fun' d DictUnpack a b c -> DictUnpack a b <$> fun' c compIfExpr fun' (CompIf a b c) = CompIf a b <$> fun' c compForExpr fun' (CompFor a b c d e) = (\c' -> CompFor a b c' d) <$> fun' c <*> fun' e compExpr fun' (Comprehension a b c d) = Comprehension a <$> fun' b <*> compForExpr fun' c <*> traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d dictCompExpr fun' (Comprehension a b c d) = Comprehension a <$> dictItemExpr fun' b <*> compForExpr fun' c <*> traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d setCompExpr fun' (Comprehension a b c d) = Comprehension a <$> setItemExpr fun' b <*> compForExpr fun' c <*> traverse (bitraverse (compForExpr fun') (compIfExpr fun')) d subscriptExpr fun' ss = case ss of SubscriptExpr a -> SubscriptExpr <$> fun' a SubscriptSlice a b c d -> (\a' -> SubscriptSlice a' b) <$> traverse fun' a <*> traverse fun' c <*> (traverse._2.traverse) fun' d argExpr fun' arg = case arg of PositionalArg a b -> PositionalArg a <$> fun' b KeywordArg a b c d -> KeywordArg a b c <$> fun' d StarArg a b c -> StarArg a b <$> fun' c DoubleStarArg a b c -> DoubleStarArg a b <$> fun' c instance HasExprs Expr where _Exprs = id -- | -- @shouldGroupLeft op left@ returns true if @left@ needs to be parenthesised -- when it is the left argument of @op@ shouldGroupLeft :: BinOp a -> Expr v a -> Bool shouldGroupLeft op left = let entry = lookupOpEntry op operatorTable lEntry = case left of BinOp _ _ lOp _ -> Just $ lookupOpEntry lOp operatorTable _ -> Nothing leftf = case entry ^. opAssoc of R | Just (OpEntry _ prec R) <- lEntry -> prec <= entry ^. opPrec _ -> False leftf' = case (left, op) of (UnOp{}, Exp{}) -> True (Tuple{}, _) -> True (Not{}, BoolAnd{}) -> False (Not{}, BoolOr{}) -> False (Not{}, _) -> True _ -> maybe False (\p -> p < entry ^. opPrec) (lEntry ^? _Just.opPrec) in leftf || leftf' -- | -- @shouldGroupRight op right@ returns true if @right@ needs to be parenthesised -- when it is the right argument of @op@ shouldGroupRight :: BinOp a -> Expr v a -> Bool shouldGroupRight op right = let entry = lookupOpEntry op operatorTable rEntry = case right of BinOp _ _ rOp _ -> Just $ lookupOpEntry rOp operatorTable _ -> Nothing rightf = case entry ^. opAssoc of L | Just (OpEntry _ prec L) <- rEntry -> prec <= entry ^. opPrec _ -> False rightf' = case (op, right) of (_, Tuple{}) -> True (BoolAnd{}, Not{}) -> False (BoolOr{}, Not{}) -> False (_, Not{}) -> True _ -> maybe False (\p -> p < entry ^. opPrec) (rEntry ^? _Just.opPrec) in rightf || rightf'