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, \
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.
# 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):
'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):
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)))
#-------------------------------------------------------------------
#
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):
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):
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
# 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):
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,
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):
from cStringIO import StringIO
from PyrexTypes import CPtrType
+import Annotate
import Code
import Naming
import Nodes
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)
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:
return header, footer
def generate_struct_union_definition(self, entry, code):
+ code.mark_pos(entry.pos)
type = entry.type
scope = type.scope
if scope:
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 = \
# 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
"};")
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:
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:
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:
for entry in entries:
code.putln("static PyObject *%s;" % entry.cname)
del entries[:]
-
+
class StatListNode(Node):
# stats a list of StatNode
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):
def generate_execution_code(self, code):
pass
+
+ def annotate(self, code):
+ self.body.annotate(code)
class CDeclaratorNode(Node):
# 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 = []
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.
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)
# 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):
def generate_execution_code(self, code):
pass
+ def annotate(self, code):
+ self.body.annotate(code)
+
class GlobalNode(StatNode):
# Global variable declaration.
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.
def generate_execution_code(self, code):
self.generate_rhs_evaluation_code(code)
self.generate_assignment_code(code)
-
+
class SingleAssignmentNode(AssignmentNode):
# The simplest case:
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:
# 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:
#
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:
#
"%": "PyNumber_InPlaceRemainder",
}
+ def annotate(self, code):
+ self.lhs.annotate(code)
+ self.rhs.annotate(code)
+ self.dup.annotate(code)
+
class PrintStatNode(StatNode):
# print statement
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):
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
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
# "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):
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):
self.cond.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
#
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)
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):
# end_label)
code.put_goto(end_label)
code.putln("}")
+
+ def annotate(self, code):
+ self.condition.annotate(code)
+ self.body.annotate(code)
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'):
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
'>=': ("", "--"),
'>' : ("-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):
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.
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
code.putln(
"}")
+ def annotate(self, code):
+ self.body.annotate(code)
+ self.finally_clause.annotate(code)
+
class GILStatNode(TryFinallyStatNode):
# 'with gil' or 'with nogil' statement