Commit 057375c9 authored by Stefan Behnel's avatar Stefan Behnel

merge of Robert's changes for 0.9.6.11

parents 96fb7ea3 c93ab4d4
# Note: Work in progress # Note: Work in progress
import os
import re import re
import time
from StringIO import StringIO from StringIO import StringIO
import Version
from Code import CCodeWriter from Code import CCodeWriter
# need one-characters subsitutions (for now) so offsets aren't off
special_chars = [('<', '\xF0', '&lt;'),
('>', '\xF1', '&gt;'),
('&', '\xF2', '&amp;')]
class AnnotationCCodeWriter(CCodeWriter): class AnnotationCCodeWriter(CCodeWriter):
...@@ -29,14 +34,13 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -29,14 +34,13 @@ class AnnotationCCodeWriter(CCodeWriter):
# if pos is not None: # if pos is not None:
# CCodeWriter.mark_pos(self, pos) # CCodeWriter.mark_pos(self, pos)
# return # return
print "marking", pos
if self.last_pos: if self.last_pos:
try: try:
code = self.code[self.last_pos[1]] code = self.code[self.last_pos[1]]
except KeyError: except KeyError:
code = "" code = ""
self.code[self.last_pos[1]] = code + self.buffer.getvalue() self.code[self.last_pos[1]] = code + self.buffer.getvalue()
self.buffer = StringIO() self.buffer = StringIO()
self.last_pos = pos self.last_pos = pos
def annotate(self, pos, item): def annotate(self, pos, item):
...@@ -47,12 +51,10 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -47,12 +51,10 @@ class AnnotationCCodeWriter(CCodeWriter):
f = open(filename) f = open(filename)
lines = f.readlines() lines = f.readlines()
for k in range(len(lines)): for k in range(len(lines)):
# there has to be a better way to do this line = lines[k]
lines[k] = lines[k].replace(' ','\t ') for c, cc, html in special_chars:
lines[k] = lines[k].replace(' ','\t\t') line = line.replace(c, cc)
# TODO: this is incorrect lines[k] = line
lines[k] = lines[k].replace('<', '~')
lines[k] = lines[k].replace('>', '~')
f.close() f.close()
all = [] all = []
for pos, item in self.annotations: for pos, item in self.annotations:
...@@ -86,6 +88,7 @@ body { font-family: courier; font-size: 12; } ...@@ -86,6 +88,7 @@ body { font-family: courier; font-size: 12; }
.py_api { color: red; } .py_api { color: red; }
.pyx_api { color: #FF3000; } .pyx_api { color: #FF3000; }
.py_macro_api { color: #FF8000; } .py_macro_api { color: #FF8000; }
.error_goto { color: #FF8000; }
.tag { } .tag { }
...@@ -97,6 +100,8 @@ body { font-family: courier; font-size: 12; } ...@@ -97,6 +100,8 @@ body { font-family: courier; font-size: 12; }
.py_call { color: #FF0000; font-weight: bold; } .py_call { color: #FF0000; font-weight: bold; }
.c_call { color: #0000FF; } .c_call { color: #0000FF; }
.line { margin: 0em }
</style> </style>
<script> <script>
function toggleDiv(id) { function toggleDiv(id) {
...@@ -108,11 +113,15 @@ function toggleDiv(id) { ...@@ -108,11 +113,15 @@ function toggleDiv(id) {
</head> </head>
""") """)
f.write('<body>\n') f.write('<body>\n')
f.write('<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime()))
c_file = os.path.basename(filename)[:-3] + 'c'
f.write('<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file))
k = 0 k = 0
py_c_api = re.compile('(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)') py_c_api = re.compile('(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)')
pyx_api = re.compile('(__Pyx[A-Za-z_]+)\(') pyx_api = re.compile('(__Pyx[A-Za-z_]+)\(')
py_marco_api = re.compile('(Py[A-Za-z]*_[A-Z][A-Z_]+)') py_marco_api = re.compile('(Py[A-Za-z]*_[A-Z][A-Z_]+)')
error_goto = re.compile(r'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})')
for line in lines: for line in lines:
...@@ -125,16 +134,20 @@ function toggleDiv(id) { ...@@ -125,16 +134,20 @@ function toggleDiv(id) {
code, c_api_calls = py_c_api.subn(r"<span class='py_api'>\1</span>", code) code, c_api_calls = py_c_api.subn(r"<span class='py_api'>\1</span>", code)
code, pyx_api_calls = pyx_api.subn(r"<span class='pyx_api'>\1</span>(", code) code, pyx_api_calls = pyx_api.subn(r"<span class='pyx_api'>\1</span>(", code)
code, macro_api_calls = py_marco_api.subn(r"<span class='py_macro_api'>\1</span>", code) code, macro_api_calls = py_marco_api.subn(r"<span class='py_macro_api'>\1</span>", code)
code, error_goto_calls = error_goto.subn(r"<span class='error_goto'>\1</span>", code)
code = code.replace("<span class='error_goto'>;", ";<span class='error_goto'>")
color = "FFFF%02x" % int(255/(1+(5*c_api_calls+2*pyx_api_calls+macro_api_calls)/10.0)) color = "FFFF%02x" % int(255/(1+(5*c_api_calls+2*pyx_api_calls+macro_api_calls)/10.0))
f.write("<div class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k)) f.write("<pre class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k))
f.write(" %d: " % k) f.write(" %d: " % k)
line = line.replace('\t', '&nbsp;') for c, cc, html in special_chars:
f.write(line) line = line.replace(cc, html)
f.write(line.rstrip())
f.write('</div>\n') f.write('</pre>\n')
f.write("<div id='line%s' class='code' style='background-color: #%s'>%s</div>" % (k, color, code.replace('\n', '\n<br>'))) f.write("<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>" % (k, color, code))
f.write('</body></html>\n') f.write('</body></html>\n')
f.close() f.close()
......
...@@ -98,6 +98,8 @@ class CCodeWriter: ...@@ -98,6 +98,8 @@ class CCodeWriter:
return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4] return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
def mark_pos(self, pos): def mark_pos(self, pos):
if pos is None:
return
file, line, col = pos file, line, col = pos
contents = self.file_contents(file) contents = self.file_contents(file)
......
...@@ -1931,7 +1931,7 @@ class AttributeNode(ExprNode): ...@@ -1931,7 +1931,7 @@ class AttributeNode(ExprNode):
code.putln( code.putln(
'%s = PyObject_GetAttrString(%s, "%s"); %s' % ( '%s = PyObject_GetAttrString(%s, "%s"); %s' % (
self.result_code, self.result_code,
self.objpy_result(), self.obj.py_result(),
self.attribute, self.attribute,
code.error_goto_if_null(self.result_code, self.pos))) code.error_goto_if_null(self.result_code, self.pos)))
...@@ -2118,6 +2118,19 @@ class SequenceNode(ExprNode): ...@@ -2118,6 +2118,19 @@ class SequenceNode(ExprNode):
class TupleNode(SequenceNode): class TupleNode(SequenceNode):
# Tuple constructor. # Tuple constructor.
def analyse_types(self, env):
if len(self.args) == 0:
self.type = py_object_type
self.is_temp = 0
else:
SequenceNode.analyse_types(self, env)
def calculate_result_code(self):
if len(self.args) > 0:
error(pos, "Positive length tuples must be constructed.")
else:
return Naming.empty_tuple
def compile_time_value(self, denv): def compile_time_value(self, denv):
values = self.compile_time_value_list(denv) values = self.compile_time_value_list(denv)
...@@ -2127,6 +2140,9 @@ class TupleNode(SequenceNode): ...@@ -2127,6 +2140,9 @@ class TupleNode(SequenceNode):
self.compile_time_value_error(e) self.compile_time_value_error(e)
def generate_operation_code(self, code): def generate_operation_code(self, code):
if len(self.args) == 0:
# result_code is Naming.empty_tuple
return
code.putln( code.putln(
"%s = PyTuple_New(%s); %s" % ( "%s = PyTuple_New(%s); %s" % (
self.result_code, self.result_code,
...@@ -2565,6 +2581,8 @@ def unop_node(pos, operator, operand): ...@@ -2565,6 +2581,8 @@ def unop_node(pos, operator, operand):
# given operator. # given operator.
if isinstance(operand, IntNode) and operator == '-': if isinstance(operand, IntNode) and operator == '-':
return IntNode(pos = operand.pos, value = -int(operand.value)) return IntNode(pos = operand.pos, value = -int(operand.value))
elif isinstance(operand, UnopNode) and operand.operator == operator:
warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
return unop_node_classes[operator](pos, return unop_node_classes[operator](pos,
operator = operator, operator = operator,
operand = operand) operand = operand)
...@@ -3582,20 +3600,7 @@ class CoerceFromPyTypeNode(CoercionNode): ...@@ -3582,20 +3600,7 @@ class CoerceFromPyTypeNode(CoercionNode):
code.putln('%s = %s; %s' % ( code.putln('%s = %s; %s' % (
self.result_code, self.result_code,
rhs, rhs,
code.error_goto_if(self.error_cond(), self.pos))) code.error_goto_if(self.type.error_condition(self.result_code), self.pos)))
def error_cond(self):
conds = []
if self.type.is_string:
conds.append("(!%s)" % self.result_code)
elif self.type.exception_value is not None:
conds.append("(%s == %s)" % (self.result_code, self.type.exception_value))
if self.type.exception_check:
conds.append("PyErr_Occurred()")
if len(conds) > 0:
return " && ".join(conds)
else:
return 0
class CoerceToBooleanNode(CoercionNode): class CoerceToBooleanNode(CoercionNode):
......
...@@ -17,7 +17,6 @@ import Parsing ...@@ -17,7 +17,6 @@ import Parsing
from Symtab import BuiltinScope, ModuleScope from Symtab import BuiltinScope, ModuleScope
import Code import Code
from Cython.Utils import replace_suffix from Cython.Utils import replace_suffix
import Builtin
from Cython import Utils from Cython import Utils
verbose = 0 verbose = 0
...@@ -34,6 +33,7 @@ class Context: ...@@ -34,6 +33,7 @@ class Context:
def __init__(self, include_directories): def __init__(self, include_directories):
#self.modules = {"__builtin__" : BuiltinScope()} #self.modules = {"__builtin__" : BuiltinScope()}
import Builtin
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
self.include_directories = include_directories self.include_directories = include_directories
......
...@@ -217,12 +217,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -217,12 +217,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_py_string_decls(env, code) self.generate_py_string_decls(env, code)
self.generate_cached_builtins_decls(env, code) self.generate_cached_builtins_decls(env, code)
self.body.generate_function_definitions(env, code) self.body.generate_function_definitions(env, code)
code.mark_pos(None)
self.generate_interned_name_table(env, code) self.generate_interned_name_table(env, code)
self.generate_py_string_table(env, code) self.generate_py_string_table(env, code)
self.generate_typeobj_definitions(env, code) self.generate_typeobj_definitions(env, code)
self.generate_method_table(env, code) self.generate_method_table(env, code)
self.generate_filename_init_prototype(code) self.generate_filename_init_prototype(code)
self.generate_module_init_func(modules[:-1], env, code) self.generate_module_init_func(modules[:-1], env, code)
code.mark_pos(None)
self.generate_module_cleanup_func(env, code) self.generate_module_cleanup_func(env, code)
self.generate_filename_table(code) self.generate_filename_table(code)
self.generate_utility_functions(env, code) self.generate_utility_functions(env, code)
...@@ -284,6 +286,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -284,6 +286,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln('') code.putln('')
code.putln('static PyObject *%s;' % env.module_cname) code.putln('static PyObject *%s;' % env.module_cname)
code.putln('static PyObject *%s;' % Naming.builtins_cname) code.putln('static PyObject *%s;' % Naming.builtins_cname)
code.putln('static PyObject *%s;' % Naming.empty_tuple)
if Options.pre_import is not None: if Options.pre_import is not None:
code.putln('static PyObject *%s;' % Naming.preimport_cname) code.putln('static PyObject *%s;' % Naming.preimport_cname)
code.putln('static int %s;' % Naming.lineno_cname) code.putln('static int %s;' % Naming.lineno_cname)
...@@ -605,6 +608,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -605,6 +608,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.declaration_code(""))) type.declaration_code("")))
def generate_new_function(self, scope, code): def generate_new_function(self, scope, code):
tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
slot_func = scope.mangle_internal("tp_new")
type = scope.parent_type type = scope.parent_type
base_type = type.base_type base_type = type.base_type
py_attrs = [] py_attrs = []
...@@ -621,9 +626,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -621,9 +626,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"%s;" "%s;"
% scope.parent_type.declaration_code("p")) % scope.parent_type.declaration_code("p"))
if base_type: if base_type:
tp_new = TypeSlots.get_base_slot_function(scope, tp_slot)
if tp_new is None:
tp_new = "%s->tp_new" % base_type.typeptr_cname
code.putln( code.putln(
"PyObject *o = %s->tp_new(t, a, k);" % "PyObject *o = %s(t, a, k);" % tp_new)
base_type.typeptr_cname)
else: else:
code.putln( code.putln(
"PyObject *o = (*t->tp_alloc)(t, 0);") "PyObject *o = (*t->tp_alloc)(t, 0);")
...@@ -647,9 +654,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -647,9 +654,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put_init_var_to_py_none(entry, "p->%s") code.put_init_var_to_py_none(entry, "p->%s")
entry = scope.lookup_here("__new__") entry = scope.lookup_here("__new__")
if entry: if entry:
if entry.trivial_signature:
cinit_args = "o, %s, NULL" % Naming.empty_tuple
else:
cinit_args = "o, a, k"
code.putln( code.putln(
"if (%s(o, a, k) < 0) {" % "if (%s(%s) < 0) {" %
entry.func_cname) (entry.func_cname, cinit_args))
code.put_decref_clear("o", py_object_type); code.put_decref_clear("o", py_object_type);
code.putln( code.putln(
"}") "}")
...@@ -659,7 +670,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -659,7 +670,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"}") "}")
def generate_dealloc_function(self, scope, code): def generate_dealloc_function(self, scope, code):
tp_slot = TypeSlots.ConstructorSlot("tp_dealloc", '__dealloc__')
slot_func = scope.mangle_internal("tp_dealloc")
base_type = scope.parent_type.base_type base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
return # never used
code.putln("") code.putln("")
code.putln( code.putln(
"static void %s(PyObject *o) {" "static void %s(PyObject *o) {"
...@@ -676,12 +691,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -676,12 +691,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in py_attrs: for entry in py_attrs:
code.put_xdecref("p->%s" % entry.cname, entry.type) code.put_xdecref("p->%s" % entry.cname, entry.type)
if base_type: if base_type:
tp_dealloc = TypeSlots.get_base_slot_function(scope, tp_slot)
if tp_dealloc is None:
tp_dealloc = "%s->tp_dealloc" % base_type.typeptr_cname
code.putln( code.putln(
"%s->tp_dealloc(o);" % "%s(o);" % tp_dealloc)
base_type.typeptr_cname)
else: else:
code.putln( code.putln(
"(*o->ob_type->tp_free)(o);") "(*o->ob_type->tp_free)(o);")
code.putln( code.putln(
"}") "}")
...@@ -709,26 +726,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -709,26 +726,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"}") "}")
def generate_traverse_function(self, scope, code): def generate_traverse_function(self, scope, code):
tp_slot = TypeSlots.GCDependentSlot("tp_traverse")
slot_func = scope.mangle_internal("tp_traverse")
base_type = scope.parent_type.base_type base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
return # never used
code.putln("") code.putln("")
code.putln( code.putln(
"static int %s(PyObject *o, visitproc v, void *a) {" "static int %s(PyObject *o, visitproc v, void *a) {"
% scope.mangle_internal("tp_traverse")) % slot_func)
py_attrs = [] py_attrs = []
for entry in scope.var_entries: for entry in scope.var_entries:
if entry.type.is_pyobject and entry.name != "__weakref__": if entry.type.is_pyobject and entry.name != "__weakref__":
py_attrs.append(entry) py_attrs.append(entry)
if base_type or py_attrs: if base_type or py_attrs:
code.putln( code.putln("int e;")
"int e;")
if py_attrs: if py_attrs:
self.generate_self_cast(scope, code) self.generate_self_cast(scope, code)
if base_type: if base_type:
code.putln("if (%s->tp_traverse) {" % base_type.typeptr_cname) # want to call it explicitly if possible so inlining can be performed
code.putln( static_call = TypeSlots.get_base_slot_function(scope, tp_slot)
"e = %s->tp_traverse(o, v, a); if (e) return e;" % if static_call:
base_type.typeptr_cname) code.putln("e = %s(o, v, a); if (e) return e;" % static_call)
code.putln("}") else:
code.putln("if (%s->tp_traverse) {" % base_type.typeptr_cname)
code.putln(
"e = %s->tp_traverse(o, v, a); if (e) return e;" %
base_type.typeptr_cname)
code.putln("}")
for entry in py_attrs: for entry in py_attrs:
var_code = "p->%s" % entry.cname var_code = "p->%s" % entry.cname
code.putln( code.putln(
...@@ -747,11 +772,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -747,11 +772,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"}") "}")
def generate_clear_function(self, scope, code): def generate_clear_function(self, scope, code):
tp_slot = TypeSlots.GCDependentSlot("tp_clear")
slot_func = scope.mangle_internal("tp_clear")
base_type = scope.parent_type.base_type base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
return # never used
code.putln("") code.putln("")
code.putln( code.putln("static int %s(PyObject *o) {" % slot_func)
"static int %s(PyObject *o) {"
% scope.mangle_internal("tp_clear"))
py_attrs = [] py_attrs = []
for entry in scope.var_entries: for entry in scope.var_entries:
if entry.type.is_pyobject and entry.name != "__weakref__": if entry.type.is_pyobject and entry.name != "__weakref__":
...@@ -760,21 +787,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -760,21 +787,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_self_cast(scope, code) self.generate_self_cast(scope, code)
code.putln("PyObject* tmp;") code.putln("PyObject* tmp;")
if base_type: if base_type:
code.putln("if (%s->tp_clear) {" % base_type.typeptr_cname) # want to call it explicitly if possible so inlining can be performed
code.putln( static_call = TypeSlots.get_base_slot_function(scope, tp_slot)
"%s->tp_clear(o);" % if static_call:
base_type.typeptr_cname) code.putln("%s(o);" % static_call)
code.putln("}") else:
code.putln("if (%s->tp_clear) {" % base_type.typeptr_cname)
code.putln("%s->tp_clear(o);" % base_type.typeptr_cname)
code.putln("}")
for entry in py_attrs: for entry in py_attrs:
name = "p->%s" % entry.cname name = "p->%s" % entry.cname
if entry.type.is_extension_type:
name = "((PyObject*)%s)" % name
code.putln("tmp = %s;" % name) code.putln("tmp = %s;" % name)
code.put_init_to_py_none(name, entry.type) code.put_init_to_py_none(name, PyrexTypes.py_object_type)
code.putln("Py_XDECREF(tmp);") code.putln("Py_XDECREF(tmp);")
code.putln( code.putln(
"return 0;") "return 0;")
code.putln( code.putln(
"}") "}")
def generate_getitem_int_function(self, scope, code): def generate_getitem_int_function(self, scope, code):
# This function is put into the sq_item slot when # This function is put into the sq_item slot when
# a __getitem__ method is present. It converts its # a __getitem__ method is present. It converts its
...@@ -1203,6 +1235,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1203,6 +1235,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"};") "};")
def generate_interned_name_table(self, env, code): def generate_interned_name_table(self, env, code):
code.mark_pos(None)
items = env.intern_map.items() items = env.intern_map.items()
if items: if items:
items.sort() items.sort()
...@@ -1268,6 +1301,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1268,6 +1301,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if Options.cache_builtins: if Options.cache_builtins:
code.putln("/*--- Builtin init code ---*/") code.putln("/*--- Builtin init code ---*/")
self.generate_builtin_init_code(env, code) self.generate_builtin_init_code(env, code)
code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)));
code.putln("/*--- Global init code ---*/") code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code) self.generate_global_init_code(env, code)
...@@ -1287,6 +1322,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1287,6 +1322,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_type_import_code_for_module(module, env, code) self.generate_type_import_code_for_module(module, env, code)
code.putln("/*--- Execution code ---*/") code.putln("/*--- Execution code ---*/")
code.mark_pos(None)
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
if Options.generate_cleanup_code: if Options.generate_cleanup_code:
...@@ -1320,6 +1356,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1320,6 +1356,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("/*--- Builtin cleanup code ---*/") code.putln("/*--- Builtin cleanup code ---*/")
for entry in env.cached_builtins: for entry in env.cached_builtins:
code.put_var_decref_clear(entry) code.put_var_decref_clear(entry)
code.putln("Py_DECREF(%s); %s = 0;" % (Naming.empty_tuple, Naming.empty_tuple));
code.putln("/*--- Intern cleanup code ---*/") code.putln("/*--- Intern cleanup code ---*/")
for entry in env.pynum_entries: for entry in env.pynum_entries:
code.put_var_decref_clear(entry) code.put_var_decref_clear(entry)
......
...@@ -58,6 +58,8 @@ vtabslot_cname = pyrex_prefix + "vtab" ...@@ -58,6 +58,8 @@ vtabslot_cname = pyrex_prefix + "vtab"
c_api_tab_cname = pyrex_prefix + "c_api_tab" c_api_tab_cname = pyrex_prefix + "c_api_tab"
gilstate_cname = pyrex_prefix + "state" gilstate_cname = pyrex_prefix + "state"
skip_dispatch_cname = pyrex_prefix + "skip_dispatch" skip_dispatch_cname = pyrex_prefix + "skip_dispatch"
empty_tuple = pyrex_prefix + "empty_tuple"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C" extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
......
...@@ -88,8 +88,6 @@ class Node: ...@@ -88,8 +88,6 @@ class Node:
# mro does the wrong thing # mro does the wrong thing
if isinstance(self, BlockNode): if isinstance(self, BlockNode):
self.body.annotate(code) self.body.annotate(code)
else:
print "skipping", self
class BlockNode: class BlockNode:
...@@ -985,6 +983,8 @@ class DefNode(FuncDefNode): ...@@ -985,6 +983,8 @@ class DefNode(FuncDefNode):
elif len(self.args) == 2: elif len(self.args) == 2:
if self.args[1].default is None and not self.args[1].kw_only: if self.args[1].default is None and not self.args[1].kw_only:
self.entry.signature = TypeSlots.ibinaryfunc self.entry.signature = TypeSlots.ibinaryfunc
elif self.entry.is_special:
self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
sig = self.entry.signature sig = self.entry.signature
nfixed = sig.num_fixed_args() nfixed = sig.num_fixed_args()
for i in range(nfixed): for i in range(nfixed):
...@@ -1363,12 +1363,13 @@ class DefNode(FuncDefNode): ...@@ -1363,12 +1363,13 @@ class DefNode(FuncDefNode):
def generate_arg_conversion_from_pyobject(self, arg, code): def generate_arg_conversion_from_pyobject(self, arg, code):
new_type = arg.type new_type = arg.type
func = new_type.from_py_function func = new_type.from_py_function
# copied from CoerceFromPyTypeNode
if func: if func:
code.putln("%s = %s(%s); %s" % ( code.putln("%s = %s(%s); %s" % (
arg.entry.cname, arg.entry.cname,
func, func,
arg.hdr_cname, arg.hdr_cname,
code.error_goto_if_PyErr(arg.pos))) code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
else: else:
error(arg.pos, error(arg.pos,
"Cannot convert Python object argument to type '%s'" "Cannot convert Python object argument to type '%s'"
......
...@@ -21,7 +21,7 @@ incref_local_binop = 0 ...@@ -21,7 +21,7 @@ incref_local_binop = 0
# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects # 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects
# Mostly for reducing noise for Valgrind, only executes at process exit # Mostly for reducing noise for Valgrind, only executes at process exit
# (when all memory will be reclaimed anyways). # (when all memory will be reclaimed anyways).
generate_cleanup_code = 3 generate_cleanup_code = 0
annotate = 0 annotate = 0
......
...@@ -302,6 +302,19 @@ class CType(PyrexType): ...@@ -302,6 +302,19 @@ class CType(PyrexType):
from_py_function = None from_py_function = None
exception_value = None exception_value = None
exception_check = 1 exception_check = 1
def error_condition(self, result_code):
conds = []
if self.is_string:
conds.append("(!%s)" % result_code)
elif self.exception_value is not None:
conds.append("(%s == (%s)%s)" % (result_code, self.sign_and_name(), self.exception_value))
if self.exception_check:
conds.append("PyErr_Occurred()")
if len(conds) > 0:
return " && ".join(conds)
else:
return 0
class CVoidType(CType): class CVoidType(CType):
...@@ -432,7 +445,7 @@ class CUIntType(CIntType): ...@@ -432,7 +445,7 @@ class CUIntType(CIntType):
to_py_function = "PyLong_FromUnsignedLong" to_py_function = "PyLong_FromUnsignedLong"
from_py_function = "PyInt_AsUnsignedLongMask" from_py_function = "PyInt_AsUnsignedLongMask"
exception_value = None exception_value = -1
class CULongType(CUIntType): class CULongType(CUIntType):
......
...@@ -184,6 +184,7 @@ class Scope: ...@@ -184,6 +184,7 @@ class Scope:
self.pow_function_used = 0 self.pow_function_used = 0
self.string_to_entry = {} self.string_to_entry = {}
self.num_to_entry = {} self.num_to_entry = {}
self.obj_to_entry = {}
self.pystring_entries = [] self.pystring_entries = []
def __str__(self): def __str__(self):
...@@ -469,6 +470,27 @@ class Scope: ...@@ -469,6 +470,27 @@ class Scope:
genv.num_to_entry[value] = entry genv.num_to_entry[value] = entry
genv.pynum_entries.append(entry) genv.pynum_entries.append(entry)
return entry return entry
def add_py_obj(self, obj, c_prefix=''):
obj.check_const()
cname = self.new_const_cname(c_prefix)
entry = Entry("", cname, py_object_type, init = value)
entry.used = 1
entry.is_interned = 1
self.const_entries.append(entry)
self.interned_objs.append(entry)
return entry
def get_py_obj(self, obj, c_prefix=''):
# Get entry for a generic constant. Returns an existing
# one if possible, otherwise creates a new one.
genv = self.global_scope()
entry = genv.obj_to_entry.get(obj)
if not entry:
entry = genv.add_py_num(obj, c_prefix)
genv.obj_to_entry[obj] = entry
return entry
def new_const_cname(self): def new_const_cname(self):
# Create a new globally-unique name for a constant. # Create a new globally-unique name for a constant.
...@@ -675,6 +697,7 @@ class ModuleScope(Scope): ...@@ -675,6 +697,7 @@ class ModuleScope(Scope):
self.intern_map = {} self.intern_map = {}
self.interned_names = [] self.interned_names = []
self.interned_nums = [] self.interned_nums = []
self.interned_objs = []
self.all_pystring_entries = [] self.all_pystring_entries = []
self.types_imported = {} self.types_imported = {}
self.pynum_entries = [] self.pynum_entries = []
...@@ -813,11 +836,11 @@ class ModuleScope(Scope): ...@@ -813,11 +836,11 @@ class ModuleScope(Scope):
self.default_entries.append(entry) self.default_entries.append(entry)
return entry return entry
def new_const_cname(self): def new_const_cname(self, prefix=''):
# Create a new globally-unique name for a constant. # Create a new globally-unique name for a constant.
n = self.const_counter n = self.const_counter
self.const_counter = n + 1 self.const_counter = n + 1
return "%s%d" % (Naming.const_prefix, n) return "%s%s_%d" % (Naming.const_prefix, prefix, n)
def use_utility_code(self, new_code): def use_utility_code(self, new_code):
# Add string to list of utility code to be included, # Add string to list of utility code to be included,
......
...@@ -228,7 +228,31 @@ class GCDependentSlot(InternalMethodSlot): ...@@ -228,7 +228,31 @@ class GCDependentSlot(InternalMethodSlot):
# functions are defined in the same module # functions are defined in the same module
parent_type_scope = scope.parent_type.base_type.scope parent_type_scope = scope.parent_type.base_type.scope
if scope.parent_scope is parent_type_scope.parent_scope: if scope.parent_scope is parent_type_scope.parent_scope:
return self.slot_code(parent_type_scope) entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return self.slot_code(parent_type_scope)
return InternalMethodSlot.slot_code(self, scope)
class ConstructorSlot(InternalMethodSlot):
# Descriptor for tp_new and tp_dealloc.
def __init__(self, slot_name, method):
InternalMethodSlot.__init__(self, slot_name)
self.method = method
def slot_code(self, scope):
if scope.parent_type.base_type \
and not scope.has_pyobject_attrs \
and not scope.lookup_here(self.method):
# if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent
# functions are defined in the same module
parent_type_scope = scope.parent_type.base_type.scope
if scope.parent_scope is parent_type_scope.parent_scope:
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return self.slot_code(parent_type_scope)
return InternalMethodSlot.slot_code(self, scope) return InternalMethodSlot.slot_code(self, scope)
...@@ -373,6 +397,19 @@ def get_property_accessor_signature(name): ...@@ -373,6 +397,19 @@ def get_property_accessor_signature(name):
# Return signature of accessor for an extension type # Return signature of accessor for an extension type
# property, else None. # property, else None.
return property_accessor_signatures.get(name) return property_accessor_signatures.get(name)
def get_base_slot_function(scope, slot):
# Returns the function implementing this slot in the baseclass.
# This is useful for enabling the compiler to optimize calls
# that recursively climb the class hierarchy.
base_type = scope.parent_type.base_type
if scope.parent_scope is base_type.scope.parent_scope:
parent_slot = slot.slot_code(base_type.scope)
if parent_slot != '0':
entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
if entry.visibility != 'extern':
return parent_slot
return None
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
# #
...@@ -558,7 +595,7 @@ PyBufferProcs = ( ...@@ -558,7 +595,7 @@ PyBufferProcs = (
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
slot_table = ( slot_table = (
InternalMethodSlot("tp_dealloc"), ConstructorSlot("tp_dealloc", '__dealloc__'),
EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"), EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
EmptySlot("tp_getattr"), EmptySlot("tp_getattr"),
EmptySlot("tp_setattr"), EmptySlot("tp_setattr"),
......
version = '0.9.6.10b' version = '0.9.6.11'
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