Commit 9ca28dd6 authored by YOU's avatar YOU Committed by Dylan Trotter

Add unary plus (#253)

parent d641069a
......@@ -410,6 +410,7 @@ class ExprVisitor(algorithm.Visitor):
_UNARY_OP_TEMPLATES = {
ast.Invert: 'πg.Invert(πF, {operand})',
ast.UAdd: 'πg.Pos(πF, {operand})',
ast.USub: 'πg.Neg(πF, {operand})',
}
......
......@@ -220,11 +220,7 @@ class ExprVisitorTest(unittest.TestCase):
testUnaryOpNot = _MakeExprTest('not True')
testUnaryOpInvert = _MakeExprTest('~4')
def testUnaryOpNotImplemented(self):
self.assertRaisesRegexp(util.ParseError, 'unary op not implemented',
_ParseAndVisitExpr, '+foo')
testUnaryOpPos = _MakeExprTest('+4')
def _MakeModuleBlock():
return block.ModuleBlock('__main__', 'grumpy', 'grumpy/lib', '<test>', '',
......
......@@ -640,6 +640,16 @@ func Oct(f *Frame, o *Object) (*Object, *BaseException) {
return o, nil
}
// Pos returns the result of o.__pos__ and is equivalent to the Python
// expression "+o".
func Pos(f *Frame, o *Object) (*Object, *BaseException) {
pos := o.typ.slots.Pos
if pos == nil {
return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("bad operand type for unary +: '%s'", o.typ.Name()))
}
return pos.Fn(f, o)
}
// Print implements the Python print statement. It calls str() on the given args
// and outputs the results to stdout separated by spaces. Similar to the Python
// print statement.
......
......@@ -795,6 +795,26 @@ func TestOct(t *testing.T) {
}
}
func TestPos(t *testing.T) {
pos := newTestClass("pos", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__pos__": newBuiltinFunction("__pos__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
return NewInt(-42).ToObject(), nil
}).ToObject(),
}))
cases := []invokeTestCase{
{args: wrapArgs(42), want: NewInt(42).ToObject()},
{args: wrapArgs(1.2), want: NewFloat(1.2).ToObject()},
{args: wrapArgs(NewLong(big.NewInt(123))), want: NewLong(big.NewInt(123)).ToObject()},
{args: wrapArgs(newObject(pos)), want: NewInt(-42).ToObject()},
{args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "bad operand type for unary +: 'str'")},
}
for _, cas := range cases {
if err := runInvokeTestCase(wrapFuncForTest(Pos), &cas); err != "" {
t.Error(err)
}
}
}
func TestPyPrint(t *testing.T) {
fun := wrapFuncForTest(func(f *Frame, args *Tuple, sep, end string) (string, *BaseException) {
return captureStdout(f, func() *BaseException {
......
......@@ -194,6 +194,10 @@ func floatNonZero(f *Frame, o *Object) (*Object, *BaseException) {
return GetBool(toFloatUnsafe(o).Value() != 0).ToObject(), nil
}
func floatPos(f *Frame, o *Object) (*Object, *BaseException) {
return o, nil
}
func floatPow(f *Frame, v, w *Object) (*Object, *BaseException) {
return floatArithmeticOp(f, "__pow__", v, w, func(v, w float64) float64 { return math.Pow(v, w) })
}
......@@ -257,6 +261,7 @@ func initFloatType(dict map[string]*Object) {
FloatType.slots.Neg = &unaryOpSlot{floatNeg}
FloatType.slots.New = &newSlot{floatNew}
FloatType.slots.NonZero = &unaryOpSlot{floatNonZero}
FloatType.slots.Pos = &unaryOpSlot{floatPos}
FloatType.slots.Pow = &binaryOpSlot{floatPow}
FloatType.slots.RAdd = &binaryOpSlot{floatRAdd}
FloatType.slots.RDiv = &binaryOpSlot{floatRDiv}
......
......@@ -264,6 +264,10 @@ func intOr(f *Frame, v, w *Object) (*Object, *BaseException) {
return NewInt(toIntUnsafe(v).Value() | toIntUnsafe(w).Value()).ToObject(), nil
}
func intPos(f *Frame, o *Object) (*Object, *BaseException) {
return o, nil
}
func intPow(f *Frame, v, w *Object) (*Object, *BaseException) {
if w.isInstance(IntType) {
// First try to use the faster floating point arithmetic
......@@ -388,6 +392,7 @@ func initIntType(dict map[string]*Object) {
IntType.slots.NonZero = &unaryOpSlot{intNonZero}
IntType.slots.Oct = &unaryOpSlot{intOct}
IntType.slots.Or = &binaryOpSlot{intOr}
IntType.slots.Pos = &unaryOpSlot{intPos}
IntType.slots.Pow = &binaryOpSlot{intPow}
IntType.slots.RAdd = &binaryOpSlot{intRAdd}
IntType.slots.RAnd = &binaryOpSlot{intAnd}
......
......@@ -307,6 +307,10 @@ func longOr(z, x, y *big.Int) {
z.Or(x, y)
}
func longPos(z, x *big.Int) {
z.Set(x)
}
func longRepr(f *Frame, o *Object) (*Object, *BaseException) {
return NewStr(toLongUnsafe(o).value.Text(10) + "L").ToObject(), nil
}
......@@ -355,6 +359,7 @@ func initLongType(dict map[string]*Object) {
LongType.slots.NonZero = longUnaryBoolOpSlot(longNonZero)
LongType.slots.Oct = &unaryOpSlot{longOct}
LongType.slots.Or = longBinaryOpSlot(longOr)
LongType.slots.Pos = longUnaryOpSlot(longPos)
// This operation can return a float, it must use binaryOpSlot directly.
LongType.slots.Pow = &binaryOpSlot{longPow}
LongType.slots.RAdd = longRBinaryOpSlot(longAdd)
......
......@@ -420,6 +420,7 @@ type typeSlots struct {
NonZero *unaryOpSlot
Oct *unaryOpSlot
Or *binaryOpSlot
Pos *unaryOpSlot
Pow *binaryOpSlot
RAdd *binaryOpSlot
RAnd *binaryOpSlot
......
......@@ -81,5 +81,28 @@ def TestNeg():
assert -x == -100
def TestPos():
x = 12
assert +x == 12
x = 1.1
assert +x == 1.1
x = 0.0
assert +x == 0.0
x = float('inf')
assert math.isinf(+x)
x = +float('inf')
assert math.isinf(+x)
x = float('nan')
assert math.isnan(+x)
x = long(100)
assert +x == 100
if __name__ == '__main__':
weetest.RunTests()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment