Open awf opened 3 years ago
So I think my proposal is something like this. Change existing code like this (from the hashing example).
I do see that it is more code, and that it means that hashing may have a different enumeration of e.g. the children of an "if" than matching, but actually I think it is reasonable for every traversal to ask itself "do I need to worry about the order of application of If"?
And if new nodes were to be added to the AST, I would much prefer to get a NotImplementedError
than to ask "where are these children used? who needs to know about ordering?"
The "duplication" in the (single) example you give is annoying to have to write, but I'm more worried about the sheer number of places which depend upon knowledge of the Expr representation. I feel it would be good to minimise the number of places which would need to change were a new Expr type added. The idea of subexps_no_binds
is not that everything has to use it; but that many callers would want to, and they might well change in the same way. If some new Expr-node makes the definition of "no_binds" unclear, then rename subexps_no_binds and every callsite fails...and many can be patched up by propagating said rename.
who needs to know about ordering?
I'm not sure whether you mean
subexps_no_binds is roughly aiming at the first of these; to me that seems reasonable, but I'm open to ways of restructuring. For example, one might write a variation on the present ExprVisitor/ExprTransformer framework:
T = TypeVar()
class ExprVisitorWithDefault(ABC, Generic[T]):
....
@abstractmethod
def visit_default(e : Expr, child_results: List[T], *args, **kwargs) -> T:
""" Subclasses must override; or raise if all cases are overridden and no default is required """
def visit_call(self, c: Call, *args, **kwargs) -> T:
return self.visit_default(c, [self.visit(a, *args, **kwargs) for a in c.args], *args, **kwargs)
def visit_if(self, if_node: If, *args, **kwargs) -> T:
return self.visit_default(if_node, [self.visit(if_node.cond, *args, **kwargs), self.visit(if_node.t_body, *args, **kwargs), self.visit(if_node.f_body, *args, **kwargs)], *args, **kwargs)
....visit_lam, visit_let, visit_assert, visit_var, visit_const all calling visit_default similarly....
(And that visitor class could even have a flag as to whether to include binding occurrences, decl
Vars, etc.)
Currently subexps_no_binds is used in:
Originally posted by @acl33 in https://github.com/microsoft/knossos-ksc/issues/842#issuecomment-852852472