Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/libs/ecl.pyx
8815 views
1
r"""
2
Library interface to Embeddable Common Lisp (ECL)
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2009 Nils Bruin <[email protected]>
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
# as published by the Free Software Foundation; either version 2 of
9
# the License, or (at your option) any later version.
10
# http://www.gnu.org/licenses/
11
#*****************************************************************************
12
13
#This version of the library interface prefers to convert ECL integers and
14
#rationals to SAGE types Integer and Rational. These parts could easily be
15
#adapted to work with pure Python types.
16
17
include "sage/ext/signals.pxi"
18
include "sage/ext/interrupt.pxi"
19
include "sage/ext/cdefs.pxi"
20
21
from sage.rings.integer cimport Integer
22
from sage.rings.rational cimport Rational
23
from sage.rings.rational import Rational
24
25
#it would be preferrable to let bint_symbolp wrap an efficient macro
26
#but the macro provided in object.h doesn't seem to work
27
cdef bint bint_symbolp(cl_object obj):
28
return not(cl_symbolp(obj) == Cnil)
29
30
#these type predicates are only provided in "cl_*" form, so we wrap them
31
#with the proper type cast.
32
33
cdef bint bint_numberp(cl_object obj):
34
return not(cl_numberp(obj) == Cnil)
35
cdef bint bint_integerp(cl_object obj):
36
return not(cl_integerp(obj) == Cnil)
37
cdef bint bint_rationalp(cl_object obj):
38
return not(cl_rationalp(obj) == Cnil)
39
40
cdef extern from "eclsig.h":
41
int ecl_sig_on() except 0
42
void ecl_sig_off()
43
cdef Sigaction ecl_sigint_handler
44
cdef Sigaction ecl_sigbus_handler
45
cdef Sigaction ecl_sigsegv_handler
46
cdef mpz_t* ecl_mpz_from_bignum(cl_object obj)
47
cdef cl_object ecl_bignum_from_mpz(mpz_t* num)
48
49
cdef cl_object string_to_object(char * s):
50
return ecl_read_from_cstring(s)
51
52
# We need to keep a list of objects bound to python, to protect them from being
53
# garbage collected. We want a list in which we can quickly add and remove
54
# elements. Lookup is not necessary. A doubly linked list seems
55
# most appropriate. A node looks like
56
# N = ( value next . prev)
57
# so that car(N)=value, cadr(N)=next, cddr(N)=prev.
58
# we write routines to insert a node after a given node
59
# and to delete a given node. This can all be done with modifying pointers.
60
# note that circular structures are unpleasant for most lisp routines.
61
# perhaps this even puts a strain on the garbage collector?
62
# an alternative data structure would be an array where the free nodes get
63
# chained in a "free list" for quick allocation (and if the free list is empty
64
# upon allocating a node, the array needs to be extended)
65
66
cdef cl_object insert_node_after(cl_object node,cl_object value):
67
cdef cl_object next,newnode
68
69
next=cl_cadr(node)
70
newnode=cl_cons(value,cl_cons(next,node))
71
cl_rplaca(cl_cdr(node),newnode)
72
if next != Cnil:
73
cl_rplacd(cl_cdr(next),newnode)
74
return newnode
75
76
cdef void remove_node(cl_object node):
77
cdef cl_object next, prev
78
next=cl_cadr(node)
79
prev=cl_cddr(node)
80
if next != Cnil:
81
cl_rplacd(cl_cdr(next),prev)
82
if prev != Cnil:
83
cl_rplaca(cl_cdr(prev),next)
84
85
# our global list of pointers. This will be a pointer to a sentinel node,
86
# after which all new nodes can be inserted. list_of_object gets initialised
87
# by init_ecl() and bound to the global ECL variable *SAGE-LIST-OF-OBJECTS*
88
89
cdef cl_object list_of_objects
90
91
cdef cl_object safe_eval_clobj #our own error catching eval
92
cdef cl_object safe_apply_clobj #our own error catching apply
93
cdef cl_object safe_funcall_clobj #our own error catching funcall
94
cdef cl_object read_from_string_clobj #our own error catching reader
95
96
cdef bint ecl_has_booted = 0
97
98
# ECL signal handling
99
100
def test_sigint_before_ecl_sig_on():
101
"""
102
TESTS:
103
104
If an interrupt arrives *before* ecl_sig_on(), we should get an
105
ordinary KeyboardInterrupt::
106
107
sage: from sage.libs.ecl import test_sigint_before_ecl_sig_on
108
sage: test_sigint_before_ecl_sig_on()
109
Traceback (most recent call last):
110
...
111
KeyboardInterrupt
112
"""
113
# Raise a SIGINT *now*. Since we are outside of sig_on() at this
114
# point, this SIGINT will not be seen yet.
115
signal_raise(SIGINT)
116
# An ordinary KeyboardInterrupt should be raised by ecl_sig_on()
117
# since ecl_sig_on() calls sig_on() before anything else. This
118
# will catch the pending SIGINT.
119
ecl_sig_on()
120
# We should never get here.
121
abort()
122
123
def test_ecl_options():
124
"""
125
Print an overview of the ECL options
126
127
TESTS::
128
129
sage: from sage.libs.ecl import test_ecl_options
130
sage: test_ecl_options()
131
ECL_OPT_INCREMENTAL_GC = 0
132
ECL_OPT_TRAP_SIGSEGV = 1
133
ECL_OPT_TRAP_SIGFPE = 1
134
ECL_OPT_TRAP_SIGINT = 1
135
ECL_OPT_TRAP_SIGILL = 1
136
ECL_OPT_TRAP_SIGBUS = 1
137
ECL_OPT_TRAP_SIGCHLD = 0
138
ECL_OPT_TRAP_SIGPIPE = 1
139
ECL_OPT_TRAP_INTERRUPT_SIGNAL = 1
140
ECL_OPT_SIGNAL_HANDLING_THREAD = 0
141
ECL_OPT_SIGNAL_QUEUE_SIZE = 16
142
ECL_OPT_BOOTED = 1
143
ECL_OPT_BIND_STACK_SIZE = ...
144
ECL_OPT_BIND_STACK_SAFETY_AREA = ...
145
ECL_OPT_FRAME_STACK_SIZE = ...
146
ECL_OPT_FRAME_STACK_SAFETY_AREA = ...
147
ECL_OPT_LISP_STACK_SIZE = ...
148
ECL_OPT_LISP_STACK_SAFETY_AREA = ...
149
ECL_OPT_C_STACK_SIZE = ...
150
ECL_OPT_C_STACK_SAFETY_AREA = ...
151
ECL_OPT_SIGALTSTACK_SIZE = 1
152
ECL_OPT_HEAP_SIZE = ...
153
ECL_OPT_HEAP_SAFETY_AREA = ...
154
ECL_OPT_THREAD_INTERRUPT_SIGNAL = 0
155
ECL_OPT_SET_GMP_MEMORY_FUNCTIONS = 0
156
"""
157
print('ECL_OPT_INCREMENTAL_GC = {0}'.format(
158
ecl_get_option(ECL_OPT_INCREMENTAL_GC)))
159
print('ECL_OPT_TRAP_SIGSEGV = {0}'.format(
160
ecl_get_option(ECL_OPT_TRAP_SIGSEGV)))
161
print('ECL_OPT_TRAP_SIGFPE = {0}'.format(
162
ecl_get_option(ECL_OPT_TRAP_SIGFPE)))
163
print('ECL_OPT_TRAP_SIGINT = {0}'.format(
164
ecl_get_option(ECL_OPT_TRAP_SIGINT)))
165
print('ECL_OPT_TRAP_SIGILL = {0}'.format(
166
ecl_get_option(ECL_OPT_TRAP_SIGILL)))
167
print('ECL_OPT_TRAP_SIGBUS = {0}'.format(
168
ecl_get_option(ECL_OPT_TRAP_SIGBUS)))
169
print('ECL_OPT_TRAP_SIGCHLD = {0}'.format(
170
ecl_get_option(ECL_OPT_TRAP_SIGCHLD)))
171
print('ECL_OPT_TRAP_SIGPIPE = {0}'.format(
172
ecl_get_option(ECL_OPT_TRAP_SIGPIPE)))
173
print('ECL_OPT_TRAP_INTERRUPT_SIGNAL = {0}'.format(
174
ecl_get_option(ECL_OPT_TRAP_INTERRUPT_SIGNAL)))
175
print('ECL_OPT_SIGNAL_HANDLING_THREAD = {0}'.format(
176
ecl_get_option(ECL_OPT_SIGNAL_HANDLING_THREAD)))
177
print('ECL_OPT_SIGNAL_QUEUE_SIZE = {0}'.format(
178
ecl_get_option(ECL_OPT_SIGNAL_QUEUE_SIZE)))
179
print('ECL_OPT_BOOTED = {0}'.format(
180
ecl_get_option(ECL_OPT_BOOTED)))
181
print('ECL_OPT_BIND_STACK_SIZE = {0}'.format(
182
ecl_get_option(ECL_OPT_BIND_STACK_SIZE)))
183
print('ECL_OPT_BIND_STACK_SAFETY_AREA = {0}'.format(
184
ecl_get_option(ECL_OPT_BIND_STACK_SAFETY_AREA)))
185
print('ECL_OPT_FRAME_STACK_SIZE = {0}'.format(
186
ecl_get_option(ECL_OPT_FRAME_STACK_SIZE)))
187
print('ECL_OPT_FRAME_STACK_SAFETY_AREA = {0}'.format(
188
ecl_get_option(ECL_OPT_FRAME_STACK_SAFETY_AREA)))
189
print('ECL_OPT_LISP_STACK_SIZE = {0}'.format(
190
ecl_get_option(ECL_OPT_LISP_STACK_SIZE)))
191
print('ECL_OPT_LISP_STACK_SAFETY_AREA = {0}'.format(
192
ecl_get_option(ECL_OPT_LISP_STACK_SAFETY_AREA)))
193
print('ECL_OPT_C_STACK_SIZE = {0}'.format(
194
ecl_get_option(ECL_OPT_C_STACK_SIZE)))
195
print('ECL_OPT_C_STACK_SAFETY_AREA = {0}'.format(
196
ecl_get_option(ECL_OPT_C_STACK_SAFETY_AREA)))
197
print('ECL_OPT_SIGALTSTACK_SIZE = {0}'.format(
198
ecl_get_option(ECL_OPT_SIGALTSTACK_SIZE)))
199
print('ECL_OPT_HEAP_SIZE = {0}'.format(
200
ecl_get_option(ECL_OPT_HEAP_SIZE)))
201
print('ECL_OPT_HEAP_SAFETY_AREA = {0}'.format(
202
ecl_get_option(ECL_OPT_HEAP_SAFETY_AREA)))
203
print('ECL_OPT_THREAD_INTERRUPT_SIGNAL = {0}'.format(
204
ecl_get_option(ECL_OPT_THREAD_INTERRUPT_SIGNAL)))
205
print('ECL_OPT_SET_GMP_MEMORY_FUNCTIONS = {0}'.format(
206
ecl_get_option(ECL_OPT_SET_GMP_MEMORY_FUNCTIONS)))
207
208
def init_ecl():
209
r"""
210
Internal function to initialize ecl. Do not call.
211
212
This function initializes the ECL library for use within Python.
213
This routine should only be called once and importing the ecl library
214
interface already does that, so do not call this yourself.
215
216
EXAMPLES::
217
218
sage: from sage.libs.ecl import *
219
220
At this point, init_ecl() has run. Explicitly executing it
221
gives an error::
222
223
sage: init_ecl()
224
Traceback (most recent call last):
225
...
226
RuntimeError: ECL is already initialized
227
"""
228
global list_of_objects
229
global safe_eval_clobj
230
global safe_apply_clobj
231
global safe_funcall_clobj
232
global read_from_string_clobj
233
global ecl_has_booted
234
cdef char *argv[1]
235
cdef Sigaction sage_action[32]
236
cdef int i
237
238
if ecl_has_booted:
239
raise RuntimeError, "ECL is already initialized"
240
241
# we need it to stop handling SIGCHLD
242
ecl_set_option(ECL_OPT_TRAP_SIGCHLD, 0);
243
244
#we keep our own GMP memory functions. ECL should not claim them
245
ecl_set_option(ECL_OPT_SET_GMP_MEMORY_FUNCTIONS,0);
246
247
#we need a dummy argv for cl_boot (we just don't give any parameters)
248
argv[0]="sage"
249
250
#get all the signal handlers before initializing Sage so we can
251
#put them back afterwards.
252
for i in range(1,32):
253
sigaction(i, NULL, &sage_action[i])
254
255
#initialize ECL
256
ecl_set_option(ECL_OPT_SIGNAL_HANDLING_THREAD, 0)
257
cl_boot(1, argv)
258
259
#save signal handler from ECL
260
sigaction(SIGINT, NULL, &ecl_sigint_handler)
261
sigaction(SIGBUS, NULL, &ecl_sigbus_handler)
262
sigaction(SIGSEGV, NULL, &ecl_sigsegv_handler)
263
264
#verify that no SIGCHLD handler was installed
265
cdef Sigaction sig_test
266
sigaction(SIGCHLD, NULL, &sig_test)
267
assert sage_action[SIGCHLD].sa_handler == NULL # Sage does not set SIGCHLD handler
268
assert sig_test.sa_handler == NULL # And ECL bootup did not set one
269
270
#and put the Sage signal handlers back
271
for i in range(1,32):
272
sigaction(i, &sage_action[i], NULL)
273
274
#initialise list of objects and bind to global variable
275
# *SAGE-LIST-OF-OBJECTS* to make it rooted in the reachable tree for the GC
276
list_of_objects=cl_cons(Cnil,cl_cons(Cnil,Cnil))
277
cl_set(string_to_object("*SAGE-LIST-OF-OBJECTS*"),list_of_objects)
278
279
# We define our own error catching eval, apply and funcall/
280
# Presently these routines are only converted to byte-code. If they
281
# ever turn out to be a bottle neck, it should be easy to properly
282
# compile them.
283
284
read_from_string_clobj=cl_eval(string_to_object("(symbol-function 'read-from-string)"))
285
286
cl_eval(string_to_object("""
287
(defun sage-safe-eval (form)
288
(handler-case
289
(values (eval form))
290
(serious-condition (cnd)
291
(values nil (princ-to-string cnd)))))
292
"""))
293
safe_eval_clobj=cl_eval(string_to_object("(symbol-function 'sage-safe-eval)"))
294
295
cl_eval(string_to_object("""
296
(defun sage-safe-apply (func args)
297
(handler-case
298
(values (apply func args))
299
(serious-condition (cnd)
300
(values nil (princ-to-string cnd)))))
301
"""))
302
303
safe_apply_clobj=cl_eval(string_to_object("(symbol-function 'sage-safe-apply)"))
304
cl_eval(string_to_object("""
305
(defun sage-safe-funcall (func arg)
306
(handler-case
307
(values (funcall func arg))
308
(serious-condition (cnd)
309
(values nil (princ-to-string cnd)))))
310
"""))
311
safe_funcall_clobj=cl_eval(string_to_object("(symbol-function 'sage-safe-funcall)"))
312
313
ecl_has_booted = 1
314
315
cdef cl_object ecl_safe_eval(cl_object form) except NULL:
316
"""
317
TESTS:
318
319
Test interrupts::
320
321
sage: from sage.libs.ecl import *
322
sage: from sage.tests.interrupt import *
323
sage: ecl_eval("(setf i 0)")
324
<ECL: 0>
325
sage: inf_loop=ecl_eval("(defun infinite() (loop (incf i)))")
326
sage: interrupt_after_delay(1000)
327
sage: inf_loop()
328
Traceback (most recent call last):
329
...
330
RuntimeError: ECL says: Console interrupt.
331
"""
332
ecl_sig_on()
333
cl_funcall(2,safe_eval_clobj,form)
334
ecl_sig_off()
335
336
if ecl_nvalues > 1:
337
raise RuntimeError, "ECL says: "+ecl_base_string_pointer_safe(ecl_values(1))
338
else:
339
return ecl_values(0)
340
341
cdef cl_object ecl_safe_funcall(cl_object func, cl_object arg) except NULL:
342
cdef cl_object l
343
l = cl_cons(func,cl_cons(arg,Cnil));
344
345
ecl_sig_on()
346
cl_apply(2,safe_funcall_clobj,cl_cons(func,cl_cons(arg,Cnil)))
347
ecl_sig_off()
348
349
if ecl_nvalues > 1:
350
raise RuntimeError, "ECL says: "+ecl_base_string_pointer_safe(ecl_values(1))
351
else:
352
return ecl_values(0)
353
354
cdef cl_object ecl_safe_apply(cl_object func, cl_object args) except NULL:
355
ecl_sig_on()
356
cl_funcall(3,safe_apply_clobj,func,args)
357
ecl_sig_off()
358
359
if ecl_nvalues > 1:
360
raise RuntimeError, "ECL says: "+ecl_base_string_pointer_safe(ecl_values(1))
361
else:
362
return ecl_values(0)
363
364
cdef cl_object ecl_safe_read_string(char * s) except NULL:
365
cdef cl_object o
366
o = ecl_cstring_to_base_string_or_nil(s)
367
o = ecl_safe_funcall(read_from_string_clobj,o)
368
return o
369
370
def shutdown_ecl():
371
r"""
372
Shut down ecl. Do not call.
373
374
Given the way that ECL is used from python, it is very difficult to ensure
375
that no ECL objects exist at a particular time. Hence, destroying ECL is a
376
risky proposition.
377
378
EXAMPLE::
379
380
sage: from sage.libs.ecl import *
381
sage: shutdown_ecl()
382
"""
383
cl_shutdown()
384
385
#this prints the objects that sage wants the GC to keep track of.
386
#these should be all non-immediate EclObject wrapped objects
387
def print_objects():
388
r"""
389
Print GC-protection list
390
391
Diagnostic function. ECL objects that are bound to Python objects need to
392
be protected from being garbage collected. We do this by including them
393
in a doubly linked list bound to the global ECL symbol
394
*SAGE-LIST-OF-OBJECTS*. Only non-immediate values get included, so
395
small integers do not get linked in. This routine prints the values
396
currently stored.
397
398
EXAMPLE::
399
400
sage: from sage.libs.ecl import *
401
sage: a=EclObject("hello")
402
sage: b=EclObject(10)
403
sage: c=EclObject("world")
404
sage: print_objects() #random because previous test runs can have left objects
405
NIL
406
WORLD
407
HELLO
408
"""
409
410
cdef cl_object c
411
c = list_of_objects
412
while True:
413
print ecl_base_string_pointer_safe(cl_write_to_string(1,cl_car(c)))
414
c=cl_cadr(c)
415
if c == Cnil:
416
break
417
418
cdef cl_object python_to_ecl(pyobj) except NULL:
419
# conversion of a python object into an ecl object
420
# most conversions are straightforward. Noteworthy are:
421
# python lists -> lisp (NIL terminated) lists
422
# tuples -> dotted lists
423
# strings ->parsed by lisp reader
424
425
cdef bytes s
426
cdef cl_object L, ptr
427
428
if isinstance(pyobj,bool):
429
if pyobj:
430
return Ct
431
else:
432
return Cnil
433
elif pyobj is None:
434
return Cnil
435
elif isinstance(pyobj,int):
436
return ecl_make_integer(pyobj)
437
elif isinstance(pyobj,long):
438
if pyobj >= MOST_NEGATIVE_FIXNUM and pyobj <= MOST_POSITIVE_FIXNUM:
439
return ecl_make_integer(pyobj)
440
else:
441
return python_to_ecl(Integer(pyobj))
442
elif isinstance(pyobj,float):
443
return ecl_make_doublefloat(pyobj)
444
elif isinstance(pyobj,unicode):
445
s=<bytes>(str(pyobj))
446
return ecl_safe_read_string(s)
447
elif isinstance(pyobj,bytes):
448
s=<bytes>pyobj
449
return ecl_safe_read_string(s)
450
elif isinstance(pyobj,Integer):
451
if pyobj >= MOST_NEGATIVE_FIXNUM and pyobj <= MOST_POSITIVE_FIXNUM:
452
return ecl_make_integer(pyobj)
453
else:
454
return ecl_bignum_from_mpz( (<Integer>pyobj).get_value() )
455
elif isinstance(pyobj,Rational):
456
return ecl_make_ratio(
457
python_to_ecl( (<Rational>pyobj).numerator() ),
458
python_to_ecl( (<Rational>pyobj).denominator()))
459
elif isinstance(pyobj,EclObject):
460
return (<EclObject>pyobj).obj
461
elif isinstance(pyobj,list):
462
if len(pyobj) == 0:
463
return Cnil
464
else:
465
L=cl_cons(python_to_ecl(pyobj[0]),Cnil)
466
ptr=L
467
for a in pyobj[1:]:
468
cl_rplacd(ptr,cl_cons(python_to_ecl(a),Cnil))
469
ptr=cl_cdr(ptr)
470
return L
471
elif isinstance(pyobj,tuple):
472
if len(pyobj) == 0:
473
return Cnil
474
elif len(pyobj) == 1:
475
return python_to_ecl(pyobj[0])
476
else:
477
L=cl_cons(python_to_ecl(pyobj[0]),Cnil)
478
ptr=L
479
for a in pyobj[1:-1]:
480
cl_rplacd(ptr,cl_cons(python_to_ecl(a),Cnil))
481
ptr=cl_cdr(ptr)
482
cl_rplacd(ptr,python_to_ecl(pyobj[-1]))
483
return L
484
else:
485
raise TypeError,"Unimplemented type for python_to_ecl"
486
487
cdef ecl_to_python(cl_object o):
488
cdef Integer N
489
# conversions from an ecl object to a python object.
490
491
if o == Cnil:
492
return None
493
elif bint_fixnump(o):
494
#SAGE specific conversion
495
#return ecl_fixint(o)
496
return Integer(ecl_fixint(o))
497
elif bint_integerp(o):
498
#SAGE specific conversion
499
N = Integer.__new__(Integer)
500
N.set_from_mpz(ecl_mpz_from_bignum(o))
501
return N
502
elif bint_rationalp(o):
503
#SAGE specific conversion
504
#vanilla python does not have a class to represent rational numbers
505
return Rational((ecl_to_python(cl_numerator(o)),ecl_to_python(cl_denominator(o))))
506
elif bint_floatp(o):
507
#Python conversion
508
#Since SAGE mainly uses mpfr, perhaps "double is not an appropriate return type
509
return ecl_to_double(o)
510
elif o == Ct:
511
return True
512
elif bint_consp(o):
513
L=[]
514
while o != Cnil:
515
L.append(ecl_to_python(cl_car(o)))
516
o = cl_cdr(o)
517
if not(bint_listp(o)):
518
L.append(ecl_to_python(o))
519
return tuple(L)
520
return L
521
else:
522
return ecl_base_string_pointer_safe(cl_write_to_string(1,o))
523
524
#Maxima's BFLOAT multiprecision float type can be read with:
525
#def bfloat_to_python(e):
526
# prec=Integer(str(e.car().cddr().car()))
527
# mant=Integer(str(e.cdr().car()))
528
# exp=Integer(str(e.cddr().car()))
529
# return 2^(exp-prec)*mant
530
531
cdef class EclObject:
532
r"""
533
Python wrapper of ECL objects
534
535
The ``EclObject`` forms a wrapper around ECL objects. The wrapper ensures
536
that the data structure pointed to is protected from garbage collection in
537
ECL by installing a pointer to it from a global data structure within the
538
scope of the ECL garbage collector. This pointer is destroyed upon
539
destruction of the EclObject.
540
541
EclObject() takes a Python object and tries to find a representation of it
542
in Lisp.
543
544
EXAMPLES:
545
546
Python lists get mapped to LISP lists. None and Boolean values to
547
appropriate values in LISP::
548
549
sage: from sage.libs.ecl import *
550
sage: EclObject([None,true,false])
551
<ECL: (NIL T NIL)>
552
553
Numerical values are translated to the appropriate type in LISP::
554
555
sage: EclObject(1)
556
<ECL: 1>
557
sage: EclObject(10**40)
558
<ECL: 10000000000000000000000000000000000000000>
559
560
Floats in Python are IEEE double, which LISP has as well. However,
561
the printing of floating point types in LISP depends on settings::
562
563
sage: a = EclObject(float(10**40))
564
sage: ecl_eval("(setf *read-default-float-format* 'single-float)")
565
<ECL: SINGLE-FLOAT>
566
sage: a
567
<ECL: 9.999999999999999d39>
568
sage: ecl_eval("(setf *read-default-float-format* 'double-float)")
569
<ECL: DOUBLE-FLOAT>
570
sage: a
571
<ECL: 9.999999999999999e39>
572
573
Tuples are translated to dotted lists::
574
575
sage: EclObject( (false, true))
576
<ECL: (NIL . T)>
577
578
Strings are fed to the reader, so a string normally results in a symbol::
579
580
sage: EclObject("Symbol")
581
<ECL: SYMBOL>
582
583
But with proper quotation one can construct a lisp string object too::
584
585
sage: EclObject('"Symbol"')
586
<ECL: "Symbol">
587
588
EclObjects translate to themselves, so one can mix::
589
590
sage: EclObject([1,2,EclObject([3])])
591
<ECL: (1 2 (3))>
592
593
Calling an EclObject translates into the appropriate LISP ``apply'',
594
where the argument is transformed into an EclObject itself, so one can
595
flexibly apply LISP functions::
596
597
sage: car=EclObject("car")
598
sage: cdr=EclObject("cdr")
599
sage: car(cdr([1,2,3]))
600
<ECL: 2>
601
602
and even construct and evaluate arbitrary S-expressions::
603
604
sage: eval=EclObject("eval")
605
sage: quote=EclObject("quote")
606
sage: eval([car, [cdr, [quote,[1,2,3]]]])
607
<ECL: 2>
608
609
TESTS:
610
611
We check that multiprecision integers are converted correctly::
612
613
sage: i = 10 ^ (10 ^ 5)
614
sage: EclObject(i) == EclObject(str(i))
615
True
616
sage: EclObject(-i) == EclObject(str(-i))
617
True
618
sage: EclObject(i).python() == i
619
True
620
sage: EclObject(-i).python() == -i
621
True
622
"""
623
cdef cl_object obj #the wrapped object
624
cdef cl_object node #linked list pointer: car(node) == obj
625
626
cdef void set_obj(EclObject self, cl_object o):
627
if self.node:
628
remove_node(self.node)
629
self.node=NULL
630
self.obj=o
631
if not(bint_fixnump(o) or bint_characterp(o) or bint_nullp(o)):
632
self.node=insert_node_after(list_of_objects,o)
633
634
def __init__(self,*args):
635
r"""
636
Create an EclObject
637
638
See EclObject for full documentation.
639
640
EXAMPLES::
641
642
sage: from sage.libs.ecl import *
643
sage: EclObject([None,true,false])
644
<ECL: (NIL T NIL)>
645
646
"""
647
if len(args) != 0:
648
self.set_obj(python_to_ecl(args[0]))
649
650
def __reduce__(self):
651
r"""
652
This is used for pickling. Not implemented
653
654
Ecl does not natively support serialization of its objects, so the
655
python wrapper class EclObject does not support pickling. There are
656
independent efforts for developing serialization for Common Lisp, such as
657
CL-STORE. Look at those if you need serialization of ECL objects.
658
659
EXAMPLES::
660
661
sage: from sage.libs.ecl import *
662
sage: s=EclObject([1,2,3])
663
sage: s.__reduce__()
664
Traceback (most recent call last):
665
...
666
NotImplementedError: EclObjects do not have a pickling method
667
sage: s==loads(dumps(s))
668
Traceback (most recent call last):
669
...
670
NotImplementedError: EclObjects do not have a pickling method
671
"""
672
raise NotImplementedError, "EclObjects do not have a pickling method"
673
674
def python(self):
675
r"""
676
Convert an EclObject to a python object.
677
678
EXAMPLES::
679
680
sage: from sage.libs.ecl import *
681
sage: L=EclObject([1,2,("three",'"four"')])
682
sage: L.python()
683
[1, 2, ('THREE', '"four"')]
684
685
"""
686
return ecl_to_python(self.obj)
687
688
def __dealloc__(self):
689
r"""
690
Deallocate EclObject
691
692
It is important to remove the GC preventing reference to the object upon
693
deletion of the wrapper.
694
695
EXAMPLES::
696
697
sage: from sage.libs.ecl import *
698
sage: L=EclObject("symbol")
699
sage: del L
700
701
"""
702
if self.node:
703
remove_node(self.node)
704
705
def __repr__(self):
706
r"""
707
Produce a string representation suitable for interactive printing.
708
709
Converts the wrapped LISP object to a string, decorated in such a way that
710
it can be recognised as a LISP object.
711
712
EXAMPLES::
713
714
sage: from sage.libs.ecl import *
715
sage: L=EclObject("symbol")
716
sage: repr(L)
717
'<ECL: SYMBOL>'
718
719
"""
720
return "<ECL: "+str(self)+">"
721
722
def __str__(self):
723
r"""
724
Produce a string representation.
725
726
Converts the wrapped LISP object to a string and returns that as a Python
727
string.
728
729
EXAMPLES::
730
731
sage: from sage.libs.ecl import *
732
sage: L=EclObject("symbol")
733
sage: str(L)
734
'SYMBOL'
735
736
"""
737
cdef cl_object s
738
s = cl_write_to_string(1,self.obj)
739
return ecl_base_string_pointer_safe(s)
740
741
def __hash__(self):
742
r"""
743
Return a hash value of the object
744
745
Returns the hash value returned by SXHASH, which is a routine that is
746
specified in Common Lisp. According to the specification, lisp objects that
747
are EQUAL have the same SXHASH value. Since two EclObjects are equal if
748
their wrapped objects are EQUAL according to lisp, this is compatible with
749
Python's concept of hash values.
750
751
It is not possible to enforce immutability of lisp objects, so care should
752
be taken in using EclObjects as dictionary keys.
753
754
EXAMPLES::
755
756
sage: from sage.libs.ecl import *
757
sage: L=EclObject([1,2])
758
sage: L
759
<ECL: (1 2)>
760
sage: hash(L) #random
761
463816586
762
sage: L.rplacd(EclObject(3))
763
sage: L
764
<ECL: (1 . 3)>
765
sage: hash(L) #random
766
140404060
767
768
"""
769
return ecl_fixint(cl_sxhash(self.obj))
770
771
def __call__(self, *args):
772
r"""
773
Apply self to arguments.
774
775
EXAMPLES::
776
777
sage: from sage.libs.ecl import *
778
sage: sqr=EclObject("(lambda (x) (* x x))").eval()
779
sage: sqr(10)
780
<ECL: 100>
781
782
"""
783
lispargs = EclObject(list(args))
784
return ecl_wrap(ecl_safe_apply(self.obj,(<EclObject>lispargs).obj))
785
786
def __richcmp__(left, right, int op):
787
r"""
788
Comparison test.
789
790
An EclObject is not equal to any non-EclObject. Two EclObjects are equal
791
if their wrapped lisp objects are EQUAL. Since LISP has no univeral ordering,
792
less than and greater than tests are not implemented for EclObjects.
793
794
EXAMPLES::
795
796
sage: from sage.libs.ecl import *
797
sage: a=EclObject(1)
798
sage: b=EclObject(2)
799
sage: a==b
800
False
801
sage: a<b
802
Traceback (most recent call last):
803
...
804
NotImplementedError: EclObjects can only be compared for equality
805
sage: EclObject("<")(a,b)
806
<ECL: T>
807
"""
808
if op == 2: # "=="
809
if not(isinstance(left,EclObject)) or not(isinstance(right,EclObject)):
810
return False
811
else:
812
return bint_equal((<EclObject>left).obj,(<EclObject>right).obj)
813
elif op == 3: # "!="
814
if not(isinstance(left,EclObject)) or not(isinstance(right,EclObject)):
815
return True
816
else:
817
return not(bint_equal((<EclObject>left).obj,(<EclObject>right).obj))
818
819
#Common lisp only seems to be able to compare numeric and string types
820
#and does not have generic routines for doing that.
821
#we could dispatch based on type here, but that seems
822
#inappropriate for an *interface*.
823
raise NotImplementedError,"EclObjects can only be compared for equality"
824
825
#if not(isinstance(left,EclObject)) or not(isinstance(right,EclObject)):
826
# raise TypeError,"Can only compare EclObjects"
827
#if op == 0: # "<"
828
# pass
829
#elif op == 1: # "<="
830
# pass
831
#elif op == 4: # ">"
832
# pass
833
#elif op == 5: # ">="
834
# pass
835
#else:
836
# raise ValueError,"richcmp received operation code %d"%op
837
838
def __iter__(self):
839
r"""
840
Implements the iterator protocol for EclObject.
841
842
EclObject implements the iterator protocol for lists. This means
843
one can use an EclObject in the context where an iterator is
844
expected (for instance, in a list comprehension or in a for loop).
845
The iterator produces EclObjects wrapping the members of the list that
846
the original EclObject wraps.
847
848
The wrappers returned are all newly constructed but refer to the
849
original members of the list iterated over. This is usually what is
850
intended but, just as in Python, can cause surprises if the original
851
object is changed between calls to the iterator.
852
853
Since EclObject translates Python Lists into LISP lists and Python
854
tuples into LISP "dotted" lists (lists for which the final CDR is not
855
necessarily NIL), and both these python structures are iterable, the
856
corresponding EclObjects are iterable as well.
857
858
EclObjects that are not lists are not iterable.
859
860
EXAMPLES::
861
862
sage: from sage.libs.ecl import *
863
sage: [i for i in EclObject("(1 2 3)")]
864
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
865
sage: [i for i in EclObject("(1 2 . 3)")]
866
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
867
sage: [i for i in EclObject("NIL")]
868
[]
869
870
TESTS:
871
872
These show that Python lists and tuples behave as
873
described above::
874
875
sage: [i for i in EclObject([1,2,3])]
876
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
877
sage: [i for i in EclObject((1,2,3))]
878
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
879
880
This tests that we cannot iterate EclObjects we shouldn't,
881
as described above::
882
883
sage: [i for i in EclObject("T")]
884
Traceback (most recent call last):
885
...
886
TypeError: ECL object is not iterable
887
888
"""
889
return EclListIterator(self)
890
891
def eval(self):
892
r"""
893
Evaluate object as an S-Expression
894
895
EXAMPLES::
896
897
sage: from sage.libs.ecl import *
898
sage: S=EclObject("(+ 1 2)")
899
sage: S
900
<ECL: (+ 1 2)>
901
sage: S.eval()
902
<ECL: 3>
903
904
"""
905
cdef cl_object o
906
o=ecl_safe_eval(self.obj)
907
if o == NULL:
908
raise RuntimeError,"ECL runtime error"
909
return ecl_wrap(o)
910
911
def cons(self,EclObject d):
912
r"""
913
apply cons to self and argument and return the result.
914
915
EXAMPLES::
916
917
sage: from sage.libs.ecl import *
918
sage: a=EclObject(1)
919
sage: b=EclObject(2)
920
sage: a.cons(b)
921
<ECL: (1 . 2)>
922
923
"""
924
return ecl_wrap(cl_cons(self.obj,d.obj))
925
926
def rplaca(self,EclObject d):
927
r"""
928
Destructively replace car(self) with d.
929
930
EXAMPLES::
931
932
sage: from sage.libs.ecl import *
933
sage: L=EclObject((1,2))
934
sage: L
935
<ECL: (1 . 2)>
936
sage: a=EclObject(3)
937
sage: L.rplaca(a)
938
sage: L
939
<ECL: (3 . 2)>
940
941
"""
942
if not(bint_consp(self.obj)):
943
raise TypeError,"rplaca can only be applied to a cons"
944
cl_rplaca(self.obj, d.obj)
945
946
947
def rplacd(self,EclObject d):
948
r"""
949
Destructively replace cdr(self) with d.
950
951
EXAMPLES::
952
953
sage: from sage.libs.ecl import *
954
sage: L=EclObject((1,2))
955
sage: L
956
<ECL: (1 . 2)>
957
sage: a=EclObject(3)
958
sage: L.rplacd(a)
959
sage: L
960
<ECL: (1 . 3)>
961
962
"""
963
if not(bint_consp(self.obj)):
964
raise TypeError,"rplacd can only be applied to a cons"
965
cl_rplacd(self.obj, d.obj)
966
967
def car(self):
968
r"""
969
Return the car of self
970
971
EXAMPLES::
972
973
sage: from sage.libs.ecl import *
974
sage: L=EclObject([[1,2],[3,4]])
975
sage: L.car()
976
<ECL: (1 2)>
977
sage: L.cdr()
978
<ECL: ((3 4))>
979
sage: L.caar()
980
<ECL: 1>
981
sage: L.cadr()
982
<ECL: (3 4)>
983
sage: L.cdar()
984
<ECL: (2)>
985
sage: L.cddr()
986
<ECL: NIL>
987
"""
988
if not(bint_consp(self.obj)):
989
raise TypeError,"car can only be applied to a cons"
990
return ecl_wrap(cl_car(self.obj))
991
992
def cdr(self):
993
r"""
994
Return the cdr of self
995
996
EXAMPLES::
997
998
sage: from sage.libs.ecl import *
999
sage: L=EclObject([[1,2],[3,4]])
1000
sage: L.car()
1001
<ECL: (1 2)>
1002
sage: L.cdr()
1003
<ECL: ((3 4))>
1004
sage: L.caar()
1005
<ECL: 1>
1006
sage: L.cadr()
1007
<ECL: (3 4)>
1008
sage: L.cdar()
1009
<ECL: (2)>
1010
sage: L.cddr()
1011
<ECL: NIL>
1012
"""
1013
if not(bint_consp(self.obj)):
1014
raise TypeError,"cdr can only be applied to a cons"
1015
return ecl_wrap(cl_cdr(self.obj))
1016
1017
def caar(self):
1018
r"""
1019
Return the caar of self
1020
1021
EXAMPLES::
1022
1023
sage: from sage.libs.ecl import *
1024
sage: L=EclObject([[1,2],[3,4]])
1025
sage: L.car()
1026
<ECL: (1 2)>
1027
sage: L.cdr()
1028
<ECL: ((3 4))>
1029
sage: L.caar()
1030
<ECL: 1>
1031
sage: L.cadr()
1032
<ECL: (3 4)>
1033
sage: L.cdar()
1034
<ECL: (2)>
1035
sage: L.cddr()
1036
<ECL: NIL>
1037
"""
1038
if not(bint_consp(self.obj) and bint_consp(cl_car(self.obj))):
1039
raise TypeError,"caar can only be applied to a cons"
1040
return ecl_wrap(cl_caar(self.obj))
1041
1042
def cadr(self):
1043
r"""
1044
Return the cadr of self
1045
1046
EXAMPLES::
1047
1048
sage: from sage.libs.ecl import *
1049
sage: L=EclObject([[1,2],[3,4]])
1050
sage: L.car()
1051
<ECL: (1 2)>
1052
sage: L.cdr()
1053
<ECL: ((3 4))>
1054
sage: L.caar()
1055
<ECL: 1>
1056
sage: L.cadr()
1057
<ECL: (3 4)>
1058
sage: L.cdar()
1059
<ECL: (2)>
1060
sage: L.cddr()
1061
<ECL: NIL>
1062
"""
1063
if not(bint_consp(self.obj) and bint_consp(cl_cdr(self.obj))):
1064
raise TypeError,"cadr can only be applied to a cons"
1065
return ecl_wrap(cl_cadr(self.obj))
1066
1067
def cdar(self):
1068
r"""
1069
Return the cdar of self
1070
1071
EXAMPLES::
1072
1073
sage: from sage.libs.ecl import *
1074
sage: L=EclObject([[1,2],[3,4]])
1075
sage: L.car()
1076
<ECL: (1 2)>
1077
sage: L.cdr()
1078
<ECL: ((3 4))>
1079
sage: L.caar()
1080
<ECL: 1>
1081
sage: L.cadr()
1082
<ECL: (3 4)>
1083
sage: L.cdar()
1084
<ECL: (2)>
1085
sage: L.cddr()
1086
<ECL: NIL>
1087
"""
1088
if not(bint_consp(self.obj) and bint_consp(cl_car(self.obj))):
1089
raise TypeError,"cdar can only be applied to a cons"
1090
return ecl_wrap(cl_cdar(self.obj))
1091
1092
def cddr(self):
1093
r"""
1094
Return the cddr of self
1095
1096
EXAMPLES::
1097
1098
sage: from sage.libs.ecl import *
1099
sage: L=EclObject([[1,2],[3,4]])
1100
sage: L.car()
1101
<ECL: (1 2)>
1102
sage: L.cdr()
1103
<ECL: ((3 4))>
1104
sage: L.caar()
1105
<ECL: 1>
1106
sage: L.cadr()
1107
<ECL: (3 4)>
1108
sage: L.cdar()
1109
<ECL: (2)>
1110
sage: L.cddr()
1111
<ECL: NIL>
1112
"""
1113
if not(bint_consp(self.obj) and bint_consp(cl_cdr(self.obj))):
1114
raise TypeError,"cddr can only be applied to a cons"
1115
return ecl_wrap(cl_cddr(self.obj))
1116
1117
def fixnump(self):
1118
r"""
1119
Return True if self is a fixnum, False otherwise
1120
1121
EXAMPLES::
1122
1123
sage: from sage.libs.ecl import *
1124
sage: EclObject(2**3).fixnump()
1125
True
1126
sage: EclObject(2**200).fixnump()
1127
False
1128
1129
"""
1130
return bint_fixnump(self.obj)
1131
1132
def characterp(self):
1133
r"""
1134
Return True if self is a character, False otherwise
1135
1136
Strings are not characters
1137
1138
EXAMPLES:
1139
1140
sage: from sage.libs.ecl import *
1141
sage: EclObject('"a"').characterp()
1142
False
1143
1144
"""
1145
return bint_characterp(self.obj)
1146
1147
def nullp(self):
1148
r"""
1149
Return True if self is NIL, False otherwise
1150
1151
EXAMPLES::
1152
1153
sage: from sage.libs.ecl import *
1154
sage: EclObject([]).nullp()
1155
True
1156
sage: EclObject([[]]).nullp()
1157
False
1158
"""
1159
return bint_nullp(self.obj)
1160
1161
def listp(self):
1162
r"""
1163
Return True if self is a list, False otherwise. NIL is a list.
1164
1165
EXAMPLES::
1166
1167
sage: from sage.libs.ecl import *
1168
sage: EclObject([]).listp()
1169
True
1170
sage: EclObject([[]]).listp()
1171
True
1172
"""
1173
return bint_listp(self.obj)
1174
1175
def consp(self):
1176
r"""
1177
Return True if self is a cons, False otherwise. NIL is not a cons.
1178
1179
EXAMPLES::
1180
1181
sage: from sage.libs.ecl import *
1182
sage: EclObject([]).consp()
1183
False
1184
sage: EclObject([[]]).consp()
1185
True
1186
"""
1187
return bint_consp(self.obj)
1188
1189
def atomp(self):
1190
r"""
1191
Return True if self is atomic, False otherwise.
1192
1193
EXAMPLES::
1194
1195
sage: from sage.libs.ecl import *
1196
sage: EclObject([]).atomp()
1197
True
1198
sage: EclObject([[]]).atomp()
1199
False
1200
1201
"""
1202
return bint_atomp(self.obj)
1203
1204
def symbolp(self):
1205
r"""
1206
Return True if self is a symbol, False otherwise.
1207
1208
EXAMPLES::
1209
1210
sage: from sage.libs.ecl import *
1211
sage: EclObject([]).symbolp()
1212
True
1213
sage: EclObject([[]]).symbolp()
1214
False
1215
1216
"""
1217
return bint_symbolp(self.obj)
1218
1219
cdef class EclListIterator:
1220
r"""
1221
Iterator object for an ECL list
1222
1223
This class is used to implement the iterator protocol for EclObject.
1224
Do not instantiate this class directly but use the iterator method
1225
on an EclObject instead. It is an error if the EclObject is not a list.
1226
1227
EXAMPLES::
1228
1229
sage: from sage.libs.ecl import *
1230
sage: I=EclListIterator(EclObject("(1 2 3)"))
1231
sage: type(I)
1232
<type 'sage.libs.ecl.EclListIterator'>
1233
sage: [i for i in I]
1234
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
1235
sage: [i for i in EclObject("(1 2 3)")]
1236
[<ECL: 1>, <ECL: 2>, <ECL: 3>]
1237
sage: EclListIterator(EclObject("1"))
1238
Traceback (most recent call last):
1239
...
1240
TypeError: ECL object is not iterable
1241
1242
"""
1243
cdef EclObject current
1244
1245
def __init__(EclListIterator self, EclObject o):
1246
r"""
1247
Initialize EclListIterator
1248
1249
EXAMPLES::
1250
1251
sage: from sage.libs.ecl import *
1252
sage: I=EclListIterator(EclObject("(1 2 3)"))
1253
sage: type(I)
1254
<type 'sage.libs.ecl.EclListIterator'>
1255
1256
"""
1257
if not o.listp():
1258
raise TypeError,"ECL object is not iterable"
1259
self.current = ecl_wrap(o.obj)
1260
1261
def __iter__(EclListIterator self):
1262
r"""
1263
Return self
1264
1265
It seems standard that iterators return themselves if asked to produce
1266
an iterator.
1267
1268
EXAMPLES::
1269
1270
sage: from sage.libs.ecl import *
1271
sage: I=EclListIterator(EclObject("(1 2 3)"))
1272
sage: id(I) == id(I.__iter__())
1273
True
1274
1275
"""
1276
return self
1277
1278
def __next__(EclListIterator self):
1279
r"""
1280
Get next element from iterator
1281
1282
EXAMPLES::
1283
1284
sage: from sage.libs.ecl import *
1285
sage: I=EclListIterator(EclObject("(1 2 3)"))
1286
sage: I.next()
1287
<ECL: 1>
1288
sage: I.next()
1289
<ECL: 2>
1290
sage: I.next()
1291
<ECL: 3>
1292
sage: I.next()
1293
Traceback (most recent call last):
1294
...
1295
StopIteration
1296
1297
"""
1298
1299
if self.current.nullp():
1300
raise StopIteration
1301
elif self.current.consp():
1302
r = self.current.car()
1303
self.current = self.current.cdr()
1304
else:
1305
r = self.current
1306
self.current = ecl_wrap(Cnil)
1307
return r
1308
1309
#input: a cl-object. Output: EclObject wrapping that.
1310
cdef EclObject ecl_wrap(cl_object o):
1311
cdef EclObject obj = EclObject.__new__(EclObject)
1312
obj.set_obj(o)
1313
return obj
1314
1315
#convenience routine to more easily evaluate strings
1316
cpdef EclObject ecl_eval(bytes s):
1317
"""
1318
Read and evaluate string in Lisp and return the result
1319
1320
EXAMPLES::
1321
1322
sage: from sage.libs.ecl import *
1323
sage: ecl_eval("(defun fibo (n)(cond((= n 0) 0)((= n 1) 1)(T (+ (fibo (- n 1)) (fibo (- n 2))))))")
1324
<ECL: FIBO>
1325
sage: ecl_eval("(mapcar 'fibo '(1 2 3 4 5 6 7))")
1326
<ECL: (1 1 2 3 5 8 13)>
1327
1328
"""
1329
cdef cl_object o
1330
o=ecl_safe_read_string(s)
1331
o=ecl_safe_eval(o)
1332
return ecl_wrap(o)
1333
1334
init_ecl()
1335
1336