def make_setfrommap_type(mask, maptype): """Given a mask and a map type, determine the corresponding relation type. We obtain by lattice join the smallest map type that is at least as big as the given map type and that has the correct key tuple arity. This should have the form {(K1, ..., Kn): V}. The relation type is then a set of tuples of these types interleaved according to the mask. If no such type exists, e.g. if the given relation type is {Top: Top} or the key is not a tuple of correct arity, we instead give the relation type {Top}. """ nb = mask.m.count('b') assert mask.m.count('u') == 1 bottom_maptype = T.Map(T.Tuple([T.Bottom] * nb), T.Bottom) top_maptype = T.Map(T.Tuple([T.Top] * nb), T.Top) norm_type = maptype.join(bottom_maptype) well_typed = norm_type.issmaller(top_maptype) if well_typed: assert (isinstance(norm_type, T.Map) and isinstance(norm_type.key, T.Tuple) and len(norm_type.key.elts) == nb) t_elts = L.combine_by_mask(mask, norm_type.key.elts, [norm_type.value]) rel_type = T.Set(T.Tuple(t_elts)) else: rel_type = T.Set(T.Top) return rel_type
def make_auxmap_type(auxmapinv, reltype): """Given a mask and a relation type, determine the corresponding auxiliary map type. We obtain by lattice join the smallest relation type that is at least as big as the given relation type and that has the correct arity. This should have the form {(T1, ..., Tn)}. The map type is then from a tuple of some Ts to a set of tuples of the remaining Ts. If no such type exists, e.g. if the given relation type is {Top} or a set of tuples of incorrect arity, we instead give the map type {Top: Top}. """ mask = auxmapinv.mask arity = len(mask.m) bottom_reltype = T.Set(T.Tuple([T.Bottom] * arity)) top_reltype = T.Set(T.Tuple([T.Top] * arity)) norm_type = reltype.join(bottom_reltype) well_typed = norm_type.issmaller(top_reltype) if well_typed: assert (isinstance(norm_type, T.Set) and isinstance(norm_type.elt, T.Tuple) and len(norm_type.elt.elts) == arity) t_bs, t_us = L.split_by_mask(mask, norm_type.elt.elts) t_key = t_bs[0] if auxmapinv.unwrap_key else T.Tuple(t_bs) t_value = t_us[0] if auxmapinv.unwrap_value else T.Tuple(t_us) map_type = T.Map(t_key, T.Set(t_value)) else: map_type = T.Map(T.Top, T.Top) return map_type
class MapSymbol(TypedSymbolMixin, Symbol): min_type = T.Map(T.Bottom, T.Bottom) max_type = T.Map(T.Top, T.Top) def __str__(self): s = 'Map {}'.format(self.name) if self.type is not None: s += ' (type: {})'.format(self.type) return s decl_constructor = 'Map'
def incrementalize_aggr(tree, symtab, query, result_var): # Form the invariant. aggrinv = aggrinv_from_query(symtab, query, result_var) handler = aggrinv.get_handler() # Transform to maintain it. trans = AggrMaintainer(symtab.fresh_names.vars, aggrinv) tree = trans.process(tree) symtab.maint_funcs.update(trans.maint_funcs) # Transform occurrences of the aggregate. zero = None if aggrinv.uses_demand else handler.make_zero_expr() state_expr = L.DictLookup(L.Name(aggrinv.map), L.tuplify(aggrinv.params), zero) lookup_expr = handler.make_projection_expr(state_expr) class AggrExpander(S.QueryRewriter): expand = True def rewrite_aggr(self, symbol, name, expr): if name == query.name: return lookup_expr tree = AggrExpander.run(tree, symtab) # Determine the result map's type and define its symbol. t_rel = get_rel_type(symtab, aggrinv.rel) btypes, _ = L.split_by_mask(aggrinv.mask, t_rel.elt.elts) t_key = T.Tuple(btypes) t_val = handler.result_type(t_rel) t_map = T.Map(t_key, t_val) symtab.define_map(aggrinv.map, type=t_map) symtab.stats['aggrs_transformed'] += 1 return tree