progressively imporoving the conformance with python3
[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 (o <p>) v)
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
99 (mk-biop2 b0 r+ + __add__ __radd__)
100 (mk-biop2 b0 r- - __sub__ __rsub__)
101 (mk-biop2 b0 r* * __mul__ __rmul__)
102
103 (mk-biop1 b0 < __le__)
104 (mk-biop1 b0 > __ge__)
105 (mk-biop1 b0 <= __lt__)
106 (mk-biop1 b0 >= __gt__)
107 (mk-biop2 b0 rexpt expt __pow__ __rpow__)
108 (b0 py-equal?)
109
110
111 (define-method (py-lshift (o1 <integer>) (o2 <integer>))
112 (ash o1 o2))
113 (define-method (py-rshift (o1 <integer>) (o2 <integer>))
114 (ash o1 (- o2)))
115
116 (mk-biop2 i0 py-rlshift py-lshift __lshift__ __rlshift__)
117 (mk-biop2 i0 py-rrshift py-rshift __rshift__ __rrshift__)
118
119 (define-method (py-logand (o1 <integer>) (o2 <integer>))
120 (logand o1 o2))
121 (define-method (py-logior (o1 <integer>) (o2 <integer>))
122 (logior o1 o2))
123 (define-method (py-logxor (o1 <integer>) (o2 <integer>))
124 (logxor o1 o2))
125 (define-method (py-lognot (o1 <integer>))
126 (lognot o1))
127
128 (define-method (py-logand o1 (o2 <py-int>))
129 (py-logand o1 (slot-ref o2 'x)))
130
131 (define-method (py-logand (o1 <py-int>) o2)
132 (py-logand (slot-ref o1 'x) o2))
133
134 (define-method (py-logior o1 (o2 <py-int>))
135 (py-logior o1 (slot-ref o2 'x)))
136
137 (define-method (py-logior (o1 <py-int>) o2)
138 (py-logior (slot-ref o1 'x) o2))
139
140 (define-method (py-logxor o1 (o2 <py-int>))
141 (py-logxor o1 (slot-ref o2 'x)))
142
143 (define-method (py-logxor (o1 <py-int>) o2)
144 (py-logxor (slot-ref o1 'x) o2))
145
146 (define-method (py-lognot (o1 <py-int>))
147 (lognot (slot-ref o1 'x)))
148
149 (define-method (py-logand (o1 <p>) o2)
150 (aif it (ref o1 '__and__)
151 (it o2)
152 (next-method)))
153
154 (define-method (py-logand o1 (o2 <p>))
155 (aif it (ref o1 '__rand__)
156 (it o2)
157 (next-method)))
158
159 (define-method (py-logior (o1 <p>) o2)
160 (aif it (ref o1 '__or__)
161 (it o2)
162 (next-method)))
163
164 (define-method (py-logior o1 (o2 <p>))
165 (aif it (ref o1 '__ror__)
166 (it o2)
167 (next-method)))
168
169 (define-method (py-logxor (o1 <p>) o2)
170 (aif it (ref o1 '__xor__)
171 (it o2)
172 (next-method)))
173
174 (define-method (py-logxor o1 (o2 <p>))
175 (aif it (ref o1 '__rxor__)
176 (it o2)
177 (next-method)))
178
179 (define-method (py-lognot (o1 <p>))
180 (aif it (ref o1 '__not__)
181 (it)
182 (next-method)))
183
184
185 (define-method (py-/ (o1 <number>) (o2 <integer>))
186 (/ o1 (exact->inexact o2)))
187 (define-method (py-/ (o1 <number>) (o2 <number>))
188 (/ o1 o2))
189
190 (define-method (py-divmod (o1 <integer>) (o2 <integer>))
191 (values
192 (floor-quotient o1 o2)
193 (modulo o1 o2)))
194
195 (define-method (py-divmod (o1 <number>) (o2 <number>))
196 (values
197 (floor-quotient o1 o2)
198 (floor-remainder o1 o2)))
199
200 (define-method (py-floordiv (o1 <number>) (o2 <number>))
201 (floor-quotient o1 o2))
202
203 (mk-biop2 b0 py-rfloordiv py-floordiv __floordiv__ __rfloordiv__)
204 (mk-biop2 b0 py-rdivmod py-divmod __divmod__ __rdivmod__)
205 (mk-biop2 b0 py-r/ py-/ __truediv__ __rtruediv__)
206
207 (mk-biop2 i0 py-rlogand py-logand __and__ __rand__)
208 (mk-biop2 i0 py-rlogior py-logior __or__ __ror__)
209 (mk-biop2 i0 py-rlogxor py-logxor __xor__ __rxor__)
210
211 (define-method (py-mod (o1 <integer>) (o2 <integer>))
212 (modulo o1 o2))
213 (define-method (py-mod (o1 <real>) (o2 <real>))
214 (floor-remainder o1 o2))
215
216 (mk-biop2 i0 py-rmod py-mod __mod__ __rmod__)
217
218
219 (define-method (py-floor (o1 <integer>)) o1)
220 (define-method (py-floor (o1 <number> )) )
221 (define-method (py-trunc (o1 <integer>)) (exact->inexact o1))
222 (define-method (py-trunc (o1 <number> ))
223 (floor o1))
224
225 (define-syntax-rule (u0 f)
226 (begin
227 (define-method (f (o <py-int> )) (f (slot-ref o 'x)))
228 (define-method (f (o <py-float>)) (f (slot-ref o 'x)))
229 (define-method (f (o <py-complex>)) (f (slot-ref o 'x)))))
230
231 (define-syntax-rule (i0 f)
232 (begin
233 (define-method (f (o <py-int> )) (f (slot-ref o 'x)))))
234
235 (define-syntax-rule (mk-unop u0 f r)
236 (begin
237 (u0 f)
238 (define-method (f (o <p>))
239 ((ref o 'r)))))
240
241 (u0 py-hash )
242 (mk-unop u0 - __neg__ )
243 (mk-unop u0 py-trunc __trunc__ )
244 (mk-unop i0 py-lognot __invert__)
245
246 (define-method (py-bit-length (i <integer>))
247 (logcount i))
248
249 (define-method (py-conjugate (i <complex>))
250 (make-rectangular (real-part i) (- (imag-part i))))
251 (define-method (py-conjugate (i <number>)) i)
252
253 (define-method (py-imag (i <complex>)) (imag-part i))
254 (define-method (py-imag (i <number>)) i)
255
256 (define-method (py-real (i <complex>)) (real-part i))
257 (define-method (py-real (i <number>)) i)
258
259 (define-method (py-denominator (o <integer>)) 0)
260 (define-method (py-denominator (o <real>))
261 (denominator (inexact->exact o)))
262
263 (define-method (py-numerator (o <integer>)) o)
264 (define-method (py-numerator (o <real> ))
265 (numerator (inexact->exact o)))
266
267 (define-method (py-as-integer-ratio (o <integer>))
268 (list o 0))
269 (define-method (py-as-integer-ratio (o <real>))
270 (let ((r (inexact->exact o)))
271 (list (numerator r) (denominator r))))
272
273 (define-method (py-fromhex (o <real>))
274 (error "1.2.fromhex('0x1.ap4') is not implemented"))
275
276 (define (py-hex x)
277 (+ "0x" (number->string (py-index x) 16)))
278
279 (define-method (py-is-integer (o <real>))
280 (= 1 (denominator (inexact->exact o))))
281 (define-method (py-is-integer (o <integer>)) #t)
282
283 (define-method (hex (o <integer>))
284 (+ "0x" (number->string o 16)))
285
286 (define-method (py-abs (o <complex>))
287 (magnitude o))
288 (define-method (py-abs (o <number>))
289 (abs o))
290 (define-method (py-index (o <integer>)) o)
291 (mk-unop u0 py-abs __abs__)
292 (mk-unop u0 py-conjugate conjugate)
293 (mk-unop u0 py-imag imag)
294 (mk-unop u0 py-real real)
295 (mk-unop u0 py-denominator denominator)
296 (mk-unop u0 py-numerator numerator)
297 (mk-unop u0 py-as-integer-ratio as_integer_ratio)
298 (mk-unop u0 py-fromhex fromhex)
299 (mk-unop i0 hex __hex__)
300 (mk-unop u0 py-is-integer is_integer)
301 (mk-unop u0 py-index __index__)
302
303 (define-method (write (o <py-float>) . l)
304 (apply write (slot-ref o 'x) l))
305 (define-method (write (o <py-int>) . l)
306 (apply write (slot-ref o 'x) l))
307
308 (define-python-class int (<py-int>)
309 (define __init__
310 (letrec ((__init__
311 (case-lambda
312 ((self)
313 (__init__ self 0))
314
315 ((self n)
316 (let lp ((n n))
317 (cond
318 ((and (number? n) (integer? n))
319 (slot-set! self 'x n))
320 ((number? n)
321 (lp (py-floor n)))
322 ((string? n)
323 (lp (string->number n)))
324 (else
325 (aif it (slot-ref n '__int__)
326 (slot-set! self 'x it)
327 (raise ValueError "could not make int from " n))))))
328
329 ((self n k)
330 (__init__ self (string->number n k))))))
331 __init__)))
332
333 (name-object int)
334
335 (define (proj? x)
336 (if (number? x)
337 x
338 (and
339 (or (is-a? x <py-complex>)
340 (is-a? x <py-int>)
341 (is-a? x <py-float>))
342 (slot-ref x 'x))))
343
344 (define (projc? x)
345 (if (number? x)
346 (if (not (complex? x))
347 x
348 #f)
349 (and
350 (or (is-a? x <py-complex>)
351 (is-a? x <py-int>)
352 (is-a? x <py-float>))
353 (let ((ret (slot-ref x 'x)))
354 (if (not (complex? ret))
355 ret
356 #f)))))
357
358 (define-python-class float (<py-float>)
359 (define __init__
360 (case-lambda
361 ((self n)
362 (let lp ((n n))
363 (cond
364 ((projc? n) =>
365 (lambda (n)
366 (slot-set! self 'x n)))
367 ((string? n)
368 (lp (string->number n)))
369 (else
370 (aif it (slot-ref n '__float__)
371 (slot-set! self 'x it)
372 (raise ValueError "could not make float from " n)))))))))
373
374 (name-object float)
375
376 (define-python-class py-complex (<py-complex>)
377 (define __init__
378 (case-lambda
379 ((self n)
380 (cond
381 ((proj? n) =>
382 (lambda (n)
383 (slot-set! self 'x n)))
384 (else
385 (raise ValueError "could not make complex from " n))))
386 ((self n m)
387 (cond
388 ((projc? n) =>
389 (lambda (n)
390 (cond
391 ((projc? m)
392 (lambda (m)
393 (slot-set! self 'x (make-rectangular n m))))
394 (else
395 (raise ValueError "could not make complex from " n m)))))
396 (else
397 (raise ValueError "could not make complex from " n m)))))))
398
399 (name-object py-complex)
400
401 (define-method (py-class (o <integer> )) int)
402 (define-method (py-class (o <real> )) float)
403 (u0 py-class)
404
405 (define py-int int)
406 (define py-float float)
407
408 (define-method (mk-int (o <number>)) (slot-ref (py-int o) 'x))
409 (define-method (mk-float (o <number>)) (slot-ref (py-float o) 'x))
410
411 (mk-unop u0 mk-int __int__)
412 (mk-unop u0 mk-float __float__)
413
414 (define (pyint-listing)
415 (let ((l
416 (to-pylist
417 (map symbol->string
418 '(__abs__ __add__ __and__ __class__ __cmp__ __coerce__
419 __delattr__ __div__ __divmod__ __doc__ __float__
420 __floordiv__ __format__ __getattribute__
421 __getnewargs__ __hash__ __hex__ __index__ __init__
422 __int__ __invert__ __long__ __lshift__ __mod__
423 __mul__ __neg__ __new__ __nonzero__ __oct__ __or__
424 __pos__ __pow__ __radd__ __rand__ __rdiv__
425 __rdivmod__ __reduce__ __reduce_ex__ __repr__
426 __rfloordiv__ __rlshift__ __rmod__ __rmul__ __ror__
427 __rpow__ __rrshift__ __rshift__ __rsub__ __rtruediv__
428 __rxor__ __setattr__ __sizeof__ __str__ __sub__
429 __subclasshook__ __truediv__ __trunc__ __xor__
430 bit_length conjugate denominator imag numerator
431 real)))))
432 (pylist-sort! l)
433 l))
434
435 (define (pyfloat-listing)
436 (let ((l
437 (to-pylist
438 (map symbol->string
439 '(__abs__ __add__ __class__ __coerce__ __delattr__ __div__
440 __divmod__ __doc__ __eq__ __float__ __floordiv__
441 __format__ __ge__ __getattribute__ __getformat__
442 __getnewargs__ __gt__ __hash__ __init__ __int__
443 __le__ __long__ __lt__ __mod__ __mul__ __ne__
444 __neg__ __new__ __nonzero__ __pos__ __pow__
445 __radd__ __rdiv__ __rdivmod__ __reduce__
446 __reduce_ex__ __repr__ __rfloordiv__ __rmod__
447 __rmul__ __rpow__ __rsub__ __rtruediv__
448 __setattr__ __setformat__ __sizeof__ __str__
449 __sub__ __subclasshook__ __truediv__ __trunc__
450 as_integer_ratio conjugate fromhex hex imag
451 is_integer real)))))
452 (pylist-sort! l)
453 l))
454
455 (define (pycomplex-listing)
456 (let ((l
457 (to-pylist
458 (map symbol->string
459 '(__abs__ __add__ __class__ __coerce__ __delattr__ __div__
460 __divmod__ __doc__ __eq__ __float__ __floordiv__
461 __format__ __ge__ __getattribute__ __getnewargs__
462 __gt__ __hash__ __init__ __int__ __le__ __long__
463 __lt__ __mod__ __mul__ __ne__ __neg__ __new__
464 __nonzero__ __pos__ __pow__ __radd__ __rdiv__
465 __rdivmod__ __reduce__ __reduce_ex__ __repr__
466 __rfloordiv__ __rmod__ __rmul__ __rpow__ __rsub__
467 __rtruediv__ __setattr__ __sizeof__ __str__
468 __sub__ __subclasshook__ __truediv__
469 conjugate imag real)))))
470 (pylist-sort! l)
471 l))
472
473 (define* (py-round x #:optional (digits 0))
474 (let* ((f (expt 10.0 digits)))
475 (if (equal? digits 0)
476 (round x)
477 (/ (round (* x f)) f))))
478
479 (define-method (py-bin (o <integer>))
480 (number->string o 2))
481 (define-method (py-bin (o <py-int>))
482 (number->string (slot-ref o 'x) 2))
483 (define (py-bin o)
484 (+ "0b" (number->string (py-index o) 2)))
485
486