Skip to content

Commit

Permalink
Merge branch 'master-rhino-8.x' into rhino-8.x-RH-80651
Browse files Browse the repository at this point in the history
  • Loading branch information
eirannejad committed Mar 15, 2024
2 parents 3e9eff6 + f3bc494 commit bfb8408
Show file tree
Hide file tree
Showing 16 changed files with 730 additions and 13 deletions.
9 changes: 6 additions & 3 deletions src/runtime/Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ internal static ThunkInfo GetThunk(Delegate @delegate)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int BP_I32(BorrowedReference ob, IntPtr arg);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int BPP_I32(BorrowedReference ob, IntPtr a1, IntPtr a2);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate long B_I64(BorrowedReference ob);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr B_P(BorrowedReference ob);

Expand All @@ -187,9 +193,6 @@ internal static ThunkInfo GetThunk(Delegate @delegate)

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void N_V(NewReference ob);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int BPP_I32(BorrowedReference ob, IntPtr a1, IntPtr a2);
}


Expand Down
1 change: 1 addition & 0 deletions src/runtime/Native/ITypeOffsets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ interface ITypeOffsets
int tp_dictoffset { get; }
int tp_flags { get; }
int tp_free { get; }
int tp_getattr { get; }
int tp_getattro { get; }
int tp_hash { get; }
int tp_is_gc { get; }
Expand Down
18 changes: 18 additions & 0 deletions src/runtime/Native/PyIdentifier_.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ static class PyIdentifier
public static BorrowedReference __init__ => new(f__init__);
static IntPtr f__repr__;
public static BorrowedReference __repr__ => new(f__repr__);
static IntPtr f__getitem__;
public static BorrowedReference __getitem__ => new(f__getitem__);
static IntPtr f__len__;
public static BorrowedReference __len__ => new(f__len__);
static IntPtr f__iter__;
public static BorrowedReference __iter__ => new(f__iter__);
static IntPtr f__str__;
public static BorrowedReference __str__ => new(f__str__);
static IntPtr f__getattribute__;
public static BorrowedReference __getattribute__ => new(f__getattribute__);
static IntPtr f__getattr__;
public static BorrowedReference __getattr__ => new(f__getattr__);
static IntPtr f__import__;
public static BorrowedReference __import__ => new(f__import__);
static IntPtr f__builtins__;
Expand Down Expand Up @@ -59,6 +71,12 @@ static partial class InternString
"__annotations__",
"__init__",
"__repr__",
"__getitem__",
"__len__",
"__iter__",
"__str__",
"__getattribute__",
"__getattr__",
"__import__",
"__builtins__",
"builtins",
Expand Down
1 change: 1 addition & 0 deletions src/runtime/Native/TypeOffset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static partial class TypeOffset
internal static int tp_dictoffset { get; private set; }
internal static int tp_flags { get; private set; }
internal static int tp_free { get; private set; }
internal static int tp_getattr { get; private set; }
internal static int tp_getattro { get; private set; }
internal static int tp_hash { get; private set; }
internal static int tp_is_gc { get; private set; }
Expand Down
6 changes: 5 additions & 1 deletion src/runtime/TypeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ internal static unsafe PyType CreateType(Type impl)
return type;
}


internal static void InitializeClassCore(Type clrType, PyType pyType, ClassBase impl)
{
if (pyType.BaseReference != null)
Expand Down Expand Up @@ -881,6 +880,11 @@ public static IntPtr GetDefaultSlot(int offset)
// PyType_GenericNew
return Util.ReadIntPtr(Runtime.PySuper_Type, TypeOffset.tp_new);
}
else if (offset == TypeOffset.tp_getattr)
{
// PyObject_GetAttr
return Util.ReadIntPtr(Runtime.PyBaseObjectType, TypeOffset.tp_getattr);
}
else if (offset == TypeOffset.tp_getattro)
{
// PyObject_GenericGetAttr
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/Types/ClassDerived.cs
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,8 @@ class Void { }
pyMethodName = methodName;

using var pyself = new PyObject(self.CheckRun());
using PyObject method = pyself.GetAttr(pyMethodName, Runtime.None);
using var methodNameObj = new PyString(pyMethodName);
using PyObject method = pyself.GetAttr(methodNameObj);
BorrowedReference dt = Runtime.PyObject_TYPE(method);
if (method.Reference != Runtime.PyNone && dt != Runtime.PyMethodWrapperType)
{
Expand Down
31 changes: 25 additions & 6 deletions src/runtime/Types/InterfaceObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,34 @@ public static NewReference tp_getattro(BorrowedReference ob, BorrowedReference k
}

string? name = Runtime.GetManagedString(key);
if (name == "__implementation__")
if (name != null)
{
return Converter.ToPython(clrObj.inst);
}
else if (name == "__raw_implementation__")
{
return CLRObject.GetReference(clrObj.inst);
if (name == "__implementation__")
{
return Converter.ToPython(clrObj.inst);
}
else if (name == "__raw_implementation__")
{
return CLRObject.GetReference(clrObj.inst);
}
else
{
// try get attr from pure interface wrapper
var value = Runtime.PyObject_GenericGetAttr(ob, key);
if (Exceptions.ErrorOccurred())
{
// if that didn't work, clear errors
// and try get from wrapped object
Exceptions.Clear();

using var pyObj = Converter.ToPython(clrObj.inst);
return Runtime.PyObject_GenericGetAttr(pyObj.Borrow(), key);
}
return value;
}
}


return Runtime.PyObject_GenericGetAttr(ob, key);
}

Expand Down
231 changes: 231 additions & 0 deletions src/runtime/Types/ReflectedClrType.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;

using static Python.Runtime.PythonException;
Expand Down Expand Up @@ -93,6 +94,54 @@ internal static NewReference CreateSubclass(ClassBase baseType, IEnumerable<Type
ThrowIfIsNotZero(Runtime.PyDict_DelItemString(cls_dict, "__classcell__"));
}

const BindingFlags tbFlags = BindingFlags.Public | BindingFlags.Static;

var tp_getattro_default = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.tp_getattro), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.tp_getattro, Interop.GetThunk(tp_getattro_default).Address);

using var clsDict = new PyDict(dict);
using var keys = clsDict.Keys();
foreach (PyObject pyKey in keys)
{
string? keyStr = Runtime.GetManagedString(pyKey);
if (keyStr is null)
{
continue;
}

if (keyStr.StartsWith(nameof(PyIdentifier.__getitem__)))
{
var mp_subscript = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.mp_subscript), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.mp_subscript, Interop.GetThunk(mp_subscript).Address);
}

if (keyStr.StartsWith(nameof(PyIdentifier.__len__)))
{
var sq_length = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.sq_length), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.sq_length, Interop.GetThunk(sq_length).Address);
}

if (keyStr.StartsWith(nameof(PyIdentifier.__iter__)))
{
var tp_iter = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.tp_iter), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.tp_iter, Interop.GetThunk(tp_iter).Address);
}

if (keyStr.StartsWith(nameof(PyIdentifier.__str__)))
{
var tp_str = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.tp_str), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.tp_str, Interop.GetThunk(tp_str).Address);
}

if (keyStr.StartsWith(nameof(PyIdentifier.__repr__)))
{
var tp_repr = typeof(ReflectedClrType).GetMethod(nameof(ReflectedClrType.tp_repr), tbFlags);
Util.WriteIntPtr(pyTypeObj, TypeOffset.tp_repr, Interop.GetThunk(tp_repr).Address);
}

pyKey.Dispose();
}

return new NewReference(pyTypeObj);
}
catch (Exception e)
Expand All @@ -101,6 +150,188 @@ internal static NewReference CreateSubclass(ClassBase baseType, IEnumerable<Type
}
}

public static NewReference mp_subscript(BorrowedReference ob, BorrowedReference key)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
return Exceptions.RaiseTypeError("invalid object");
}

if (TryCallBoundMethod1(ob, key, nameof(PyIdentifier.__getitem__), out NewReference result))
{
return result;
}

using var objRepr = Runtime.PyObject_Repr(ob);
using var keyRepr = Runtime.PyObject_Repr(key);
Exceptions.SetError(
Exceptions.KeyError,
Runtime.GetManagedString(keyRepr.BorrowOrThrow())!
);
return default;
}

