1# Python bindings for Yasm: Pyrex input file for symrec.h
2#
3#  Copyright (C) 2006  Michael Urman, Peter Johnson
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
15# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
18# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24# POSSIBILITY OF SUCH DAMAGE.
25
26cdef class Symbol:
27    cdef yasm_symrec *sym
28
29    def __cinit__(self, symrec):
30        self.sym = NULL
31        if PyCObject_Check(symrec):
32            self.sym = <yasm_symrec *>__get_voidp(symrec, Symbol)
33        else:
34            raise NotImplementedError
35
36    # no deref or destroy necessary
37
38    property name:
39        def __get__(self): return yasm_symrec_get_name(self.sym)
40
41    property status:
42        def __get__(self):
43            cdef yasm_sym_status status
44            s = set()
45            status = yasm_symrec_get_status(self.sym)
46            if <int>status & <int>YASM_SYM_USED: s.add('used')
47            if <int>status & <int>YASM_SYM_DEFINED: s.add('defined')
48            if <int>status & <int>YASM_SYM_VALUED: s.add('valued')
49            return s
50
51    property in_table:
52        def __get__(self):
53            return bool(<int>yasm_symrec_get_status(self.sym) &
54                        <int>YASM_SYM_NOTINTABLE)
55
56    property visibility:
57        def __get__(self):
58            cdef yasm_sym_vis vis
59            s = set()
60            vis = yasm_symrec_get_visibility(self.sym)
61            if <int>vis & <int>YASM_SYM_GLOBAL: s.add('global')
62            if <int>vis & <int>YASM_SYM_COMMON: s.add('common')
63            if <int>vis & <int>YASM_SYM_EXTERN: s.add('extern')
64            if <int>vis & <int>YASM_SYM_DLOCAL: s.add('dlocal')
65            return s
66
67    property equ:
68        def __get__(self):
69            cdef yasm_expr *e
70            e = yasm_symrec_get_equ(self.sym)
71            if not e:
72                raise AttributeError("not an EQU")
73            return __make_expression(yasm_expr_copy(e))
74
75    property label:
76        def __get__(self):
77            cdef yasm_symrec_get_label_bytecodep bc
78            if yasm_symrec_get_label(self.sym, &bc):
79                return None #Bytecode(bc)
80            else:
81                raise AttributeError("not a label or not defined")
82
83    property is_special:
84        def __get__(self): return bool(yasm_symrec_is_special(self.sym))
85
86    property is_curpos:
87        def __get__(self): return bool(yasm_symrec_is_curpos(self.sym))
88
89    def get_data(self): pass # TODO
90        #return <object>(yasm_symrec_get_data(self.sym, PyYasmAssocData))
91
92    def set_data(self, data): pass # TODO
93        #yasm_symrec_set_data(self.sym, PyYasmAssocData, data)
94
95#
96# Use associated data mechanism to keep Symbol reference paired with symrec.
97#
98
99cdef void __python_symrec_cb_destroy(void *data):
100    Py_DECREF(<object>data)
101cdef void __python_symrec_cb_print(void *data, FILE *f, int indent_level):
102    pass
103__python_symrec_cb = __assoc_data_callback(
104        PyCObject_FromVoidPtr(&__python_symrec_cb_destroy, NULL),
105        PyCObject_FromVoidPtr(&__python_symrec_cb_print, NULL))
106
107cdef object __make_symbol(yasm_symrec *symrec):
108    cdef void *data
109    __error_check()
110    data = yasm_symrec_get_data(symrec,
111                                (<__assoc_data_callback>__python_symrec_cb).cb)
112    if data != NULL:
113        return <object>data
114    symbol = Symbol(__pass_voidp(symrec, Symbol))
115    yasm_symrec_add_data(symrec,
116                         (<__assoc_data_callback>__python_symrec_cb).cb,
117                         <void *>symbol)
118    Py_INCREF(symbol)       # We're keeping a reference on the C side!
119    return symbol
120
121cdef class Bytecode
122cdef class SymbolTable
123
124cdef class SymbolTableKeyIterator:
125    cdef yasm_symtab_iter *iter
126
127    def __cinit__(self, symtab):
128        if not isinstance(symtab, SymbolTable):
129            raise TypeError
130        self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
131
132    def __iter__(self):
133        return self
134
135    def __next__(self):
136        if self.iter == NULL:
137            raise StopIteration
138        rv = yasm_symrec_get_name(yasm_symtab_iter_value(self.iter))
139        self.iter = yasm_symtab_next(self.iter)
140        return rv
141
142cdef class SymbolTableValueIterator:
143    cdef yasm_symtab_iter *iter
144
145    def __cinit__(self, symtab):
146        if not isinstance(symtab, SymbolTable):
147            raise TypeError
148        self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
149
150    def __iter__(self):
151        return self
152
153    def __next__(self):
154        if self.iter == NULL:
155            raise StopIteration
156        rv = __make_symbol(yasm_symtab_iter_value(self.iter))
157        self.iter = yasm_symtab_next(self.iter)
158        return rv
159
160cdef class SymbolTableItemIterator:
161    cdef yasm_symtab_iter *iter
162
163    def __cinit__(self, symtab):
164        if not isinstance(symtab, SymbolTable):
165            raise TypeError
166        self.iter = yasm_symtab_first((<SymbolTable>symtab).symtab)
167
168    def __iter__(self):
169        return self
170
171    def __next__(self):
172        cdef yasm_symrec *sym
173        if self.iter == NULL:
174            raise StopIteration
175        sym = yasm_symtab_iter_value(self.iter)
176        rv = (yasm_symrec_get_name(sym), __make_symbol(sym))
177        self.iter = yasm_symtab_next(self.iter)
178        return rv
179
180cdef int __parse_vis(vis) except -1:
181    if not vis or vis == 'local': return YASM_SYM_LOCAL
182    if vis == 'global': return YASM_SYM_GLOBAL
183    if vis == 'common': return YASM_SYM_COMMON
184    if vis == 'extern': return YASM_SYM_EXTERN
185    if vis == 'dlocal': return YASM_SYM_DLOCAL
186    msg = "bad visibility value %r" % vis
187    PyErr_SetString(ValueError, msg)
188    return -1
189
190cdef class SymbolTable:
191    cdef yasm_symtab *symtab
192
193    def __cinit__(self):
194        self.symtab = yasm_symtab_create()
195
196    def __dealloc__(self):
197        if self.symtab != NULL: yasm_symtab_destroy(self.symtab)
198
199    def use(self, name, line):
200        return __make_symbol(yasm_symtab_use(self.symtab, name, line))
201
202    def define_equ(self, name, expr, line):
203        if not isinstance(expr, Expression):
204            raise TypeError
205        return __make_symbol(yasm_symtab_define_equ(self.symtab, name,
206                yasm_expr_copy((<Expression>expr).expr), line))
207
208    def define_label(self, name, precbc, in_table, line):
209        if not isinstance(precbc, Bytecode):
210            raise TypeError
211        return __make_symbol(yasm_symtab_define_label(self.symtab, name,
212                (<Bytecode>precbc).bc, in_table, line))
213
214    def define_special(self, name, vis):
215        return __make_symbol(
216            yasm_symtab_define_special(self.symtab, name,
217                                       <yasm_sym_vis>__parse_vis(vis)))
218
219    def declare(self, name, vis, line):
220        return __make_symbol(
221            yasm_symtab_declare(self.symtab, name,
222                                <yasm_sym_vis>__parse_vis(vis), line))
223
224    #
225    # Methods to make SymbolTable behave like a dictionary of Symbols.
226    #
227
228    def __getitem__(self, key):
229        cdef yasm_symrec *symrec
230        symrec = yasm_symtab_get(self.symtab, key)
231        if symrec == NULL:
232            raise KeyError
233        return __make_symbol(symrec)
234
235    def __contains__(self, key):
236        cdef yasm_symrec *symrec
237        symrec = yasm_symtab_get(self.symtab, key)
238        return symrec != NULL
239
240    def keys(self):
241        cdef yasm_symtab_iter *iter
242        l = []
243        iter = yasm_symtab_first(self.symtab)
244        while iter != NULL:
245            l.append(yasm_symrec_get_name(yasm_symtab_iter_value(iter)))
246            iter = yasm_symtab_next(iter)
247        return l
248
249    def values(self):
250        cdef yasm_symtab_iter *iter
251        l = []
252        iter = yasm_symtab_first(self.symtab)
253        while iter != NULL:
254            l.append(__make_symbol(yasm_symtab_iter_value(iter)))
255            iter = yasm_symtab_next(iter)
256        return l
257
258    def items(self):
259        cdef yasm_symtab_iter *iter
260        cdef yasm_symrec *sym
261        l = []
262        iter = yasm_symtab_first(self.symtab)
263        while iter != NULL:
264            sym = yasm_symtab_iter_value(iter)
265            l.append((yasm_symrec_get_name(sym), __make_symbol(sym)))
266            iter = yasm_symtab_next(iter)
267        return l
268
269    def has_key(self, key):
270        cdef yasm_symrec *symrec
271        symrec = yasm_symtab_get(self.symtab, key)
272        return symrec != NULL
273
274    def get(self, key, x):
275        cdef yasm_symrec *symrec
276        symrec = yasm_symtab_get(self.symtab, key)
277        if symrec == NULL:
278            return x
279        return __make_symbol(symrec)
280
281    def iterkeys(self): return SymbolTableKeyIterator(self)
282    def itervalues(self): return SymbolTableValueIterator(self)
283    def iteritems(self): return SymbolTableItemIterator(self)
284    def __iter__(self): return SymbolTableKeyIterator(self)
285
286