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