1# Copyright © 2007-2019 Jakub Wilk <jwilk@jwilk.net>
2#
3# This file is part of python-djvulibre.
4#
5# python-djvulibre is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 2 as published by
7# the Free Software Foundation.
8#
9# python-djvulibre is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12# more details.
13
14#cython: autotestdict=False
15#cython: language_level=2
16
17'''
18DjVuLibre bindings: module for handling Lisp S-expressions
19'''
20
21cimport cython
22
23include 'common.pxi'
24
25cdef extern from 'libdjvu/miniexp.h':
26    int cexpr_is_int 'miniexp_numberp'(cexpr_t sexp) nogil
27    int cexpr_to_int 'miniexp_to_int'(cexpr_t sexp) nogil
28    cexpr_t int_to_cexpr 'miniexp_number'(int n) nogil
29
30    int cexpr_is_symbol 'miniexp_symbolp'(cexpr_t sexp) nogil
31    char* cexpr_to_symbol 'miniexp_to_name'(cexpr_t sexp) nogil
32    cexpr_t symbol_to_cexpr 'miniexp_symbol'(char* name) nogil
33
34    cexpr_t cexpr_nil 'miniexp_nil'
35    cexpr_t cexpr_dummy 'miniexp_dummy'
36    int cexpr_is_list 'miniexp_listp'(cexpr_t exp) nogil
37    int cexpr_is_nonempty_list 'miniexp_consp'(cexpr_t exp) nogil
38    int cexpr_length 'miniexp_length'(cexpr_t exp) nogil
39    cexpr_t cexpr_head 'miniexp_car'(cexpr_t exp) nogil
40    cexpr_t cexpr_tail 'miniexp_cdr'(cexpr_t exp) nogil
41    cexpr_t cexpr_nth 'miniexp_nth'(int n, cexpr_t exp) nogil
42    cexpr_t pair_to_cexpr 'miniexp_cons'(cexpr_t head, cexpr_t tail) nogil
43    cexpr_t cexpr_replace_head 'miniexp_rplaca'(cexpr_t exp, cexpr_t new_head) nogil
44    cexpr_t cexpr_replace_tail 'miniexp_rplacd'(cexpr_t exp, cexpr_t new_tail) nogil
45    cexpr_t cexpr_reverse_list 'miniexp_reverse'(cexpr_t exp) nogil
46
47    int cexpr_is_str 'miniexp_stringp'(cexpr_t cexpr) nogil
48    const char * cexpr_to_str 'miniexp_to_str'(cexpr_t cexpr) nogil
49    cexpr_t str_to_cexpr 'miniexp_string'(const char *s) nogil
50    cexpr_t cexpr_substr 'miniexp_substring'(const char *s, int n) nogil
51    cexpr_t cexpr_concat 'miniexp_concat'(cexpr_t cexpr_list) nogil
52
53    cexpr_t gc_lock 'minilisp_acquire_gc_lock'(cexpr_t cexpr) nogil
54    cexpr_t gc_unlock 'minilisp_release_gc_lock'(cexpr_t cexpr) nogil
55
56    cvar_t* cvar_new 'minivar_alloc'() nogil
57    void cvar_free 'minivar_free'(cvar_t* v) nogil
58    cexpr_t* cvar_ptr 'minivar_pointer'(cvar_t* v) nogil
59
60    IF HAVE_MINIEXP_IO_T:
61        ctypedef cexpr_io_s cexpr_io_t 'miniexp_io_t'
62        struct cexpr_io_s 'miniexp_io_s':
63            int (*puts 'fputs')(cexpr_io_t*, char*)
64            int (*getc 'fgetc')(cexpr_io_t*)
65            int (*ungetc)(cexpr_io_t*, int)
66            void *data[4]
67            int *p_flags
68        void cexpr_io_init 'miniexp_io_init'(cexpr_io_t *cio)
69        enum:
70            cexpr_io_print7bits 'miniexp_io_print7bits'
71        cexpr_t cexpr_read 'miniexp_read_r'(cexpr_io_t *cio)
72        cexpr_t cexpr_print 'miniexp_prin_r'(cexpr_io_t *cio, cexpr_t cexpr)
73        cexpr_t cexpr_printw 'miniexp_pprin_r'(cexpr_io_t *cio, cexpr_t cexpr, int width)
74    ELSE:
75        int io_7bit 'minilisp_print_7bits'
76        int (*io_puts 'minilisp_puts')(char *s)
77        int (*io_getc 'minilisp_getc')()
78        int (*io_ungetc 'minilisp_ungetc')(int c)
79        cexpr_t cexpr_read 'miniexp_read'()
80        cexpr_t cexpr_print 'miniexp_prin'(cexpr_t cexpr)
81        cexpr_t cexpr_printw 'miniexp_pprin'(cexpr_t cexpr, int width)
82
83cdef extern from 'stdio.h':
84    int EOF
85
86cdef object sys
87import sys
88
89cdef object format_exc
90from traceback import format_exc
91
92cdef object StringIO
93IF PY3K:
94    from io import StringIO
95ELSE:
96    from cStringIO import StringIO
97
98cdef object BytesIO
99from io import BytesIO
100
101cdef object weakref
102import weakref
103
104cdef object symbol_dict
105symbol_dict = weakref.WeakValueDictionary()
106
107cdef object codecs
108import codecs
109
110IF not HAVE_MINIEXP_IO_T:
111    cdef Lock _myio_lock
112    _myio_lock = allocate_lock()
113
114cdef class _ExpressionIO:
115    IF HAVE_MINIEXP_IO_T:
116        cdef cexpr_io_t cio
117        cdef int flags
118    ELSE:
119        cdef int (*backup_io_puts)(const char *s)
120        cdef int (*backup_io_getc)()
121        cdef int (*backup_io_ungetc)(int c)
122        cdef int backup_io_7bit
123    cdef object stdin 'stdin_fp'
124    cdef object stdout 'stdout_fp'
125    cdef int stdout_binary
126    cdef object buffer
127    cdef object exc
128
129    _reentrant = HAVE_MINIEXP_IO_T
130
131    def __init__(self, object stdin=None, object stdout=None, int escape_unicode=True):
132        IF not HAVE_MINIEXP_IO_T:
133            global io_7bit, io_puts, io_getc, io_ungetc
134            global _myio
135            with nogil:
136                acquire_lock(_myio_lock, WAIT_LOCK)
137            self.backup_io_7bit = io_7bit
138            self.backup_io_puts = io_puts
139            self.backup_io_getc = io_getc
140            self.backup_io_ungetc = io_ungetc
141        self.stdin = stdin
142        self.stdout = stdout
143        IF PY3K:
144            self.stdout_binary = not hasattr(stdout, 'encoding')
145        ELSE:
146            # In Python 2, sys.stdout has the encoding attribute,
147            # even though it accepts byte strings.
148            # Let's only make a special-case for codecs.
149            self.stdout_binary = not isinstance(stdout, codecs.StreamReaderWriter)
150        self.buffer = []
151        self.exc = None
152        IF HAVE_MINIEXP_IO_T:
153            cexpr_io_init(&self.cio)
154            self.cio.data[0] = <void*>self
155            self.cio.getc = _myio_getc
156            self.cio.ungetc = _myio_ungetc
157            self.cio.puts = _myio_puts
158            if escape_unicode:
159                self.flags = cexpr_io_print7bits
160            else:
161                self.flags = 0
162            self.cio.p_flags = &self.flags
163        ELSE:
164            io_getc = _myio_getc
165            io_ungetc = _myio_ungetc
166            io_puts = _myio_puts
167            io_7bit = escape_unicode
168            _myio = self
169
170    @cython.final
171    cdef close(self):
172        IF not HAVE_MINIEXP_IO_T:
173            global io_7bit, io_puts, io_getc, io_ungetc
174            global _myio
175            _myio = None
176        self.stdin = None
177        self.stdout = None
178        self.buffer = None
179        IF not HAVE_MINIEXP_IO_T:
180            io_7bit = self.backup_io_7bit
181            io_puts = self.backup_io_puts
182            io_getc = self.backup_io_getc
183            io_ungetc = self.backup_io_ungetc
184        try:
185            if self.exc is not None:
186                raise self.exc[0], self.exc[1], self.exc[2]
187        finally:
188            IF not HAVE_MINIEXP_IO_T:
189                release_lock(_myio_lock)
190            self.exc = None
191
192    IF HAVE_MINIEXP_IO_T:
193
194        @cython.final
195        cdef cexpr_t read(self):
196            return cexpr_read(&self.cio)
197
198        @cython.final
199        cdef cexpr_t print_(self, cexpr_t cexpr):
200            return cexpr_print(&self.cio, cexpr)
201
202        @cython.final
203        cdef cexpr_t printw(self, cexpr_t cexpr, int width):
204            return cexpr_printw(&self.cio, cexpr, width)
205
206    ELSE:
207
208        @cython.final
209        cdef cexpr_t read(self):
210            return cexpr_read()
211
212        @cython.final
213        cdef cexpr_t print_(self, cexpr_t cexpr):
214            return cexpr_print(cexpr)
215
216        @cython.final
217        cdef cexpr_t printw(self, cexpr_t cexpr, int width):
218            return cexpr_printw(cexpr, width)
219
220IF HAVE_MINIEXP_IO_T:
221
222    cdef int _myio_puts(cexpr_io_t* cio, const char *s):
223        cdef _ExpressionIO io
224        xio = <_ExpressionIO> cio.data[0]
225        try:
226            if xio.stdout_binary:
227                xio.stdout.write(s)
228            else:
229                xio.stdout.write(decode_utf8(s))
230        except:
231            xio.exc = sys.exc_info()
232            return EOF
233
234    cdef int _myio_getc(cexpr_io_t* cio):
235        cdef _ExpressionIO xio
236        cdef int result
237        xio = <_ExpressionIO> cio.data[0]
238        if xio.buffer:
239            return xio.buffer.pop()
240        try:
241            s = xio.stdin.read(1)
242            if not s:
243                return EOF
244            if is_unicode(s):
245                s = encode_utf8(s)
246            IF PY3K:
247                xio.buffer += reversed(s)
248            ELSE:
249                xio.buffer += map(ord, reversed(s))
250            return xio.buffer.pop()
251        except:
252            xio.exc = sys.exc_info()
253            return EOF
254
255    cdef int _myio_ungetc(cexpr_io_t* cio, int c):
256        cdef _ExpressionIO io
257        xio = <_ExpressionIO> cio.data[0]
258        list_append(xio.buffer, c)
259
260ELSE:
261
262    cdef _ExpressionIO _myio
263
264    cdef int _myio_puts(const char *s):
265        try:
266            if _myio.stdout_binary:
267                _myio.stdout.write(s)
268            else:
269                _myio.stdout.write(decode_utf8(s))
270        except:
271            _myio.exc = sys.exc_info()
272            return EOF
273
274    cdef int _myio_getc():
275        cdef int result
276        if _myio.buffer:
277            return _myio.buffer.pop()
278        try:
279            s = _myio.stdin.read(1)
280            if not s:
281                return EOF
282            if is_unicode(s):
283                s = encode_utf8(s)
284            IF PY3K:
285                _myio.buffer += reversed(s)
286            ELSE:
287                _myio.buffer += map(ord, reversed(s))
288            return _myio.buffer.pop()
289        except:
290            _myio.exc = sys.exc_info()
291            return EOF
292
293    cdef int _myio_ungetc(int c):
294        list_append(_myio.buffer, c)
295
296cdef object the_sentinel
297the_sentinel = object()
298
299cdef class _WrappedCExpr:
300
301    def __cinit__(self, object sentinel):
302        if sentinel is not the_sentinel:
303            raise_instantiation_error(type(self))
304        self.cvar = cvar_new()
305
306    cdef cexpr_t cexpr(self):
307        return cvar_ptr(self.cvar)[0]
308
309    cdef object print_into(self, object stdout, object width, bint escape_unicode):
310        cdef cexpr_t cexpr
311        cdef _ExpressionIO xio
312        if width is None:
313            pass
314        elif not is_int(width):
315            raise TypeError('width must be an integer')
316        elif width <= 0:
317            raise ValueError('width <= 0')
318        cexpr = self.cexpr()
319        xio = _ExpressionIO(stdout=stdout, escape_unicode=escape_unicode)
320        try:
321            if width is None:
322                xio.print_(cexpr)
323            else:
324                xio.printw(cexpr, width)
325        finally:
326            xio.close()
327
328    cdef object as_string(self, object width, bint escape_unicode):
329        stdout = StringIO()
330        try:
331            self.print_into(stdout, width, escape_unicode)
332            return stdout.getvalue()
333        finally:
334            stdout.close()
335
336    def __dealloc__(self):
337        cvar_free(self.cvar)
338
339cdef _WrappedCExpr wexpr(cexpr_t cexpr):
340    cdef _WrappedCExpr wexpr
341    wexpr = _WrappedCExpr(sentinel = the_sentinel)
342    cvar_ptr(wexpr.cvar)[0] = cexpr
343    return wexpr
344
345cdef class _MissingCExpr(_WrappedCExpr):
346
347    cdef object print_into(self, object stdout, object width, bint escape_unicode):
348        raise NotImplementedError
349
350    cdef object as_string(self, object width, bint escape_unicode):
351        raise NotImplementedError
352
353cdef _MissingCExpr wexpr_missing():
354    return _MissingCExpr(the_sentinel)
355
356
357cdef class BaseSymbol:
358
359    cdef object __weakref__
360    cdef object _bytes
361
362    def __cinit__(self, bytes):
363        cdef char *cbytes
364        cbytes = bytes
365        self._bytes = cbytes
366
367    def __repr__(self):
368        IF PY3K:
369            try:
370                string = self._bytes.decode('UTF-8')
371            except UnicodeDecodeError:
372                string = self._bytes
373        ELSE:
374            string = self._bytes
375        return '{tp}({s!r})'.format(tp=get_type_name(_Symbol_), s=string)
376
377    def __richcmp__(self, object other, int op):
378        cdef BaseSymbol _self, _other
379        if not typecheck(self, BaseSymbol) or not typecheck(other, BaseSymbol):
380            return NotImplemented
381        _self = self
382        _other = other
383        return richcmp(_self._bytes, _other._bytes, op)
384
385    def __hash__(self):
386        return hash(self._bytes)
387
388    property bytes:
389        def __get__(self):
390            return self._bytes
391
392    IF not PY3K:
393        def __str__(self):
394            return self._bytes
395
396    IF PY3K:
397        def __str__(self):
398            return self._bytes.decode('UTF-8')
399    ELSE:
400        def __unicode__(self):
401            return self._bytes.decode('UTF-8')
402
403    def __reduce__(self):
404        return (Symbol, (self._bytes,))
405
406class Symbol(BaseSymbol):
407
408    @staticmethod
409    def __new__(cls, name):
410        '''
411        Symbol(name) -> a symbol
412        '''
413        self = None
414        if is_unicode(name):
415            name = encode_utf8(name)
416        try:
417            if cls is _Symbol_:
418                self = symbol_dict[name]
419        except KeyError:
420            pass
421        if self is None:
422            if not is_bytes(name):
423                name = str(name)
424                IF PY3K:
425                    name = encode_utf8(name)
426            self = BaseSymbol.__new__(cls, name)
427            if cls is _Symbol_:
428                symbol_dict[name] = self
429        return self
430
431cdef object _Symbol_
432_Symbol_ = Symbol
433
434def _expression_from_string(s):
435    '''
436    Expression.from_string(s) -> an expression
437
438    Read an expression from a string.
439    '''
440    if is_unicode(s):
441        s = encode_utf8(s)
442    stdin = BytesIO(s)
443    try:
444        return _Expression_.from_stream(stdin)
445    finally:
446        stdin.close()
447
448class Expression(BaseExpression):
449
450    '''
451    Notes about the textual representation of S-expressions
452    -------------------------------------------------------
453
454    Special characters are:
455
456    * the parenthesis '(' and ')',
457    * the double quote '"',
458    * the vertical bar '|'.
459
460    Symbols are represented by their name. Vertical bars | can be used to
461    delimit names that contain blanks, special characters, non printable
462    characters, non-ASCII characters, or can be confused as a number.
463
464    Numbers follow the syntax specified by the C function strtol() with
465    base=0.
466
467    Strings are delimited by double quotes. All C string escapes are
468    recognized. Non-printable ASCII characters must be escaped.
469
470    List are represented by an open parenthesis '(' followed by the space
471    separated list elements, followed by a closing parenthesis ')'.
472
473    When the cdr of the last pair is non zero, the closed parenthesis is
474    preceded by a space, a dot '.', a space, and the textual representation
475    of the cdr. (This is only partially supported by Python bindings.)
476
477    '''
478
479    @staticmethod
480    def __new__(cls, value):
481        '''
482        Expression(value) -> an expression
483        '''
484        if typecheck(value, _Expression_) and (not typecheck(value, ListExpression) or not value):
485            return value
486        if is_int(value):
487            return IntExpression(value)
488        elif typecheck(value, _Symbol_):
489            return SymbolExpression(value)
490        elif is_unicode(value):
491            return StringExpression(encode_utf8(value))
492        elif is_bytes(value):
493            if PY3K:
494                return StringExpression(bytes(value))
495            else:
496                return StringExpression(str(value))
497        else:
498            return ListExpression(iter(value))
499
500    @staticmethod
501    def from_stream(stdin):
502        '''
503        Expression.from_stream(stream) -> an expression
504
505        Read an expression from a stream.
506        '''
507        cdef _ExpressionIO xio
508        try:
509            xio = _ExpressionIO(stdin=stdin)
510            try:
511                return _c2py(xio.read())
512            except InvalidExpression:
513                raise ExpressionSyntaxError
514        finally:
515            xio.close()
516
517    from_string = staticmethod(_expression_from_string)
518
519cdef object _Expression_
520_Expression_ = Expression
521
522cdef object BaseExpression_richcmp(object left, object right, int op):
523    if not typecheck(left, BaseExpression):
524        return NotImplemented
525    elif not typecheck(right, BaseExpression):
526        return NotImplemented
527    return richcmp(left.value, right.value, op)
528
529cdef class BaseExpression:
530    '''
531    Don't use this class directly. Use the Expression class instead.
532    '''
533
534    cdef _WrappedCExpr wexpr
535
536    def __cinit__(self, *args, **kwargs):
537        self.wexpr = wexpr_missing()
538
539    def print_into(self, stdout, width=None, escape_unicode=True):
540        '''
541        expr.print_into(file, width=None, escape_unicode=True) -> None
542
543        Print the expression into the file.
544        '''
545        self.wexpr.print_into(stdout, width, escape_unicode)
546
547    def as_string(self, width=None, escape_unicode=True):
548        '''
549        expr.as_string(width=None, escape_unicode=True) -> a string
550
551        Return a string representation of the expression.
552        '''
553        return self.wexpr.as_string(width, escape_unicode)
554
555    def __str__(self):
556        return self.as_string()
557
558    IF not PY3K:
559        def __unicode__(self):
560            return self.as_string().decode('UTF-8')
561
562    property value:
563        '''
564        The "pythonic" value of the expression.
565        Lisp lists as mapped to Python tuples.
566        '''
567        def __get__(self):
568            return self._get_value()
569
570    property lvalue:
571        '''
572        The "pythonic" value of the expression.
573        Lisp lists as mapped to Python lists.
574        '''
575        def __get__(self):
576            return self._get_lvalue()
577
578    def _get_value(self):
579        return self._get_lvalue()
580
581    def _get_lvalue(self):
582        raise NotImplementedError
583
584    def __richcmp__(self, other, int op):
585        return BaseExpression_richcmp(self, other, op)
586
587    def __repr__(self):
588        return '{tp}({expr!r})'.format(tp=get_type_name(_Expression_), expr=self.lvalue)
589
590    def __copy__(self):
591        # Most of S-expressions are immutable.
592        # Mutable S-expressions should override this method.
593        return self
594
595    def __deepcopy__(self, memo):
596        # Most of S-expressions are immutable.
597        # Mutable S-expressions should override this method.
598        return self
599
600    def __reduce__(self):
601        return (_expression_from_string, (self.as_string(),))
602
603class IntExpression(_Expression_):
604
605    '''
606    IntExpression can represent any integer in range(-2 ** 29, 2 ** 29).
607
608    To create objects of this class, use the Expression class constructor.
609    '''
610
611    @staticmethod
612    def __new__(cls, value):
613        '''
614        IntExpression(n) -> an integer expression
615        '''
616        cdef BaseExpression self
617        self = BaseExpression.__new__(cls)
618        if typecheck(value, _WrappedCExpr):
619            self.wexpr = value
620        elif is_int(value):
621            if -1 << 29 <= value < 1 << 29:
622                self.wexpr = wexpr(int_to_cexpr(value))
623            else:
624                raise ValueError('value not in range(-2 ** 29, 2 ** 29)')
625        else:
626            raise TypeError('value must be an integer')
627        return self
628
629    IF PY3K:
630        def __bool__(self):
631            return bool(self.value)
632    ELSE:
633        def __nonzero__(self):
634            return bool(self.value)
635
636    def __int__(self):
637        return self.value
638
639    def __long__(self):
640        return long(self.value)
641
642    def __float__(self):
643        return 0.0 + self.value
644
645    def _get_lvalue(BaseExpression self not None):
646        return cexpr_to_int(self.wexpr.cexpr())
647
648    def __richcmp__(self, other, int op):
649        return BaseExpression_richcmp(self, other, op)
650
651    def __hash__(self):
652        return hash(self.value)
653
654class SymbolExpression(_Expression_):
655    '''
656    To create objects of this class, use the Expression class constructor.
657    '''
658
659    @staticmethod
660    def __new__(cls, value):
661        '''
662        SymbolExpression(Symbol(s)) -> a symbol expression
663        '''
664        cdef BaseExpression self
665        cdef BaseSymbol symbol
666        self = BaseExpression.__new__(cls)
667        if typecheck(value, _WrappedCExpr):
668            self.wexpr = value
669        elif typecheck(value, _Symbol_):
670            symbol = value
671            self.wexpr = wexpr(symbol_to_cexpr(symbol._bytes))
672        else:
673            raise TypeError('value must be a Symbol')
674        return self
675
676    def _get_lvalue(BaseExpression self not None):
677        return _Symbol_(cexpr_to_symbol(self.wexpr.cexpr()))
678
679    def __richcmp__(self, other, int op):
680        return BaseExpression_richcmp(self, other, op)
681
682    def __hash__(self):
683        return hash(self.value)
684
685class StringExpression(_Expression_):
686    '''
687    To create objects of this class, use the Expression class constructor.
688    '''
689
690    @staticmethod
691    def __new__(cls, value):
692        '''
693        SymbolExpression(s) -> a string expression
694        '''
695        cdef BaseExpression self
696        self = BaseExpression.__new__(cls)
697        if typecheck(value, _WrappedCExpr):
698            self.wexpr = value
699        elif is_bytes(value):
700            gc_lock(NULL)  # protect from collecting a just-created object
701            try:
702                self.wexpr = wexpr(str_to_cexpr(value))
703            finally:
704                gc_unlock(NULL)
705        else:
706            raise TypeError('value must be a byte string')
707        return self
708
709    @property
710    def bytes(BaseExpression self not None):
711        return cexpr_to_str(self.wexpr.cexpr())
712
713    def _get_lvalue(BaseExpression self not None):
714        cdef const char *bytes
715        bytes = cexpr_to_str(self.wexpr.cexpr())
716        IF PY3K:
717            return decode_utf8(bytes)
718        ELSE:
719            return bytes
720
721    IF PY3K:
722        def __repr__(BaseExpression self not None):
723            cdef const char *bytes
724            bytes = cexpr_to_str(self.wexpr.cexpr())
725            try:
726                string = decode_utf8(bytes)
727            except UnicodeDecodeError:
728                string = bytes
729            return '{tp}({s!r})'.format(tp=get_type_name(_Expression_), s=string)
730
731    def __richcmp__(self, other, int op):
732        return BaseExpression_richcmp(self, other, op)
733
734    def __hash__(self):
735        return hash(self.value)
736
737class InvalidExpression(ValueError):
738    pass
739
740class ExpressionSyntaxError(Exception):
741    '''
742    Invalid expression syntax.
743    '''
744    pass
745
746cdef _WrappedCExpr public_py2c(object o):
747    cdef BaseExpression pyexpr
748    pyexpr = _Expression_(o)
749    if pyexpr is None:
750        raise TypeError
751    return pyexpr.wexpr
752
753cdef object public_c2py(cexpr_t cexpr):
754    return _c2py(cexpr)
755
756cdef BaseExpression _c2py(cexpr_t cexpr):
757    if cexpr == cexpr_dummy:
758        raise InvalidExpression
759    _wexpr = wexpr(cexpr)
760    if cexpr_is_int(cexpr):
761        result = IntExpression(_wexpr)
762    elif cexpr_is_symbol(cexpr):
763        result = SymbolExpression(_wexpr)
764    elif cexpr_is_list(cexpr):
765        result = ListExpression(_wexpr)
766    elif cexpr_is_str(cexpr):
767        result = StringExpression(_wexpr)
768    else:
769        raise InvalidExpression
770    return result
771
772cdef _WrappedCExpr _build_list_cexpr(object items):
773    cdef cexpr_t cexpr
774    cdef BaseExpression citem
775    gc_lock(NULL)  # protect from collecting a just-created object
776    try:
777        cexpr = cexpr_nil
778        for item in items:
779            if typecheck(item, BaseExpression):
780                citem = item
781            else:
782                citem = _Expression_(item)
783            if citem is None:
784                raise TypeError
785            cexpr = pair_to_cexpr(citem.wexpr.cexpr(), cexpr)
786        cexpr = cexpr_reverse_list(cexpr)
787        return wexpr(cexpr)
788    finally:
789        gc_unlock(NULL)
790
791
792class ListExpression(_Expression_):
793    '''
794    To create objects of this class, use the Expression class constructor.
795    '''
796
797    @staticmethod
798    def __new__(cls, items):
799        '''
800        ListExpression(iterable) -> a list expression
801        '''
802        cdef BaseExpression self
803        self = BaseExpression.__new__(cls)
804        if typecheck(items, _WrappedCExpr):
805            self.wexpr = items
806        else:
807            self.wexpr = _build_list_cexpr(items)
808        return self
809
810    IF PY3K:
811        def __bool__(BaseExpression self not None):
812            return self.wexpr.cexpr() != cexpr_nil
813    ELSE:
814        def __nonzero__(BaseExpression self not None):
815            return self.wexpr.cexpr() != cexpr_nil
816
817    def __len__(BaseExpression self not None):
818        cdef cexpr_t cexpr
819        cdef int n
820        cexpr = self.wexpr.cexpr()
821        n = 0
822        while cexpr != cexpr_nil:
823            cexpr = cexpr_tail(cexpr)
824            n = n + 1
825        return n
826
827    def __getitem__(BaseExpression self not None, key):
828        cdef cexpr_t cexpr
829        cdef int n
830        cexpr = self.wexpr.cexpr()
831        if is_int(key):
832            n = key
833            if n < 0:
834                n = n + len(self)
835            if n < 0:
836                raise IndexError('list index of out range')
837            while True:
838                if cexpr == cexpr_nil:
839                    raise IndexError('list index of out range')
840                if n > 0:
841                    n = n - 1
842                    cexpr = cexpr_tail(cexpr)
843                else:
844                    cexpr = cexpr_head(cexpr)
845                    break
846        elif is_slice(key):
847            if (is_int(key.start) or key.start is None) and key.stop is None and key.step is None:
848                n = key.start or 0
849                if n < 0:
850                    n = n + len(self)
851                while n > 0 and cexpr != cexpr_nil:
852                    cexpr = cexpr_tail(cexpr)
853                    n = n - 1
854            else:
855                raise NotImplementedError('only [n:] slices are supported')
856        else:
857            raise TypeError('key must be an integer or a slice')
858        return _c2py(cexpr)
859
860    def __setitem__(BaseExpression self not None, key, value):
861        cdef cexpr_t cexpr
862        cdef cexpr_t prev_cexpr
863        cdef cexpr_t new_cexpr
864        cdef int n
865        cdef BaseExpression pyexpr
866        cexpr = self.wexpr.cexpr()
867        pyexpr = _Expression_(value)
868        new_cexpr = pyexpr.wexpr.cexpr()
869        if is_int(key):
870            n = key
871            if n < 0:
872                n = n + len(self)
873            if n < 0:
874                raise IndexError('list index of out range')
875            while True:
876                if cexpr == cexpr_nil:
877                    raise IndexError('list index of out range')
878                if n > 0:
879                    n = n - 1
880                    cexpr = cexpr_tail(cexpr)
881                else:
882                    cexpr_replace_head(cexpr, new_cexpr)
883                    break
884        elif is_slice(key):
885            if not cexpr_is_list(new_cexpr):
886                raise TypeError('can only assign a list expression')
887            if (is_int(key.start) or key.start is None) and key.stop is None and key.step is None:
888                n = key.start or 0
889                if n < 0:
890                    n = n + len(self)
891                prev_cexpr = cexpr_nil
892                while n > 0 and cexpr != cexpr_nil:
893                    prev_cexpr = cexpr
894                    cexpr = cexpr_tail(cexpr)
895                    n = n - 1
896                if prev_cexpr == cexpr_nil:
897                    self.wexpr = wexpr(new_cexpr)
898                else:
899                    cexpr_replace_tail(prev_cexpr, new_cexpr)
900            else:
901                raise NotImplementedError('only [n:] slices are supported')
902        else:
903            raise TypeError('key must be an integer or a slice')
904
905    def __delitem__(BaseExpression self not None, key):
906        if is_int(key):
907            self.pop(key)
908        elif is_slice(key):
909            self[key] = ()
910        else:
911            raise TypeError('key must be an integer or a slice')
912
913    def extend(self, iterable):
914        iter(iterable)
915        self[len(self):] = iterable
916
917    def __iadd__(self, iterable):
918        iter(iterable)
919        self[len(self):] = iterable
920        return self
921
922    def insert(BaseExpression self not None, long index, item):
923        cdef cexpr_t cexpr, new_cexpr
924        cdef BaseExpression citem
925        cexpr = self.wexpr.cexpr()
926        if index < 0:
927            index += len(self)
928        if index < 0:
929            index = 0
930        if typecheck(item, BaseExpression):
931            citem = item
932        else:
933            citem = _Expression_(item)
934        if citem is None:
935            raise TypeError
936        if index == 0 or cexpr == cexpr_nil:
937            gc_lock(NULL)  # protect from collecting a just-created object
938            try:
939                new_cexpr = pair_to_cexpr(citem.wexpr.cexpr(), cexpr)
940                self.wexpr = wexpr(new_cexpr)
941            finally:
942                gc_unlock(NULL)
943            return
944        while True:
945            assert cexpr != cexpr_nil
946            if index > 1 and cexpr_tail(cexpr) != cexpr_nil:
947                index = index - 1
948                cexpr = cexpr_tail(cexpr)
949            else:
950                gc_lock(NULL)  # protect from collecting a just-created object
951                try:
952                    new_cexpr = pair_to_cexpr(citem.wexpr.cexpr(), cexpr_tail(cexpr))
953                    cexpr_replace_tail(cexpr, new_cexpr)
954                finally:
955                    gc_unlock(NULL)
956                break
957
958    def append(BaseExpression self not None, item):
959        return self.insert(len(self), item)
960
961    def reverse(BaseExpression self not None):
962        cdef cexpr_t cexpr, new_cexpr
963        gc_lock(NULL)  # protect from collecting a just-created object
964        try:
965            new_cexpr = cexpr_reverse_list(self.wexpr.cexpr())
966            self.wexpr = wexpr(new_cexpr)
967        finally:
968            gc_unlock(NULL)
969
970    def pop(BaseExpression self not None, long index=-1):
971        cdef cexpr_t cexpr, citem
972        cexpr = self.wexpr.cexpr()
973        if cexpr == cexpr_nil:
974            raise IndexError('pop from empty list')
975        if index < 0:
976            index += len(self)
977        if index < 0:
978            raise IndexError('pop index of out range')
979        if index == 0:
980            result = _c2py(cexpr_head(cexpr))
981            self.wexpr = wexpr(cexpr_tail(cexpr))
982            return result
983        while cexpr_tail(cexpr) != cexpr_nil:
984            if index > 1:
985                index = index - 1
986                cexpr = cexpr_tail(cexpr)
987            else:
988                result = _c2py(cexpr_head(cexpr_tail(cexpr)))
989                cexpr_replace_tail(cexpr, cexpr_tail(cexpr_tail(cexpr)))
990                return result
991        raise IndexError('pop index of out range')
992
993    def remove(BaseExpression self not None, item):
994        cdef cexpr_t cexpr
995        cdef BaseExpression citem
996        cexpr = self.wexpr.cexpr()
997        if cexpr == cexpr_nil:
998            raise IndexError('item not in list')
999        if _c2py(cexpr_head(cexpr)) == item:
1000            self.wexpr = wexpr(cexpr_tail(cexpr))
1001            return
1002        while True:
1003            assert cexpr != cexpr_nil
1004            if cexpr_tail(cexpr) == cexpr_nil:
1005                raise IndexError('item not in list')
1006            if _c2py(cexpr_head(cexpr_tail(cexpr))) == item:
1007                cexpr_replace_tail(cexpr, cexpr_tail(cexpr_tail(cexpr)))
1008                return
1009            cexpr = cexpr_tail(cexpr)
1010
1011    def index(self, value):
1012        # TODO: optimize
1013        for i, v in enumerate(self):
1014            if v == value:
1015                return i
1016        raise ValueError('value not in list')
1017
1018    def count(self, value):
1019        # TODO: optimize
1020        cdef long counter = 0
1021        for v in self:
1022            if v == value:
1023                counter += 1
1024        return counter
1025
1026    def __iter__(self):
1027        return _ListExpressionIterator(self)
1028
1029    __hash__ = None
1030
1031    def _get_value(BaseExpression self not None):
1032        cdef cexpr_t current
1033        current = self.wexpr.cexpr()
1034        result = []
1035        while current != cexpr_nil:
1036            list_append(result, _c2py(cexpr_head(current))._get_value())
1037            current = cexpr_tail(current)
1038        return tuple(result)
1039
1040    def _get_lvalue(BaseExpression self not None):
1041        cdef cexpr_t current
1042        current = self.wexpr.cexpr()
1043        result = []
1044        while current != cexpr_nil:
1045            list_append(result, _c2py(cexpr_head(current))._get_lvalue())
1046            current = cexpr_tail(current)
1047        return result
1048
1049    def __copy__(self):
1050        return _Expression_(self)
1051
1052    def __deepcopy__(self, memo):
1053        return _Expression_(self._get_value())
1054
1055if sys.version_info >= (3, 3):
1056    import collections.abc as collections_abc
1057else:
1058    import collections as collections_abc
1059collections_abc.MutableSequence.register(ListExpression)
1060del collections_abc
1061
1062cdef class _ListExpressionIterator:
1063
1064    cdef BaseExpression expression
1065    cdef cexpr_t cexpr
1066
1067    def __cinit__(self, BaseExpression expression not None):
1068        self.expression = expression
1069        self.cexpr = expression.wexpr.cexpr()
1070
1071    def __next__(self):
1072        cdef cexpr_t cexpr
1073        cexpr = self.cexpr
1074        if cexpr == cexpr_nil:
1075            raise StopIteration
1076        self.cexpr = cexpr_tail(cexpr)
1077        cexpr = cexpr_head(cexpr)
1078        return _c2py(cexpr)
1079
1080    def __iter__(self):
1081        return self
1082
1083
1084__all__ = ('Symbol', 'Expression', 'IntExpression', 'SymbolExpression', 'StringExpression', 'ListExpression', 'InvalidExpression', 'ExpressionSyntaxError')
1085__author__ = 'Jakub Wilk <jwilk@jwilk.net>'
1086IF PY3K:
1087    __version__ = decode_utf8(PYTHON_DJVULIBRE_VERSION)
1088ELSE:
1089    __version__ = str(PYTHON_DJVULIBRE_VERSION)
1090
1091# vim:ts=4 sts=4 sw=4 et ft=pyrex
1092