Commit 26634fc5 authored by Stefan Behnel's avatar Stefan Behnel

merged in changes from Cython 0.9.6.7

parents df831940 997ac5b6
......@@ -85,7 +85,8 @@ class CCodeWriter:
try:
return self.input_file_contents[file]
except KeyError:
F = open(file).readlines()
F = [line.replace('*/', '*[inserted by cython to avoid comment closer]/')
for line in open(file).readlines()]
self.input_file_contents[file] = F
return F
......
......@@ -596,6 +596,22 @@ class CharNode(ConstNode):
class IntNode(ConstNode):
type = PyrexTypes.c_long_type
def coerce_to(self, dst_type, env):
# Arrange for a Python version of the string to be pre-allocated
# when coercing to a Python type.
if dst_type.is_pyobject:
self.entry = env.get_py_num(self.value)
self.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type,
# in which case a type test node will be needed.
return ConstNode.coerce_to(self, dst_type, env)
def calculate_result_code(self):
if self.type.is_pyobject:
return self.entry.cname
else:
return str(self.value)
class FloatNode(ConstNode):
type = PyrexTypes.c_double_type
......@@ -814,24 +830,45 @@ class NameNode(AtomicExprNode):
entry = self.entry
if entry is None:
return # There was an error earlier
# is_pyglobal seems to be True for module level-globals only.
# We use this to access class->tp_dict if necessary.
if entry.is_pyglobal:
namespace = self.entry.namespace_cname
if Options.intern_names:
code.put_error_if_neg(self.pos,
'PyObject_SetAttr(%s, %s, %s)' % (
namespace,
entry.interned_cname,
rhs.py_result()))
else:
code.put_error_if_neg(self.pos,
'PyObject_SetAttrString(%s, "%s", %s)' % (
namespace,
entry.name,
rhs.py_result()))
if debug_disposal_code:
print "NameNode.generate_assignment_code:"
print "...generating disposal code for", rhs
rhs.generate_disposal_code(code)
if entry.is_member:
# if we entry is a member we have to cheat: SetAttr does not work
# on types, so we create a descriptor which is then added to tp_dict
if Options.intern_names:
code.put_error_if_neg(self.pos,
'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
namespace,
entry.interned_cname,
rhs.py_result()))
else:
code.put_error_if_neg(self.pos,
'PyDict_SetItemString(%s->tp_dict, %s, %s)' % (
namespace,
entry.name,
rhs.py_result()))
else:
if Options.intern_names:
code.put_error_if_neg(self.pos,
'PyObject_SetAttr(%s, %s, %s)' % (
namespace,
entry.interned_cname,
rhs.py_result()))
else:
code.put_error_if_neg(self.pos,
'PyObject_SetAttrString(%s, "%s", %s)' % (
namespace,
entry.name,
rhs.py_result()))
if debug_disposal_code:
print "NameNode.generate_assignment_code:"
print "...generating disposal code for", rhs
rhs.generate_disposal_code(code)
else:
if self.type.is_pyobject:
#print "NameNode.generate_assignment_code: to", self.name ###
......@@ -1012,6 +1049,9 @@ class TempNode(AtomicExprNode):
if type.is_pyobject:
self.result_ctype = py_object_type
self.is_temp = 1
def analyse_types(self, env):
return self.type
def generate_result_code(self, code):
pass
......@@ -1654,6 +1694,8 @@ class AttributeNode(ExprNode):
entry = None
if obj_type.attributes_known():
entry = obj_type.scope.lookup_here(self.attribute)
if entry and entry.is_member:
entry = None
else:
error(self.pos,
"Cannot select attribute of incomplete type '%s'"
......@@ -1663,6 +1705,8 @@ class AttributeNode(ExprNode):
if entry:
if obj_type.is_extension_type and entry.name == "__weakref__":
error(self.pos, "Illegal use of special attribute __weakref__")
# methods need the normal attribute lookup
# because they do not have struct entries
if entry.is_variable or entry.is_cmethod:
self.type = entry.type
self.member = entry.cname
......@@ -2295,6 +2339,8 @@ unop_node_classes = {
def unop_node(pos, operator, operand):
# Construct unnop node of appropriate class for
# given operator.
if isinstance(operand, IntNode) and operator == '-':
return IntNode(pos = operand.pos, value = -int(operand.value))
return unop_node_classes[operator](pos,
operator = operator,
operand = operand)
......@@ -2716,7 +2762,7 @@ class BoolBinopNode(ExprNode):
if self.type.is_pyobject:
test_result = self.temp_bool.result_code
code.putln(
"%s = PyObject_IsTrue(%s); %s" % (
"%s = __Pyx_PyObject_IsTrue(%s); %s" % (
test_result,
self.operand1.py_result(),
code.error_goto_if_neg(test_result, self.pos)))
......@@ -2742,15 +2788,14 @@ class CondExprNode(ExprNode):
self.true_val.analyse_types(env)
self.false_val.analyse_types(env)
self.type = self.compute_result_type(self.true_val.type, self.false_val.type)
if self.type:
if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
self.true_val = self.true_val.coerce_to(self.type, env)
self.false_val = self.false_val.coerce_to(self.type, env)
# must be tmp variables so they can share a result
self.true_val = self.true_val.coerce_to_temp(env)
self.false_val = self.false_val.coerce_to_temp(env)
self.is_temp = 1
else:
if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
self.true_val = self.true_val.coerce_to(self.type, env)
self.false_val = self.false_val.coerce_to(self.type, env)
# must be tmp variables so they can share a result
self.true_val = self.true_val.coerce_to_temp(env)
self.false_val = self.false_val.coerce_to_temp(env)
self.is_temp = 1
if self.type == PyrexTypes.error_type:
self.type_error()
def allocate_temps(self, env, result_code = None):
......@@ -2784,15 +2829,19 @@ class CondExprNode(ExprNode):
return type1
elif type1.is_pyobject or type2.is_pyobject:
return py_object_type
elif type1.assignable_from(type2):
return type1
elif type2.assignable_from(type1):
return type2
else:
return None
return PyrexTypes.error_type
def type_error(self):
if not (self.true_val.type.is_error or self.false_val.type.is_error):
error(self.pos, "Incompatable types in conditional expression (%s; %s)" %
(self.true_val.type, self.false_val.type))
self.type = PyrexTypes.error_type
def check_const(self):
self.test.check_const()
self.true_val.check_const()
......@@ -2807,6 +2856,16 @@ class CondExprNode(ExprNode):
code.putln("}")
self.test.generate_disposal_code(code)
richcmp_constants = {
"<" : "Py_LT",
"<=": "Py_LE",
"==": "Py_EQ",
"!=": "Py_NE",
"<>": "Py_NE",
">" : "Py_GT",
">=": "Py_GE",
}
class CmpNode:
# Mixin class containing code common to PrimaryCmpNodes
# and CascadedCmpNodes.
......@@ -2816,6 +2875,10 @@ class CmpNode:
or (self.cascade and self.cascade.is_python_comparison())
or self.operator in ('in', 'not_in'))
def is_python_result(self):
return ((self.has_python_operands() and self.operator not in ('is', 'is_not', 'in', 'not_in'))
or (self.cascade and self.cascade.is_python_result()))
def check_types(self, env, operand1, op, operand2):
if not self.types_okay(operand1, op, operand2):
error(self.pos, "Invalid types for '%s' (%s, %s)" %
......@@ -2842,33 +2905,40 @@ class CmpNode:
def generate_operation_code(self, code, result_code,
operand1, op , operand2):
if self.type is PyrexTypes.py_object_type:
coerce_result = "__Pyx_PyBool_FromLong"
else:
coerce_result = ""
if 'not' in op: negation = "!"
else: negation = ""
if op == 'in' or op == 'not_in':
code.putln(
"%s = PySequence_Contains(%s, %s); %s" % (
"%s = %s(%sPySequence_Contains(%s, %s)); %s" % (
result_code,
coerce_result,
negation,
operand2.py_result(),
operand1.py_result(),
code.error_goto_if_neg(result_code, self.pos)))
if op == 'not_in':
code.putln(
"%s = !%s;" % (
result_code, result_code))
elif (operand1.type.is_pyobject
and op not in ('is', 'is_not')):
code.put_error_if_neg(self.pos,
"PyObject_Cmp(%s, %s, &%s)" % (
code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s" % (
result_code,
operand1.py_result(),
operand2.py_result(),
result_code))
code.putln(
"%s = %s %s 0;" % (
result_code, result_code, op))
richcmp_constants[op],
code.error_goto_if_null(result_code, self.pos)))
else:
code.putln("%s = %s %s %s;" % (
if operand1.type.is_pyobject:
res1, res2 = operand1.py_result(), operand2.py_result()
else:
res1, res2 = operand1.result_code, operand2.result_code
code.putln("%s = %s(%s %s %s);" % (
result_code,
operand1.result_code,
coerce_result,
res1,
self.c_operator(op),
operand2.result_code))
res2))
def c_operator(self, op):
if op == 'is':
......@@ -2908,7 +2978,14 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.operand2 = self.operand2.coerce_to_simple(env)
self.cascade.coerce_cascaded_operands_to_temp(env)
self.check_operand_types(env)
self.type = PyrexTypes.c_bint_type
if self.is_python_result():
self.type = PyrexTypes.py_object_type
else:
self.type = PyrexTypes.c_bint_type
cdr = self.cascade
while cdr:
cdr.type = self.type
cdr = cdr.cascade
if self.is_pycmp or self.cascade:
self.is_temp = 1
......@@ -3019,7 +3096,10 @@ class CascadedCmpNode(Node, CmpNode):
self.cascade.release_subexpr_temps(env)
def generate_evaluation_code(self, code, result, operand1):
code.putln("if (%s) {" % result)
if self.type.is_pyobject:
code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
else:
code.putln("if (%s) {" % result)
self.operand2.generate_evaluation_code(code)
self.generate_operation_code(code, result,
operand1, self.operator, self.operand2)
......@@ -3213,7 +3293,7 @@ class CoerceToBooleanNode(CoercionNode):
def generate_result_code(self, code):
if self.arg.type.is_pyobject:
code.putln(
"%s = PyObject_IsTrue(%s); %s" % (
"%s = __Pyx_PyObject_IsTrue(%s); %s" % (
self.result_code,
self.arg.py_result(),
code.error_goto_if_neg(self.result_code, self.pos)))
......
......@@ -125,6 +125,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name)
self.generate_const_definitions(env, code)
self.generate_interned_num_decls(env, code)
self.generate_interned_name_decls(env, code)
self.generate_py_string_decls(env, code)
self.generate_cached_builtins_decls(env, code)
......@@ -995,7 +996,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"static struct PyMethodDef %s[] = {" %
env.method_table_cname)
for entry in env.pyfunc_entries:
code.put_pymethoddef(entry, ",")
code.put_pymethoddef(entry, ",")
code.putln(
"{0, 0, 0, 0}")
code.putln(
......@@ -1238,6 +1239,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.error_goto(self.pos)));
def generate_intern_code(self, env, code):
for entry in env.pynum_entries:
code.putln("%s = PyInt_FromLong(%s); %s;" % (
entry.cname,
entry.init,
code.error_goto_if_null(entry.cname, self.pos)))
if env.intern_map:
env.use_utility_code(Nodes.init_intern_tab_utility_code);
code.putln(
......
......@@ -21,6 +21,7 @@ pymethdef_prefix = pyrex_prefix + "mdef_"
methtab_prefix = pyrex_prefix + "methods_"
memtab_prefix = pyrex_prefix + "members_"
interned_prefix = pyrex_prefix + "n_"
interned_num_prefix = pyrex_prefix + "num_"
objstruct_prefix = pyrex_prefix + "obj_"
typeptr_prefix = pyrex_prefix + "ptype_"
prop_set_prefix = pyrex_prefix + "setprop_"
......@@ -56,3 +57,7 @@ c_api_tab_cname = pyrex_prefix + "c_api_tab"
gilstate_cname = pyrex_prefix + "state"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
def py_version_hex(major, minor=0, micro=0, release_level=0, release_serial=0):
return (major << 24) | (minor << 16) | (micro << 8) | (release_level << 4) | (release_serial)
......@@ -115,6 +115,18 @@ class BlockNode:
for entry in entries:
code.putln(
"static PyObject *%s;" % entry.pystring_cname)
def generate_interned_num_decls(self, env, code):
# Flush accumulated interned nums from the global scope
# and generate declarations for them.
genv = env.global_scope()
entries = genv.interned_nums
if entries:
code.putln("")
for entry in entries:
code.putln(
"static PyObject *%s;" % entry.cname)
del entries[:]
def generate_cached_builtins_decls(self, env, code):
entries = env.builtin_scope().undeclared_cached_entries
......@@ -429,6 +441,9 @@ class CVarDefNode(StatNode):
"Python object cannot be declared extern")
name = name_declarator.name
cname = name_declarator.cname
if name == '':
error(declarator.pos, "Missing name in declaration.")
return
if type.is_cfunction:
dest_scope.declare_cfunction(name, type, declarator.pos,
cname = cname, visibility = self.visibility)
......@@ -534,6 +549,8 @@ class FuncDefNode(StatNode, BlockNode):
# #filename string C name of filename string const
# entry Symtab.Entry
py_func = None
def analyse_expressions(self, env):
pass
......@@ -551,6 +568,7 @@ class FuncDefNode(StatNode, BlockNode):
# Code for nested function definitions would go here
# if we supported them, which we probably won't.
# ----- Top-level constants used by this function
self.generate_interned_num_decls(lenv, code)
self.generate_interned_name_decls(lenv, code)
self.generate_py_string_decls(lenv, code)
self.generate_cached_builtins_decls(lenv, code)
......@@ -559,6 +577,10 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_const_definitions(lenv, code)
# ----- Function header
code.putln("")
if self.py_func:
self.py_func.generate_function_header(code,
with_pymethdef = env.is_py_class_scope,
proto_only=True)
self.generate_function_header(code,
with_pymethdef = env.is_py_class_scope)
# ----- Local variable declarations
......@@ -639,7 +661,11 @@ class FuncDefNode(StatNode, BlockNode):
# retval_code)
code.putln("return %s;" % retval_code)
code.putln("}")
# ----- Python version
if self.py_func:
self.py_func.generate_function_definitions(env, code)
def put_stararg_decrefs(self, code):
pass
......@@ -671,7 +697,7 @@ class FuncDefNode(StatNode, BlockNode):
class CFuncDefNode(FuncDefNode):
# C function definition.
#
# modifiers 'inline ' or ''
# modifiers ['inline']
# visibility 'private' or 'public' or 'extern'
# base_type CBaseTypeNode
# declarator CDeclaratorNode
......@@ -700,7 +726,30 @@ class CFuncDefNode(FuncDefNode):
cname = cname, visibility = self.visibility,
defining = self.body is not None)
self.return_type = type.return_type
if self.overridable:
import ExprNodes
arg_names = [arg.name for arg in self.type.args]
self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.declarator.base.name)
c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names[1:]])
py_func_body = ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
self.py_func = DefNode(pos = self.pos,
name = self.declarator.base.name,
args = self.declarator.args,
star_arg = None,
starstar_arg = None,
doc = None, # self.doc,
body = py_func_body)
self.py_func.analyse_declarations(env)
# Reset scope entry the above cfunction
env.entries[name] = self.entry
if Options.intern_names:
self.py_func.interned_attr_cname = env.intern(self.py_func.entry.name)
self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
self.body.stats.insert(0, self.override)
def declare_arguments(self, env):
for arg in self.type.args:
if not arg.name:
......@@ -730,9 +779,9 @@ class CFuncDefNode(FuncDefNode):
storage_class = "%s " % Naming.extern_c_macro
else:
storage_class = ""
code.putln("%s%s%s {" % (
code.putln("%s%s %s {" % (
storage_class,
self.modifiers,
' '.join(self.modifiers).upper(), # macro forms
header))
def generate_argument_declarations(self, env, code):
......@@ -792,7 +841,7 @@ class CFuncDefNode(FuncDefNode):
def caller_will_check_exceptions(self):
return self.entry.type.exception_check
class PyArgDeclNode(Node):
# Argument which must be a Python object (used
......@@ -925,7 +974,7 @@ class DefNode(FuncDefNode):
else:
self.entry.doc = self.doc
self.entry.func_cname = \
Naming.func_prefix + env.scope_prefix + self.name
Naming.func_prefix + "py_" + env.scope_prefix + self.name
self.entry.doc_cname = \
Naming.funcdoc_prefix + env.scope_prefix + self.name
self.entry.pymethdef_cname = \
......@@ -967,13 +1016,14 @@ class DefNode(FuncDefNode):
self.synthesize_assignment_node(env)
def analyse_default_values(self, env):
genv = env.global_scope()
for arg in self.args:
if arg.default:
if arg.is_generic:
arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, env)
arg.default.allocate_temps(env)
arg.default_entry = env.add_default_value(arg.type)
arg.default.analyse_types(genv)
arg.default = arg.default.coerce_to(arg.type, genv)
arg.default.allocate_temps(genv)
arg.default_entry = genv.add_default_value(arg.type)
arg.default_entry.used = 1
else:
error(arg.pos,
......@@ -991,7 +1041,7 @@ class DefNode(FuncDefNode):
self.assmt.analyse_declarations(env)
self.assmt.analyse_expressions(env)
def generate_function_header(self, code, with_pymethdef):
def generate_function_header(self, code, with_pymethdef, proto_only=0):
arg_code_list = []
sig = self.entry.signature
if sig.has_dummy_arg:
......@@ -1014,6 +1064,8 @@ class DefNode(FuncDefNode):
dc = self.return_type.declaration_code(self.entry.func_cname)
header = "static %s(%s)" % (dc, arg_code)
code.putln("%s; /*proto*/" % header)
if proto_only:
return
if self.entry.doc:
code.putln(
'static char %s[] = "%s";' % (
......@@ -1184,7 +1236,10 @@ class DefNode(FuncDefNode):
old_type = arg.hdr_type
new_type = arg.type
if old_type.is_pyobject:
code.putln("if (likely(%s)) {" % arg.hdr_cname)
if arg.default:
code.putln("if (%s) {" % arg.hdr_cname)
else:
code.putln("assert(%s); {" % arg.hdr_cname)
self.generate_arg_conversion_from_pyobject(arg, code)
code.putln("}")
elif new_type.is_pyobject:
......@@ -1275,6 +1330,50 @@ class DefNode(FuncDefNode):
def caller_will_check_exceptions(self):
return 1
class OverrideCheckNode(StatNode):
# A Node for dispatching to the def method if it
# is overriden.
#
# py_func
#
# args
# func_temp
# body
def analyse_expressions(self, env):
self.args = env.arg_entries
import ExprNodes
self.func_node = ExprNodes.PyTempNode(self.pos, env)
call_tuple = ExprNodes.TupleNode(self.pos, args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[1:]])
call_node = ExprNodes.SimpleCallNode(self.pos,
function=self.func_node,
args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[1:]])
self.body = ReturnStatNode(self.pos, value=call_node)
# self.func_temp = env.allocate_temp_pyobject()
self.body.analyse_expressions(env)
# env.release_temp(self.func_temp)
def generate_execution_code(self, code):
# Check to see if we are an extension type
self_arg = "((PyObject *)%s)" % self.args[0].cname
code.putln("/* Check if overriden in Python */")
code.putln("if (unlikely(%s->ob_type->tp_dictoffset != 0)) {" % self_arg)
err = code.error_goto_if_null(self_arg, self.pos)
# need to get attribute manually--scope would return cdef method
if Options.intern_names:
code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (self.func_node.result_code, self_arg, self.py_func.interned_attr_cname, err))
else:
code.putln('%s = PyObject_GetAttrString(%s, "%s"); %s' % (self.func_node.result_code, self_arg, self.py_func.entry.name, err))
# It appears that this type is not anywhere exposed in the Python/C API
is_builtin_function_or_method = '(strcmp(%s->ob_type->tp_name, "builtin_function_or_method") == 0)' % self.func_node.result_code
is_overridden = '(PyCFunction_GET_FUNCTION(%s) != &%s)' % (self.func_node.result_code, self.py_func.entry.func_cname)
code.putln('if (!%s || %s) {' % (is_builtin_function_or_method, is_overridden))
self.body.generate_execution_code(code)
code.putln('}')
# code.put_decref(self.func_temp, PyrexTypes.py_object_type)
code.putln("}")
class PyClassDefNode(StatNode, BlockNode):
# A Python class definition.
......@@ -1414,7 +1513,8 @@ class CClassDefNode(StatNode):
def analyse_expressions(self, env):
if self.body:
self.body.analyse_expressions(env)
scope = self.entry.type.scope
self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code):
if self.body:
......
......@@ -1209,13 +1209,21 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private'):
if level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here")
return p_ctypedef_statement(s, level, visibility)
overridable = 0
if s.sy == 'cdef':
cdef_flag = 1
s.next()
if s.sy == 'rdef':
cdef_flag = 1
overridable = 1
s.next()
if cdef_flag:
if level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
s.error('cdef statement not allowed here')
return p_cdef_statement(s, level, visibility)
return p_cdef_statement(s, level, visibility, overridable = overridable)
# elif s.sy == 'rdef':
# s.next()
# return p_c_func_or_var_declaration(s, level, s.position(), visibility = visibility, overridable = True)
elif s.sy == 'def':
if level not in ('module', 'class', 'c_class', 'property'):
s.error('def statement not allowed here')
......@@ -1234,8 +1242,6 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private'):
if level in ('c_class', 'c_class_pxd'):
if s.sy == 'pass':
return p_pass_statement(s, with_newline = 1)
else:
s.error("Executable statement not allowed here")
if s.sy == 'if':
return p_if_statement(s)
elif s.sy == 'while':
......@@ -1572,8 +1578,10 @@ def p_c_arg_decl(s, in_pyfunc, cmethod_flag = 0, kw_only = 0):
default = default,
kw_only = kw_only)
def p_cdef_statement(s, level, visibility = 'private'):
def p_cdef_statement(s, level, visibility = 'private', overridable = False):
pos = s.position()
if overridable and level not in ('c_class', 'c_class_pxd'):
error(pos, "Overridable cdef function not allowed here")
visibility = p_visibility(s, visibility)
if visibility == 'extern' and s.sy in ('from' ,':'):
return p_cdef_extern_block(s, level, pos)
......@@ -1595,7 +1603,7 @@ def p_cdef_statement(s, level, visibility = 'private'):
s.expect_newline('Expected a newline')
return node
else:
return p_c_func_or_var_declaration(s, level, pos, visibility)
return p_c_func_or_var_declaration(s, level, pos, visibility, overridable)
def p_cdef_extern_block(s, level, pos):
include_file = None
......@@ -1700,13 +1708,13 @@ def p_visibility(s, prev_visibility):
return visibility
def p_c_modifiers(s):
if s.systring in ('inline', ):
modifier = s.systring.upper() # uppercase is macro defined for various compilers
if s.sy == 'IDENT' and s.systring in ('inline',):
modifier = s.systring
s.next()
return modifier + ' ' + p_c_modifiers(s)
return ""
return [modifier] + p_c_modifiers(s)
return []
def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', overridable = False):
cmethod_flag = level in ('c_class', 'c_class_pxd')
modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s)
......@@ -1720,7 +1728,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
base_type = base_type,
declarator = declarator,
body = suite,
modifiers = modifiers)
modifiers = modifiers,
overridable = overridable)
else:
if level == 'module_pxd' and visibility <> 'extern':
error(pos,
......
......@@ -346,8 +346,6 @@ class CIntType(CNumericType):
class CBIntType(CIntType):
# TODO: this should be a macro "(__ ? Py_True : Py_False)"
# and no error checking should be needed (just an incref).
to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
exception_check = 0
......
......@@ -138,7 +138,7 @@ reserved_words = [
"raise", "import", "exec", "try", "except", "finally",
"while", "if", "elif", "else", "for", "in", "assert",
"and", "or", "not", "is", "in", "lambda", "from",
"NULL", "cimport", "by", "with"
"NULL", "cimport", "by", "with", "rdef"
]
function_contexts = [ # allowed arguments to the "with" option
......
......@@ -30,6 +30,7 @@ class Entry:
# or class attribute during
# class construction
# is_special boolean Is a special class method
# is_member boolean Is an assigned class member
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type
......@@ -72,6 +73,7 @@ class Entry:
is_cglobal = 0
is_pyglobal = 0
is_special = 0
is_member = 0
is_variable = 0
is_cfunction = 0
is_cmethod = 0
......@@ -121,6 +123,7 @@ class Scope:
# free_temp_entries [Entry] Temp variables currently unused
# temp_counter integer Counter for naming temp vars
# cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping
# pow_function_used boolean The C pow() function is used
# return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope
......@@ -167,6 +170,7 @@ class Scope:
self.cname_to_entry = {}
self.pow_function_used = 0
self.string_to_entry = {}
self.num_to_entry = {}
self.pystring_entries = []
def __str__(self):
......@@ -392,6 +396,28 @@ class Scope:
entry.pystring_cname = entry.cname + "p"
self.pystring_entries.append(entry)
self.global_scope().all_pystring_entries.append(entry)
def add_py_num(self, value):
# Add an entry for an int constant.
cname = "%s%s" % (Naming.interned_num_prefix, value)
cname = cname.replace('-', 'neg_').replace('.','_')
entry = Entry("", cname, c_long_type, init = value)
entry.used = 1
entry.is_interned = 1
self.const_entries.append(entry)
self.interned_nums.append(entry)
return entry
def get_py_num(self, value):
# Get entry for int constant. Returns an existing
# one if possible, otherwise creates a new one.
genv = self.global_scope()
entry = genv.num_to_entry.get(value)
if not entry:
entry = genv.add_py_num(value)
genv.num_to_entry[value] = entry
genv.pynum_entries.append(entry)
return entry
def new_const_cname(self):
# Create a new globally-unique name for a constant.
......@@ -606,8 +632,10 @@ class ModuleScope(Scope):
self.cimported_modules = []
self.intern_map = {}
self.interned_names = []
self.interned_nums = []
self.all_pystring_entries = []
self.types_imported = {}
self.pynum_entries = []
def qualifying_scope(self):
return self.parent_module
......@@ -1052,45 +1080,58 @@ class CClassScope(ClassScope):
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
# Add an entry for an attribute.
if self.defined:
error(pos,
"C attributes cannot be added in implementation part of"
" extension type")
if get_special_method_signature(name):
error(pos,
"The name '%s' is reserved for a special method."
% name)
if not cname:
cname = name
entry = self.declare(name, cname, type, pos)
entry.visibility = visibility
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject:
self.has_pyobject_attrs = 1
if visibility not in ('private', 'public', 'readonly'):
error(pos,
"Attribute of extension type cannot be declared %s" % visibility)
if visibility in ('public', 'readonly'):
if type.pymemberdef_typecode:
self.public_attr_entries.append(entry)
if name == "__weakref__":
error(pos, "Special attribute __weakref__ cannot be exposed to Python")
else:
if is_cdef:
# Add an entry for an attribute.
if self.defined:
error(pos,
"C attribute of type '%s' cannot be accessed from Python" % type)
if visibility == 'public' and type.is_extension_type:
error(pos,
"Non-generic Python attribute cannot be exposed for writing from Python")
return entry
"C attributes cannot be added in implementation part of"
" extension type")
if get_special_method_signature(name):
error(pos,
"The name '%s' is reserved for a special method."
% name)
if not cname:
cname = name
entry = self.declare(name, cname, type, pos)
entry.visibility = visibility
entry.is_variable = 1
self.var_entries.append(entry)
if type.is_pyobject:
self.has_pyobject_attrs = 1
if visibility not in ('private', 'public', 'readonly'):
error(pos,
"Attribute of extension type cannot be declared %s" % visibility)
if visibility in ('public', 'readonly'):
if type.pymemberdef_typecode:
self.public_attr_entries.append(entry)
if name == "__weakref__":
error(pos, "Special attribute __weakref__ cannot be exposed to Python")
else:
error(pos,
"C attribute of type '%s' cannot be accessed from Python" % type)
if visibility == 'public' and type.is_extension_type:
error(pos,
"Non-generic Python attribute cannot be exposed for writing from Python")
return entry
else:
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
entry.is_member = 1
entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
# I keep it in for now. is_member should be enough
# later on
entry.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname
if Options.intern_names:
entry.interned_cname = self.intern(name)
return entry
def declare_pyfunction(self, name, pos):
# Add an entry for a method.
if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
error(pos, "Special method %s must be implemented via __richcmp__"
% name)
entry = self.declare(name, name, py_object_type, pos)
error(pos, "Special method %s must be implemented via __richcmp__" % name)
entry = self.declare_var(name, py_object_type, pos)
special_sig = get_special_method_signature(name)
if special_sig:
# Special methods get put in the method table with a particular
......@@ -1168,8 +1209,29 @@ class CClassScope(ClassScope):
entry = self.add_cfunction(base_entry.name, base_entry.type, None,
adapt(base_entry.cname), base_entry.visibility)
entry.is_inherited = 1
def allocate_temp(self, type):
return Scope.allocate_temp(self.global_scope(), type)
def release_temp(self, cname):
return Scope.release_temp(self.global_scope(), cname)
def lookup(self, name):
if name == "classmethod":
# We don't want to use the builtin classmethod here 'cause it won't do the
# right thing in this scope (as the class memebers aren't still functions).
# Don't want to add a cfunction to this scope 'cause that would mess with
# the type definition, so we just return the right entry.
self.use_utility_code(classmethod_utility_code)
entry = Entry("classmethod",
"__Pyx_Method_ClassMethod",
CFuncType(py_object_type, [CFuncTypeArg("", py_object_type, None)], 0, 0))
entry.is_cfunction = 1
return entry
else:
return Scope.lookup(self, name)
class PropertyScope(Scope):
# Scope holding the __get__, __set__ and __del__ methods for
# a property of an extension type.
......@@ -1188,3 +1250,25 @@ class PropertyScope(Scope):
error(pos, "Only __get__, __set__ and __del__ methods allowed "
"in a property declaration")
return None
# Should this go elsewhere (and then get imported)?
#------------------------------------------------------------------------------------
classmethod_utility_code = [
"""
#include "descrobject.h"
static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
""","""
static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
/* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */
/* if (!PyObject_TypeCheck(method, &PyMethodDescr_Type)) { */
if (strcmp(method->ob_type->tp_name, "method_descriptor") != 0) {
PyErr_Format(PyExc_TypeError, "Extension type classmethod() can only be called on a method_descriptor.");
return NULL;
}
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
return PyDescr_NewClassMethod(descr->d_type, descr->d_method);
}
"""
]
......@@ -5,6 +5,7 @@
import Naming
import PyrexTypes
import sys
class Signature:
# Method slot signature descriptor.
......@@ -163,7 +164,7 @@ class GCDependentSlot(SlotDescriptor):
# the type participates in GC.
def __init__(self, slot_name, no_gc_value, gc_value, dynamic = 0):
SlotDescriptor.__init__(self, slot_name, dynamic)
SlotDescriptor.__init__(self, slot_name, dynamic = dynamic)
self.no_gc_value = no_gc_value
self.gc_value = gc_value
......
version = '0.9.6.6'
version = '0.9.6.7'
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