public static long sq_length(BorrowedReference ob)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
Exceptions.RaiseTypeError("invalid object");
return 0;
}

if (TryCallBoundMethod0(ob, nameof(PyIdentifier.__len__), out NewReference result))
{
long? r = Runtime.PyLong_AsLongLong(result.Borrow());
if (r is null)
{
Exceptions.SetError(Exceptions.TypeError, $"TypeError: 'NoneType' object cannot be interpreted as an integer");
}

return r!.Value;
}

return 0;
}

public static NewReference tp_iter(BorrowedReference ob)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
return Exceptions.RaiseTypeError("invalid object");
}

if (TryCallBoundMethod0(ob, nameof(PyIdentifier.__iter__), out NewReference result))
{
return result;
}

return new NewReference(Runtime.None);
}

public static NewReference tp_str(BorrowedReference ob)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
return Exceptions.RaiseTypeError("invalid object");
}

if (TryCallBoundMethod0(ob, nameof(PyIdentifier.__str__), out NewReference result))
{
return result;
}

return ClassObject.tp_str(ob);
}

public static NewReference tp_repr(BorrowedReference ob)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
return Exceptions.RaiseTypeError("invalid object");
}

if (TryCallBoundMethod0(ob, nameof(PyIdentifier.__repr__), out NewReference result))
{
return result;
}

return ClassObject.tp_repr(ob);
}

public static NewReference tp_getattro(BorrowedReference ob, BorrowedReference key)
{
CLRObject? clrObj = ManagedType.GetManagedObject(ob) as CLRObject;
if (clrObj is null)
{
return Exceptions.RaiseTypeError("invalid object");
}

if (TryGetBuiltinAttr(ob, key, out NewReference builtinAttr))
{
return builtinAttr;
}

if (TryCallBoundMethod1(ob, key, nameof(PyIdentifier.__getattribute__), out NewReference getAttro))
{
if (Exceptions.ExceptionMatches(Exceptions.AttributeError))
{
Exceptions.Clear();

if (TryCallBoundMethod1(ob, key, nameof(PyIdentifier.__getattr__), out NewReference getAttr))
{
return getAttr;
}

Exceptions.SetError(Exceptions.AttributeError, $"");
}

return getAttro;
}

return Runtime.PyObject_GenericGetAttr(ob, key);
}

static bool TryCallBoundMethod0(BorrowedReference ob, string keyName, out NewReference result)
{
result = default;

using var pyType = Runtime.PyObject_Type(ob);
using var getAttrKey = new PyString(keyName);
var getattr = Runtime._PyType_Lookup(pyType.Borrow(), getAttrKey);
if (getattr.IsNull)
{
return false;
}

using var method = Runtime.PyObject_GenericGetAttr(ob, getAttrKey);
using var args = Runtime.PyTuple_New(0);
result = Runtime.PyObject_Call(method.Borrow(), args.Borrow(), null);
return true;
}

static bool TryCallBoundMethod1(BorrowedReference ob, BorrowedReference key, string keyName, out NewReference result)
{
result = default;

using var pyType = Runtime.PyObject_Type(ob);
using var getAttrKey = new PyString(keyName);
var getattr = Runtime._PyType_Lookup(pyType.Borrow(), getAttrKey);
if (getattr.IsNull)
{
return false;
}

using var method = Runtime.PyObject_GenericGetAttr(ob, getAttrKey);
using var args = Runtime.PyTuple_New(1);
Runtime.PyTuple_SetItem(args.Borrow(), 0, key);
result = Runtime.PyObject_Call(method.Borrow(), args.Borrow(), null);
return true;
}

static bool TryGetBuiltinAttr(BorrowedReference ob, BorrowedReference key, out NewReference result)
{
result = default;

string? keyStr = Runtime.GetManagedString(key);
if (keyStr is null)
{
return false;
}

if (keyStr == nameof(PyIdentifier.__init__))
{
result = Runtime.PyObject_GenericGetAttr(ob, key);
return true;
}

return false;
}

static ReflectedClrType AllocateClass(Type clrType)
{
string name = TypeManager.GetPythonTypeName(clrType);
Expand Down
Loading

0 comments on commit bfb8408

Please sign in to comment.