88// ==========================================================================
99
1010using System ;
11+ using System . Dynamic ;
12+ using System . Linq . Expressions ;
1113
1214namespace Python . Runtime {
1315
@@ -17,7 +19,7 @@ namespace Python.Runtime {
1719 /// http://www.python.org/doc/current/api/object.html for details.
1820 /// </summary>
1921
20- public class PyObject : IDisposable {
22+ public class PyObject : DynamicObject , IDisposable {
2123
2224 protected internal IntPtr obj = IntPtr . Zero ;
2325 private bool disposed = false ;
@@ -95,7 +97,7 @@ public static PyObject FromManagedObject(object ob) {
9597
9698 public object AsManagedObject ( Type t ) {
9799 Object result ;
98- if ( ! Converter . ToManaged ( this . Handle , t , out result , false ) ) {
100+ if ( ! Converter . ToManaged ( this . obj , t , out result , false ) ) {
99101 throw new InvalidCastException ( "cannot convert object to target type" ) ;
100102 }
101103 return result ;
@@ -609,7 +611,7 @@ public PyObject Invoke(PyTuple args) {
609611
610612 public PyObject Invoke ( PyObject [ ] args , PyDict kw ) {
611613 PyTuple t = new PyTuple ( args ) ;
612- IntPtr r = Runtime . PyObject_Call ( obj , t . obj , kw . obj ) ;
614+ IntPtr r = Runtime . PyObject_Call ( obj , t . obj , kw != null ? kw . obj : IntPtr . Zero ) ;
613615 t . Dispose ( ) ;
614616 if ( r == IntPtr . Zero ) {
615617 throw new PythonException ( ) ;
@@ -628,7 +630,7 @@ public PyObject Invoke(PyObject[] args, PyDict kw) {
628630 /// </remarks>
629631
630632 public PyObject Invoke ( PyTuple args , PyDict kw ) {
631- IntPtr r = Runtime . PyObject_Call ( obj , args . obj , kw . obj ) ;
633+ IntPtr r = Runtime . PyObject_Call ( obj , args . obj , kw != null ? kw . obj : IntPtr . Zero ) ;
632634 if ( r == IntPtr . Zero ) {
633635 throw new PythonException ( ) ;
634636 }
@@ -862,8 +864,222 @@ public override int GetHashCode() {
862864 return Runtime . PyObject_Hash ( obj ) . ToInt32 ( ) ;
863865 }
864866
867+ public override bool TryGetMember ( GetMemberBinder binder , out object result )
868+ {
869+ if ( this . HasAttr ( binder . Name ) )
870+ {
871+ result = this . GetAttr ( binder . Name ) ;
872+ return true ;
873+ }
874+ else
875+ return base . TryGetMember ( binder , out result ) ;
876+ }
877+
878+ public override bool TrySetMember ( SetMemberBinder binder , object value )
879+ {
880+ if ( this . HasAttr ( binder . Name ) )
881+ {
882+ this . SetAttr ( binder . Name , ( PyObject ) value ) ;
883+ return true ;
884+ }
885+ else
886+ return base . TrySetMember ( binder , value ) ;
887+ }
888+
889+ private void GetArgs ( object [ ] inargs , out PyTuple args , out PyDict kwargs )
890+ {
891+ int arg_count ;
892+ for ( arg_count = 0 ; arg_count < inargs . Length && ! ( inargs [ arg_count ] is Py . KeywordArguments ) ; ++ arg_count ) ;
893+ IntPtr argtuple = Runtime . PyTuple_New ( arg_count ) ;
894+ for ( int i = 0 ; i < arg_count ; i ++ )
895+ {
896+ IntPtr ptr ;
897+ if ( inargs [ i ] is PyObject )
898+ {
899+ ptr = ( ( PyObject ) inargs [ i ] ) . Handle ;
900+ Runtime . Incref ( ptr ) ;
901+ }
902+ else
903+ {
904+ ptr = Converter . ToPython ( inargs [ i ] , inargs [ i ] . GetType ( ) ) ;
905+ }
906+ if ( Runtime . PyTuple_SetItem ( argtuple , i , ptr ) < 0 )
907+ throw new PythonException ( ) ;
908+ }
909+ args = new PyTuple ( argtuple ) ;
910+ kwargs = null ;
911+ for ( int i = arg_count ; i < inargs . Length ; i ++ )
912+ {
913+ if ( ! ( inargs [ i ] is Py . KeywordArguments ) )
914+ throw new ArgumentException ( "Keyword arguments must come after normal arguments." ) ;
915+ if ( kwargs == null )
916+ kwargs = ( Py . KeywordArguments ) inargs [ i ] ;
917+ else
918+ kwargs . Update ( ( Py . KeywordArguments ) inargs [ i ] ) ;
919+ }
920+ }
865921
922+ public override bool TryInvokeMember ( InvokeMemberBinder binder , object [ ] args , out object result )
923+ {
924+ if ( this . HasAttr ( binder . Name ) && this . GetAttr ( binder . Name ) . IsCallable ( ) )
925+ {
926+ PyTuple pyargs ;
927+ PyDict kwargs ;
928+ GetArgs ( args , out pyargs , out kwargs ) ;
929+ result = InvokeMethod ( binder . Name , pyargs , kwargs ) ;
930+ return true ;
931+ }
932+ else
933+ return base . TryInvokeMember ( binder , args , out result ) ;
866934 }
867935
936+ public override bool TryInvoke ( InvokeBinder binder , object [ ] args , out object result )
937+ {
938+ if ( this . IsCallable ( ) )
939+ {
940+ PyTuple pyargs ;
941+ PyDict kwargs ;
942+ GetArgs ( args , out pyargs , out kwargs ) ;
943+ result = Invoke ( pyargs , kwargs ) ;
944+ return true ;
945+ }
946+ else
947+ return base . TryInvoke ( binder , args , out result ) ;
948+ }
949+
950+ public override bool TryConvert ( ConvertBinder binder , out object result )
951+ {
952+ return Converter . ToManaged ( this . obj , binder . Type , out result , false ) ;
953+ }
868954
955+ public override bool TryBinaryOperation ( BinaryOperationBinder binder , Object arg , out Object result ) {
956+ IntPtr res ;
957+ if ( ! ( arg is PyObject ) )
958+ arg = arg . ToPython ( ) ;
959+
960+ switch ( binder . Operation )
961+ {
962+ case ExpressionType . Add :
963+ res = Runtime . PyNumber_Add ( this . obj , ( ( PyObject ) arg ) . obj ) ;
964+ break ;
965+ case ExpressionType . AddAssign :
966+ res = Runtime . PyNumber_InPlaceAdd ( this . obj , ( ( PyObject ) arg ) . obj ) ;
967+ break ;
968+ case ExpressionType . Subtract :
969+ res = Runtime . PyNumber_Subtract ( this . obj , ( ( PyObject ) arg ) . obj ) ;
970+ break ;
971+ case ExpressionType . SubtractAssign :
972+ res = Runtime . PyNumber_InPlaceSubtract ( this . obj , ( ( PyObject ) arg ) . obj ) ;
973+ break ;
974+ case ExpressionType . Multiply :
975+ res = Runtime . PyNumber_Multiply ( this . obj , ( ( PyObject ) arg ) . obj ) ;
976+ break ;
977+ case ExpressionType . MultiplyAssign :
978+ res = Runtime . PyNumber_InPlaceMultiply ( this . obj , ( ( PyObject ) arg ) . obj ) ;
979+ break ;
980+ case ExpressionType . Divide :
981+ res = Runtime . PyNumber_Divide ( this . obj , ( ( PyObject ) arg ) . obj ) ;
982+ break ;
983+ case ExpressionType . DivideAssign :
984+ res = Runtime . PyNumber_InPlaceDivide ( this . obj , ( ( PyObject ) arg ) . obj ) ;
985+ break ;
986+ case ExpressionType . And :
987+ res = Runtime . PyNumber_And ( this . obj , ( ( PyObject ) arg ) . obj ) ;
988+ break ;
989+ case ExpressionType . AndAssign :
990+ res = Runtime . PyNumber_InPlaceAnd ( this . obj , ( ( PyObject ) arg ) . obj ) ;
991+ break ;
992+ case ExpressionType . ExclusiveOr :
993+ res = Runtime . PyNumber_Xor ( this . obj , ( ( PyObject ) arg ) . obj ) ;
994+ break ;
995+ case ExpressionType . ExclusiveOrAssign :
996+ res = Runtime . PyNumber_InPlaceXor ( this . obj , ( ( PyObject ) arg ) . obj ) ;
997+ break ;
998+ case ExpressionType . GreaterThan :
999+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) > 0 ;
1000+ return true ;
1001+ case ExpressionType . GreaterThanOrEqual :
1002+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) >= 0 ;
1003+ return true ;
1004+ case ExpressionType . LeftShift :
1005+ res = Runtime . PyNumber_Lshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1006+ break ;
1007+ case ExpressionType . LeftShiftAssign :
1008+ res = Runtime . PyNumber_InPlaceLshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1009+ break ;
1010+ case ExpressionType . LessThan :
1011+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) < 0 ;
1012+ return true ;
1013+ case ExpressionType . LessThanOrEqual :
1014+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) <= 0 ;
1015+ return true ;
1016+ case ExpressionType . Modulo :
1017+ res = Runtime . PyNumber_Remainder ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1018+ break ;
1019+ case ExpressionType . ModuloAssign :
1020+ res = Runtime . PyNumber_InPlaceRemainder ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1021+ break ;
1022+ case ExpressionType . NotEqual :
1023+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) != 0 ;
1024+ return true ;
1025+ case ExpressionType . Or :
1026+ res = Runtime . PyNumber_Or ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1027+ break ;
1028+ case ExpressionType . OrAssign :
1029+ res = Runtime . PyNumber_InPlaceOr ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1030+ break ;
1031+ case ExpressionType . Power :
1032+ res = Runtime . PyNumber_Power ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1033+ break ;
1034+ case ExpressionType . RightShift :
1035+ res = Runtime . PyNumber_Rshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1036+ break ;
1037+ case ExpressionType . RightShiftAssign :
1038+ res = Runtime . PyNumber_InPlaceRshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1039+ break ;
1040+ default :
1041+ result = null ;
1042+ return false ;
1043+ }
1044+ result = new PyObject ( res ) ;
1045+ return true ;
1046+ }
1047+
1048+ public override bool TryUnaryOperation ( UnaryOperationBinder binder , out Object result )
1049+ {
1050+ int r ;
1051+ IntPtr res ;
1052+ switch ( binder . Operation )
1053+ {
1054+ case ExpressionType . Negate :
1055+ res = Runtime . PyNumber_Negative ( this . obj ) ;
1056+ break ;
1057+ case ExpressionType . UnaryPlus :
1058+ res = Runtime . PyNumber_Positive ( this . obj ) ;
1059+ break ;
1060+ case ExpressionType . OnesComplement :
1061+ res = Runtime . PyNumber_Invert ( this . obj ) ;
1062+ break ;
1063+ case ExpressionType . Not :
1064+ r = Runtime . PyObject_Not ( this . obj ) ;
1065+ result = r == 1 ;
1066+ return r != - 1 ;
1067+ case ExpressionType . IsFalse :
1068+ r = Runtime . PyObject_IsTrue ( this . obj ) ;
1069+ result = r == 0 ;
1070+ return r != - 1 ;
1071+ case ExpressionType . IsTrue :
1072+ r = Runtime . PyObject_IsTrue ( this . obj ) ;
1073+ result = r == 1 ;
1074+ return r != - 1 ;
1075+ case ExpressionType . Decrement :
1076+ case ExpressionType . Increment :
1077+ default :
1078+ result = null ;
1079+ return false ;
1080+ }
1081+ result = new PyObject ( res ) ;
1082+ return true ;
1083+ }
1084+ }
8691085}
0 commit comments