def unflatten_set_clause(cl): """Opposite of above. Unflatten clauses over the M-set. Works for both enumerators and conditions. Returns the (possibly unchanged) clause. """ # Enumerator case. if isinstance(cl, L.Enumerator): res = get_menum(cl) if res is None: return cl cont, item = res cont = L.ContextSetter.run(cont, L.Load) new_cl = L.Enumerator(item, cont) return new_cl # Condition case. if isinstance(cl, L.expr) and L.is_cmp(cl): lhs, op, rhs = L.get_cmp(cl) if not (isinstance(op, L.In) and isinstance(lhs, L.Tuple) and len(lhs.elts) == 2 and L.is_name(rhs) and is_mrel(L.get_name(rhs))): return cl cont, item = lhs.elts new_cl = L.cmp(item, L.In(), cont) return new_cl return cl
def flatten_set_clause(cl, input_rels): """Turn a membership clause that is not over a comprehension, special relation, or input relation, into a clause over the M-set. Return a pair of the (possibly unchanged) clause and a bool indicating whether or not the change was done. This also works on condition clauses that express membership constraints. The rewritten clause is still a condition clause. """ def should_trans(rhs): return (not isinstance(rhs, L.Comp) and not (isinstance(rhs, L.Name) and (is_specialrel(rhs.id) or rhs.id in input_rels))) # Enumerator case. if isinstance(cl, L.Enumerator) and should_trans(cl.iter): item = cl.target cont = cl.iter cont = L.ContextSetter.run(cont, L.Store) new_cl = L.Enumerator(L.tuplify((cont, item), lval=True), L.ln(make_mrel())) return new_cl, True # Condition case. if isinstance(cl, L.expr) and L.is_cmp(cl): item, op, cont = L.get_cmp(cl) if isinstance(op, L.In) and should_trans(cont): new_cl = L.cmp(L.tuplify((cont, item)), L.In(), L.ln(make_mrel())) return new_cl, True return cl, False
def from_expr(cls, node): """Construct from a condition expression of form <vars> == <rel> """ checktype(node, L.AST) left, op, val = L.get_cmp(node) checktype(op, L.Eq) lhs = L.get_vartuple(left) return cls(lhs, val)
def from_expr(cls, node): """Construct from a membership expression (<var>, <var>) in _M """ checktype(node, L.AST) left, op, right = L.get_cmp(node) checktype(op, L.In) lhs = L.get_vartuple(left) assert len(lhs) == 2 cont, item = lhs rel = L.get_name(right) assert is_mrel(rel) return cls(cont, item)
def from_expr(cls, node): """Construct from a membership condition expression of form <vars> in <rel> Note that this is syntactically different from the form used in comprehensions, even though their textual representation in source code is the same. """ checktype(node, L.AST) left, op, right = L.get_cmp(node) checktype(op, L.In) lhs = L.get_vartuple(left) rel = L.get_name(right) return cls(lhs, rel)
def membercond_to_enum(cls, cl): """For a condition clause that expresses a membership, return an equivalent enumerator clause. For other kinds of conditions, return the same clause. For enumerators, raise TypeError. """ if cl.kind is not Clause.KIND_COND: raise TypeError compre_ast = None clast = cl.to_AST() if L.is_cmp(clast): lhs, op, rhs = L.get_cmp(clast) if (L.is_vartuple(lhs) and isinstance(op, L.In)): compre_ast = L.Enumerator( L.tuplify(L.get_vartuple(lhs), lval=True), rhs) if compre_ast is None: return cl else: return cls.from_AST(compre_ast)