Commit 3d32b841 authored by Robert Bradshaw's avatar Robert Bradshaw

HTML source annotation module

parent fdae4c23
...@@ -25,6 +25,7 @@ Options: ...@@ -25,6 +25,7 @@ Options:
--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. -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
...@@ -85,6 +86,8 @@ def parse_command_line(args): ...@@ -85,6 +86,8 @@ def parse_command_line(args):
Options.generate_cleanup_code = int(pop_arg()) Options.generate_cleanup_code = int(pop_arg())
elif option in ("-D", "--no-docstrings"): elif option in ("-D", "--no-docstrings"):
Options.docstrings = False 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:
...@@ -388,6 +395,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -388,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:
...@@ -407,6 +415,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -407,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 = \
...@@ -450,6 +459,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -450,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
...@@ -470,6 +480,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -470,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:
...@@ -478,6 +489,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -478,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.
...@@ -20,3 +20,5 @@ incref_local_binop = 0 ...@@ -20,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 = 1 generate_cleanup_code = 1
annotate = 0
\ No newline at end of file
...@@ -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:
......
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