42
42
43
43
import static com .oracle .graal .python .nodes .BuiltinNames .J_GET_REGISTERED_INTEROP_BEHAVIOR ;
44
44
import static com .oracle .graal .python .nodes .BuiltinNames .J_INTEROP_BEHAVIOR ;
45
+ import static com .oracle .graal .python .nodes .BuiltinNames .J_JAVA_INTEROP_TYPE ;
45
46
import static com .oracle .graal .python .nodes .BuiltinNames .J_REGISTER_INTEROP_BEHAVIOR ;
47
+ import static com .oracle .graal .python .nodes .BuiltinNames .J_REMOVE_JAVA_INTEROP_TYPE ;
46
48
import static com .oracle .graal .python .nodes .BuiltinNames .T_REGISTER_INTEROP_BEHAVIOR ;
47
49
import static com .oracle .graal .python .nodes .BuiltinNames .J_REGISTER_JAVA_INTEROP_TYPE ;
50
+ import static com .oracle .graal .python .nodes .BuiltinNames .T_REGISTER_JAVA_INTEROP_TYPE ;
48
51
import static com .oracle .graal .python .nodes .ErrorMessages .ARG_MUST_BE_NUMBER ;
52
+ import static com .oracle .graal .python .nodes .ErrorMessages .INTEROP_TYPE_ALREADY_REGISTERED ;
53
+ import static com .oracle .graal .python .nodes .ErrorMessages .INTEROP_TYPE_NOT_REGISTERED ;
49
54
import static com .oracle .graal .python .nodes .ErrorMessages .S_ARG_MUST_BE_S_NOT_P ;
50
55
import static com .oracle .graal .python .nodes .ErrorMessages .S_CANNOT_HAVE_S ;
51
56
import static com .oracle .graal .python .nodes .ErrorMessages .S_DOES_NOT_TAKE_VARARGS ;
@@ -744,7 +749,7 @@ public static PKeyword[] createKwDefaults(Object receiver) {
744
749
}
745
750
}
746
751
747
- @ Builtin (name = J_REGISTER_JAVA_INTEROP_TYPE , minNumOfPositionalArgs = 2 , maxNumOfPositionalArgs = 2 , takesVarArgs = true , keywordOnlyNames = "overwrite" , doc = """
752
+ @ Builtin (name = J_REGISTER_JAVA_INTEROP_TYPE , minNumOfPositionalArgs = 2 , maxNumOfPositionalArgs = 2 , takesVarKeywordArgs = true , keywordOnlyNames = { "overwrite" } , doc = """
748
753
register_java_interop_type(javaClassName, pythonClass, overwrite=None)
749
754
750
755
Example registering a custom interop type for the Java ArrayList
@@ -773,7 +778,7 @@ Object register(TruffleString javaClassName, PythonClass pythonClass, Object ove
773
778
throw raiseNode .raise (ValueError , S_ARG_MUST_BE_S_NOT_P , "second" , "a python class" , pythonClass );
774
779
}
775
780
// Get registry for custom interop types from PythonContext
776
- Map <Object , PythonClass > interopTypeRegistry = PythonContext .get (this ).getInteropTypeRegistry ();
781
+ Map <Object , PythonClass > interopTypeRegistry = PythonContext .get (this ).getInteropTypeRegistry ();
777
782
String javaClassNameAsString = javaClassName .toString ();
778
783
// Check if already registered and if overwrite is configured
779
784
if (interopTypeRegistry .containsKey (javaClassNameAsString ) && !Boolean .TRUE .equals (overwrite )) {
@@ -784,6 +789,131 @@ Object register(TruffleString javaClassName, PythonClass pythonClass, Object ove
784
789
}
785
790
}
786
791
792
+ @ Builtin (name = J_REMOVE_JAVA_INTEROP_TYPE , minNumOfPositionalArgs = 1 , maxNumOfPositionalArgs = 1 , doc = """
793
+ remove_java_interop_type(javaClassName)
794
+
795
+ Remove registration of java interop type. Future registration don't need overwrite flag anymore.
796
+ Example removes the custom interop type for the ArrayList
797
+
798
+ >>> from polyglot import remove_java_interop_type
799
+
800
+ >>> remove_java_interop_type("java.util.ArrayList")
801
+ """ )
802
+ @ GenerateNodeFactory
803
+ public abstract static class RemoveJavaInteropTypeNode extends PythonBuiltinNode {
804
+
805
+ @ Specialization
806
+ @ TruffleBoundary
807
+ Object register (TruffleString javaClassName ,
808
+ @ Cached PRaiseNode raiseNode ) {
809
+ // Get registry for custom interop types from PythonContext
810
+ Map <Object , PythonClass > interopTypeRegistry = PythonContext .get (this ).getInteropTypeRegistry ();
811
+ String javaClassNameAsString = javaClassName .toString ();
812
+ // Check if already registered and if overwrite is configured
813
+ if (!interopTypeRegistry .containsKey (javaClassNameAsString )) {
814
+ throw raiseNode .raise (KeyError , INTEROP_TYPE_NOT_REGISTERED , javaClassNameAsString );
815
+ }
816
+ interopTypeRegistry .remove (javaClassNameAsString );
817
+ return PNone .NONE ;
818
+ }
819
+ }
820
+
821
+ @ Builtin (name = J_JAVA_INTEROP_TYPE , minNumOfPositionalArgs = 1 , maxNumOfPositionalArgs = 1 , takesVarKeywordArgs = true , keywordOnlyNames = {"overwrite" }, doc = """
822
+ @java_interop_type(javaClassName, overwrite=None)
823
+
824
+ Example registering a custom interop type for the Java ArrayList
825
+
826
+ >>> from polyglot import register_java_interop_type
827
+
828
+ >>> @java_interop_type("java.util.ArrayList")
829
+ ... class jArrayList(__graalpython__.ForeignType):
830
+ ... def append(self, element):
831
+ ... self.add(element)
832
+
833
+ For subsequent registrations with overwrite behavior use
834
+ >>> @java_interop_type("java.util.ArrayList", overwrite=True)
835
+ ... class jArrayList(__graalpython__.ForeignType):
836
+ ... pass
837
+ """ )
838
+ @ GenerateNodeFactory
839
+ public abstract static class JavaInteropTypeDecoratorNode extends PythonBuiltinNode {
840
+ static final TruffleString WRAPPER = tsLiteral ("wrapper" );
841
+ public static final TruffleString KW_J_CLASS_NAME = tsLiteral ("javaClassName" );
842
+
843
+ public static final TruffleString KW_OVERWRITE = tsLiteral ("overwrite" );
844
+
845
+ static class RegisterWrapperRootNode extends PRootNode {
846
+ static final TruffleString [] KEYWORDS_HIDDEN_RECEIVER = new TruffleString []{KW_J_CLASS_NAME , KW_OVERWRITE };
847
+ private static final Signature SIGNATURE = new Signature (1 , false , -1 , false , tsArray ("pythonClass" ), KEYWORDS_HIDDEN_RECEIVER );
848
+ private static final TruffleString MODULE_POLYGLOT = tsLiteral ("polyglot" );
849
+ @ Child private ExecutionContext .CalleeContext calleeContext = ExecutionContext .CalleeContext .create ();
850
+ @ Child private PRaiseNode raiseNode = PRaiseNode .create ();
851
+ @ Child private PyObjectGetAttr getAttr = PyObjectGetAttr .create ();
852
+ @ Child private CallVarargsMethodNode callVarargsMethod = CallVarargsMethodNode .create ();
853
+
854
+ protected RegisterWrapperRootNode (TruffleLanguage <?> language ) {
855
+ super (language );
856
+ }
857
+
858
+ @ Override
859
+ public Object execute (VirtualFrame frame ) {
860
+ calleeContext .enter (frame );
861
+ Object [] frameArguments = frame .getArguments ();
862
+ Object pythonClass = PArguments .getArgument (frameArguments , 0 );
863
+ // note: the hidden kwargs are stored at the end of the positional args
864
+ Object javaClassName = PArguments .getArgument (frameArguments , 1 );
865
+ Object overwrite = PArguments .getArgument (frameArguments , 2 );
866
+ try {
867
+ if (pythonClass instanceof PythonClass klass ) {
868
+ PythonModule polyglotModule = PythonContext .get (this ).lookupBuiltinModule (MODULE_POLYGLOT );
869
+ Object register = getAttr .executeCached (frame , polyglotModule , T_REGISTER_JAVA_INTEROP_TYPE );
870
+ callVarargsMethod .execute (frame , register , new Object []{javaClassName , pythonClass }, new PKeyword []{new PKeyword (KW_OVERWRITE , overwrite )});
871
+ return klass ;
872
+ }
873
+ throw raiseNode .raise (ValueError , S_ARG_MUST_BE_S_NOT_P , "first" , "a python class" , pythonClass );
874
+ } finally {
875
+ calleeContext .exit (frame , this );
876
+ }
877
+ }
878
+
879
+ @ Override
880
+ public Signature getSignature () {
881
+ return SIGNATURE ;
882
+ }
883
+
884
+ @ Override
885
+ public boolean isPythonInternal () {
886
+ return true ;
887
+ }
888
+
889
+ @ Override
890
+ public boolean isInternal () {
891
+ return true ;
892
+ }
893
+
894
+ @ Override
895
+ public boolean setsUpCalleeContext () {
896
+ return true ;
897
+ }
898
+ }
899
+
900
+ @ Specialization
901
+ @ TruffleBoundary
902
+ public Object decorate (TruffleString receiver , Object overwrite ,
903
+ @ Cached PythonObjectFactory factory ) {
904
+
905
+ RootCallTarget callTarget = getContext ().getLanguage ().createCachedCallTarget (RegisterWrapperRootNode ::new , RegisterWrapperRootNode .class );
906
+ return factory .createBuiltinFunction (WRAPPER , null , PythonUtils .EMPTY_OBJECT_ARRAY , createKwDefaults (receiver , overwrite ), 0 , callTarget );
907
+
908
+ }
909
+
910
+ public static PKeyword [] createKwDefaults (Object receiver , Object overwrite ) {
911
+ // the receiver is passed in a hidden keyword argument
912
+ // in a pure python decorator this would be passed as a cell
913
+ return new PKeyword []{new PKeyword (KW_J_CLASS_NAME , receiver ), new PKeyword (KW_OVERWRITE , overwrite )};
914
+ }
915
+ }
916
+
787
917
@ Builtin (name = J_REGISTER_INTEROP_BEHAVIOR , minNumOfPositionalArgs = 1 , maxNumOfPositionalArgs = 1 , takesVarKeywordArgs = true , keywordOnlyNames = {"is_boolean" , "is_date" ,
788
918
"is_duration" , "is_iterator" , "is_number" , "is_string" , "is_time" , "is_time_zone" , "is_executable" , "fits_in_big_integer" , "fits_in_byte" , "fits_in_double" , "fits_in_float" ,
789
919
"fits_in_int" , "fits_in_long" , "fits_in_short" , "as_big_integer" , "as_boolean" , "as_byte" , "as_date" , "as_double" , "as_duration" , "as_float" , "as_int" , "as_long" , "as_short" ,
0 commit comments