def get_code(self, cl, bindenv, body): vars = self.lhs_vars(cl) assert_unique(vars) mask = L.mask_from_bounds(vars, bindenv) comparison = L.Compare(L.Name(cl.tup), L.Eq(), L.tuplify(cl.elts)) if L.mask_is_allbound(mask): code = (L.If(comparison, body, ()), ) needs_typecheck = True elif mask.m.startswith('b'): elts_mask = L.mask_from_bounds(cl.elts, bindenv) code = L.bind_by_mask(elts_mask, cl.elts, L.Name(cl.tup)) if L.mask_is_allunbound(elts_mask): code += body else: code += (L.If(comparison, body, ()), ) needs_typecheck = True elif mask == L.mask('u' + 'b' * len(cl.elts)): code = (L.Assign(cl.tup, L.tuplify(cl.elts)), ) code += body needs_typecheck = False else: raise L.TransformationError('Cannot emit code for TUP clause ' 'that would require an auxiliary ' 'map; use demand filtering') if needs_typecheck and self.use_typecheck: code = (L.If(L.HasArity(L.Name(cl.tup), len(cl.elts)), code, ()), ) return code
def get_code(self, cl, bindenv, body): vars = self.lhs_vars(cl) assert_unique(vars) mask = L.mask_from_bounds(vars, bindenv) lookup_expr = L.DictLookup(L.Name(cl.map), L.Name(cl.key), None) if L.mask_is_allbound(mask): comparison = L.Compare(L.Name(cl.value), L.Eq(), lookup_expr) code = (L.If(comparison, body, ()), ) needs_typecheck = True elif mask == L.mask('bbu'): code = (L.Assign(cl.value, lookup_expr), ) code += body needs_typecheck = True elif mask == L.mask('buu'): items_expr = L.Parser.pe('_MAP.items()', subst={'_MAP': cl.map}) code = (L.DecompFor([cl.key, cl.value], items_expr, body), ) needs_typecheck = True else: code = super().get_code(cl, bindenv, body) needs_typecheck = False if needs_typecheck and self.use_typecheck: code = (L.If(L.IsMap(L.Name(cl.map)), code, ()), ) return code
def visit_AttrAssign(self, node): if node.attr not in self.objrels.Fs: return pair = L.Tuple([node.obj, node.value]) var = next(self.fresh_vars) return (L.Assign(var, pair), L.RelUpdate(N.F(node.attr), L.SetAdd(), var))
def visit_DictAssign(self, node): if not self.objrels.MAP: return triple = L.Tuple([node.target, node.key, node.value]) var = next(self.fresh_vars) return (L.Assign(var, triple), L.RelUpdate(N.MAP, L.SetAdd(), var))
def visit_AttrDelete(self, node): if node.attr not in self.objrels.Fs: return lookup = L.Attribute(node.obj, node.attr) pair = L.Tuple([node.obj, lookup]) var = next(self.fresh_vars) return (L.Assign(var, pair), L.RelUpdate(N.F(node.attr), L.SetRemove(), var))
def visit_DictDelete(self, node): if not self.objrels.MAP: return lookup = L.DictLookup(node.target, node.key, None) triple = L.Tuple([node.target, node.key, lookup]) var = next(self.fresh_vars) return (L.Assign(var, triple), L.RelUpdate(N.MAP, L.SetRemove(), var))
def visit_SetUpdate(self, node): if not isinstance(node.op, (L.SetAdd, L.SetRemove)): return if not self.objrels.M: return pair = L.Tuple([node.target, node.value]) var = next(self.fresh_vars) return (L.Assign(var, pair), L.RelUpdate(N.M, node.op, var))
def make_setfrommap_maint_func(fresh_vars, setfrommap: SetFromMapInvariant, op: str): mask = setfrommap.mask nb = L.break_mapmask(mask) # Fresh variables for components of the key and value. key_vars = N.get_subnames('_key', nb) decomp_code = (L.DecompAssign(key_vars, L.Name('_key')), ) vars = L.combine_by_mask(mask, key_vars, ['_val']) elem = L.tuplify(vars) fresh_var_prefix = next(fresh_vars) elem_var = fresh_var_prefix + '_elem' decomp_code += (L.Assign(elem_var, elem), ) setopcls = {'assign': L.SetAdd, 'delete': L.SetRemove}[op] update_code = (L.RelUpdate(setfrommap.rel, setopcls(), elem_var), ) func_name = setfrommap.get_maint_func_name(op) if op == 'assign': func = L.Parser.ps(''' def _FUNC(_key, _val): _DECOMP _UPDATE ''', subst={ '_FUNC': func_name, '<c>_DECOMP': decomp_code, '<c>_UPDATE': update_code }) elif op == 'delete': lookup_expr = L.DictLookup(L.Name(setfrommap.map), L.Name('_key'), None) func = L.Parser.ps(''' def _FUNC(_key): _val = _LOOKUP _DECOMP _UPDATE ''', subst={ '_FUNC': func_name, '_LOOKUP': lookup_expr, '<c>_DECOMP': decomp_code, '<c>_UPDATE': update_code }) else: assert () return func
def get_maint_code(self, fresh_var_prefix, fresh_join_names, comp, result_var, update, *, selfjoin=SelfJoin.Without, counted): """Given a comprehension (not necessarily a join) and an update to a relation, return the maintenance code -- i.e., the update to the stored result variable looped for each maintenance join. If counted is False, generate non-counted set updates. """ assert isinstance(update, L.RelUpdate) assert isinstance(update.op, (L.SetAdd, L.SetRemove)) result_elem_var = fresh_var_prefix + '_result' # Prefix LHS vars in the comp to guarantee fresh names for their # use in maintenance code. renamer = lambda x: fresh_var_prefix + '_' + x comp = self.comp_rename_lhs_vars(comp, renamer) body = () body += (L.Assign(result_elem_var, comp.resexp), ) body += L.rel_update(result_var, update.op, result_elem_var, counted=counted) join = self.make_join_from_comp(comp) maint_joins = self.get_maint_join_union(join, update.rel, L.Name(update.elem), selfjoin=selfjoin) code = () for maint_join in maint_joins: join_name = next(fresh_join_names) code += self.get_loop_for_join(maint_join, body, join_name) return code
def get_code(self, cl, bindenv, body): vars = self.lhs_vars(cl) assert_unique(vars) mask = L.mask_from_bounds(vars, bindenv) if L.mask_is_allbound(mask): comparison = L.Compare(L.Name(cl.value), L.Eq(), L.Attribute(L.Name(cl.obj), cl.attr)) code = (L.If(comparison, body, ()), ) needs_typecheck = True elif mask == L.mask('bu'): code = (L.Assign(cl.value, L.Attribute(L.Name(cl.obj), cl.attr)), ) code += body needs_typecheck = True else: code = super().get_code(cl, bindenv, body) needs_typecheck = False if needs_typecheck and self.use_typecheck: code = (L.If(L.HasField(L.Name(cl.obj), cl.attr), code, ()), ) return code
def make_update_state_code(self, prefix, state, op, value): opcls = {L.SetAdd: L.Add, L.SetRemove: L.Sub}[op.__class__] by = {'count': L.Num(1), 'sum': L.Name(value)}[self.kind] return (L.Assign(state, L.BinOp(L.Name(state), opcls(), by)), )