@@ -29,6 +29,17 @@ module Python.Internal.Eval
29
29
, mustThrowPyError
30
30
, checkThrowBadPyType
31
31
, throwOnNULL
32
+ -- * Exec & eval
33
+ , Namespace (.. )
34
+ , Main (.. )
35
+ , Temp (.. )
36
+ , Dict (.. )
37
+ , DictPtr (.. )
38
+ , Module (.. )
39
+ , ModulePtr (.. )
40
+ , unsafeWithCode
41
+ , eval
42
+ , exec
32
43
-- * Debugging
33
44
, debugPrintPy
34
45
) where
@@ -42,6 +53,8 @@ import Control.Monad.IO.Class
42
53
import Control.Monad.Trans.Cont
43
54
import Data.Maybe
44
55
import Data.Function
56
+ import Data.ByteString qualified as BS
57
+ import Data.ByteString.Unsafe qualified as BS
45
58
import Foreign.Concurrent qualified as GHC
46
59
import Foreign.Ptr
47
60
import Foreign.ForeignPtr
@@ -662,6 +675,157 @@ checkThrowBadPyType = do
662
675
_ -> throwM BadPyType
663
676
664
677
678
+ ----------------------------------------------------------------
679
+ -- Eval/exec
680
+ ----------------------------------------------------------------
681
+
682
+ -- | Type class for values representing python dictionaries containing
683
+ -- global or local variables.
684
+ --
685
+ -- @since 0.2@
686
+ class Namespace a where
687
+ -- | Returns dictionary object. Caller takes ownership of returned
688
+ -- object.
689
+ basicNamespaceDict :: a -> Py (Ptr PyObject )
690
+
691
+
692
+ -- | Namespace for the top level code execution.
693
+ --
694
+ -- @since 0.2@
695
+ data Main = Main
696
+
697
+ instance Namespace Main where
698
+ basicNamespaceDict _ =
699
+ throwOnNULL =<< Py [CU. block | PyObject* {
700
+ PyObject* main_module = PyImport_AddModule("__main__");
701
+ if( PyErr_Occurred() )
702
+ return NULL;
703
+ PyObject* dict = PyModule_GetDict(main_module);
704
+ Py_XINCREF(dict);
705
+ return dict;
706
+ }|]
707
+
708
+
709
+ -- | Temporary namespace which get destroyed after execution
710
+ --
711
+ -- @since 0.2@
712
+ data Temp = Temp
713
+
714
+ instance Namespace Temp where
715
+ basicNamespaceDict _ = basicNewDict
716
+
717
+
718
+ -- | Newtype wrapper for bare python object. It's assumed to be a
719
+ -- dictionary. This is not checked.
720
+ --
721
+ -- @since 0.2@
722
+ newtype DictPtr = DictPtr (Ptr PyObject )
723
+
724
+ instance Namespace DictPtr where
725
+ basicNamespaceDict (DictPtr p) = p <$ incref p
726
+
727
+
728
+ -- | Newtype wrapper for bare python object. It's assumed to be a
729
+ -- dictionary. This is not checked.
730
+ --
731
+ -- @since 0.2@
732
+ newtype Dict = Dict PyObject
733
+
734
+ instance Namespace Dict where
735
+ basicNamespaceDict (Dict d)
736
+ -- NOTE: We're incrementing counter inside bracket so we're safe.
737
+ = unsafeWithPyObject d (basicNamespaceDict . DictPtr )
738
+
739
+ -- | Newtype wrapper over module object.
740
+ --
741
+ -- @since 0.2@
742
+ newtype ModulePtr = ModulePtr (Ptr PyObject )
743
+
744
+ instance Namespace ModulePtr where
745
+ basicNamespaceDict (ModulePtr p) = do
746
+ throwOnNULL =<< Py [CU. block | PyObject* {
747
+ PyObject* dict = PyModule_GetDict($(PyObject* p));
748
+ Py_XINCREF(dict);
749
+ return dict;
750
+ }|]
751
+
752
+ -- | Newtype wrapper over module object.
753
+ newtype Module = Module PyObject
754
+
755
+ instance Namespace Module where
756
+ basicNamespaceDict (Module d)
757
+ -- NOTE: We're incrementing counter inside bracket so we're safe.
758
+ = unsafeWithPyObject d (basicNamespaceDict . ModulePtr )
759
+
760
+
761
+ -- | Evaluate python expression
762
+ --
763
+ -- @since 0.2@
764
+ eval :: (Namespace global , Namespace local )
765
+ => global -- ^ Data type providing global variables dictionary
766
+ -> local -- ^ Data type providing local variables dictionary
767
+ -> PyQuote -- ^ Source code
768
+ -> Py PyObject
769
+ eval globals locals q = runProgram $ do
770
+ p_py <- unsafeWithCode q. code
771
+ p_globals <- takeOwnership =<< progPy (basicNamespaceDict globals)
772
+ p_locals <- takeOwnership =<< progPy (basicNamespaceDict locals)
773
+ progPy $ do
774
+ q. binder. bind p_locals
775
+ p_res <- Py [C. block | PyObject* {
776
+ PyObject* globals = $(PyObject* p_globals);
777
+ PyObject* locals = $(PyObject* p_locals);
778
+ // Compile code
779
+ PyObject *code = Py_CompileString($(char* p_py), "<interactive>", Py_eval_input);
780
+ if( PyErr_Occurred() ) {
781
+ return NULL;
782
+ }
783
+ // Evaluate expression
784
+ PyObject* r = PyEval_EvalCode(code, globals, locals);
785
+ Py_DECREF(code);
786
+ return r;
787
+ }|]
788
+ checkThrowPyError
789
+ newPyObject p_res
790
+ {-# SPECIALIZE eval :: Main -> Temp -> PyQuote -> Py PyObject #-}
791
+
792
+ -- | Evaluate sequence of python statements
793
+ --
794
+ -- @since 0.2@
795
+ exec :: (Namespace global , Namespace local )
796
+ => global -- ^ Data type providing global variables dictionary
797
+ -> local -- ^ Data type providing local variables dictionary
798
+ -> PyQuote -- ^ Source code
799
+ -> Py ()
800
+ exec globals locals q = runProgram $ do
801
+ p_py <- unsafeWithCode q. code
802
+ p_globals <- takeOwnership =<< progPy (basicNamespaceDict globals)
803
+ p_locals <- takeOwnership =<< progPy (basicNamespaceDict locals)
804
+ progPy $ do
805
+ q. binder. bind p_locals
806
+ Py [C. block | void {
807
+ PyObject* globals = $(PyObject* p_globals);
808
+ PyObject* locals = $(PyObject* p_locals);
809
+ // Compile code
810
+ PyObject *code = Py_CompileString($(char* p_py), "<interactive>", Py_file_input);
811
+ if( PyErr_Occurred() ){
812
+ return;
813
+ }
814
+ // Execute statements
815
+ PyObject* res = PyEval_EvalCode(code, globals, locals);
816
+ Py_XDECREF(res);
817
+ Py_DECREF(code);
818
+ } |]
819
+ checkThrowPyError
820
+ {-# SPECIALIZE exec :: Main -> Main -> PyQuote -> Py () #-}
821
+ {-# SPECIALIZE exec :: Main -> Temp -> PyQuote -> Py () #-}
822
+
823
+ -- | Obtain pointer to code
824
+ unsafeWithCode :: Code -> Program r (Ptr CChar )
825
+ unsafeWithCode (Code bs) = Program $ ContT $ \ fun ->
826
+ Py (BS. unsafeUseAsCString bs $ unsafeRunPy . fun)
827
+
828
+
665
829
----------------------------------------------------------------
666
830
-- Debugging
667
831
----------------------------------------------------------------
0 commit comments