Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions rt4core/src/main/java/uk/co/farowl/vsj4/core/PyFloat.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c)2025 Jython Developers.
// Copyright (c)2026 Jython Developers.
// Licensed to PSF under a contributor agreement.
package uk.co.farowl.vsj4.core;

Expand Down Expand Up @@ -140,6 +140,9 @@ public static double asDouble(Object o)
throw Abstract.requiredTypeError("a real number", o);
}

@Override
public String toString() { return PyUtil.defaultToString(this); }

// Constructor from Python ----------------------------------------

/**
Expand Down Expand Up @@ -178,7 +181,6 @@ public static Object __new__(PyType cls, double x) {

// Special methods -----------------------------------------------

// TODO: implement __format__ and (revised) stringlib
@SuppressWarnings("unused")
private static String __repr__(Object self) {
assert TYPE.check(self);
Expand Down
75 changes: 46 additions & 29 deletions rt4core/src/main/java/uk/co/farowl/vsj4/core/PyNumber.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c)2025 Jython Developers.
// Copyright (c)2026 Jython Developers.
// Licensed to PSF under a contributor agreement.
package uk.co.farowl.vsj4.core;

Expand Down Expand Up @@ -36,6 +36,21 @@ public static Object negative(Object v) throws Throwable {
}
}

/**
* {@code +v}: unary positive with Python semantics.
*
* @param v operand
* @return {@code +v}
* @throws Throwable from invoked implementations
*/
public static Object positive(Object v) throws Throwable {
try {
return representation(v).op_pos().invokeExact(v);
} catch (EmptyException e) {
throw SpecialMethod.op_pos.operandError(v);
}
}

/**
* {@code ~v}: unary bitwise inversion with Python semantics.
*
Expand Down Expand Up @@ -144,19 +159,19 @@ static final Object xor(Object v, Object w) throws Throwable {
*
* @param v left operand
* @param w right operand
* @param binop operation to apply
* @param op operation to apply
* @return result of operation
* @throws PyBaseException ({@link PyExc#TypeError TypeError}) if
* neither operand implements the operation
* @throws Throwable from the implementation of the operation
*/
private static Object binary_op(Object v, Object w,
SpecialMethod binop) throws PyBaseException, Throwable {
SpecialMethod op) throws PyBaseException, Throwable {
try {
Object r = binary_op1(v, w, binop);
Object r = binary_op1(v, w, op);
if (r != Py.NotImplemented) { return r; }
} catch (EmptyException e) {}
throw binop.operandError(v, w);
throw op.operandError(v, w);
}

/**
Expand All @@ -167,51 +182,53 @@ private static Object binary_op(Object v, Object w,
*
* @param v left operand
* @param w right operand
* @param binop operation to apply
* @param op operation to apply
* @return result or {@code Py.NotImplemented}
* @throws EmptyException when an empty slot is invoked
* @throws Throwable from the implementation of the operation
*/
private static Object binary_op1(Object v, Object w,
SpecialMethod binop) throws EmptyException, Throwable {

Representation vOps = representation(v);
PyType vType = vOps.pythonType(v);
SpecialMethod op) throws EmptyException, Throwable {

Representation wOps = representation(w);
PyType wType = wOps.pythonType(w);
Representation vRep = representation(v);
PyType vType = vRep.pythonType(v);
MethodHandle vMH; // e.g. type(v).__sub__

MethodHandle slotv, slotw;
Representation wRep = representation(w);
PyType wType = wRep.pythonType(w);
MethodHandle wRA; // e.g. type(w).__rsub__

/*
* CPython would also test: (slotw = rbinop.handle(wtype)) ==
* slotv as an optimisation , but that's never the case since we
* use distinct binop and rbinop slots.
* CPython would also test: vMH == wRA as an optimisation, but
* that's never the case since we always use distinct __op__ and
* __rop__ methods. (Well, hardly ever: __eq__?)
*/
if (wType == vType) {
// Same types so only try the binop slot
slotv = binop.handle(vOps);
return slotv.invokeExact(v, w);
// Same types so only one type to ask.
vMH = op.handle(vRep);
return vMH.invokeExact(v, w);

} else if (!wType.isSubTypeOf(vType)) {
// Ask left (if not empty) then right.
slotv = binop.handle(vOps);
// Ask left type then right.
vMH = op.handle(vRep);
try {
Object r = slotv.invokeExact(v, w);
Object r = vMH.invokeExact(v, w);
if (r != Py.NotImplemented) { return r; }
} catch (EmptyException e) {}
slotw = binop.getAltSlot(wOps);
return slotw.invokeExact(w, v);
// Left does not define binop. Try right reflected.
wRA = op.reflected(wRep);
return wRA.invokeExact(w, v);

} else {
// Right is sub-class: ask first (if not empty).
slotw = binop.getAltSlot(wOps);
// Right is sub-type of left: ask first.
wRA = op.reflected(wRep);
try {
Object r = slotw.invokeExact(w, v);
Object r = wRA.invokeExact(w, v);
if (r != Py.NotImplemented) { return r; }
} catch (EmptyException e) {}
slotv = binop.handle(vOps);
return slotv.invokeExact(v, w);
// Right does not define alt-binop. Try left.
vMH = op.handle(vRep);
return vMH.invokeExact(v, w);
}
}

Expand Down
Loading