@@ -479,22 +479,95 @@ func maybeConvertValue(f *Frame, o *Object, expectedRType reflect.Type) (reflect
479479 if raised != nil {
480480 return reflect.Value {}, raised
481481 }
482- rtype := val .Type ()
483482 for {
483+ rtype := val .Type ()
484484 if rtype == expectedRType {
485485 return val , nil
486486 }
487487 if rtype .ConvertibleTo (expectedRType ) {
488488 return val .Convert (expectedRType ), nil
489489 }
490- if rtype .Kind () == reflect .Ptr {
490+ switch rtype .Kind () {
491+ case reflect .Ptr :
491492 val = val .Elem ()
492- rtype = val .Type ()
493493 continue
494+
495+ case reflect .Func :
496+ if fn , ok := val .Interface ().(func (f * Frame , args Args , kwargs KWArgs ) (* Object , * BaseException )); ok {
497+ val = nativeToPyFuncBridge (Func (fn ), expectedRType )
498+ continue
499+ }
494500 }
495- break
501+ return val , f .RaiseType (TypeErrorType , fmt .Sprintf ("cannot convert %s to %s" , rtype , expectedRType ))
502+ }
503+ }
504+
505+ func nativeToPyFuncBridge (fn Func , target reflect.Type ) reflect.Value {
506+ firstInIsFrame := target .NumIn () > 0 && target .In (0 ) == reflect .TypeOf ((* Frame )(nil ))
507+
508+ outs := make ([]reflect.Type , target .NumOut ())
509+ for i := range outs {
510+ outs [i ] = target .Out (i )
496511 }
497- return reflect.Value {}, f .RaiseType (TypeErrorType , fmt .Sprintf ("cannot convert %s to %s" , rtype , expectedRType ))
512+
513+ return reflect .MakeFunc (target , func (args []reflect.Value ) []reflect.Value {
514+ var frame * Frame
515+ if firstInIsFrame {
516+ frame , args = args [0 ].Interface ().(* Frame ), args [1 :]
517+ } else {
518+ frame = NewRootFrame ()
519+ }
520+
521+ pyArgs := frame .MakeArgs (len (args ))
522+ for i , arg := range args {
523+ var raised * BaseException
524+ pyArgs [i ], raised = WrapNative (frame , arg )
525+ if raised != nil {
526+ panic (fmt .Sprintf ("WrapNative(%v)=%v" , arg , raised )) // TODO: Figure this out...
527+ }
528+ }
529+
530+ ret , raised := fn (frame , pyArgs , nil )
531+ if raised != nil {
532+ panic (fmt .Sprintf ("python error %v crossing into Go" , raised )) // TODO: Figure this out...
533+ }
534+
535+ switch len (outs ) {
536+ case 0 :
537+ if ret != nil && ret != None {
538+ panic (fmt .Sprintf ("unexpected return of %v when None expected" , ret )) // TODO: Figure this out...
539+ }
540+ return nil
541+
542+ case 1 :
543+ v , raised := maybeConvertValue (frame , ret , outs [0 ])
544+ if raised != nil {
545+ panic (fmt .Sprintf ("maybeConvertValue(%v)=%v" , ret , raised )) // TODO: Figure this out...
546+ }
547+ return []reflect.Value {v }
548+ }
549+
550+ // TODO: Support other iterables?
551+ if ! ret .isInstance (TupleType ) {
552+ panic (fmt .Sprintf ("return value %v is not a tuple" , ret )) // TODO
553+ }
554+
555+ retTuple := toTupleUnsafe (ret )
556+ if retTuple .Len () != len (outs ) {
557+ panic (fmt .Sprintf ("return value has wrong length %v, want %v" , retTuple .Len (), len (outs ))) // TODO
558+ }
559+
560+ converted := make ([]reflect.Value , len (outs ))
561+ for i , out := range outs {
562+ var raised * BaseException
563+ converted [i ], raised = maybeConvertValue (frame , retTuple .GetItem (i ), out )
564+ if raised != nil {
565+ panic (fmt .Sprintf ("maybeConvertValue(%v)=%v" , retTuple .GetItem (i ), raised )) // TODO: Figure this out...
566+ }
567+ }
568+
569+ return converted
570+ })
498571}
499572
500573func nativeFuncTypeName (rtype reflect.Type ) string {
0 commit comments