1# Python bindings for Yasm: Pyrex input file for intnum.h
2#
3#  Copyright (C) 2006  Michael Urman, Peter Johnson
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
15# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
18# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24# POSSIBILITY OF SUCH DAMAGE.
25
26cdef class IntNum
27
28cdef object __intnum_op_ex(object x, yasm_expr_op op, object y):
29    value = __intnum_op(x, op, y)
30    __error_check()
31    return value
32
33cdef object __intnum_op(object x, yasm_expr_op op, object y):
34    if isinstance(x, IntNum):
35        result = IntNum(x)
36        if y is None:
37            yasm_intnum_calc((<IntNum>result).intn, op, NULL)
38        else:
39            # Coerce to intnum if not already
40            if isinstance(y, IntNum):
41                rhs = y
42            else:
43                rhs = IntNum(y)
44            yasm_intnum_calc((<IntNum>result).intn, op, (<IntNum>rhs).intn)
45        return result
46    elif isinstance(y, IntNum):
47        # Reversed operation - x OP y still, just y is intnum, x isn't.
48        result = IntNum(x)
49        yasm_intnum_calc((<IntNum>result).intn, op, (<IntNum>y).intn)
50        return result
51    else:
52        raise NotImplementedError
53
54cdef object __make_intnum(yasm_intnum *intn):
55    return IntNum(__pass_voidp(intn, IntNum))
56
57cdef class IntNum:
58    cdef yasm_intnum *intn
59
60    def __cinit__(self, value, base=None):
61        cdef unsigned char buf[16]
62
63        self.intn = NULL
64
65        if isinstance(value, IntNum):
66            self.intn = yasm_intnum_copy((<IntNum>value).intn)
67            return
68        if PyCObject_Check(value):
69            self.intn = <yasm_intnum *>__get_voidp(value, IntNum)
70            return
71
72        if isinstance(value, str):
73            if base == 2:
74                self.intn = yasm_intnum_create_bin(value)
75            elif base == 8:
76                self.intn = yasm_intnum_create_oct(value)
77            elif base == 10 or base is None:
78                self.intn = yasm_intnum_create_dec(value)
79            elif base == 16:
80                self.intn = yasm_intnum_create_hex(value)
81            elif base == "nasm":
82                self.intn = yasm_intnum_create_charconst_nasm(value)
83            else:
84                raise ValueError("base must be 2, 8, 10, 16, or \"nasm\"")
85        elif isinstance(value, (int, long)):
86            _PyLong_AsByteArray(long(value), buf, 16, 1, 1)
87            self.intn = yasm_intnum_create_sized(buf, 1, 16, 0)
88        else:
89            raise ValueError
90
91    def __dealloc__(self):
92        if self.intn != NULL: yasm_intnum_destroy(self.intn)
93
94    def __long__(self):
95        cdef unsigned char buf[16]
96        yasm_intnum_get_sized(self.intn, buf, 16, 128, 0, 0, 0)
97        return _PyLong_FromByteArray(buf, 16, 1, 1)
98
99    def __repr__(self):
100        return "IntNum(%d)" % self
101
102    def __int__(self): return int(self.__long__())
103    def __complex__(self): return complex(self.__long__())
104    def __float__(self): return float(self.__long__())
105
106    def __oct__(self): return oct(int(self.__long__()))
107    def __hex__(self): return hex(int(self.__long__()))
108
109    def __add__(x, y): return __intnum_op(x, YASM_EXPR_ADD, y)
110    def __sub__(x, y): return __intnum_op(x, YASM_EXPR_SUB, y)
111    def __mul__(x, y): return __intnum_op(x, YASM_EXPR_MUL, y)
112    def __div__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNDIV, y)
113    def __floordiv__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNDIV, y)
114    def __mod__(x, y): return __intnum_op_ex(x, YASM_EXPR_SIGNMOD, y)
115    def __neg__(self): return __intnum_op(self, YASM_EXPR_NEG, None)
116    def __pos__(self): return self
117    def __abs__(self):
118        if yasm_intnum_sign(self.intn) >= 0: return IntNum(self)
119        else: return __intnum_op(self, YASM_EXPR_NEG, None)
120    def __nonzero__(self): return not yasm_intnum_is_zero(self.intn)
121    def __invert__(self): return __intnum_op(self, YASM_EXPR_NOT, None)
122    def __lshift__(x, y): return __intnum_op(x, YASM_EXPR_SHL, y)
123    def __rshift__(x, y): return __intnum_op(x, YASM_EXPR_SHR, y)
124    def __and__(x, y): return __intnum_op(x, YASM_EXPR_AND, y)
125    def __or__(x, y): return __intnum_op(x, YASM_EXPR_OR, y)
126    def __xor__(x, y): return __intnum_op(x, YASM_EXPR_XOR, y)
127
128    cdef object __op(self, yasm_expr_op op, object x):
129        if isinstance(x, IntNum):
130            rhs = x
131        else:
132            rhs = IntNum(x)
133        yasm_intnum_calc(self.intn, op, (<IntNum>rhs).intn)
134        return self
135
136    def __iadd__(self, x): return self.__op(YASM_EXPR_ADD, x)
137    def __isub__(self, x): return self.__op(YASM_EXPR_SUB, x)
138    def __imul__(self, x): return self.__op(YASM_EXPR_MUL, x)
139    def __idiv__(self, x): return self.__op(YASM_EXPR_SIGNDIV, x)
140    def __ifloordiv__(self, x): return self.__op(YASM_EXPR_SIGNDIV, x)
141    def __imod__(self, x): return self.__op(YASM_EXPR_MOD, x)
142    def __ilshift__(self, x): return self.__op(YASM_EXPR_SHL, x)
143    def __irshift__(self, x): return self.__op(YASM_EXPR_SHR, x)
144    def __iand__(self, x): return self.__op(YASM_EXPR_AND, x)
145    def __ior__(self, x): return self.__op(YASM_EXPR_OR, x)
146    def __ixor__(self, x): return self.__op(YASM_EXPR_XOR, x)
147
148    def __cmp__(self, x):
149        cdef yasm_intnum *t
150        t = yasm_intnum_copy(self.intn)
151        if isinstance(x, IntNum):
152            rhs = x
153        else:
154            rhs = IntNum(x)
155        yasm_intnum_calc(t, YASM_EXPR_SUB, (<IntNum>rhs).intn)
156        result = yasm_intnum_sign(t)
157        yasm_intnum_destroy(t)
158        return result
159
160    def __richcmp__(x, y, op):
161        cdef yasm_expr_op aop
162        if op == 0: aop = YASM_EXPR_LT
163        elif op == 1: aop = YASM_EXPR_LE
164        elif op == 2: aop = YASM_EXPR_EQ
165        elif op == 3: aop = YASM_EXPR_NE
166        elif op == 4: aop = YASM_EXPR_GT
167        elif op == 5: aop = YASM_EXPR_GE
168        else: raise NotImplementedError
169        v = __intnum_op(x, aop, y)
170        return bool(not yasm_intnum_is_zero((<IntNum>v).intn))
171