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:
......
...@@ -83,6 +83,13 @@ class Node: ...@@ -83,6 +83,13 @@ class Node:
def generate_code(self, code): def generate_code(self, code):
raise InternalError("generate_code not implemented for %s" % \ raise InternalError("generate_code not implemented for %s" % \
self.__class__.__name__) self.__class__.__name__)
def annotate(self, code):
# mro does the wrong thing
if isinstance(self, BlockNode):
self.body.annotate(code)
else:
print "skipping", self
class BlockNode: class BlockNode:
...@@ -135,7 +142,7 @@ class BlockNode: ...@@ -135,7 +142,7 @@ class BlockNode:
for entry in entries: for entry in entries:
code.putln("static PyObject *%s;" % entry.cname) code.putln("static PyObject *%s;" % entry.cname)
del entries[:] del entries[:]
class StatListNode(Node): class StatListNode(Node):
# stats a list of StatNode # stats a list of StatNode
...@@ -160,6 +167,10 @@ class StatListNode(Node): ...@@ -160,6 +167,10 @@ class StatListNode(Node):
for stat in self.stats: for stat in self.stats:
code.mark_pos(stat.pos) code.mark_pos(stat.pos)
stat.generate_execution_code(code) stat.generate_execution_code(code)
def annotate(self, code):
for stat in self.stats:
stat.annotate(code)
class StatNode(Node): class StatNode(Node):
...@@ -200,6 +211,9 @@ class CDefExternNode(StatNode): ...@@ -200,6 +211,9 @@ class CDefExternNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
pass pass
def annotate(self, code):
self.body.annotate(code)
class CDeclaratorNode(Node): class CDeclaratorNode(Node):
...@@ -302,6 +316,8 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -302,6 +316,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
# exception_check boolean True if PyErr_Occurred check needed # exception_check boolean True if PyErr_Occurred check needed
# nogil boolean Can be called without gil # nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body # with_gil boolean Acquire gil around function body
overridable = 0
def analyse(self, return_type, env): def analyse(self, return_type, env):
func_type_args = [] func_type_args = []
...@@ -351,7 +367,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -351,7 +367,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
return_type, func_type_args, self.has_varargs, return_type, func_type_args, self.has_varargs,
exception_value = exc_val, exception_check = exc_check, exception_value = exc_val, exception_check = exc_check,
calling_convention = self.base.calling_convention, calling_convention = self.base.calling_convention,
nogil = self.nogil, with_gil = self.with_gil) nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
return self.base.analyse(func_type, env) return self.base.analyse(func_type, env)
...@@ -373,6 +389,10 @@ class CArgDeclNode(Node): ...@@ -373,6 +389,10 @@ class CArgDeclNode(Node):
base_type = self.base_type.analyse(env) base_type = self.base_type.analyse(env)
return self.declarator.analyse(base_type, env) return self.declarator.analyse(base_type, env)
def annotate(self, code):
if self.default:
self.default.annotate(code)
class CBaseTypeNode(Node): class CBaseTypeNode(Node):
# Abstract base class for C base type nodes. # Abstract base class for C base type nodes.
...@@ -599,6 +619,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -599,6 +619,7 @@ class FuncDefNode(StatNode, BlockNode):
return 0 return 0
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
code.mark_pos(self.pos)
# Generate C code for header and body of function # Generate C code for header and body of function
genv = env.global_scope() genv = env.global_scope()
lenv = LocalScope(name = self.entry.name, outer_scope = genv) lenv = LocalScope(name = self.entry.name, outer_scope = genv)
...@@ -783,7 +804,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -783,7 +804,7 @@ class CFuncDefNode(FuncDefNode):
args = self.declarator.args, args = self.declarator.args,
star_arg = None, star_arg = None,
starstar_arg = None, starstar_arg = None,
doc = None, # self.doc, doc = self.doc,
body = py_func_body) body = py_func_body)
self.py_func.analyse_declarations(env) self.py_func.analyse_declarations(env)
# Reset scope entry the above cfunction # Reset scope entry the above cfunction
...@@ -1024,7 +1045,9 @@ class DefNode(FuncDefNode): ...@@ -1024,7 +1045,9 @@ class DefNode(FuncDefNode):
Naming.pyfunc_prefix + prefix + name Naming.pyfunc_prefix + prefix + name
entry.pymethdef_cname = \ entry.pymethdef_cname = \
Naming.pymethdef_prefix + prefix + name Naming.pymethdef_prefix + prefix + name
if not entry.is_special: if not Options.docstrings:
self.entry.doc = None
else:
if Options.embed_pos_in_docstring: if Options.embed_pos_in_docstring:
entry.doc = 'File: %s (starting at line %s)'%relative_position(self.pos) entry.doc = 'File: %s (starting at line %s)'%relative_position(self.pos)
if not self.doc is None: if not self.doc is None:
...@@ -1120,7 +1143,7 @@ class DefNode(FuncDefNode): ...@@ -1120,7 +1143,7 @@ class DefNode(FuncDefNode):
code.putln("%s; /*proto*/" % header) code.putln("%s; /*proto*/" % header)
if proto_only: if proto_only:
return return
if self.entry.doc: if self.entry.doc and Options.docstrings:
code.putln( code.putln(
'static char %s[] = "%s";' % ( 'static char %s[] = "%s";' % (
self.entry.doc_cname, self.entry.doc_cname,
...@@ -1433,7 +1456,7 @@ class PyClassDefNode(StatNode, BlockNode): ...@@ -1433,7 +1456,7 @@ class PyClassDefNode(StatNode, BlockNode):
self.body = body self.body = body
import ExprNodes import ExprNodes
self.dict = ExprNodes.DictNode(pos, key_value_pairs = []) self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
if self.doc: if self.doc and Options.docstrings:
if Options.embed_pos_in_docstring: if Options.embed_pos_in_docstring:
doc = 'File: %s (starting at line %s)'%relative_position(self.pos) doc = 'File: %s (starting at line %s)'%relative_position(self.pos)
doc = doc + '\\n' + self.doc doc = doc + '\\n' + self.doc
...@@ -1546,7 +1569,7 @@ class CClassDefNode(StatNode): ...@@ -1546,7 +1569,7 @@ class CClassDefNode(StatNode):
api = self.api) api = self.api)
scope = self.entry.type.scope scope = self.entry.type.scope
if self.doc: if self.doc and Options.docstrings:
if Options.embed_pos_in_docstring: if Options.embed_pos_in_docstring:
scope.doc = 'File: %s (starting at line %s)'%relative_position(self.pos) scope.doc = 'File: %s (starting at line %s)'%relative_position(self.pos)
scope.doc = scope.doc + '\\n' + self.doc scope.doc = scope.doc + '\\n' + self.doc
...@@ -1576,6 +1599,10 @@ class CClassDefNode(StatNode): ...@@ -1576,6 +1599,10 @@ class CClassDefNode(StatNode):
# default values of method arguments. # default values of method arguments.
if self.body: if self.body:
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
def annotate(self, code):
if self.body:
self.body.annotate(code)
class PropertyNode(StatNode): class PropertyNode(StatNode):
...@@ -1588,7 +1615,7 @@ class PropertyNode(StatNode): ...@@ -1588,7 +1615,7 @@ class PropertyNode(StatNode):
def analyse_declarations(self, env): def analyse_declarations(self, env):
entry = env.declare_property(self.name, self.doc, self.pos) entry = env.declare_property(self.name, self.doc, self.pos)
if entry: if entry:
if self.doc: if self.doc and Options.docstrings:
doc_entry = env.get_string_const(self.doc) doc_entry = env.get_string_const(self.doc)
entry.doc_cname = doc_entry.cname entry.doc_cname = doc_entry.cname
self.body.analyse_declarations(entry.scope) self.body.analyse_declarations(entry.scope)
...@@ -1602,6 +1629,9 @@ class PropertyNode(StatNode): ...@@ -1602,6 +1629,9 @@ class PropertyNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
pass pass
def annotate(self, code):
self.body.annotate(code)
class GlobalNode(StatNode): class GlobalNode(StatNode):
# Global variable declaration. # Global variable declaration.
...@@ -1634,6 +1664,9 @@ class ExprStatNode(StatNode): ...@@ -1634,6 +1664,9 @@ class ExprStatNode(StatNode):
code.putln("%s;" % self.expr.result_code) code.putln("%s;" % self.expr.result_code)
self.expr.generate_disposal_code(code) self.expr.generate_disposal_code(code)
def annotate(self, code):
self.expr.annotate(code)
class AssignmentNode(StatNode): class AssignmentNode(StatNode):
# Abstract base class for assignment nodes. # Abstract base class for assignment nodes.
...@@ -1656,7 +1689,7 @@ class AssignmentNode(StatNode): ...@@ -1656,7 +1689,7 @@ class AssignmentNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.generate_rhs_evaluation_code(code) self.generate_rhs_evaluation_code(code)
self.generate_assignment_code(code) self.generate_assignment_code(code)
class SingleAssignmentNode(AssignmentNode): class SingleAssignmentNode(AssignmentNode):
# The simplest case: # The simplest case:
...@@ -1703,6 +1736,10 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -1703,6 +1736,10 @@ class SingleAssignmentNode(AssignmentNode):
def generate_assignment_code(self, code): def generate_assignment_code(self, code):
self.lhs.generate_assignment_code(self.rhs, code) self.lhs.generate_assignment_code(self.rhs, code)
def annotate(self, code):
self.lhs.annotate(code)
self.rhs.annotate(code)
class CascadedAssignmentNode(AssignmentNode): class CascadedAssignmentNode(AssignmentNode):
# An assignment with multiple left hand sides: # An assignment with multiple left hand sides:
...@@ -1779,6 +1816,13 @@ class CascadedAssignmentNode(AssignmentNode): ...@@ -1779,6 +1816,13 @@ class CascadedAssignmentNode(AssignmentNode):
# Assignment has disposed of the cloned RHS # Assignment has disposed of the cloned RHS
self.rhs.generate_disposal_code(code) self.rhs.generate_disposal_code(code)
def annotate(self, code):
for i in range(len(self.lhs_list)):
lhs = self.lhs_list[i].annotate(code)
rhs = self.coerced_rhs_list[i].annotate(code)
self.rhs.annotate(code)
class ParallelAssignmentNode(AssignmentNode): class ParallelAssignmentNode(AssignmentNode):
# A combined packing/unpacking assignment: # A combined packing/unpacking assignment:
# #
...@@ -1816,6 +1860,11 @@ class ParallelAssignmentNode(AssignmentNode): ...@@ -1816,6 +1860,11 @@ class ParallelAssignmentNode(AssignmentNode):
for stat in self.stats: for stat in self.stats:
stat.generate_assignment_code(code) stat.generate_assignment_code(code)
def annotate(self, code):
for stat in self.stats:
stat.annotate(code)
class InPlaceAssignmentNode(AssignmentNode): class InPlaceAssignmentNode(AssignmentNode):
# An in place arithmatic operand: # An in place arithmatic operand:
# #
...@@ -1920,6 +1969,11 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -1920,6 +1969,11 @@ class InPlaceAssignmentNode(AssignmentNode):
"%": "PyNumber_InPlaceRemainder", "%": "PyNumber_InPlaceRemainder",
} }
def annotate(self, code):
self.lhs.annotate(code)
self.rhs.annotate(code)
self.dup.annotate(code)
class PrintStatNode(StatNode): class PrintStatNode(StatNode):
# print statement # print statement
...@@ -1950,6 +2004,10 @@ class PrintStatNode(StatNode): ...@@ -1950,6 +2004,10 @@ class PrintStatNode(StatNode):
code.putln( code.putln(
"if (__Pyx_PrintNewline() < 0) %s" % "if (__Pyx_PrintNewline() < 0) %s" %
code.error_goto(self.pos)) code.error_goto(self.pos))
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
class DelStatNode(StatNode): class DelStatNode(StatNode):
...@@ -1974,6 +2032,10 @@ class DelStatNode(StatNode): ...@@ -1974,6 +2032,10 @@ class DelStatNode(StatNode):
arg.generate_deletion_code(code) arg.generate_deletion_code(code)
# else error reported earlier # else error reported earlier
def annotate(self, code):
for arg in self.args:
arg.annotate(code)
class PassStatNode(StatNode): class PassStatNode(StatNode):
# pass statement # pass statement
...@@ -2047,6 +2109,7 @@ class ReturnStatNode(StatNode): ...@@ -2047,6 +2109,7 @@ class ReturnStatNode(StatNode):
error(self.pos, "Return value required") error(self.pos, "Return value required")
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.mark_pos(self.pos)
if not self.return_type: if not self.return_type:
# error reported earlier # error reported earlier
return return
...@@ -2072,6 +2135,10 @@ class ReturnStatNode(StatNode): ...@@ -2072,6 +2135,10 @@ class ReturnStatNode(StatNode):
# "goto %s;" % # "goto %s;" %
# code.return_label) # code.return_label)
code.put_goto(code.return_label) code.put_goto(code.return_label)
def annotate(self, code):
if self.value:
self.value.annotate(code)
class RaiseStatNode(StatNode): class RaiseStatNode(StatNode):
...@@ -2139,6 +2206,14 @@ class RaiseStatNode(StatNode): ...@@ -2139,6 +2206,14 @@ class RaiseStatNode(StatNode):
code.putln( code.putln(
code.error_goto(self.pos)) code.error_goto(self.pos))
def annotate(self, code):
if self.exc_type:
self.exc_type.annotate(code)
if self.exc_value:
self.exc_value.annotate(code)
if self.exc_tb:
self.exc_tb.annotate(code)
class ReraiseStatNode(StatNode): class ReraiseStatNode(StatNode):
...@@ -2174,15 +2249,15 @@ class AssertStatNode(StatNode): ...@@ -2174,15 +2249,15 @@ class AssertStatNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS") code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
self.cond.generate_evaluation_code(code) self.cond.generate_evaluation_code(code)
if self.value:
self.value.generate_evaluation_code(code)
code.putln( code.putln(
"if (unlikely(!%s)) {" % "if (unlikely(!%s)) {" %
self.cond.result_code) self.cond.result_code)
if self.value: if self.value:
self.value.generate_evaluation_code(code)
code.putln( code.putln(
"PyErr_SetObject(PyExc_AssertionError, %s);" % "PyErr_SetObject(PyExc_AssertionError, %s);" %
self.value.py_result()) self.value.py_result())
self.value.generate_disposal_code(code)
else: else:
code.putln( code.putln(
"PyErr_SetNone(PyExc_AssertionError);") "PyErr_SetNone(PyExc_AssertionError);")
...@@ -2191,10 +2266,14 @@ class AssertStatNode(StatNode): ...@@ -2191,10 +2266,14 @@ class AssertStatNode(StatNode):
code.putln( code.putln(
"}") "}")
self.cond.generate_disposal_code(code) self.cond.generate_disposal_code(code)
if self.value:
self.value.generate_disposal_code(code)
code.putln("#endif") code.putln("#endif")
def annotate(self, code):
self.cond.annotate(code)
if self.value:
self.value.annotate(code)
class IfStatNode(StatNode): class IfStatNode(StatNode):
# if statement # if statement
# #
...@@ -2214,6 +2293,7 @@ class IfStatNode(StatNode): ...@@ -2214,6 +2293,7 @@ class IfStatNode(StatNode):
self.else_clause.analyse_expressions(env) self.else_clause.analyse_expressions(env)
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.mark_pos(self.pos)
end_label = code.new_label() end_label = code.new_label()
for if_clause in self.if_clauses: for if_clause in self.if_clauses:
if_clause.generate_execution_code(code, end_label) if_clause.generate_execution_code(code, end_label)
...@@ -2222,6 +2302,12 @@ class IfStatNode(StatNode): ...@@ -2222,6 +2302,12 @@ class IfStatNode(StatNode):
self.else_clause.generate_execution_code(code) self.else_clause.generate_execution_code(code)
code.putln("}") code.putln("}")
code.put_label(end_label) code.put_label(end_label)
def annotate(self, code):
for if_clause in self.if_clauses:
if_clause.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class IfClauseNode(Node): class IfClauseNode(Node):
...@@ -2252,6 +2338,10 @@ class IfClauseNode(Node): ...@@ -2252,6 +2338,10 @@ class IfClauseNode(Node):
# end_label) # end_label)
code.put_goto(end_label) code.put_goto(end_label)
code.putln("}") code.putln("}")
def annotate(self, code):
self.condition.annotate(code)
self.body.annotate(code)
class WhileStatNode(StatNode): class WhileStatNode(StatNode):
...@@ -2294,6 +2384,12 @@ class WhileStatNode(StatNode): ...@@ -2294,6 +2384,12 @@ class WhileStatNode(StatNode):
code.putln("}") code.putln("}")
code.put_label(break_label) code.put_label(break_label)
def annotate(self, code):
self.condition.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
def ForStatNode(pos, **kw): def ForStatNode(pos, **kw):
if kw.has_key('iterator'): if kw.has_key('iterator'):
...@@ -2351,6 +2447,14 @@ class ForInStatNode(StatNode): ...@@ -2351,6 +2447,14 @@ class ForInStatNode(StatNode):
code.put_label(break_label) code.put_label(break_label)
self.iterator.generate_disposal_code(code) self.iterator.generate_disposal_code(code)
def annotate(self, code):
self.target.annotate(code)
self.iterator.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
self.item.annotate(code)
class ForFromStatNode(StatNode): class ForFromStatNode(StatNode):
# for name from expr rel name rel expr # for name from expr rel name rel expr
...@@ -2468,6 +2572,16 @@ class ForFromStatNode(StatNode): ...@@ -2468,6 +2572,16 @@ class ForFromStatNode(StatNode):
'>=': ("", "--"), '>=': ("", "--"),
'>' : ("-1", "--") '>' : ("-1", "--")
} }
def annotate(self, code):
self.target.annotate(code)
self.bound1.annotate(code)
self.bound2.annotate(code)
if self.step:
self.bound2.annotate(code)
self.body.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class TryExceptStatNode(StatNode): class TryExceptStatNode(StatNode):
...@@ -2524,6 +2638,13 @@ class TryExceptStatNode(StatNode): ...@@ -2524,6 +2638,13 @@ class TryExceptStatNode(StatNode):
code.put_goto(code.error_label) code.put_goto(code.error_label)
code.put_label(end_label) code.put_label(end_label)
def annotate(self, code):
self.body.annotate(code)
for except_node in self.except_clauses:
except_node.annotate(code)
if self.else_clause:
self.else_clause.annotate(code)
class ExceptClauseNode(Node): class ExceptClauseNode(Node):
# Part of try ... except statement. # Part of try ... except statement.
...@@ -2597,6 +2718,12 @@ class ExceptClauseNode(Node): ...@@ -2597,6 +2718,12 @@ class ExceptClauseNode(Node):
code.putln( code.putln(
"}") "}")
def annotate(self, code):
self.pattern.annotate(code)
if self.target:
self.target.annotate(code)
self.body.annotate(code)
class TryFinallyStatNode(StatNode): class TryFinallyStatNode(StatNode):
# try ... finally statement # try ... finally statement
...@@ -2763,6 +2890,10 @@ class TryFinallyStatNode(StatNode): ...@@ -2763,6 +2890,10 @@ class TryFinallyStatNode(StatNode):
code.putln( code.putln(
"}") "}")
def annotate(self, code):
self.body.annotate(code)
self.finally_clause.annotate(code)
class GILStatNode(TryFinallyStatNode): class GILStatNode(TryFinallyStatNode):
# 'with gil' or 'with nogil' statement # 'with gil' or 'with nogil' statement
......
...@@ -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