Commit c24f9ace authored by Stefan Behnel's avatar Stefan Behnel

merge of Cython 0.9.6.9

parents 837aa28c cd1f577d
# Note: Work in progress
import re
from StringIO import StringIO
from Code import CCodeWriter
class AnnotationCCodeWriter(CCodeWriter):
def __init__(self, f):
CCodeWriter.__init__(self, self)
self.buffer = StringIO()
self.real_f = f
self.annotations = []
self.last_pos = None
self.code = {}
def getvalue(self):
return self.real_f.getvalue()
def write(self, s):
self.real_f.write(s)
self.buffer.write(s)
def mark_pos(self, pos):
# if pos is not None:
# CCodeWriter.mark_pos(self, pos)
# return
print "marking", pos
if self.last_pos:
try:
code = self.code[self.last_pos[1]]
except KeyError:
code = ""
self.code[self.last_pos[1]] = code + self.buffer.getvalue()
self.buffer = StringIO()
self.last_pos = pos
def annotate(self, pos, item):
self.annotations.append((pos, item))
def save_annotation(self, filename):
self.mark_pos(None)
f = open(filename)
lines = f.readlines()
for k in range(len(lines)):
# there has to be a better way to do this
lines[k] = lines[k].replace(' ','\t ')
lines[k] = lines[k].replace(' ','\t\t')
# TODO: this is incorrect
lines[k] = lines[k].replace('<', '~')
lines[k] = lines[k].replace('>', '~')
f.close()
all = []
for pos, item in self.annotations:
if pos[0] == filename:
start = item.start()
size, end = item.end()
if size:
all.append((pos, start))
all.append(((filename, pos[1], pos[2]+size), end))
else:
all.append((pos, start+end))
all.sort()
all.reverse()
for pos, item in all:
_, line_no, col = pos
line_no -= 1
col += 1
line = lines[line_no]
lines[line_no] = line[:col] + item + line[col:]
f = open("%s.html" % filename, "w")
f.write('<html>\n')
f.write("""
<head>
<style type="text/css">
body { font-family: courier; font-size: 12; }
.code { font-size: 9; color: #444444; display: none; margin-left: 20px; }
.py_api { color: red; }
.pyx_api { color: #FF3000; }
.py_macro_api { color: #FF8000; }
.tag { }
.coerce { color: #008000; border: 1px dotted #008000 }
.py_attr { color: #FF0000; font-weight: bold; }
.c_attr { color: #0000FF; }
.py_call { color: #FF0000; font-weight: bold; }
.c_call { color: #0000FF; }
</style>
<script>
function toggleDiv(id) {
theDiv = document.getElementById(id);
if (theDiv.style.display == 'none') theDiv.style.display = 'block';
else theDiv.style.display = 'none';
}
</script>
</head>
""")
f.write('<body>\n')
k = 0
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_]+)\(')
py_marco_api = re.compile('(Py[A-Za-z]*_[A-Z][A-Z_]+)')
for line in lines:
k += 1
try:
code = self.code[k]
except KeyError:
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, macro_api_calls = py_marco_api.subn(r"<span class='py_macro_api'>\1</span>", code)
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(" %d: " % k)
line = line.replace('\t', '&nbsp;')
f.write(line)
f.write('</div>\n')
f.write("<div id='line%s' class='code' style='background-color: #%s'>%s</div>" % (k, color, code.replace('\n', '\n<br>')))
f.write('</body></html>\n')
f.close()
# TODO: make this cleaner
def escape(raw_string):
raw_string = raw_string.replace("\'", r"&#146;")
raw_string = raw_string.replace('\"', r'&quot;')
raw_string = raw_string.replace('\n', r'<br>\n')
raw_string = raw_string.replace('\t', r'\t')
return raw_string
class AnnotationItem:
def __init__(self, style, text, tag="", size=0):
self.style = style
self.text = text
self.tag = tag
self.size = size
def start(self):
return "<span class='tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
def end(self):
return self.size, "</span>"
...@@ -23,7 +23,9 @@ Options: ...@@ -23,7 +23,9 @@ Options:
module. Emulates the behavior of putting module. Emulates the behavior of putting
"from <module> import *" at the top of the file. "from <module> import *" at the top of the file.
--incref-local-binop Force local an extra incref on local variables before --incref-local-binop Force local an extra incref on local variables before
performing any binary operations. performing any binary operations.
-D, --no-docstrings Remove docstrings.
-a, --annotate Produce an colorized version of the source.
""" """
#The following experimental options are supported only on MacOSX: #The following experimental options are supported only on MacOSX:
# -C, --compile Compile generated .c file to .o file # -C, --compile Compile generated .c file to .o file
...@@ -82,6 +84,10 @@ def parse_command_line(args): ...@@ -82,6 +84,10 @@ def parse_command_line(args):
Options.incref_local_binop = 1 Options.incref_local_binop = 1
elif option == "--cleanup": elif option == "--cleanup":
Options.generate_cleanup_code = int(pop_arg()) Options.generate_cleanup_code = int(pop_arg())
elif option in ("-D", "--no-docstrings"):
Options.docstrings = False
elif option in ("-a", "--annotate"):
Options.annotate = True
else: else:
bad_usage() bad_usage()
else: else:
......
...@@ -96,6 +96,8 @@ class CCodeWriter: ...@@ -96,6 +96,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 self.marker is not None:
# print "new marker"
file, line, col = pos file, line, col = pos
contents = self.file_contents(file) contents = self.file_contents(file)
......
...@@ -12,6 +12,7 @@ import PyrexTypes ...@@ -12,6 +12,7 @@ import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type from PyrexTypes import py_object_type, c_long_type, typecast, error_type
import Symtab import Symtab
import Options import Options
from Annotate import AnnotationItem
from Cython.Debugging import print_call_chain from Cython.Debugging import print_call_chain
from DebugFlags import debug_disposal_code, debug_temp_alloc, \ from DebugFlags import debug_disposal_code, debug_temp_alloc, \
...@@ -404,6 +405,7 @@ class ExprNode(Node): ...@@ -404,6 +405,7 @@ class ExprNode(Node):
code.put_incref(self.result_code, self.ctype()) code.put_incref(self.result_code, self.ctype())
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
# Generate code to evaluate this node and # Generate code to evaluate this node and
# its sub-expressions, and dispose of any # its sub-expressions, and dispose of any
# temporary results of its sub-expressions. # temporary results of its sub-expressions.
...@@ -456,6 +458,12 @@ class ExprNode(Node): ...@@ -456,6 +458,12 @@ class ExprNode(Node):
# will have been reported earlier. # will have been reported earlier.
pass pass
# ---------------- Annotation ---------------------
def annotate(self, code):
for node in self.subexpr_nodes():
node.annotate(code)
# ----------------- Coercion ---------------------- # ----------------- Coercion ----------------------
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
...@@ -969,6 +977,14 @@ class NameNode(AtomicExprNode): ...@@ -969,6 +977,14 @@ class NameNode(AtomicExprNode):
'PyObject_DelAttrString(%s, "%s")' % ( 'PyObject_DelAttrString(%s, "%s")' % (
Naming.module_cname, Naming.module_cname,
self.entry.name)) self.entry.name))
def annotate(self, code):
if hasattr(self, 'is_called') and self.is_called:
pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
if self.type.is_pyobject:
code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
else:
code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
class BackquoteNode(ExprNode): class BackquoteNode(ExprNode):
...@@ -1970,6 +1986,12 @@ class AttributeNode(ExprNode): ...@@ -1970,6 +1986,12 @@ class AttributeNode(ExprNode):
else: else:
error(self.pos, "Cannot delete C attribute of extension type") error(self.pos, "Cannot delete C attribute of extension type")
self.obj.generate_disposal_code(code) self.obj.generate_disposal_code(code)
def annotate(self, code):
if self.is_py_attr:
code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
else:
code.annotate(self.pos, AnnotationItem('c_attr', 'c attribute', size=len(self.attribute)))
#------------------------------------------------------------------- #-------------------------------------------------------------------
# #
...@@ -2089,6 +2111,15 @@ class SequenceNode(ExprNode): ...@@ -2089,6 +2111,15 @@ class SequenceNode(ExprNode):
self.iterator.generate_disposal_code(code) self.iterator.generate_disposal_code(code)
code.putln("}") code.putln("}")
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
if self.unpacked_items:
for arg in self.unpacked_items:
arg.annotate(code)
for arg in self.coerced_unpacked_items:
arg.annotate(code)
class TupleNode(SequenceNode): class TupleNode(SequenceNode):
...@@ -2176,6 +2207,9 @@ class ListComprehensionNode(SequenceNode): ...@@ -2176,6 +2207,9 @@ class ListComprehensionNode(SequenceNode):
0, 0,
code.error_goto_if_null(self.result_code, self.pos))) code.error_goto_if_null(self.result_code, self.pos)))
self.loop.generate_execution_code(code) self.loop.generate_execution_code(code)
def annotate(self, code):
self.loop.annotate(code)
class ListComprehensionAppendNode(ExprNode): class ListComprehensionAppendNode(ExprNode):
...@@ -2249,7 +2283,11 @@ class DictNode(ExprNode): ...@@ -2249,7 +2283,11 @@ class DictNode(ExprNode):
value.py_result())) value.py_result()))
key.generate_disposal_code(code) key.generate_disposal_code(code)
value.generate_disposal_code(code) value.generate_disposal_code(code)
def annotate(self, code):
for key, value in self.key_value_pairs:
key.annotate(code)
value.annotate(code)
class ClassNode(ExprNode): class ClassNode(ExprNode):
# Helper class used in the implementation of Python # Helper class used in the implementation of Python
...@@ -3321,6 +3359,12 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -3321,6 +3359,12 @@ class PrimaryCmpNode(ExprNode, CmpNode):
# so only need to dispose of the two main operands. # so only need to dispose of the two main operands.
self.operand1.generate_disposal_code(code) self.operand1.generate_disposal_code(code)
self.operand2.generate_disposal_code(code) self.operand2.generate_disposal_code(code)
def annotate(self, code):
self.operand1.annotate(code)
self.operand2.annotate(code)
if self.cascade:
self.cascade.annotate(code)
class CascadedCmpNode(Node, CmpNode): class CascadedCmpNode(Node, CmpNode):
...@@ -3385,6 +3429,11 @@ class CascadedCmpNode(Node, CmpNode): ...@@ -3385,6 +3429,11 @@ class CascadedCmpNode(Node, CmpNode):
self.operand2.generate_disposal_code(code) self.operand2.generate_disposal_code(code)
code.putln("}") code.putln("}")
def annotate(self, code):
self.operand2.annotate(code)
if self.cascade:
self.cascade.annotate(code)
binop_node_classes = { binop_node_classes = {
"or": BoolBinopNode, "or": BoolBinopNode,
...@@ -3434,6 +3483,12 @@ class CoercionNode(ExprNode): ...@@ -3434,6 +3483,12 @@ class CoercionNode(ExprNode):
self.arg = arg self.arg = arg
if debug_coercion: if debug_coercion:
print self, "Coercing", self.arg print self, "Coercing", self.arg
def annotate(self, code):
self.arg.annotate(code)
if self.arg.type != self.type:
file, line, col = self.pos
code.annotate((file, line, col-1), AnnotationItem(style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
class CastNode(CoercionNode): class CastNode(CoercionNode):
......
...@@ -6,6 +6,7 @@ import os, time ...@@ -6,6 +6,7 @@ import os, time
from cStringIO import StringIO from cStringIO import StringIO
from PyrexTypes import CPtrType from PyrexTypes import CPtrType
import Annotate
import Code import Code
import Naming import Naming
import Nodes import Nodes
...@@ -200,7 +201,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -200,7 +201,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_c_code(self, env, result): def generate_c_code(self, env, result):
modules = self.referenced_modules modules = self.referenced_modules
code = Code.CCodeWriter(StringIO()) if Options.annotate:
code = Annotate.AnnotationCCodeWriter(StringIO())
else:
code = Code.CCodeWriter(StringIO())
code.h = Code.CCodeWriter(StringIO()) code.h = Code.CCodeWriter(StringIO())
code.init_labels() code.init_labels()
self.generate_module_preamble(env, modules, code.h) self.generate_module_preamble(env, modules, code.h)
...@@ -233,6 +237,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -233,6 +237,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f.write(code.f.getvalue()) f.write(code.f.getvalue())
f.close() f.close()
result.c_file_generated = 1 result.c_file_generated = 1
if Options.annotate:
self.annotate(code)
code.save_annotation(result.c_file[:-1] + "pyx") # change?
def find_referenced_modules(self, env, module_list, modules_seen): def find_referenced_modules(self, env, module_list, modules_seen):
if env not in modules_seen: if env not in modules_seen:
...@@ -260,6 +267,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -260,6 +267,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #define PyNumber_Index(o) PyNumber_Int(o)") code.putln(" #define PyNumber_Index(o) PyNumber_Int(o)")
code.putln(" #define PyIndex_Check(o) PyNumber_Check(o)") code.putln(" #define PyIndex_Check(o) PyNumber_Check(o)")
code.putln("#endif") code.putln("#endif")
code.putln("#if PY_VERSION_HEX < 0x02040000")
code.putln(" #define METH_COEXIST 0")
code.putln("#endif")
code.putln("#ifndef WIN32") code.putln("#ifndef WIN32")
code.putln(" #define __stdcall") code.putln(" #define __stdcall")
code.putln(" #define __cdecl") code.putln(" #define __cdecl")
...@@ -385,6 +395,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -385,6 +395,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
return header, footer return header, footer
def generate_struct_union_definition(self, entry, code): def generate_struct_union_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type type = entry.type
scope = type.scope scope = type.scope
if scope: if scope:
...@@ -404,6 +415,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -404,6 +415,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(footer) code.putln(footer)
def generate_enum_definition(self, entry, code): def generate_enum_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type type = entry.type
name = entry.cname or entry.name or "" name = entry.cname or entry.name or ""
header, footer = \ header, footer = \
...@@ -447,6 +459,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -447,6 +459,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# code.putln("staticforward PyTypeObject %s;" % name) # code.putln("staticforward PyTypeObject %s;" % name)
def generate_exttype_vtable_struct(self, entry, code): def generate_exttype_vtable_struct(self, entry, code):
code.mark_pos(entry.pos)
# Generate struct declaration for an extension type's vtable. # Generate struct declaration for an extension type's vtable.
type = entry.type type = entry.type
scope = type.scope scope = type.scope
...@@ -467,6 +480,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -467,6 +480,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"};") "};")
def generate_exttype_vtabptr_declaration(self, entry, code): def generate_exttype_vtabptr_declaration(self, entry, code):
code.mark_pos(entry.pos)
# Generate declaration of pointer to an extension type's vtable. # Generate declaration of pointer to an extension type's vtable.
type = entry.type type = entry.type
if type.vtabptr_cname: if type.vtabptr_cname:
...@@ -475,6 +489,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -475,6 +489,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.vtabptr_cname)) type.vtabptr_cname))
def generate_obj_struct_definition(self, type, code): def generate_obj_struct_definition(self, type, code):
code.mark_pos(type.pos)
# Generate object struct definition for an # Generate object struct definition for an
# extension type. # extension type.
if not type.scope: if not type.scope:
......
This diff is collapsed.
...@@ -9,6 +9,7 @@ embed_pos_in_docstring = 0 ...@@ -9,6 +9,7 @@ embed_pos_in_docstring = 0
gcc_branch_hints = 1 gcc_branch_hints = 1
pre_import = None pre_import = None
docstrings = True
# This is a SAGE-specific option that will # This is a SAGE-specific option that will
# cause Cython to incref local variables before # cause Cython to incref local variables before
...@@ -19,3 +20,5 @@ incref_local_binop = 0 ...@@ -19,3 +20,5 @@ incref_local_binop = 0
# Decref global variables in this module on exit for garbage collection. # Decref global variables in this module on exit for garbage collection.
# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects # 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects
generate_cleanup_code = 3 generate_cleanup_code = 3
annotate = 0
\ No newline at end of file
...@@ -1300,7 +1300,7 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0): ...@@ -1300,7 +1300,7 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0):
if level not in ('module', 'module_pxd'): if level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here") s.error("ctypedef statement not allowed here")
if api: if api:
error(s.pos, "'api' not allowed with 'ctypedef'") error(s.position(), "'api' not allowed with 'ctypedef'")
return p_ctypedef_statement(s, level, visibility, api) return p_ctypedef_statement(s, level, visibility, api)
elif s.sy == 'DEF': elif s.sy == 'DEF':
return p_DEF_statement(s) return p_DEF_statement(s)
...@@ -1859,15 +1859,17 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0, ...@@ -1859,15 +1859,17 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0,
modifiers = p_c_modifiers(s) modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s) base_type = p_c_base_type(s)
declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1, nonempty = 1) declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1, nonempty = 1)
declarator.overridable = overridable
if s.sy == ':': if s.sy == ':':
if level not in ('module', 'c_class'): if level not in ('module', 'c_class'):
s.error("C function definition not allowed here") s.error("C function definition not allowed here")
suite = p_suite(s, 'function', with_pseudo_doc = 1) doc, suite = p_suite(s, 'function', with_doc = 1)
result = Nodes.CFuncDefNode(pos, result = Nodes.CFuncDefNode(pos,
visibility = visibility, visibility = visibility,
base_type = base_type, base_type = base_type,
declarator = declarator, declarator = declarator,
body = suite, body = suite,
doc = doc,
modifiers = modifiers, modifiers = modifiers,
api = api, api = api,
overridable = overridable) overridable = overridable)
...@@ -1887,7 +1889,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0, ...@@ -1887,7 +1889,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0,
base_type = base_type, base_type = base_type,
declarators = declarators, declarators = declarators,
in_pxd = level == 'module_pxd', in_pxd = level == 'module_pxd',
api = api) api = api,
overridable = overridable)
return result return result
def p_ctypedef_statement(s, level, visibility = 'private', api = 0): def p_ctypedef_statement(s, level, visibility = 'private', api = 0):
......
...@@ -847,6 +847,7 @@ class ModuleScope(Scope): ...@@ -847,6 +847,7 @@ class ModuleScope(Scope):
# #
if not entry: if not entry:
type = PyExtensionType(name, typedef_flag, base_type) type = PyExtensionType(name, typedef_flag, base_type)
type.pos = pos
if visibility == 'extern': if visibility == 'extern':
type.module_name = module_name type.module_name = module_name
else: else:
......
version = '0.9.6.8' version = '0.9.6.9'
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