PageRenderTime 90ms CodeModel.GetById 52ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/nuitka/codegen/Identifiers.py

https://bitbucket.org/pombredanne/nuitka
Python | 340 lines | 312 code | 4 blank | 24 comment | 2 complexity | edf329be77a4767c7681575d956c7a49 MD5 | raw file
  1#     Copyright 2013, Kay Hayen, mailto:kay.hayen@gmail.com
  2#
  3#     Part of "Nuitka", an optimizing Python compiler that is compatible and
  4#     integrates with CPython, but also works on its own.
  5#
  6#     Licensed under the Apache License, Version 2.0 (the "License");
  7#     you may not use this file except in compliance with the License.
  8#     You may obtain a copy of the License at
  9#
 10#        http://www.apache.org/licenses/LICENSE-2.0
 11#
 12#     Unless required by applicable law or agreed to in writing, software
 13#     distributed under the License is distributed on an "AS IS" BASIS,
 14#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15#     See the License for the specific language governing permissions and
 16#     limitations under the License.
 17#
 18""" Identifiers hold code references.
 19
 20These are generally the means to effectively hide the reference count. The best part
 21is where getCheapRefCount tries to not allocate references not needed.
 22"""
 23
 24# The method signatures do not always require usage of self, sometimes can be decided
 25# based on class. pylint: disable=R0201
 26
 27from nuitka import Utils
 28
 29def encodeNonAscii( var_name ):
 30    if Utils.python_version < 300:
 31        return var_name
 32    else:
 33        var_name = var_name.encode( "ascii", "xmlcharrefreplace" )
 34
 35        return var_name.decode( "ascii" ).replace( "&#", "$$" ).replace( ";", "" )
 36
 37class Identifier:
 38    def __init__( self, code, ref_count ):
 39        self.code = code
 40        self.ref_count = ref_count
 41
 42    def getRefCount( self ):
 43        return self.ref_count
 44
 45    def getCheapRefCount( self ):
 46        return self.ref_count
 47
 48    def getCode( self ):
 49        return self.code
 50
 51    def getCodeObject( self ):
 52        return self.code
 53
 54    def getCodeExportRef( self ):
 55        if self.getRefCount():
 56            return self.getCodeObject()
 57        else:
 58            return "INCREASE_REFCOUNT( %s )" % self.getCodeObject()
 59
 60    def getCodeTemporaryRef( self ):
 61        if self.getRefCount():
 62            return "PyObjectTemporary( %s ).asObject()" % self.getCodeObject()
 63        else:
 64            return self.getCodeObject()
 65
 66    def getCodeDropRef( self ):
 67        if self.ref_count == 0:
 68            return self.getCodeTemporaryRef()
 69        else:
 70            return "DECREASE_REFCOUNT( %s )" % self.getCodeObject()
 71
 72    def __repr__( self ):
 73        return "<Identifier %s (%d)>" % ( self.code, self.ref_count )
 74
 75    def isConstantIdentifier( self ):
 76        return False
 77
 78
 79class ConstantIdentifier( Identifier ):
 80    def __init__( self, constant_code, constant_value ):
 81        Identifier.__init__( self, constant_code, 0 )
 82
 83        self.constant_value = constant_value
 84
 85    def __repr__( self ):
 86        return "<ConstantIdentifier %s>" % self.code
 87
 88    def isConstantIdentifier( self ):
 89        return True
 90
 91    def getCheapRefCount( self ):
 92        return 0
 93
 94    def getConstant( self ):
 95        return self.constant_value
 96
 97
 98class SpecialConstantIdentifier( ConstantIdentifier ):
 99    def __init__( self, constant_value ):
