Commit 2dc560a7 authored by Stefan Behnel's avatar Stefan Behnel

Added getattr3() builtin

parent 0f319c23
#
# 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()
...@@ -99,9 +99,9 @@ class ExprNode(Node): ...@@ -99,9 +99,9 @@ class ExprNode(Node):
# temps used during assignment. # temps used during assignment.
# #
# calculate_result_code # calculate_result_code
# - Return a C code fragment evaluating to # - Called during the Allocate Temps phase. Should return a
# the result. This is only called when the # C code fragment evaluating to the result. This is only
# result is not a temporary. # called when the result is not a temporary.
# #
# target_code # target_code
# Called by the default implementation of allocate_target_temps. # Called by the default implementation of allocate_target_temps.
...@@ -365,7 +365,10 @@ class ExprNode(Node): ...@@ -365,7 +365,10 @@ class ExprNode(Node):
if debug_temp_alloc: if debug_temp_alloc:
print self, "Allocated result", self.result_code print self, "Allocated result", self.result_code
else: 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): def target_code(self):
# Return code fragment for use as LHS of a C assignment. # Return code fragment for use as LHS of a C assignment.
...@@ -814,13 +817,13 @@ class NameNode(AtomicExprNode): ...@@ -814,13 +817,13 @@ class NameNode(AtomicExprNode):
if entry.is_pyglobal or entry.is_builtin: if entry.is_pyglobal or entry.is_builtin:
assert type.is_pyobject, "Python global or builtin not a Python object" assert type.is_pyobject, "Python global or builtin not a Python object"
if Options.intern_names: if Options.intern_names:
self.interned_cname = env.intern(self.name) self.interned_cname = env.intern(self.entry.name)
def check_identifier_kind(self): def check_identifier_kind(self):
#print "NameNode.check_identifier_kind:", self.entry.name ### #print "NameNode.check_identifier_kind:", self.entry.name ###
#print self.entry.__dict__ ### #print self.entry.__dict__ ###
entry = self.entry entry = self.entry
entry.used = 1 #entry.used = 1
if not (entry.is_const or entry.is_variable if not (entry.is_const or entry.is_variable
or entry.is_builtin or entry.is_cfunction): or entry.is_builtin or entry.is_cfunction):
if self.entry.as_variable: if self.entry.as_variable:
...@@ -856,15 +859,23 @@ class NameNode(AtomicExprNode): ...@@ -856,15 +859,23 @@ class NameNode(AtomicExprNode):
# result is in a temporary. # result is in a temporary.
return 0 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): def calculate_result_code(self):
if self.entry is None: entry = self.entry
if not entry:
return "<error>" # There was an error earlier return "<error>" # There was an error earlier
return self.entry.cname entry.used = 1
return entry.cname
def generate_result_code(self, code): def generate_result_code(self, code):
assert hasattr(self, 'entry') 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 entry = self.entry
if entry is None: if entry is None:
return # There was an error earlier return # There was an error earlier
...@@ -876,12 +887,10 @@ class NameNode(AtomicExprNode): ...@@ -876,12 +887,10 @@ class NameNode(AtomicExprNode):
else: # entry.is_pyglobal else: # entry.is_pyglobal
namespace = entry.namespace_cname namespace = entry.namespace_cname
if Options.intern_names: if Options.intern_names:
#assert entry.interned_cname is not None
code.putln( code.putln(
'%s = __Pyx_GetName(%s, %s); %s' % ( '%s = __Pyx_GetName(%s, %s); %s' % (
self.result_code, self.result_code,
namespace, namespace,
#entry.interned_cname,
self.interned_cname, self.interned_cname,
code.error_goto_if_null(self.result_code, self.pos))) code.error_goto_if_null(self.result_code, self.pos)))
else: else:
......
...@@ -69,6 +69,7 @@ class Entry: ...@@ -69,6 +69,7 @@ class Entry:
# of an extension type # of an extension type
# defined_in_pxd boolean Is defined in a .pxd file (not just declared) # defined_in_pxd boolean Is defined in a .pxd file (not just declared)
# api boolean Generate C API for C class or function # api boolean Generate C API for C class or function
# utility_code string Utility code needed when this entry is used
borrowed = 0 borrowed = 0
init = "" init = ""
...@@ -105,6 +106,7 @@ class Entry: ...@@ -105,6 +106,7 @@ class Entry:
is_special = 0 is_special = 0
defined_in_pxd = 0 defined_in_pxd = 0
api = 0 api = 0
utility_code = None
def __init__(self, name, cname, type, pos = None, init = None): def __init__(self, name, cname, type, pos = None, init = None):
self.name = name self.name = name
...@@ -574,13 +576,19 @@ class BuiltinScope(Scope): ...@@ -574,13 +576,19 @@ class BuiltinScope(Scope):
self.cached_entries.append(entry) self.cached_entries.append(entry)
self.undeclared_cached_entries.append(entry) self.undeclared_cached_entries.append(entry)
else: else:
entry.is_builtin = 1 entry.is_builtin = 1
return entry 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) entry = self.declare_cfunction(name, type, None, cname)
if with_python_equiv: entry.utility_code = utility_code
var_entry = Entry(name, name, py_object_type) 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_variable = 1
var_entry.is_builtin = 1 var_entry.is_builtin = 1
entry.as_variable = var_entry entry.as_variable = var_entry
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment