6d93435f04cb7f14b2accdb8e5381c7223745151
[software/python-on-guile.git] / modules / language / python / number.scm
1 (define-module (language python number)
2 #:use-module (oop pf-objects)
3 #:use-module (oop goops)
4 #:use-module (language python hash)
5 #:use-module (language python list)
6 #:use-module (language python try)
7 #:use-module (language python exceptions)
8 #:use-module (language python persist)
9 #:export (py-int py-float py-complex
10 py-/ py-logand py-logior py-logxor py-abs py-trunc
11 py-lshift py-rshift py-mod py-floordiv py-round py-iadd
12 py-lognot py-matmul
13 <py-int> <py-float> <py-complex>
14 py-divmod pyfloat-listing pyint-listing pycomplex-listing
15 py-as-integer-ratio py-conjugate py-fromhex py-hex py-imag
16 py-is-integer py-real hex py-bin py-index
17 py-ifloordiv py-ilshift py-imod py-imul py-imatmul
18 py-ilogior py-ilogand py-ipow py-isub py-i/
19 py-irshift py-ilogxor))
20
21 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
22
23 (define-syntax-rule (mki py-iadd __iadd__)
24 (define (py-iadd x y)
25 ((ref x '__iadd__) y)))
26
27 (mki py-iadd __iadd__)
28
29 (mki py-matmul __matmul__)
30 (mki py-ifloordiv __ifloordiv__)
31 (mki py-ilshift __ilshift__)
32 (mki py-imod __imod__)
33 (mki py-imul __imul__)
34 (mki py-imatmul __imatmul__)
35 (mki py-ilogior __ior__)
36 (mki py-ilogand __iand__)
37 (mki py-ipow __ipow__)
38 (mki py-isub __isub__)
39 (mki py-irshift __irshift__)
40 (mki py-ilogxor __ixor__)
41 (mki py-i/ __itruediv__)
42
43
44 (define-class <py-int> () x)
45 (define-class <py-float> () x)
46 (define-class <py-complex> () x)
47
48 (name-object <py-int>)
49 (name-object <py-float>)
50 (name-object <py-complex>)
51
52 (define-syntax-rule (mk <py-int>)
53 (cpit <py-int> (o (lambda (o x) (slot-set! o 'x x)) (list (slot-ref o 'x)))))
54
55 (mk <py-int>)
56 (mk <py-float>)
57 (mk <py-complex>)
58
59 (define-syntax-rule (b0 op)
60 (begin
61 (define-method (op (o1 <py-int>) o2)
62 (op (slot-ref o1 'x) o2))
63 (define-method (op (o1 <py-float>) o2)
64 (op (slot-ref o1 'x) o2))
65 (define-method (op (o1 <py-complex>) o2)
66 (op (slot-ref o1 'x) o2))
67 (define-method (op o2 (o1 <py-int>))
68 (op (slot-ref o1 'x) o2))
69 (define-method (op o2 (o1 <py-complex>))
70 (op (slot-ref o1 'x) o2))
71 (define-method (op o2 (o1 <py-float>))
72 (op (slot-ref o1 'x) o2))))
73
74 (define-syntax-rule (mk-biop1 mk-biop0 op r1)
75 (begin
76 (mk-biop0 op)
77 (define-method (op v (o <p>))
78 (aif it (ref o 'r1)
79 (it v)
80 (next-method)))))
81
82 (define-syntax-rule (mk-biop2 mk-biop0 rop op r1 r2)
83 (begin
84 (define-syntax-rule (rop x y) (op y x))
85 (mk-biop1 mk-biop0 op r1)
86 (define-method (op v (o <p>))
87 (aif it (ref o 'r2)
88 (it v)
89 (next-method)))))
90
91 (define-syntax-rule (i0 op)
92 (begin
93 (define-method (op (o1 <py-int>) o2)
94 (op (slot-ref o1 'x) o2))
95 (define-method (op o2 (o1 <py-int>))
96 (op o2 (slot-ref o1 'x)))))
97
98 (mk-biop2 b0 r+ + __add__ __radd__)
99 (mk-biop2 b0 r- - __sub__ __rsub__)
100 (mk-biop2 b0 r* * __mul__ __rmul__)
101
102 (mk-biop1 b0 < __le__)
103 (mk-biop1 b0 > __ge__)
104 (mk-biop1 b0 <= __lt__)
105 (mk-biop1 b0 >= __gt__)
106 (mk-biop2 b0 rexpt expt __pow__ __rpow__)
107 (b0 py-equal?)
108
109 (define-method (py-lshift (o1 <integer>) (o2 <integer>))
110 (ash o1 o2))
111 (define-method (py-rshift (o1 <integer>) (o2 <integer>))
112 (ash o1 (- o2)))
113
114 (mk-biop2 i0 py-rlshift py-lshift __lshift__ __rlshift__)
115 (mk-biop2 i0 py-rrshift py-rshift __rshift__ __rrshift__)
116
117 (define-method (py-logand (o1 <integer>) (o2 <integer>))
118 (logand o1 o2))
119 (define-method (py-logior (o1 <integer>) (o2 <integer>))
120 (logior o1 o2))
121 (define-method (py-logxor (o1 <integer>) (o2 <integer>))
122 (logxor o1 o2))
123 (define-method (py-lognot (o1 <integer>))
124 (lognot o1))
125
126
127 (define-method (py-/ (o1 <number>) (o2 <integer>))
128 (/ o1 (exact->inexact o2)))
129 (define-method (py-/ (o1 <number>) (o2 <number>))
130 (/ o1 o2))
131
132 (define-method (py-divmod (o1 <integer>) (o2 <integer>))
133 (values
134 (floor-quotient o1 o2)
135 (modulo o1 o2)))
136
137 (define-method (py-divmod (o1 <number>) (o2 <number>))
138 (values
139 (floor-quotient o1 o2)
140 (floor-remainder o1 o2)))
141
142 (define-method (py-floordiv (o1 <number>) (o2 <number>))
143 (floor-quotient o1 o2))
144
145 (mk-biop2 b0 py-rfloordiv py-floordiv __floordiv__ __rfloordiv__)
146 (mk-biop2 b0 py-rdivmod py-divmod __divmod__ __rdivmod__)
147 (mk-biop2 b0 py-r/ py-/ __truediv__ __rtruediv__)
148
149 (mk-biop2 i0 py-rlogand py-logand __and__ __rand__)
150 (mk-biop2 i0 py-rlogior py-logior __or__ __ror__)
151 (mk-biop2 i0 py-rlogxor py-logxor __xor__ __rxor__)
152
153 (define-method (py-mod (o1 <integer>) (o2 <integer>))
154 (modulo o1 o2))
155 (define-method (py-mod (o1 <real>) (o2 <real>))
156 (floor-remainder o1 o2))
157
158 (mk-biop2 i0 py-rmod py-mod __mod__ __rmod__)
159
160
161 (define-method (py-floor (o1 <integer>)) o1)
162 (define-method (py-floor (o1 <number> )) )
163 (define-method (py-trunc (o1 <integer>)) (exact->inexact o1))
164 (define-method (py-trunc (o1 <number> ))
165 (floor o1))
166
167 (define-syntax-rule (u0 f)
168 (begin
169 (define-method (f (o <py-int> )) (f (slot-ref o 'x)))
170 (define-method (f (o <py-float>)) (f (slot-ref o 'x)))
171 (define-method (f (o <py-complex>)) (f (slot-ref o 'x)))))
172
173 (define-syntax-rule (i0 f)
174 (begin
175 (define-method (f (o <py-int> )) (f (slot-ref o 'x)))))
176
177 (define-syntax-rule (mk-unop u0 f r)
178 (begin
179 (u0 f)
180 (define-method (f (o <p>))
181 ((ref o 'r)))))
182
183 (u0 py-hash )
184 (mk-unop u0 - __neg__ )
185 (mk-unop u0 py-trunc __trunc__ )
186 (mk-unop i0 py-lognot __invert__)
187
188 (define-method (py-bit-length (i <integer>))
189 (logcount i))
190
191 (define-method (py-conjugate (i <complex>))
192 (make-rectangular (real-part i) (- (imag-part i))))
193 (define-method (py-conjugate (i <number>)) i)
194
195 (define-method (py-imag (i <complex>)) (imag-part i))
196 (define-method (py-imag (i <number>)) i)
197
198 (define-method (py-real (i <complex>)) (real-part i))
199 (define-method (py-real (i <number>)) i)
200
201 (define-method (py-denominator (o <integer>)) 0)
202 (define-method (py-denominator (o <real>))
203 (denominator (inexact->exact o)))
204
205 (define-method (py-numerator (o <integer>)) o)
206 (define-method (py-numerator (o <real> ))
207 (numerator (inexact->exact o)))
208
209 (define-method (py-as-integer-ratio (o <integer>))
210 (list o 0))
211 (define-method (py-as-integer-ratio (o <real>))
212 (let ((r (inexact->exact o)))
213 (list (numerator r) (denominator r))))
214
215 (define-method (py-fromhex (o <real>))
216 (error "1.2.fromhex('0x1.ap4') is not implemented"))
217
218 (define (py-hex x)
219 (+ "0x" (number->string (py-index x) 16)))
220
221 (define-method (py-is-integer (o <real>))
222 (= 1 (denominator (inexact->exact o))))
223 (define-method (py-is-integer (o <integer>)) #t)
224
225 (define-method (hex (o <integer>))
226 (+ "0x" (number->string o 16)))
227
228 (define-method (py-abs (o <complex>))
229 (magnitude o))
230 (define-method (py-abs (o <number>))
231 (abs o))
232 (define-method (py-index (o <integer>)) o)
233 (mk-unop u0 py-abs __abs__)
234 (mk-unop u0 py-conjugate conjugate)
235 (mk-unop u0 py-imag imag)
236 (mk-unop u0 py-real real)
237 (mk-unop u0 py-denominator denominator)
238 (mk-unop u0 py-numerator numerator)
239 (mk-unop u0 py-as-integer-ratio as_integer_ratio)
240 (mk-unop u0 py-fromhex fromhex)
241 (mk-unop i0 hex __hex__)
242 (mk-unop u0 py-is-integer is_integer)
243 (mk-unop u0 py-index __index__)
244
245 (define-method (write (o <py-float>) . l)
246 (apply write (slot-ref o 'x) l))
247 (define-method (write (o <py-int>) . l)
248 (apply write (slot-ref o 'x) l))
249
250 (define-python-class int (<py-int>)
251 (define __init__
252 (letrec ((__init__
253 (case-lambda
254 ((self)
255 (__init__ self 0))
256
257 ((self n)
258 (let lp ((n n))
259 (cond
260 ((and (number? n) (integer? n))
261 (slot-set! self 'x n))
262 ((number? n)
263 (lp (py-floor n)))
264 ((string? n)
265 (lp (string->number n)))
266 (else
267 (aif it (slot-ref n '__int__)
268 (slot-set! self 'x it)
269 (raise ValueError "could not make int from " n))))))
270
271 ((self n k)
272 (__init__ self (string->number n k))))))
273 __init__)))
274
275 (name-object int)
276
277 (define (proj? x)
278 (if (number? x)
279 x
280 (and
281 (or (is-a? x <py-complex>)
282 (is-a? x <py-int>)
283 (is-a? x <py-float>))
284 (slot-ref x 'x))))
285
286 (define (projc? x)
287 (if (number? x)
288 (if (not (complex? x))
289 x
290 #f)
291 (and
292 (or (is-a? x <py-complex>)
293 (is-a? x <py-int>)
294 (is-a? x <py-float>))
295 (let ((ret (slot-ref x 'x)))
296 (if (not (complex? ret))
297 ret
298 #f)))))
299
300 (define-python-class float (<py-float>)
301 (define __init__
302 (case-lambda
303 ((self n)
304 (let lp ((n n))
305 (cond
306 ((projc? n) =>
307 (lambda (n)
308 (slot-set! self 'x n)))
309 ((string? n)
310 (lp (string->number n)))
311 (else
312 (aif it (slot-ref n '__float__)
313 (slot-set! self 'x it)
314 (raise ValueError "could not make float from " n)))))))))
315
316 (name-object float)
317
318 (define-python-class py-complex (<py-complex>)
319 (define __init__
320 (case-lambda
321 ((self n)
322 (cond
323 ((proj? n) =>
324 (lambda (n)
325 (slot-set! self 'x n)))
326 (else
327 (raise ValueError "could not make complex from " n))))
328 ((self n m)
329 (cond
330 ((projc? n) =>
331 (lambda (n)
332 (cond
333 ((projc? m)
334 (lambda (m)
335 (slot-set! self 'x (make-rectangular n m))))
336 (else
337 (raise ValueError "could not make complex from " n m)))))
338 (else
339 (raise ValueError "could not make complex from " n m)))))))
340
341 (name-object py-complex)
342
343 (define-method (py-class (o <integer> )) int)
344 (define-method (py-class (o <real> )) float)
345 (u0 py-class)
346
347 (define py-int int)
348 (define py-float float)
349
350 (define-method (mk-int (o <number>)) (slot-ref (py-int o) 'x))
351 (define-method (mk-float (o <number>)) (slot-ref (py-float o) 'x))
352
353 (mk-unop u0 mk-int __int__)
354 (mk-unop u0 mk-float __float__)
355
356 (define (pyint-listing)
357 (let ((l
358 (to-pylist
359 (map symbol->string
360 '(__abs__ __add__ __and__ __class__ __cmp__ __coerce__
361 __delattr__ __div__ __divmod__ __doc__ __float__
362 __floordiv__ __format__ __getattribute__
363 __getnewargs__ __hash__ __hex__ __index__ __init__
364 __int__ __invert__ __long__ __lshift__ __mod__
365 __mul__ __neg__ __new__ __nonzero__ __oct__ __or__
366 __pos__ __pow__ __radd__ __rand__ __rdiv__
367 __rdivmod__ __reduce__ __reduce_ex__ __repr__
368 __rfloordiv__ __rlshift__ __rmod__ __rmul__ __ror__
369 __rpow__ __rrshift__ __rshift__ __rsub__ __rtruediv__
370 __rxor__ __setattr__ __sizeof__ __str__ __sub__
371 __subclasshook__ __truediv__ __trunc__ __xor__
372 bit_length conjugate denominator imag numerator
373 real)))))
374 (pylist-sort! l)
375 l))
376
377 (define (pyfloat-listing)
378 (let ((l
379 (to-pylist
380 (map symbol->string
381 '(__abs__ __add__ __class__ __coerce__ __delattr__ __div__
382 __divmod__ __doc__ __eq__ __float__ __floordiv__
383 __format__ __ge__ __getattribute__ __getformat__
384 __getnewargs__ __gt__ __hash__ __init__ __int__
385 __le__ __long__ __lt__ __mod__ __mul__ __ne__
386 __neg__ __new__ __nonzero__ __pos__ __pow__
387 __radd__ __rdiv__ __rdivmod__ __reduce__
388 __reduce_ex__ __repr__ __rfloordiv__ __rmod__
389 __rmul__ __rpow__ __rsub__ __rtruediv__
390 __setattr__ __setformat__ __sizeof__ __str__
391 __sub__ __subclasshook__ __truediv__ __trunc__
392 as_integer_ratio conjugate fromhex hex imag
393 is_integer real)))))
394 (pylist-sort! l)
395 l))
396
397 (define (pycomplex-listing)
398 (let ((l
399 (to-pylist
400 (map symbol->string
401 '(__abs__ __add__ __class__ __coerce__ __delattr__ __div__
402 __divmod__ __doc__ __eq__ __float__ __floordiv__
403 __format__ __ge__ __getattribute__ __getnewargs__
404 __gt__ __hash__ __init__ __int__ __le__ __long__
405 __lt__ __mod__ __mul__ __ne__ __neg__ __new__
406 __nonzero__ __pos__ __pow__ __radd__ __rdiv__
407 __rdivmod__ __reduce__ __reduce_ex__ __repr__
408 __rfloordiv__ __rmod__ __rmul__ __rpow__ __rsub__
409 __rtruediv__ __setattr__ __sizeof__ __str__
410 __sub__ __subclasshook__ __truediv__
411 conjugate imag real)))))
412 (pylist-sort! l)
413 l))
414
415 (define* (py-round x #:optional (digits 0))
416 (let* ((f (expt 10.0 digits)))
417 (if (equal? digits 0)
418 (round x)
419 (/ (round (* x f)) f))))
420
421 (define-method (py-bin (o <integer>))
422 (number->string o 2))
423 (define-method (py-bin (o <py-int>))
424 (number->string (slot-ref o 'x) 2))
425 (define (py-bin o)
426 (+ "0b" (number->string (py-index o) 2)))
427
428