Source code for debug.call_inspector

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
A visitor implementation that stores a representation of the calling graph into a text stream.
Its use is for debugging purposes, to check the structure of the generated program.
"""

from __future__ import print_function
from __future__ import unicode_literals

import io

from functools import singledispatch

from core import ast

global_visit_main = True

[docs]def write_graph(program, visit_main, path): with io.open(path, mode="w", encoding="utf-8") as buffer: buffer.write("digraph G {\n") buffer.write('graph [rankdir = "LR", orientation = "landscape", ranksep = 3.0, nodesep= 2.0];\n') buffer.write('node [fontsize = "8", style = "filled", color = "blue"];\n') buffer.write('edge [fontsize = "8", weight = 0.1];\n') # buffer.write('main [style = "filled", color = "red"];\n') edges = [] nodes = [] global global_visit_main global_visit_main = visit_main callinsp_visit(program, nodes, edges) for e in edges: buffer.write(e + "\n") for n in nodes: buffer.write(n + "\n") buffer.write("}\n")
[docs]@singledispatch def callinsp_visit(node, nodes, edges, *args, **kwargs): raise TypeError("Unknown node type: " + node.__class__.__name__)
@callinsp_visit.register(ast.Program) def _(program, nodes, edges): for f in program.functions: callinsp_visit(f, nodes, edges) if global_visit_main: callinsp_visit(program.main, nodes, edges) @callinsp_visit.register(ast.Function) def _(function, nodes, edges): if function.name == "main": color = "tomato" elif function.name.startswith("func"): color = "steelblue1" elif function.name.startswith("proc"): color = "greenyellow" else: raise AssertionError("Unknown type of function") nodes.append('{} [color = "{}"];'.format(function.name, color)) for s in function.stmts: callinsp_visit(s, nodes, edges, function.name, function) @callinsp_visit.register(ast.Invocation) def _(invocation, nodes, edges, func_name, parent): comment = " " if isinstance(parent, ast.Function): comment = " /* stmt invocation */" else: comment = " /* expr invocation */" edges.append("{} -> {}{}".format(func_name, invocation.func_name, comment)) if invocation.arguments: for arg in invocation.arguments: if isinstance(arg, ast.ASTNode): callinsp_visit(arg, nodes, edges, func_name, invocation) @callinsp_visit.register(ast.BinaryExpression) @callinsp_visit.register(ast.Assignment) @callinsp_visit.register(ast.ArrayAccessExpression) @callinsp_visit.register(ast.Return) @callinsp_visit.register(ast.UnaryExpression) @callinsp_visit.register(ast.StructAccessExpression) @callinsp_visit.register(ast.TernaryExpression) def _(node, nodes, edges, func_name, parent): for exp in node.children: if isinstance(exp, ast.ASTNode): callinsp_visit(exp, nodes, edges, func_name, node) @callinsp_visit.register(ast.Literal) @callinsp_visit.register(ast.Variable) @callinsp_visit.register(ast.Label) def _(node, nodes, edges, func_name, parent): pass