100        if constant_value is None:
101            ConstantIdentifier.__init__( self, "Py_None", None )
102        elif constant_value is True:
103            ConstantIdentifier.__init__( self, "Py_True", True )
104        elif constant_value is False:
105            ConstantIdentifier.__init__( self, "Py_False", False )
106        elif constant_value is Ellipsis:
107            ConstantIdentifier.__init__( self, "Py_Ellipsis", Ellipsis )
108        else:
109            assert False, constant_value
110
111
112class EmptyDictIdentifier( Identifier ):
113    def __init__( self ):
114        Identifier.__init__( self, "PyDict_New()", 1 )
115
116    def getCheapRefCount( self ):
117        return 1
118
119    def isConstantIdentifier( self ):
120        return True
121
122    def getConstant( self ):
123        return {}
124
125
126class ModuleVariableIdentifier:
127    def __init__( self, var_name, module_code_name ):
128        self.var_name = var_name
129        self.module_code_name = module_code_name
130
131    def isConstantIdentifier( self ):
132        return False
133
134    def __repr__( self ):
135        return "<ModuleVariableIdentifier %s>" % self.var_name
136
137    def getRefCount( self ):
138        return 0
139
140    def getCheapRefCount( self ):
141        # The asObject0 is the fastest way, stealing a reference directly from the module
142        # dictionary if possible.
143        return 0
144
145    def getCodeTemporaryRef( self ):
146        return "_mvar_%s_%s.asObject0()" % ( self.module_code_name, self.var_name )
147
148    def getCodeExportRef( self ):
149        return "_mvar_%s_%s.asObject()" % ( self.module_code_name, self.var_name )
150
151    def getCodeDropRef( self ):
152        return self.getCodeTemporaryRef()
153
154    def getCode( self ):
155        return "_mvar_%s_%s" % ( self.module_code_name, encodeNonAscii( self.var_name ) )
156
157
158class MaybeModuleVariableIdentifier( Identifier ):
159    def __init__( self, var_name, module_code_name ):
160        Identifier.__init__(
161            self,
162            "_mvar_%s_%s.asObject0( locals_dict.asObject() )" % (
163                module_code_name,
164                var_name
165            ),
166            0
167        )
168
169
170class LocalVariableIdentifier:
171    def __init__( self, var_name, from_context = False ):
172        assert type( var_name ) == str
173
174        self.from_context = from_context
175        self.var_name = var_name
176
177    def isConstantIdentifier( self ):
178        return False
179
180    def __repr__( self ):
181        return "<LocalVariableIdentifier %s>" % self.var_name
182
183    def getCode( self ):
184        if not self.from_context:
185            return "_python_var_" + encodeNonAscii( self.var_name )
186        else:
187            return "_python_context->python_var_" + encodeNonAscii( self.var_name )
188
189    def getRefCount( self ):
190        return 0
191
192    def getCheapRefCount( self ):
193        return 0
194
195    def getCodeObject( self ):
196        return "%s.asObject()" % self.getCode()
197
198    def getCodeTemporaryRef( self ):
199        return "%s.asObject()" % self.getCode()
200
201    def getCodeExportRef( self ):
202        return "%s.asObject1()" % self.getCode()
203
204    def getCodeDropRef( self ):
205        return self.getCodeTemporaryRef()
206
207
208class TempVariableIdentifier( Identifier ):
209    def __init__( self, var_name ):
210        self.tempvar_name = var_name
211
212        Identifier.__init__( self, "_python_tmp_" + var_name, 0 )
213
214    def __repr__( self ):
215        return "<TempVariableIdentifier %s >" % self.tempvar_name
216
217    def getCheapRefCount( self ):
218        return 0
219
220    def getCodeObject( self ):
221        return "%s.asObject()" % self.getCode()
222
223    def getClass( self ):
224        return "PyObjectTemporary"
225
226
227class TempObjectIdentifier( Identifier ):
228    def __init__( self, var_name ):
229        self.tempvar_name = var_name
230
231        Identifier.__init__( self, "_python_tmp_" + var_name, 0 )
232
233    def getCodeTemporaryRef( self ):
234        return self.code
235
236
237class ClosureVariableIdentifier( Identifier ):
238    def __init__( self, var_name, from_context ):
239        assert type( from_context ) is str
240
241        self.var_name = var_name
242        self.from_context = from_context
243
244        if self.from_context:
245            Identifier.__init__( self, self.from_context + "python_closure_" + encodeNonAscii( self.var_name ), 0 )
246        else:
247            # TODO: Use a variable object to decide naming policy
248
249            Identifier.__init__( self, "python_closure_" + encodeNonAscii( self.var_name ), 0 )
250
251    def __repr__( self ):
252        return "<ClosureVariableIdentifier %s >" % self.var_name
253
254    def getCheapRefCount( self ):
255        return 0
256
257    def getCodeObject( self ):
258        return self.getCode() + ".asObject()"
259
260
261class DefaultValueIdentifier( Identifier ):
262    def __init__( self, count ):
263        Identifier.__init__(
264            self,
265            code      = "PyTuple_GET_ITEM( self->m_defaults, %d )" % count,
266            ref_count = 0
267        )
268
269    def getCheapRefCount( self ):
270        return 0
271
272
273class NullIdentifier( Identifier ):
274    def __init__( self ):
275        Identifier.__init__(
276            self,
277            code      = "NULL",
278            ref_count = 0
279        )
280
281    def getCodeExportRef( self ):
282        return "NULL"
283
284
285class ThrowingIdentifier( Identifier ):
286    def __init__( self, code ):
287        Identifier.__init__(
288            self,
289            code      = code,
290            ref_count = 0
291        )
292
293    def getCodeExportRef( self ):
294        return self.getCodeObject()
295
296    def getCodeTemporaryRef( self ):
297        return self.getCodeObject()
298
299    def getCheapRefCount( self ):
300        return 0
301
302
303class CallIdentifier( Identifier ):
304    def __init__( self, called, args ):
305        Identifier.__init__(
306            self,
307            code      = "%s( %s )" % (
308                called,
309                ", ".join( args )
310            ),
311            ref_count = 1
312        )
313
314
315class HelperCallIdentifier( CallIdentifier ):
316    def __init__( self, helper, *args ):
317        CallIdentifier.__init__(
318            self,
319            called = helper,
320            args   = [
321                arg.getCodeTemporaryRef() if arg is not None else "NULL"
322                for arg in
323                args
324            ]
325        )
326
327
328def getCodeTemporaryRefs( identifiers ):
329    """ Helper to create temporary reference code of many identifiers at once.
330
331    """
332
333    return [ identifier.getCodeTemporaryRef() for identifier in identifiers ]
334
335def getCodeExportRefs( identifiers ):
336    """ Helper to create export reference code of many identifiers at once.
337
338    """
339
340    return [ identifier.getCodeExportRef() for identifier in identifiers ]