def emit(g: Graph) -> Module: i = 0 m = Module() variables: t.Dict[int, Symbol] = {} # TODO: with type # TODO: name original_args = [ f"{node.name} string" for node in g.nodes if node.is_primitive ] with m.func("run", *original_args, return_="error"): for node in topological_sorted(g): if node.is_primitive: variables[node.uid] = m.symbol(node.name) continue args = [] for dep in node.depends: args.append(variables[dep.uid]) m.letN return_type = node.metadata.get("return_type", "") if return_type == "": [variables[node.uid]] = m.letN([f"v{i}"], m.symbol(node.name)(*args)) elif return_type == "with-err": variables[node.uid], err = m.letN((f"v{i}", "err"), m.symbol(node.name)(*args)) with m.if_("err != nil"): m.return_("err") elif return_type == "with-cleanup": variables[node.uid], cleanup = m.letN( (f"v{i}", "cleanup"), m.symbol(node.name)(*args)) m.stmt("defer cleanup()") elif return_type == "with-cleanup-err": variables[node.uid], cleanup, err = m.letN( (f"v{i}", "cleanup", "err"), m.symbol(node.name)(*args)) with m.if_("err != nil"): m.return_("err") m.stmt("defer cleanup()") else: raise ValueError(f"unexpected return_type {return_type}") i += 1 m.return_("nil") return m
def emit(m: Module, g: Graph) -> Symbol: # TODO: name # TODO: import_ i = 0 variables: t.Dict[int, Symbol] = {} for node in topological_sorted(g): if node.is_primitive: variables[node.uid] = m.symbol(node.name) continue metadata = t.cast(Metadata, node.metadata) return_type = metadata.get("return_type", "") return_types = list(t.get_args(return_type) or [return_type]) var_names = [ f"v{i}", *[getattr(typ, "name", typ.__name__) for typ in return_types[1:]], ] spec: Fnspec = metadata.get("fnspec") provider_callable: t.Optional[Symbol] = None if spec is not None: pkg_prefix = m.import_(metadata["component_type"].gopackage) provider_callable = m.symbol(f"{pkg_prefix}.{spec.name}") if provider_callable is None: provider_callable = m.symbol(spec.name if spec else node.name) args = [variables[dep.uid] for dep in node.depends] variables[node.uid], *extra_vars = m.letN(var_names, provider_callable(*args)) if extra_vars: for sym, typ in sorted( zip(extra_vars, return_types[1:]), key=lambda pair: getattr(pair[1], "priority", 5), reverse=True, ): if hasattr(typ, "emit"): typ.emit(m, sym) i += 1 return variables[node.uid]
def emit(g: Graph) -> Module: # TODO: name # TODO: import_ i = 0 m = Module() variables: t.Dict[int, Symbol] = {} with m.func("run", *_get_args(g), return_="error"): for node in topological_sorted(g): if node.is_primitive: variables[node.uid] = m.symbol(node.name) continue metadata = t.cast(Metadata, node.metadata) return_type = metadata.get("return_type", "") return_types = list(t.get_args(return_type) or [return_type]) var_names = [ f"v{i}", *[ getattr(typ, "name", typ.__name__) for typ in return_types[1:] ], ] provider_callable = m.symbol(metadata.get("provider") or node.name) args = [variables[dep.uid] for dep in node.depends] variables[node.uid], *extra_vars = m.letN(var_names, provider_callable(*args)) if extra_vars: for sym, typ in sorted( zip(extra_vars, return_types[1:]), key=lambda pair: getattr(pair[1], "priority", 5), reverse=True, ): if hasattr(typ, "emit"): typ.emit(m, sym) i += 1 m.return_("nil") return m
def emit(g: Graph) -> Module: i = 0 m = Module() variables: t.Dict[int, Symbol] = {} # TODO: with type # TODO: name root_args = [ f"{node.name} string" for node in g.nodes if node.is_primitive ] with m.func("run", *root_args, return_="error"): for node in topological_sorted(g): if node.is_primitive: variables[node.uid] = m.symbol(node.name) continue metadata = t.cast(Metadata, node.metadata) return_type = metadata.get("return_type", "") return_types = list(t.get_args(return_type) or [return_type]) var_names = [ f"v{i}", *[ getattr(typ, "name", typ.__name__) for typ in return_types[1:] ], ] provider_callable = m.symbol(metadata.get("provider") or node.name) args = [variables[dep.uid] for dep in node.depends] variables[node.uid], *extra_vars = m.letN(var_names, provider_callable(*args)) if extra_vars: for sym, typ in zip(extra_vars, return_types[1:]): if hasattr(typ, "emit"): typ.emit(m, sym) i += 1 m.return_("nil") return m
def inject( m: Module, g: Graph, *, variables: t.Dict[int, Symbol], levels: t.Optional[t.Dict[int, int]] = None, nodes: t.Optional[t.List[Node]] = None, seen: t.Optional[t.Set[int]] = None, strict: bool = True, ) -> Symbol: # TODO: name i = len(variables) if levels is None: levels = defaultdict(int) if nodes: node = nodes[0] nodes = topological_sorted(g, seen=seen, nodes=nodes) for node in nodes: if node.is_primitive: if strict: assert node.uid in variables else: variables[node.uid] = m.symbol(node.name) continue metadata = t.cast(Metadata, node.metadata) return_type = metadata.get("return_type", "") # handling provider callable return_types = list(typing_get_args(return_type) or [return_type]) var_names = [ f"v{i}", *[getattr(typ, "name", typ.__name__) for typ in return_types[1:]], ] spec: t.Optional[Fnspec] = metadata.get("fnspec") provider_callable: t.Optional[Symbol] = None if spec is not None: provider = spec.name pkg = get_gopackage(metadata["fnspec"].body) if pkg is not None: pkg_prefix = m.import_(pkg) provider = f"{pkg_prefix}.{provider}" provider_callable = m.symbol(provider) if provider_callable is None: provider_callable = m.symbol(spec.name if spec else node.name) # handling arguments (pointer) if spec is None: args = [variables[dep.uid] for dep in node.depends] # todo: remove else: args = [] assert len(node.depends) == len(spec.arguments), ( len(node.depends), len(spec.arguments), ) for dep, (name, typ, _) in zip(node.depends, spec.arguments): # parameters? sym = variables[dep.uid] current_level = levels[dep.uid] need_level = metadata["levels"].get(name, 0) # more strict? level_diff = need_level - current_level if level_diff == 0: pass elif level_diff > 0: sym = Symbol("&" * level_diff + str(sym)) else: sym = Symbol("*" * -level_diff + str(sym)) args.append(sym) levels[node.uid] = metadata["levels"]["return"] variables[node.uid], *extra_vars = m.letN(var_names, provider_callable(*args)) # handling error and cleanup: if extra_vars: for sym, typ in sorted( zip(extra_vars, return_types[1:]), key=lambda pair: getattr( # type:ignore pair[1], "priority", priority.NORMAL), reverse=True, ): if hasattr(typ, "emit"): typ.emit(m, sym) i += 1 return variables[node.uid]