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_code(self, cl, bindenv, body): assert_unique(cl.vars) mask = L.mask_from_bounds(cl.vars, bindenv) check_eq = L.Compare(L.tuplify(cl.vars), L.Eq(), cl.value) if L.mask_is_allbound(mask): code = (L.If(check_eq, body, ()), ) elif L.mask_is_allunbound(mask): code = (L.DecompAssign(cl.vars, cl.value), ) code += body else: code = L.bind_by_mask(mask, cl.vars, cl.value) code += (L.If(check_eq, body, ()), ) return code
def make_auxmap_maint_func(fresh_vars, auxmap: AuxmapInvariant, op: L.setupop): """Make maintenance function for auxiliary map.""" # Fresh variables for components of the element. vars = N.get_subnames('_elem', len(auxmap.mask.m)) decomp_code = (L.DecompAssign(vars, L.Name('_elem')), ) key, value = L.split_by_mask(auxmap.mask, vars) key = L.tuplify(key, unwrap=auxmap.unwrap_key) value = L.tuplify(value, unwrap=auxmap.unwrap_value) fresh_var_prefix = next(fresh_vars) key_var = fresh_var_prefix + '_key' value_var = fresh_var_prefix + '_value' decomp_code += L.Parser.pc(''' _KEY_VAR = _KEY _VALUE_VAR = _VALUE ''', subst={ '_KEY_VAR': key_var, '_KEY': key, '_VALUE_VAR': value_var, '_VALUE': value }) img_func = { L.SetAdd: make_imgadd, L.SetRemove: make_imgremove }[op.__class__] img_code = img_func(fresh_vars, auxmap.map, key_var, value_var) func_name = auxmap.get_maint_func_name(op) func = L.Parser.ps(''' def _FUNC(_elem): _DECOMP _IMGCODE ''', subst={ '_FUNC': func_name, '<c>_DECOMP': decomp_code, '<c>_IMGCODE': img_code }) return func
def make_aggr_oper_maint_func(fresh_vars, aggrinv, op): """Make the maintenance function for an aggregate invariant and a given set update operation (add or remove) to the operand. """ assert isinstance(op, (L.SetAdd, L.SetRemove)) # Decompose the argument tuple into key and value components, # just like in auxmap.py. vars = N.get_subnames('_elem', len(aggrinv.mask.m)) kvars, vvars = L.split_by_mask(aggrinv.mask, vars) ktuple = L.tuplify(kvars) vtuple = L.tuplify(vvars) fresh_var_prefix = next(fresh_vars) key = fresh_var_prefix + '_key' value = fresh_var_prefix + '_value' state = fresh_var_prefix + '_state' if aggrinv.unwrap: assert len(vvars) == 1 value_expr = L.Name(vvars[0]) else: value_expr = vtuple # Logic specific to aggregate operator. handler = aggrinv.get_handler() zero = handler.make_zero_expr() updatestate_code = handler.make_update_state_code(fresh_var_prefix, state, op, value) subst = { '_KEY': key, '_KEY_EXPR': ktuple, '_VALUE': value, '_VALUE_EXPR': value_expr, '_MAP': aggrinv.map, '_STATE': state, '_ZERO': zero } if aggrinv.uses_demand: subst['_RESTR'] = aggrinv.restr else: # Empty conditions are only used when we don't have a # restriction set. subst['_EMPTY'] = handler.make_empty_cond(state) decomp_code = (L.DecompAssign(vars, L.Name('_elem')), ) decomp_code += L.Parser.pc(''' _KEY = _KEY_EXPR _VALUE = _VALUE_EXPR ''', subst=subst) # Determine what kind of get/set state code to generate. if isinstance(op, L.SetAdd): definitely_preexists = aggrinv.uses_demand setstate_mayremove = False elif isinstance(op, L.SetRemove): definitely_preexists = True setstate_mayremove = not aggrinv.uses_demand else: assert () if definitely_preexists: getstate_template = '_STATE = _MAP[_KEY]' delstate_template = '_MAP.mapdelete(_KEY)' else: getstate_template = '_STATE = _MAP.get(_KEY, _ZERO)' delstate_template = ''' if _KEY in _MAP: _MAP.mapdelete(_KEY) ''' if setstate_mayremove: setstate_template = ''' if not _EMPTY: _MAP.mapassign(_KEY, _STATE) ''' else: setstate_template = '_MAP.mapassign(_KEY, _STATE)' getstate_code = L.Parser.pc(getstate_template, subst=subst) delstate_code = L.Parser.pc(delstate_template, subst=subst) setstate_code = L.Parser.pc(setstate_template, subst=subst) maint_code = (getstate_code + updatestate_code + delstate_code + setstate_code) # Guard in test if we have a restriction set. if aggrinv.uses_demand: maint_subst = dict(subst) maint_subst['<c>_MAINT'] = maint_code maint_code = L.Parser.pc(''' if _KEY in _RESTR: _MAINT ''', subst=maint_subst) func_name = aggrinv.get_oper_maint_func_name(op) func = L.Parser.ps(''' def _FUNC(_elem): _DECOMP _MAINT ''', subst={ '_FUNC': func_name, '<c>_DECOMP': decomp_code, '<c>_MAINT': maint_code }) return func
def make_aggr_restr_maint_func(fresh_vars, aggrinv, op): """Make the maintenance function for an aggregate invariant and an update to its restriction set. """ assert isinstance(op, (L.SetAdd, L.SetRemove)) assert aggrinv.uses_demand if isinstance(op, L.SetAdd): fresh_var_prefix = next(fresh_vars) value = fresh_var_prefix + '_value' state = fresh_var_prefix + '_state' keyvars = N.get_subnames('_key', len(aggrinv.params)) decomp_key_code = (L.DecompAssign(keyvars, L.Name('_key')), ) rellookup = L.ImgLookup(L.Name(aggrinv.rel), aggrinv.mask, keyvars) handler = aggrinv.get_handler() zero = handler.make_zero_expr() updatestate_code = handler.make_update_state_code( fresh_var_prefix, state, op, value) if aggrinv.unwrap: loop_template = ''' for (_VALUE,) in _RELLOOKUP: _UPDATESTATE ''' else: loop_template = ''' for _VALUE in _RELLOOKUP: _UPDATESTATE ''' loop_code = L.Parser.pc(loop_template, subst={ '_VALUE': value, '_RELLOOKUP': rellookup, '<c>_UPDATESTATE': updatestate_code }) maint_code = L.Parser.pc(''' _STATE = _ZERO _DECOMP_KEY _LOOP _MAP.mapassign(_KEY, _STATE) ''', subst={ '_MAP': aggrinv.map, '_KEY': '_key', '_STATE': state, '_ZERO': zero, '<c>_DECOMP_KEY': decomp_key_code, '<c>_LOOP': loop_code }) else: maint_code = L.Parser.pc(''' _MAP.mapdelete(_KEY) ''', subst={ '_MAP': aggrinv.map, '_KEY': '_key' }) func_name = aggrinv.get_restr_maint_func_name(op) func = L.Parser.ps(''' def _FUNC(_key): _MAINT ''', subst={ '_FUNC': func_name, '<c>_MAINT': maint_code }) return func