From: Stefan Behnel Date: Thu, 18 Oct 2007 06:55:15 +0000 (+0200) Subject: Added getattr3() builtin X-Git-Tag: 0.9.6.14~29^2~119^2~2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=2dc560a79d00e0f56ac72702f32c67a4420c4a32;p=cython.git Added getattr3() builtin --- diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py new file mode 100644 index 00000000..0d4393ec --- /dev/null +++ b/Cython/Compiler/Builtin.py @@ -0,0 +1,115 @@ +# +# Pyrex - Builtin Definitions +# + +from Symtab import BuiltinScope +from TypeSlots import Signature + +builtin_function_table = [ + # name, args, return, C API func, py equiv = "*" + ('abs', "O", "O", "PyNumber_Absolute"), + #('chr', "", "", ""), + #('cmp', "", "", "", ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) + #('compile', "", "", ""), # PyObject* Py_CompileString( char *str, char *filename, int start) + ('delattr', "OO", "r", "PyObject_DelAttr"), + ('dir', "O", "O", "PyObject_Dir"), + ('divmod', "OO", "O", "PyNumber_Divmod"), + #('eval', "", "", ""), + #('execfile', "", "", ""), + #('filter', "", "", ""), + ('getattr', "OO", "O", "PyObject_GetAttr"), + ('getattr3', "OOO", "O", "__Pyx_GetAttr3", "getattr"), + ('hasattr', "OO", "i", "PyObject_HasAttr"), + ('hash', "O", "i", "PyObject_Hash"), + #('hex', "", "", ""), + #('id', "", "", ""), + #('input', "", "", ""), + ('intern', "s", "O", "PyString_InternFromString"), + ('isinstance', "OO", "i", "PyObject_IsInstance"), + ('issubclass', "OO", "i", "PyObject_IsSubclass"), + ('iter', "O", "O", "PyObject_GetIter"), + ('len', "O", "Z", "PyObject_Length"), + #('map', "", "", ""), + #('max', "", "", ""), + #('min', "", "", ""), + #('oct', "", "", ""), + # Not worth doing open, when second argument would become mandatory + #('open', "ss", "O", "PyFile_FromString"), + #('ord', "", "", ""), + ('pow', "OOO", "O", "PyNumber_Power"), + #('range', "", "", ""), + #('raw_input', "", "", ""), + #('reduce', "", "", ""), + ('reload', "O", "O", "PyImport_ReloadModule"), + ('repr', "O", "O", "PyObject_Repr"), + #('round', "", "", ""), + ('setattr', "OOO", "r", "PyObject_SetAttr"), + #('sum', "", "", ""), + #('unichr', "", "", ""), + #('unicode', "", "", ""), + #('vars', "", "", ""), + #('zip', "", "", ""), + # Can't do these easily until we have builtin type entries. + #('typecheck', "OO", "i", "PyObject_TypeCheck", False), + #('issubtype', "OO", "i", "PyType_IsSubtype", False), +] + +# Builtin types +# bool +# buffer +# classmethod +# dict +# enumerate +# file +# float +# int +# list +# long +# object +# property +# slice +# staticmethod +# super +# str +# tuple +# type +# xrange + +getattr3_utility_code = [""" +static PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); /*proto*/ +""",""" +static PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { + PyObject *r = PyObject_GetAttr(o, n); + if (!r) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + goto bad; + PyErr_Clear(); + r = d; + Py_INCREF(d); + } + return r; +bad: + return 0; +} +"""] + +builtin_utility_code = { + 'getattr3': getattr3_utility_code, +} + +builtin_scope = BuiltinScope() + +def declare_builtin_func(name, args, ret, cname, py_equiv = "*"): + sig = Signature(args, ret) + type = sig.function_type() + utility = builtin_utility_code.get(name) + builtin_scope.declare_builtin_cfunction(name, type, cname, py_equiv, utility) + +def init_builtin_funcs(): + for desc in builtin_function_table: + declare_builtin_func(*desc) + +def init_builtins(): + init_builtin_funcs() + +init_builtins() diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 0da16592..dad48de7 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -99,9 +99,9 @@ class ExprNode(Node): # temps used during assignment. # # calculate_result_code - # - Return a C code fragment evaluating to - # the result. This is only called when the - # result is not a temporary. + # - Called during the Allocate Temps phase. Should return a + # C code fragment evaluating to the result. This is only + # called when the result is not a temporary. # # target_code # Called by the default implementation of allocate_target_temps. @@ -365,7 +365,10 @@ class ExprNode(Node): if debug_temp_alloc: print self, "Allocated result", self.result_code else: - self.result_code = self.calculate_result_code() + self.result_code = self.calculate_result_code_with_env(env) + + def calculate_result_code_with_env(self, env): + return self.calculate_result_code() def target_code(self): # Return code fragment for use as LHS of a C assignment. @@ -814,13 +817,13 @@ class NameNode(AtomicExprNode): if entry.is_pyglobal or entry.is_builtin: assert type.is_pyobject, "Python global or builtin not a Python object" if Options.intern_names: - self.interned_cname = env.intern(self.name) + self.interned_cname = env.intern(self.entry.name) def check_identifier_kind(self): #print "NameNode.check_identifier_kind:", self.entry.name ### #print self.entry.__dict__ ### entry = self.entry - entry.used = 1 + #entry.used = 1 if not (entry.is_const or entry.is_variable or entry.is_builtin or entry.is_cfunction): if self.entry.as_variable: @@ -856,15 +859,23 @@ class NameNode(AtomicExprNode): # result is in a temporary. return 0 + def calculate_result_code_with_env(self, env): + entry = self.entry + if entry: + entry.used = 1 + if entry.utility_code: + env.use_utility_code(entry.utility_code) + return self.calculate_result_code() + def calculate_result_code(self): - if self.entry is None: + entry = self.entry + if not entry: return "" # There was an error earlier - return self.entry.cname + entry.used = 1 + return entry.cname def generate_result_code(self, code): assert hasattr(self, 'entry') - #if not hasattr(self, 'entry'): - # error(self.pos, "INTERNAL ERROR: NameNode has no entry attribute during code generation") entry = self.entry if entry is None: return # There was an error earlier @@ -876,12 +887,10 @@ class NameNode(AtomicExprNode): else: # entry.is_pyglobal namespace = entry.namespace_cname if Options.intern_names: - #assert entry.interned_cname is not None code.putln( '%s = __Pyx_GetName(%s, %s); %s' % ( self.result_code, namespace, - #entry.interned_cname, self.interned_cname, code.error_goto_if_null(self.result_code, self.pos))) else: diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index eea970f6..350004f0 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -69,6 +69,7 @@ class Entry: # of an extension type # defined_in_pxd boolean Is defined in a .pxd file (not just declared) # api boolean Generate C API for C class or function + # utility_code string Utility code needed when this entry is used borrowed = 0 init = "" @@ -105,6 +106,7 @@ class Entry: is_special = 0 defined_in_pxd = 0 api = 0 + utility_code = None def __init__(self, name, cname, type, pos = None, init = None): self.name = name @@ -574,13 +576,19 @@ class BuiltinScope(Scope): self.cached_entries.append(entry) self.undeclared_cached_entries.append(entry) else: - entry.is_builtin = 1 + entry.is_builtin = 1 return entry - - def declare_builtin_cfunction(self, name, type, cname, with_python_equiv = 0): + + def declare_builtin_cfunction(self, name, type, cname, python_equiv = None, + utility_code = None): + # If python_equiv == "*", the Python equivalent has the same name + # as the entry, otherwise it has the name specified by python_equiv. entry = self.declare_cfunction(name, type, None, cname) - if with_python_equiv: - var_entry = Entry(name, name, py_object_type) + entry.utility_code = utility_code + if python_equiv: + if python_equiv == "*": + python_equiv = name + var_entry = Entry(python_equiv, python_equiv, py_object_type) var_entry.is_variable = 1 var_entry.is_builtin = 1 entry.as_variable = var_entry