Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hack: Add very basic debug info #336

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion guppylang/compiler/func_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def compile_local_func_def(
[v.name for v, _ in captured] + list(func.ty.input_names),
)

def_node = graph.add_def(closure_ty, dfg.node, func.name)
def_node = graph.add_def(closure_ty, dfg.node, func.name, func)
def_input, input_ports = graph.add_input_with_ports(
list(closure_ty.inputs), def_node
)
Expand Down
7 changes: 5 additions & 2 deletions guppylang/definition/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def load_with_args(
# we explicitly monomorphise here and invoke the call compiler with the
# inferred type args.
fun_ty = self.ty.instantiate(type_args)
def_node = graph.add_def(fun_ty, dfg.node, self.name)
def_node = graph.add_def(fun_ty, dfg.node, self.name, self.defined_at)
with graph.parent(def_node):
_, inp_ports = graph.add_input_with_ports(list(fun_ty.inputs))
returns = self.compile_call(
Expand Down Expand Up @@ -279,7 +279,10 @@ def __init__(self, op: ops.OpType) -> None:

def compile(self, args: list[OutPortV]) -> list[OutPortV]:
node = self.graph.add_node(
self.op.model_copy(deep=True), inputs=args, parent=self.dfg.node
self.op.model_copy(deep=True),
inputs=args,
parent=self.dfg.node,
debug=self.node,
)
return_ty = get_type(self.node)
return [node.add_out_port(ty) for ty in type_to_row(return_ty)]
Expand Down
2 changes: 1 addition & 1 deletion guppylang/definition/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def compile_outer(self, graph: Hugr, parent: Node) -> "CompiledFunctionDef":
access to the other compiled functions yet. The body is compiled later in
`CompiledFunctionDef.compile_inner()`.
"""
def_node = graph.add_def(self.ty, parent, self.name)
def_node = graph.add_def(self.ty, parent, self.name, self.defined_at)
return CompiledFunctionDef(
self.id,
self.name,
Expand Down
44 changes: 37 additions & 7 deletions guppylang/hugr_builder/hugr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from hugr.serialization import serial_hugr as raw
from hugr.serialization.ops import OpType

from guppylang.ast_util import AstNode, get_file, get_line_offset, line_col
from guppylang.tys.subst import Inst
from guppylang.tys.ty import (
FunctionType,
Expand Down Expand Up @@ -298,15 +299,18 @@ class Hugr:
_children: dict[NodeIdx, list[Node]]
_default_parent: Node | None

def __init__(self, name: str | None = None) -> None:
def __init__(self, name: str | None = None, file: str | None = None) -> None:
"""Creates a new Hugr."""
self.name = name or "Unnamed"
self._default_parent = None
self._graph = nx.MultiDiGraph()
self._children = {-1: []}
meta_data: dict[str, Any] = {"name": name}
if file is not None:
meta_data["di"] = {"file": file}
self.root = self.add_node(
op=ops.OpType(ops.Module(parent=UNDEFINED)),
meta_data={"name": name},
meta_data=meta_data,
parent=None,
)

Expand Down Expand Up @@ -334,6 +338,7 @@ def add_node(
output_types: TypeList | None = None,
parent: Node | None = None,
inputs: list[OutPortV] | None = None,
debug: AstNode | None = None,
meta_data: dict[str, Any] | None = None,
) -> VNode:
"""Helper method to add a generic value node to the graph."""
Expand All @@ -346,7 +351,7 @@ def add_node(
parent=parent,
in_port_types=[p.ty for p in inputs] if inputs is not None else input_types,
out_port_types=output_types,
meta_data=meta_data or {},
meta_data=(meta_data or {}) | debug_metadata(debug),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a dictionary update? nice

)
self._insert_node(node, inputs)
return node
Expand All @@ -358,6 +363,7 @@ def _add_dfg_node(
output_types: TypeList | None = None,
parent: Node | None = None,
inputs: list[OutPortV] | None = None,
debug: AstNode | None = None,
meta_data: dict[str, Any] | None = None,
) -> DFContainingVNode:
"""Helper method to add a generic dataflow containing value node to the
Expand All @@ -371,7 +377,7 @@ def _add_dfg_node(
parent=parent,
in_port_types=[p.ty for p in inputs] if inputs is not None else input_types,
out_port_types=output_types,
meta_data=meta_data or {},
meta_data=(meta_data or {}) | debug_metadata(debug),
)
self._insert_node(node, inputs)
return node
Expand Down Expand Up @@ -624,11 +630,15 @@ def add_partial(
)

def add_def(
self, fun_ty: FunctionType, parent: Node | None, name: str
self,
fun_ty: FunctionType,
parent: Node | None,
name: str,
debug: AstNode | None = None,
) -> DFContainingVNode:
"""Adds a `FucnDefn` node to the graph."""
op = ops.FuncDefn(name=name, signature=fun_ty.to_hugr_poly(), parent=UNDEFINED)
return self._add_dfg_node(ops.OpType(op), [], [fun_ty], parent, None)
return self._add_dfg_node(ops.OpType(op), [], [fun_ty], parent, None, debug)

def add_declare(self, fun_ty: FunctionType, parent: Node, name: str) -> VNode:
"""Adds a `FuncDecl` node to the graph."""
Expand Down Expand Up @@ -837,13 +847,17 @@ def to_raw(self) -> raw.SerialHugr:
nodes: list[ops.OpType] = [
ops.OpType(ops.Module(parent=UNDEFINED))
] * self._graph.number_of_nodes()
metadata: list[dict[str, Any]] = [
{} for _ in range(self._graph.number_of_nodes())
]
for n in self.nodes():
idx = raw_index[n.idx]
# Nodes without parent have themselves as parent in the serialised format
parent = n.parent or n
n.update_op()
n.op.root.parent = raw_index[parent.idx]
nodes[idx] = n.op
metadata[idx] = n.meta_data

edges: list[raw.Edge] = []
for src, tgt in self.edges():
Expand All @@ -857,8 +871,24 @@ def to_raw(self) -> raw.SerialHugr:
for src, tgt in self.order_edges():
edges.append(((raw_index[src.idx], None), (raw_index[tgt.idx], None)))

return raw.SerialHugr(nodes=nodes, edges=edges)
return raw.SerialHugr(nodes=nodes, edges=edges, metadata=metadata)

def serialize(self) -> str:
"""Serialize this Hugr in JSON format."""
return self.to_raw().to_json()


def debug_metadata(debug: AstNode | None) -> dict[str, Any]:
if debug is not None:
file = get_file(debug)
line, col = line_col(debug)
line_offset = get_line_offset(debug)
if file is not None and line_offset is not None:
return {
"di": {
"file": get_file(debug),
"line": line + line_offset - 1,
"col": col,
}
}
return {}
8 changes: 6 additions & 2 deletions guppylang/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class GuppyModule:
"""A Guppy module that may contain function and type definitions."""

name: str
file: str | None

# Whether the module has already been compiled
_compiled: bool
Expand All @@ -59,8 +60,11 @@ class GuppyModule:
# `_register_buffered_instance_funcs` is called. This way, we can associate
_instance_func_buffer: dict[str, RawDef] | None

def __init__(self, name: str, import_builtins: bool = True):
def __init__(
self, name: str, file: str | None = None, import_builtins: bool = True
):
self.name = name
self.file = file
self._globals = Globals({}, {}, {}, {})
self._compiled_globals = {}
self._imported_globals = Globals.default()
Expand Down Expand Up @@ -197,7 +201,7 @@ def compile(self) -> Hugr:
self._globals = self._globals.update_defs(other_defs)

# Prepare Hugr for this module
graph = Hugr(self.name)
graph = Hugr(self.name, self.file)
module_node = graph.set_root_name(self.name)

# Compile definitions to Hugr
Expand Down
Loading