Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite7da0bc

Browse files
committed
Support reverse binary operations
1 parent5855a1b commite7da0bc

File tree

4 files changed

+101
-12
lines changed

4 files changed

+101
-12
lines changed

‎src/embed_tests/TestOperator.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,42 @@ public void ForwardOperatorOverloads()
202202
assert c.Num == a.Num ^ b
203203
");
204204
}
205+
206+
207+
[Test]
208+
publicvoidReverseOperatorOverloads()
209+
{
210+
stringname=string.Format("{0}.{1}",
211+
typeof(OperableObject).DeclaringType.Name,
212+
typeof(OperableObject).Name);
213+
stringmodule=MethodBase.GetCurrentMethod().DeclaringType.Namespace;
214+
215+
PythonEngine.Exec($@"
216+
from{module} import *
217+
cls ={name}
218+
a = 2
219+
b = cls(10)
220+
221+
c = a + b
222+
assert c.Num == a + b.Num
223+
224+
c = a - b
225+
assert c.Num == a - b.Num
226+
227+
c = a * b
228+
assert c.Num == a * b.Num
229+
230+
c = a & b
231+
assert c.Num == a & b.Num
232+
233+
c = a | b
234+
assert c.Num == a | b.Num
235+
236+
c = a ^ b
237+
assert c.Num == a ^ b.Num
238+
");
239+
240+
}
205241
[Test]
206242
publicvoidShiftOperatorOverloads()
207243
{

‎src/runtime/classmanager.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,14 @@ private static ClassInfo GetClassInfo(Type type)
472472
ci.members[name]=ob;
473473
if(mlist.Any(OperatorMethod.IsOperatorMethod))
474474
{
475-
ci.members[OperatorMethod.GetPyMethodName(name)]=ob;
475+
stringpyName=OperatorMethod.GetPyMethodName(name);
476+
stringpyNameReverse=pyName.Insert(2,"r");
477+
MethodInfo[]forwardMethods,reverseMethods;
478+
OperatorMethod.FilterMethods(mlist,outforwardMethods,outreverseMethods);
479+
// Only methods where the left operand is the declaring type.
480+
ci.members[pyName]=newMethodObject(type,name,forwardMethods);
481+
// Only methods where only the right operand is the declaring type.
482+
ci.members[pyNameReverse]=newMethodObject(type,name,reverseMethods);
476483
}
477484
}
478485

‎src/runtime/methodbinder.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,20 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
350350
varouts=0;
351351
intclrnargs=pi.Length;
352352
isOperator=isOperator&&pynargs==clrnargs-1;// Handle mismatched arg numbers due to Python operator being bound.
353+
// Preprocessing pi to remove either the first or second argument.
354+
boolisForward=isOperator&&OperatorMethod.IsForward((MethodInfo)mi);// Only cast if isOperator.
355+
if(isOperator&&isForward){
356+
// The first Python arg is the right operand, while the bound instance is the left.
357+
// We need to skip the first (left operand) CLR argument.
358+
pi=pi.Skip(1).Take(1).ToArray();
359+
}
360+
elseif(isOperator&&!isForward){
361+
// The first Python arg is the left operand.
362+
// We need to take the first CLR argument.
363+
pi=pi.Take(1).ToArray();
364+
}
353365
varmargs=TryConvertArguments(pi,paramsArray,args,pynargs,kwargDict,defaultArgList,
354366
needsResolution:_methods.Length>1,// If there's more than one possible match.
355-
isOperator:isOperator,
356367
outs:outouts);
357368
if(margs==null)
358369
{
@@ -364,7 +375,15 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
364375
{
365376
if(ManagedType.GetManagedObject(inst)isCLRObjectco)
366377
{
367-
margs[0]=co.inst;
378+
// Postprocessing to extend margs.
379+
varmargsTemp=newobject[2];
380+
// If forward, the bound instance is the left operand.
381+
intboundOperandIndex=isForward?0:1;
382+
// If forward, the passed instance is the right operand.
383+
intpassedOperandIndex=isForward?1:0;
384+
margsTemp[boundOperandIndex]=co.inst;
385+
margsTemp[passedOperandIndex]=margs[0];
386+
margs=margsTemp;
368387
}
369388
else{break;}
370389
}
@@ -488,15 +507,13 @@ static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out
488507
/// <param name="kwargDict">Dictionary of keyword argument name to python object pointer</param>
489508
/// <param name="defaultArgList">A list of default values for omitted parameters</param>
490509
/// <param name="needsResolution"><c>true</c>, if overloading resolution is required</param>
491-
/// <param name="isOperator"><c>true</c>, if is operator method</param>
492510
/// <param name="outs">Returns number of output parameters</param>
493511
/// <returns>An array of .NET arguments, that can be passed to a method.</returns>
494512
staticobject[]TryConvertArguments(ParameterInfo[]pi,boolparamsArray,
495513
IntPtrargs,intpyArgCount,
496514
Dictionary<string,IntPtr>kwargDict,
497515
ArrayListdefaultArgList,
498516
boolneedsResolution,
499-
boolisOperator,
500517
outintouts)
501518
{
502519
outs=0;
@@ -535,13 +552,6 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
535552
op=Runtime.PyTuple_GetItem(args,paramIndex);
536553
}
537554
}
538-
if(isOperator&&paramIndex==0)
539-
{
540-
// After we've obtained the first argument from Python, we need to skip the first argument of the CLR
541-
// because operator method is a bound method in Python
542-
paramIndex++;// Leave the first .NET param as null (margs).
543-
parameter=pi[paramIndex];
544-
}
545555

546556
boolisOut;
547557
if(!TryConvertArgument(op,parameter.ParameterType,needsResolution,outmargs[paramIndex],outisOut))

‎src/runtime/operatormethod.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,41 @@ private static PyObject GetOperatorType()
130130
returnlocals.GetItem("OperatorMethod");
131131
}
132132
}
133+
134+
publicstaticstringReversePyMethodName(stringpyName)
135+
{
136+
returnpyName.Insert(2,"r");
137+
}
138+
139+
/// <summary>
140+
/// Check if the method is performing a forward or reverse operation.
141+
/// </summary>
142+
/// <param name="method">The operator method.</param>
143+
/// <returns></returns>
144+
publicstaticboolIsForward(MethodInfomethod)
145+
{
146+
TypedeclaringType=method.DeclaringType;
147+
TypeleftOperandType=method.GetParameters()[0].ParameterType;
148+
returnleftOperandType==declaringType;
149+
}
150+
151+
publicstaticvoidFilterMethods(MethodInfo[]methods,outMethodInfo[]forwardMethods,outMethodInfo[]reverseMethods)
152+
{
153+
List<MethodInfo>forwardMethodsList=newList<MethodInfo>();
154+
List<MethodInfo>reverseMethodsList=newList<MethodInfo>();
155+
foreach(varmethodinmethods)
156+
{
157+
if(IsForward(method))
158+
{
159+
forwardMethodsList.Add(method);
160+
}else
161+
{
162+
reverseMethodsList.Add(method);
163+
}
164+
165+
}
166+
forwardMethods=forwardMethodsList.ToArray();
167+
reverseMethods=reverseMethodsList.ToArray();
168+
}
133169
}
134170
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp