copy to dir type_inference
run python -m type_inference
| from collections import defaultdict | |
| class Graph: | |
| def __init__(self): | |
| self.nodes = defaultdict(set) | |
| def add_node(self, node, neighbors): | |
| self.nodes[node].update(neighbors) | |
| for neighbor in neighbors: | |
| self.nodes[neighbor].add(node) | |
| def __iter__(self): | |
| return iter(self.nodes) | |
| def traverse_graph(self, start_node, hook_function): | |
| visited = set() | |
| def dfs(node): | |
| if node not in visited: | |
| visited.add(node) | |
| hook_function(node) | |
| for neighbor in self.nodes[node]: | |
| dfs(neighbor) | |
| dfs(start_node) | |
| def __str__(self): | |
| pretty_graph = "" | |
| for node, neighbors in self.nodes.items(): | |
| pretty_graph += f"{node} -> {', '.join(str(n) for n in neighbors)}\n" | |
| return pretty_graph |
copy to dir type_inference
run python -m type_inference
| import typing | |
| import graph | |
| class Node: | |
| def __init__( | |
| self, name: str, kind: str, typeset: typing.Optional[list] = None | |
| ) -> None: | |
| self.name = name | |
| self.kind = kind | |
| self.typeset = None | |
| if typeset: | |
| self.typeset = set(typeset) | |
| def __repr__(self) -> str: | |
| typeset = self.typeset or "any" | |
| return f"Node({self.kind} {self.name} {typeset})" | |
| def __str__(self) -> str: | |
| return self.name | |
| def infer_types(gr: graph.Graph): | |
| typed_nodes = [node for node in gr if node.typeset] | |
| for node in typed_nodes: | |
| def adjust_type(other): | |
| if other is node: | |
| return | |
| other.typeset = (other.typeset or node.typeset.copy()) & node.typeset | |
| gr.traverse_graph(node, adjust_type) | |
| # x = 1 | |
| # y = x + 2 | |
| # z = sin(y) | |
| const_1 = Node("1", "const", ["int", "float"]) | |
| const_2 = Node("2", "const", ["int", "float"]) | |
| x = Node("x", "var") | |
| fn_plus = Node("+", "op", ["int", "float"]) | |
| y = Node("y", "var") | |
| fn_sin = Node("sin", "op", ["float"]) | |
| z = Node("z", "var") | |
| gr = graph.Graph() | |
| gr.add_node(x, [fn_plus, const_1]) | |
| gr.add_node(fn_plus, [x, const_2, y]) | |
| gr.add_node(z, [fn_sin, y]) | |
| infer_types(gr) | |
| for node in gr: | |
| print(f"{node.name} {node.typeset}") |