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>"
......@@ -24,6 +24,8 @@ Options:
"from <module> import *" at the top of the file.
--incref-local-binop Force local an extra incref on local variables before
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:
# -C, --compile Compile generated .c file to .o file
......@@ -82,6 +84,10 @@ def parse_command_line(args):
Options.incref_local_binop = 1
elif option == "--cleanup":
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:
bad_usage()
else:
......
......@@ -96,6 +96,8 @@ class CCodeWriter:
return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
def mark_pos(self, pos):
# if self.marker is not None:
# print "new marker"
file, line, col = pos
contents = self.file_contents(file)
......
......@@ -12,6 +12,7 @@ import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type
import Symtab
import Options
from Annotate import AnnotationItem
from Cython.Debugging import print_call_chain
from DebugFlags import debug_disposal_code, debug_temp_alloc, \
......@@ -404,6 +405,7 @@ class ExprNode(Node):
code.put_incref(self.result_code, self.ctype())
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
# Generate code to evaluate this node and
# its sub-expressions, and dispose of any
# temporary results of its sub-expressions.
......@@ -456,6 +458,12 @@ class ExprNode(Node):
# will have been reported earlier.
pass
# ---------------- Annotation ---------------------
def annotate(self, code):
for node in self.subexpr_nodes():
node.annotate(code)
# ----------------- Coercion ----------------------
def coerce_to(self, dst_type, env):
......@@ -970,6 +978,14 @@ class NameNode(AtomicExprNode):
Naming.module_cname,
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):
# `expr`
......@@ -1971,6 +1987,12 @@ class AttributeNode(ExprNode):
error(self.pos, "Cannot delete C attribute of extension type")
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)))
#-------------------------------------------------------------------
#
# Constructor nodes
......@@ -2090,6 +2112,15 @@ class SequenceNode(ExprNode):
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):
# Tuple constructor.
......@@ -2177,6 +2208,9 @@ class ListComprehensionNode(SequenceNode):
code.error_goto_if_null(self.result_code, self.pos)))
self.loop.generate_execution_code(code)
def annotate(self, code):
self.loop.annotate(code)
class ListComprehensionAppendNode(ExprNode):
......@@ -2250,6 +2284,10 @@ class DictNode(ExprNode):
key.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):
# Helper class used in the implementation of Python
......@@ -3322,6 +3360,12 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.operand1.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):
# A CascadedCmpNode is not a complete expression node. It
......@@ -3385,6 +3429,11 @@ class CascadedCmpNode(Node, CmpNode):
self.operand2.generate_disposal_code(code)
code.putln("}")
def annotate(self, code):
self.operand2.annotate(code)
if self.cascade:
self.cascade.annotate(code)
binop_node_classes = {
"or": BoolBinopNode,
......@@ -3435,6 +3484,12 @@ class CoercionNode(ExprNode):
if debug_coercion:
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):
# Wrap a node in a C type cast.
......
......@@ -6,6 +6,7 @@ import os, time
from cStringIO import StringIO
from PyrexTypes import CPtrType
import Annotate
import Code
import Naming
import Nodes
......@@ -200,6 +201,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_c_code(self, env, result):
modules = self.referenced_modules
if Options.annotate:
code = Annotate.AnnotationCCodeWriter(StringIO())
else:
code = Code.CCodeWriter(StringIO())
code.h = Code.CCodeWriter(StringIO())
code.init_labels()
......@@ -233,6 +237,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f.write(code.f.getvalue())
f.close()
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):
if env not in modules_seen:
......@@ -260,6 +267,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #define PyNumber_Index(o) PyNumber_Int(o)")
code.putln(" #define PyIndex_Check(o) PyNumber_Check(o)")
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(" #define __stdcall")
code.putln(" #define __cdecl")
......@@ -385,6 +395,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
return header, footer
def generate_struct_union_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
scope = type.scope
if scope:
......@@ -404,6 +415,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(footer)
def generate_enum_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
name = entry.cname or entry.name or ""
header, footer = \
......@@ -447,6 +459,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# code.putln("staticforward PyTypeObject %s;" % name)
def generate_exttype_vtable_struct(self, entry, code):
code.mark_pos(entry.pos)
# Generate struct declaration for an extension type's vtable.
type = entry.type
scope = type.scope
......@@ -467,6 +480,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"};")
def generate_exttype_vtabptr_declaration(self, entry, code):
code.mark_pos(entry.pos)
# Generate declaration of pointer to an extension type's vtable.
type = entry.type
if type.vtabptr_cname:
......@@ -475,6 +489,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.vtabptr_cname))
def generate_obj_struct_definition(self, type, code):
code.mark_pos(type.pos)
# Generate object struct definition for an
# extension type.
if not type.scope:
......
This diff is collapsed.
......@@ -9,6 +9,7 @@ embed_pos_in_docstring = 0
gcc_branch_hints = 1
pre_import = None
docstrings = True
# This is a SAGE-specific option that will
# cause Cython to incref local variables before
......@@ -19,3 +20,5 @@ incref_local_binop = 0
# Decref global variables in this module on exit for garbage collection.
# 0: None, 1+: interned objects, 2+: cdef globals, 3+: types objects
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):
if level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here")
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)
elif s.sy == 'DEF':
return p_DEF_statement(s)
......@@ -1859,15 +1859,17 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0,
modifiers = p_c_modifiers(s)
base_type = p_c_base_type(s)
declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1, nonempty = 1)
declarator.overridable = overridable
if s.sy == ':':
if level not in ('module', 'c_class'):
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,
visibility = visibility,
base_type = base_type,
declarator = declarator,
body = suite,
doc = doc,
modifiers = modifiers,
api = api,
overridable = overridable)
......@@ -1887,7 +1889,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0,
base_type = base_type,
declarators = declarators,
in_pxd = level == 'module_pxd',
api = api)
api = api,
overridable = overridable)
return result
def p_ctypedef_statement(s, level, visibility = 'private', api = 0):
......
......@@ -847,6 +847,7 @@ class ModuleScope(Scope):
#
if not entry:
type = PyExtensionType(name, typedef_flag, base_type)
type.pos = pos
if visibility == 'extern':
type.module_name = module_name
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