content: {-# language OverloadedStrings, DataKinds, TemplateHaskell #-}
  module Scope (scopeTests) where
  
  import Hedgehog
  
  import Control.Lens ((#), has)
  import Data.Function ((&))
  import Data.Functor (($>))
  import Data.List.NonEmpty (NonEmpty ((:|)))
  import Data.Validation (Validation(..), _Success)
  
  import Language.Python.Validate
  import Language.Python.DSL
  import Language.Python.Optics
  import Language.Python.Syntax.Ann
  import Language.Python.Syntax.Whitespace
  
  scopeTests :: Group
  scopeTests = $$discover
  
  fullyValidate
    :: Statement '[] ()
    -> PropertyT IO
         (Validation
            (NonEmpty (ScopeError ()))
            (Statement '[Scope, Syntax, Indentation] ()))
  fullyValidate x =
    case runValidateIndentation $ validateStatementIndentation x of
      Failure errs -> do
        annotateShow (errs :: NonEmpty (IndentationError ()))
        failure
      Success a ->
        case runValidateSyntax (validateStatementSyntax a) of
          Failure errs -> do
            annotateShow (errs :: NonEmpty (SyntaxError ()))
            failure
          Success a' -> pure $ runValidateScope (validateStatementScope a')
  
  prop_scope_1 :: Property
  prop_scope_1 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" [p_ "a", p_ "b"]
            [ line_ $ if_ true_ [ line_ (var_ "c" .= 2) ]
            , line_ . return_ $ var_ "a" .+ var_ "b" .+ var_ "c"
            ]
      res <- fullyValidate expr
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "c" []) :| [])
  
  prop_scope_2 :: Property
  prop_scope_2 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" [p_ "a", p_ "b"]
            [ line_ (var_ "c" .= 0)
            , line_ $ if_ true_ [ line_ (var_ "c" .= 2) ]
            , line_ . return_ $ var_ "a" .+ var_ "b" .+ var_ "c"
            ]
      res <- fullyValidate expr
      annotateShow res
      assert $ has _Success res
  
  prop_scope_3 :: Property
  prop_scope_3 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" [p_ "a", p_ "b"]
            [ line_ . return_ $ var_ "a" .+ var_ "b" .+ var_ "c" ]
      res <- fullyValidate expr
      annotateShow res
      res === Failure (NotInScope (MkIdent (Ann ()) "c" []) :| [])
  
  prop_scope_4 :: Property
  prop_scope_4 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" [p_ "a", p_ "b"]
            [ line_ $ def_ "f" [] [ line_ $ def_ "g" [] [ line_ pass_ ] ]
            , line_ $ call_ (var_ "g") []
            ]
      res <- fullyValidate expr
      res === Failure (NotInScope (MkIdent (Ann ()) "g" []) :| [])
  
  prop_scope_5 :: Property
  prop_scope_5 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" [p_ "a"]
            [ line_ $ def_ "f" [k_ "b" (var_ "c")] [ line_ pass_ ]
            ]
      res <- fullyValidate expr
      annotateShow res
      res === Failure (NotInScope (MkIdent (Ann ()) "c" []) :| [])
  
  prop_scope_6 :: Property
  prop_scope_6 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" []
            [ line_ $
                if_ true_ [ line_ (var_ "x" .= 2) ] &
                else_ [ line_ pass_ ]
            , line_ $ var_ "x"
            ]
      res <- fullyValidate expr
      annotateShow res
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
  
  prop_scope_7 :: Property
  prop_scope_7 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" []
            [ line_ $
                if_ true_ [ line_ pass_ ] &
                else_ [ line_ (var_ "x" .= 3) ]
            , line_ $ var_ "x"
            ]
      res <- fullyValidate expr
      annotateShow res
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
  
  prop_scope_8 :: Property
  prop_scope_8 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" []
            [ line_ $
                if_ true_ [ line_ pass_ ] &
                else_ [ line_ (var_ "x" .= 3) ]
            , line_ (var_ "x" .= 1)
            , line_ $ var_ "x"
            ]
      res <- fullyValidate expr
      annotateShow res
      (res $> ()) === Success ()
  
  prop_scope_9 :: Property
  prop_scope_9 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" []
            [ line_ $ for_ ("x" `in_` [ list_ [li_ $ int_ 1] ]) [ line_ pass_ ]
            , line_ $ var_ "x"
            ]
      res <- fullyValidate expr
      annotateShow res
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
  
  prop_scope_10 :: Property
  prop_scope_10 =
    withTests 1 . property $ do
      let
        expr =
          _Fundef #
          def_ "test" []
            [ line_ $ for_ ("x" `in_` [ list_ [li_ $ int_ 1] ]) [ line_ $ var_ "x" ]
            ]
      res <- fullyValidate expr
      annotateShow res
      (res $> ()) === Success ()
  
  prop_scope_11 :: Property
  prop_scope_11 =
    withTests 1 . property $ do
      let
        st =
          _Fundef #
          def_ "test" []
            [ line_ ("x" .= 2)
            , line_ $ for_ ("x" `in_` [ list_ [li_ $ int_ 1] ]) [ line_ pass_ ]
            ]
      res <- fullyValidate st
      annotateShow res
      res === Failure (BadShadowing (MkIdent (Ann ()) "x" [Space]) :| [])
  
  prop_scope_12 :: Property
  prop_scope_12 =
    withTests 1 . property $ do
      let
        st =
          _If #
          (if_ none_ [line_ (var_ "x" .= 2)] &
           else_ [line_ (var_ "y" .= var_ "x")])
      res <- fullyValidate st
      annotateShow res
      res === Failure (NotInScope (MkIdent (Ann ()) "x" []) :| [])
  
  prop_scope_13 :: Property
  prop_scope_13 =
    withTests 1 . property $ do
      let
        st =
          _Fundef #
          def_ "test" []
          [ line_ $
            if_ none_ [line_ (var_ "x" .= 1)] &
            else_ [line_ (var_ "y" .= 2)]
          , line_ $ var_ "x"
          ]
      res <- fullyValidate st
      annotateShow res
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "x" []) :| [])
  
  prop_scope_14 :: Property
  prop_scope_14 =
    withTests 1 . property $ do
      let
        st =
          _Fundef #
          def_ "test" []
          [ line_ $
            if_ none_ [line_ (var_ "x" .= 1)] &
            else_ [line_ (var_ "y" .= 2)]
          , line_ $ var_ "y"
          ]
      res <- fullyValidate st
      annotateShow res
      res === Failure (FoundDynamic () (MkIdent (Ann ()) "y" []) :| [])
  