Coverage for local/lib/python2.7/site-packages/sage/libs/ecl.pyx : 77%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Library interface to Embeddable Common Lisp (ECL) """ #***************************************************************************** # Copyright (C) 2009 Nils Bruin <nbruin@sfu.ca> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function, absolute_import
#This version of the library interface prefers to convert ECL integers and #rationals to SAGE types Integer and Rational. These parts could easily be #adapted to work with pure Python types.
from libc.stdlib cimport abort from libc.signal cimport SIGINT, SIGBUS, SIGSEGV, SIGCHLD from libc.signal cimport raise_ as signal_raise from posix.signal cimport sigaction, sigaction_t cimport cysignals.signals
from sage.libs.gmp.types cimport mpz_t from sage.cpython.string cimport str_to_bytes, char_to_str from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from cpython.object cimport Py_EQ, Py_NE
#it would be preferrable to let bint_symbolp wrap an efficient macro #but the macro provided in object.h doesn't seem to work cdef bint bint_symbolp(cl_object obj):
#these type predicates are only provided in "cl_*" form, so we wrap them #with the proper type cast.
cdef bint bint_numberp(cl_object obj): cdef bint bint_integerp(cl_object obj): cdef bint bint_rationalp(cl_object obj):
cdef extern from "eclsig.h": int ecl_sig_on() except 0 void ecl_sig_off() cdef sigaction_t ecl_sigint_handler cdef sigaction_t ecl_sigbus_handler cdef sigaction_t ecl_sigsegv_handler cdef mpz_t ecl_mpz_from_bignum(cl_object obj) cdef cl_object ecl_bignum_from_mpz(mpz_t num)
cdef cl_object string_to_object(char * s):
# We need to keep a list of objects bound to python, to protect them from being # garbage collected. We want a list in which we can quickly add and remove # elements. Lookup is not necessary. A doubly linked list seems # most appropriate. A node looks like # N = ( value next . prev) # so that car(N)=value, cadr(N)=next, cddr(N)=prev. # we write routines to insert a node after a given node # and to delete a given node. This can all be done with modifying pointers. # note that circular structures are unpleasant for most lisp routines. # perhaps this even puts a strain on the garbage collector? # an alternative data structure would be an array where the free nodes get # chained in a "free list" for quick allocation (and if the free list is empty # upon allocating a node, the array needs to be extended)
cdef cl_object insert_node_after(cl_object node,cl_object value): cdef cl_object next,newnode
cdef void remove_node(cl_object node): cdef cl_object next, prev
# our global list of pointers. This will be a pointer to a sentinel node, # after which all new nodes can be inserted. list_of_object gets initialised # by init_ecl() and bound to the global ECL variable *SAGE-LIST-OF-OBJECTS*
cdef cl_object list_of_objects
cdef cl_object safe_eval_clobj #our own error catching eval cdef cl_object safe_apply_clobj #our own error catching apply cdef cl_object safe_funcall_clobj #our own error catching funcall cdef cl_object read_from_string_clobj #our own error catching reader
# ECL signal handling
""" TESTS:
If an interrupt arrives *before* ecl_sig_on(), we should get an ordinary KeyboardInterrupt::
sage: from sage.libs.ecl import test_sigint_before_ecl_sig_on sage: test_sigint_before_ecl_sig_on() Traceback (most recent call last): ... KeyboardInterrupt """ # Raise a SIGINT *now*. Since we are outside of sig_on() at this # point, this SIGINT will not be seen yet. # An ordinary KeyboardInterrupt should be raised by ecl_sig_on() # since ecl_sig_on() calls sig_on() before anything else. This # will catch the pending SIGINT. ecl_sig_on() # We should never get here. abort()
""" Print an overview of the ECL options
TESTS::
sage: from sage.libs.ecl import test_ecl_options sage: test_ecl_options() ECL_OPT_INCREMENTAL_GC = 0 ECL_OPT_TRAP_SIGSEGV = 1 ECL_OPT_TRAP_SIGFPE = 1 ECL_OPT_TRAP_SIGINT = 1 ECL_OPT_TRAP_SIGILL = 1 ECL_OPT_TRAP_SIGBUS = 1 ECL_OPT_TRAP_SIGCHLD = 0 ECL_OPT_TRAP_SIGPIPE = 1 ECL_OPT_TRAP_INTERRUPT_SIGNAL = 1 ECL_OPT_SIGNAL_HANDLING_THREAD = 0 ECL_OPT_SIGNAL_QUEUE_SIZE = 16 ECL_OPT_BOOTED = 1 ECL_OPT_BIND_STACK_SIZE = ... ECL_OPT_BIND_STACK_SAFETY_AREA = ... ECL_OPT_FRAME_STACK_SIZE = ... ECL_OPT_FRAME_STACK_SAFETY_AREA = ... ECL_OPT_LISP_STACK_SIZE = ... ECL_OPT_LISP_STACK_SAFETY_AREA = ... ECL_OPT_C_STACK_SIZE = ... ECL_OPT_C_STACK_SAFETY_AREA = ... ECL_OPT_SIGALTSTACK_SIZE = 1 ECL_OPT_HEAP_SIZE = ... ECL_OPT_HEAP_SAFETY_AREA = ... ECL_OPT_THREAD_INTERRUPT_SIGNAL = 0 ECL_OPT_SET_GMP_MEMORY_FUNCTIONS = 0 """
r""" Internal function to initialize ecl. Do not call.
This function initializes the ECL library for use within Python. This routine should only be called once and importing the ecl library interface already does that, so do not call this yourself.
EXAMPLES::
sage: from sage.libs.ecl import *
At this point, init_ecl() has run. Explicitly executing it gives an error::
sage: init_ecl() Traceback (most recent call last): ... RuntimeError: ECL is already initialized """ global list_of_objects global safe_eval_clobj global safe_apply_clobj global safe_funcall_clobj global read_from_string_clobj global ecl_has_booted cdef char *argv[1] cdef sigaction_t sage_action[32] cdef int i
# we need it to stop handling SIGCHLD
#we keep our own GMP memory functions. ECL should not claim them
#we need a dummy argv for cl_boot (we just don't give any parameters)
#get all the signal handlers before initializing Sage so we can #put them back afterwards.
#initialize ECL
#save signal handler from ECL
#verify that no SIGCHLD handler was installed cdef sigaction_t sig_test
#and put the Sage signal handlers back
#initialise list of objects and bind to global variable # *SAGE-LIST-OF-OBJECTS* to make it rooted in the reachable tree for the GC
(setf (logical-pathname-translations "TMP") '(("**;*.*" "%s/**/*.*")))
# We define our own error catching eval, apply and funcall/ # Presently these routines are only converted to byte-code. If they # ever turn out to be a bottle neck, it should be easy to properly # compile them.
(defun sage-safe-eval (form) (handler-case (values (eval form)) (serious-condition (cnd) (values nil (princ-to-string cnd))))) """))
(defun sage-safe-apply (func args) (handler-case (values (apply func args)) (serious-condition (cnd) (values nil (princ-to-string cnd))))) """))
(defun sage-safe-funcall (func arg) (handler-case (values (funcall func arg)) (serious-condition (cnd) (values nil (princ-to-string cnd))))) """))
cdef cl_object ecl_safe_eval(cl_object form) except NULL: """ TESTS:
Test interrupts::
sage: from sage.libs.ecl import * sage: from cysignals.tests import interrupt_after_delay sage: ecl_eval("(setf i 0)") <ECL: 0> sage: inf_loop = ecl_eval("(defun infinite() (loop (incf i)))") sage: interrupt_after_delay(1000) sage: inf_loop() Traceback (most recent call last): ... RuntimeError: ECL says: Console interrupt. """ cdef cl_object s
s = si_coerce_to_base_string(ecl_values(1)) raise RuntimeError("ECL says: {}".format( char_to_str(ecl_base_string_pointer_safe(s)))) else:
cdef cl_object ecl_safe_funcall(cl_object func, cl_object arg) except NULL: cdef cl_object l, s
s = si_coerce_to_base_string(ecl_values(1)) raise RuntimeError("ECL says: {}".format( char_to_str(ecl_base_string_pointer_safe(s)))) else:
cdef cl_object ecl_safe_apply(cl_object func, cl_object args) except NULL: cdef cl_object s
else:
cdef cl_object ecl_safe_read_string(char * s) except NULL: cdef cl_object o
r""" Shut down ecl. Do not call.
Given the way that ECL is used from python, it is very difficult to ensure that no ECL objects exist at a particular time. Hence, destroying ECL is a risky proposition.
EXAMPLES::
sage: from sage.libs.ecl import * sage: shutdown_ecl() """
#this prints the objects that sage wants the GC to keep track of. #these should be all non-immediate EclObject wrapped objects r""" Print GC-protection list
Diagnostic function. ECL objects that are bound to Python objects need to be protected from being garbage collected. We do this by including them in a doubly linked list bound to the global ECL symbol *SAGE-LIST-OF-OBJECTS*. Only non-immediate values get included, so small integers do not get linked in. This routine prints the values currently stored.
EXAMPLES::
sage: from sage.libs.ecl import * sage: a=EclObject("hello") sage: b=EclObject(10) sage: c=EclObject("world") sage: print_objects() #random because previous test runs can have left objects NIL WORLD HELLO """
cdef cl_object c, s
cdef cl_object python_to_ecl(pyobj) except NULL: # conversion of a python object into an ecl object # most conversions are straightforward. Noteworthy are: # python lists -> lisp (NIL terminated) lists # tuples -> dotted lists # strings ->parsed by lisp reader
cdef bytes s cdef cl_object L, ptr
else: if pyobj >= MOST_NEGATIVE_FIXNUM and pyobj <= MOST_POSITIVE_FIXNUM: return ecl_make_integer(pyobj) else: return python_to_ecl(Integer(pyobj)) s=str_to_bytes(pyobj) return ecl_safe_read_string(s) else: else: return Cnil return python_to_ecl(pyobj[0]) else: else:
cdef ecl_to_python(cl_object o): cdef cl_object s cdef Integer N # conversions from an ecl object to a python object.
return None #SAGE specific conversion #return ecl_fixint(o) #SAGE specific conversion #SAGE specific conversion #vanilla python does not have a class to represent rational numbers return Rational((ecl_to_python(cl_numerator(o)),ecl_to_python(cl_denominator(o)))) #Python conversion #Since SAGE mainly uses mpfr, perhaps "double is not an appropriate return type return True else:
#Maxima's BFLOAT multiprecision float type can be read with: #def bfloat_to_python(e): # prec=Integer(str(e.car().cddr().car())) # mant=Integer(str(e.cdr().car())) # exp=Integer(str(e.cddr().car())) # return 2^(exp-prec)*mant
cdef class EclObject: r""" Python wrapper of ECL objects
The ``EclObject`` forms a wrapper around ECL objects. The wrapper ensures that the data structure pointed to is protected from garbage collection in ECL by installing a pointer to it from a global data structure within the scope of the ECL garbage collector. This pointer is destroyed upon destruction of the EclObject.
EclObject() takes a Python object and tries to find a representation of it in Lisp.
EXAMPLES:
Python lists get mapped to LISP lists. None and Boolean values to appropriate values in LISP::
sage: from sage.libs.ecl import * sage: EclObject([None,true,false]) <ECL: (NIL T NIL)>
Numerical values are translated to the appropriate type in LISP::
sage: EclObject(1) <ECL: 1> sage: EclObject(10**40) <ECL: 10000000000000000000000000000000000000000>
Floats in Python are IEEE double, which LISP has as well. However, the printing of floating point types in LISP depends on settings::
sage: a = EclObject(float(10^40)) sage: ecl_eval("(setf *read-default-float-format* 'single-float)") <ECL: SINGLE-FLOAT> sage: a <ECL: 1.d40> sage: ecl_eval("(setf *read-default-float-format* 'double-float)") <ECL: DOUBLE-FLOAT> sage: a <ECL: 1.e40>
Tuples are translated to dotted lists::
sage: EclObject( (false, true)) <ECL: (NIL . T)>
Strings are fed to the reader, so a string normally results in a symbol::
sage: EclObject("Symbol") <ECL: SYMBOL>
But with proper quotation one can construct a lisp string object too::
sage: EclObject('"Symbol"') <ECL: "Symbol">
EclObjects translate to themselves, so one can mix::
sage: EclObject([1,2,EclObject([3])]) <ECL: (1 2 (3))>
Calling an EclObject translates into the appropriate LISP ``apply``, where the argument is transformed into an EclObject itself, so one can flexibly apply LISP functions::
sage: car=EclObject("car") sage: cdr=EclObject("cdr") sage: car(cdr([1,2,3])) <ECL: 2>
and even construct and evaluate arbitrary S-expressions::
sage: eval=EclObject("eval") sage: quote=EclObject("quote") sage: eval([car, [cdr, [quote,[1,2,3]]]]) <ECL: 2>
TESTS:
We check that multiprecision integers are converted correctly::
sage: i = 10 ^ (10 ^ 5) sage: EclObject(i) == EclObject(str(i)) True sage: EclObject(-i) == EclObject(str(-i)) True sage: EclObject(i).python() == i True sage: EclObject(-i).python() == -i True """ cdef cl_object obj #the wrapped object cdef cl_object node #linked list pointer: car(node) == obj
cdef void set_obj(EclObject self, cl_object o): remove_node(self.node) self.node=NULL
def __init__(self,*args): r""" Create an EclObject
See EclObject for full documentation.
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([None,true,false]) <ECL: (NIL T NIL)>
"""
def __reduce__(self): r""" This is used for pickling. Not implemented
Ecl does not natively support serialization of its objects, so the python wrapper class EclObject does not support pickling. There are independent efforts for developing serialization for Common Lisp, such as CL-STORE. Look at those if you need serialization of ECL objects.
EXAMPLES::
sage: from sage.libs.ecl import * sage: s=EclObject([1,2,3]) sage: s.__reduce__() Traceback (most recent call last): ... NotImplementedError: EclObjects do not have a pickling method sage: s==loads(dumps(s)) Traceback (most recent call last): ... NotImplementedError: EclObjects do not have a pickling method """
def python(self): r""" Convert an EclObject to a python object.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([1,2,("three",'"four"')]) sage: L.python() [1, 2, ('THREE', '"four"')]
"""
def __dealloc__(self): r""" Deallocate EclObject
It is important to remove the GC preventing reference to the object upon deletion of the wrapper.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject("symbol") sage: del L
"""
def __repr__(self): r""" Produce a string representation suitable for interactive printing.
Converts the wrapped LISP object to a string, decorated in such a way that it can be recognised as a LISP object.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject("symbol") sage: repr(L) '<ECL: SYMBOL>'
"""
def __str__(self): r""" Produce a string representation.
Converts the wrapped LISP object to a string and returns that as a Python string.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject("symbol") sage: str(L) 'SYMBOL'
""" cdef cl_object s
def __hash__(self): r""" Return a hash value of the object
Returns the hash value returned by SXHASH, which is a routine that is specified in Common Lisp. According to the specification, lisp objects that are EQUAL have the same SXHASH value. Since two EclObjects are equal if their wrapped objects are EQUAL according to lisp, this is compatible with Python's concept of hash values.
It is not possible to enforce immutability of lisp objects, so care should be taken in using EclObjects as dictionary keys.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([1,2]) sage: L <ECL: (1 2)> sage: hash(L) #random 463816586 sage: L.rplacd(EclObject(3)) sage: L <ECL: (1 . 3)> sage: hash(L) #random 140404060
"""
def __call__(self, *args): r""" Apply self to arguments.
EXAMPLES::
sage: from sage.libs.ecl import * sage: sqr=EclObject("(lambda (x) (* x x))").eval() sage: sqr(10) <ECL: 100>
"""
def __richcmp__(left, right, int op): r""" Comparison test.
An EclObject is not equal to any non-EclObject. Two EclObjects are equal if their wrapped lisp objects are EQUAL. Since LISP has no universal ordering, less than and greater than tests are not implemented for EclObjects.
EXAMPLES::
sage: from sage.libs.ecl import * sage: a=EclObject(1) sage: b=EclObject(2) sage: a==b False sage: a<b Traceback (most recent call last): ... NotImplementedError: EclObjects can only be compared for equality sage: EclObject("<")(a,b) <ECL: T> """ return False else: if not(isinstance(left,EclObject) and isinstance(right,EclObject)): return True else: return not(bint_equal((<EclObject>left).obj,(<EclObject>right).obj))
#Common lisp only seems to be able to compare numeric and string types #and does not have generic routines for doing that. #we could dispatch based on type here, but that seems #inappropriate for an *interface*.
def __iter__(self): r""" Implements the iterator protocol for EclObject.
EclObject implements the iterator protocol for lists. This means one can use an EclObject in the context where an iterator is expected (for instance, in a list comprehension or in a for loop). The iterator produces EclObjects wrapping the members of the list that the original EclObject wraps.
The wrappers returned are all newly constructed but refer to the original members of the list iterated over. This is usually what is intended but, just as in Python, can cause surprises if the original object is changed between calls to the iterator.
Since EclObject translates Python Lists into LISP lists and Python tuples into LISP "dotted" lists (lists for which the final CDR is not necessarily NIL), and both these python structures are iterable, the corresponding EclObjects are iterable as well.
EclObjects that are not lists are not iterable.
EXAMPLES::
sage: from sage.libs.ecl import * sage: [i for i in EclObject("(1 2 3)")] [<ECL: 1>, <ECL: 2>, <ECL: 3>] sage: [i for i in EclObject("(1 2 . 3)")] [<ECL: 1>, <ECL: 2>, <ECL: 3>] sage: [i for i in EclObject("NIL")] []
TESTS:
These show that Python lists and tuples behave as described above::
sage: [i for i in EclObject([1,2,3])] [<ECL: 1>, <ECL: 2>, <ECL: 3>] sage: [i for i in EclObject((1,2,3))] [<ECL: 1>, <ECL: 2>, <ECL: 3>]
This tests that we cannot iterate EclObjects we shouldn't, as described above::
sage: [i for i in EclObject("T")] Traceback (most recent call last): ... TypeError: ECL object is not iterable
"""
def eval(self): r""" Evaluate object as an S-Expression
EXAMPLES::
sage: from sage.libs.ecl import * sage: S=EclObject("(+ 1 2)") sage: S <ECL: (+ 1 2)> sage: S.eval() <ECL: 3>
""" cdef cl_object o raise RuntimeError("ECL runtime error")
def cons(self,EclObject d): r""" apply cons to self and argument and return the result.
EXAMPLES::
sage: from sage.libs.ecl import * sage: a=EclObject(1) sage: b=EclObject(2) sage: a.cons(b) <ECL: (1 . 2)>
"""
def rplaca(self,EclObject d): r""" Destructively replace car(self) with d.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject((1,2)) sage: L <ECL: (1 . 2)> sage: a=EclObject(3) sage: L.rplaca(a) sage: L <ECL: (3 . 2)>
""" raise TypeError("rplaca can only be applied to a cons")
def rplacd(self,EclObject d): r""" Destructively replace cdr(self) with d.
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject((1,2)) sage: L <ECL: (1 . 2)> sage: a=EclObject(3) sage: L.rplacd(a) sage: L <ECL: (1 . 3)>
""" raise TypeError("rplacd can only be applied to a cons")
def car(self): r""" Return the car of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("car can only be applied to a cons")
def cdr(self): r""" Return the cdr of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("cdr can only be applied to a cons")
def caar(self): r""" Return the caar of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("caar can only be applied to a cons")
def cadr(self): r""" Return the cadr of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("cadr can only be applied to a cons")
def cdar(self): r""" Return the cdar of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("cdar can only be applied to a cons")
def cddr(self): r""" Return the cddr of self
EXAMPLES::
sage: from sage.libs.ecl import * sage: L=EclObject([[1,2],[3,4]]) sage: L.car() <ECL: (1 2)> sage: L.cdr() <ECL: ((3 4))> sage: L.caar() <ECL: 1> sage: L.cadr() <ECL: (3 4)> sage: L.cdar() <ECL: (2)> sage: L.cddr() <ECL: NIL> """ raise TypeError("cddr can only be applied to a cons")
def fixnump(self): r""" Return True if self is a fixnum, False otherwise
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject(2**3).fixnump() True sage: EclObject(2**200).fixnump() False
"""
def characterp(self): r""" Return True if self is a character, False otherwise
Strings are not characters
EXAMPLES:
sage: from sage.libs.ecl import * sage: EclObject('"a"').characterp() False
"""
def nullp(self): r""" Return True if self is NIL, False otherwise
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([]).nullp() True sage: EclObject([[]]).nullp() False """
def listp(self): r""" Return True if self is a list, False otherwise. NIL is a list.
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([]).listp() True sage: EclObject([[]]).listp() True """
def consp(self): r""" Return True if self is a cons, False otherwise. NIL is not a cons.
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([]).consp() False sage: EclObject([[]]).consp() True """
def atomp(self): r""" Return True if self is atomic, False otherwise.
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([]).atomp() True sage: EclObject([[]]).atomp() False
"""
def symbolp(self): r""" Return True if self is a symbol, False otherwise.
EXAMPLES::
sage: from sage.libs.ecl import * sage: EclObject([]).symbolp() True sage: EclObject([[]]).symbolp() False
"""
cdef class EclListIterator: r""" Iterator object for an ECL list
This class is used to implement the iterator protocol for EclObject. Do not instantiate this class directly but use the iterator method on an EclObject instead. It is an error if the EclObject is not a list.
EXAMPLES::
sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: type(I) <type 'sage.libs.ecl.EclListIterator'> sage: [i for i in I] [<ECL: 1>, <ECL: 2>, <ECL: 3>] sage: [i for i in EclObject("(1 2 3)")] [<ECL: 1>, <ECL: 2>, <ECL: 3>] sage: EclListIterator(EclObject("1")) Traceback (most recent call last): ... TypeError: ECL object is not iterable
""" cdef EclObject current
def __init__(EclListIterator self, EclObject o): r""" Initialize EclListIterator
EXAMPLES::
sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: type(I) <type 'sage.libs.ecl.EclListIterator'>
"""
def __iter__(EclListIterator self): r""" Return self
It seems standard that iterators return themselves if asked to produce an iterator.
EXAMPLES::
sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: id(I) == id(I.__iter__()) True
"""
def __next__(EclListIterator self): r""" Get next element from iterator
EXAMPLES::
sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: next(I) <ECL: 1> sage: next(I) <ECL: 2> sage: next(I) <ECL: 3> sage: next(I) Traceback (most recent call last): ... StopIteration
"""
else:
#input: a cl-object. Output: EclObject wrapping that. cdef EclObject ecl_wrap(cl_object o):
#convenience routine to more easily evaluate strings cpdef EclObject ecl_eval(str s): """ Read and evaluate string in Lisp and return the result
EXAMPLES::
sage: from sage.libs.ecl import * sage: ecl_eval("(defun fibo (n)(cond((= n 0) 0)((= n 1) 1)(T (+ (fibo (- n 1)) (fibo (- n 2))))))") <ECL: FIBO> sage: ecl_eval("(mapcar 'fibo '(1 2 3 4 5 6 7))") <ECL: (1 1 2 3 5 8 13)>
""" cdef cl_object o
|