Added getattr3() builtin
authorStefan Behnel <scoder@users.berlios.de>
Thu, 18 Oct 2007 06:55:15 +0000 (08:55 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 18 Oct 2007 06:55:15 +0000 (08:55 +0200)
Cython/Compiler/Builtin.py [new file with mode: 0644]
Cython/Compiler/ExprNodes.py
Cython/Compiler/Symtab.py

diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py
new file mode 100644 (file)
index 0000000..0d4393e
--- /dev/null
@@ -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()
index 0da16592e7255051f97ac423416dfbf1d03fb36f..dad48de73e1f16439668a3fcb4c4c566ba978012 100644 (file)
@@ -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 "<error>" # 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:
index eea970f6bb438907f929822b58d96dbd75441917..350004f0c7f1dc65bbe56bf4fd484af201803748 100644 (file)
@@ -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