def test_somebuiltin(): ### Operation on built-in types class MiniPickler: def __init__(self): self.data = [] def emit(self, datum): self.data.append(datum) class __extend__(pairtype(MiniPickler, int)): def write((pickler, x)): pickler.emit('I%d' % x) class __extend__(pairtype(MiniPickler, str)): def write((pickler, x)): pickler.emit('S%s' % x) class __extend__(pairtype(MiniPickler, list)): def write((pickler, x)): for item in x: pair(pickler, item).write() pickler.emit('L%d' % len(x)) p = MiniPickler() pair(p, [1, 2, ['hello', 3]]).write() assert p.data == ['I1', 'I2', 'Shello', 'I3', 'L2', 'L3']
def setinteriorfield(hs_v1, *offsets_and_val_hs): hs_inner = hs_v1._getinterior(*offsets_and_val_hs[:-2]) hs_lastofs = offsets_and_val_hs[-2] hs_value = offsets_and_val_hs[-1] if hs_lastofs.concretetype is lltype.Signed: pair(hs_inner, hs_lastofs).setarrayitem(hs_value) else: hs_inner.setfield(hs_lastofs, hs_value)
def get_loader(type): s_obj = annotation(type, None) try: # look for a marshaller in the 'loaders' list return find_loader(s_obj) except CannotUnmarshall: # ask the annotation to produce an appropriate loader pair(_tag, s_obj).install_unmarshaller() return find_loader(s_obj)
def get_marshaller(type): """Return a marshaller function. The marshaller takes two arguments: a buffer and an object of type 'type'. The buffer is list of characters that gets extended with new data when the marshaller is called. """ s_obj = annotation(type, None) try: # look for a marshaller in the 'dumpers' list return find_dumper(s_obj) except CannotMarshal: # ask the annotation to produce an appropriate dumper pair(_tag, s_obj).install_marshaller() return find_dumper(s_obj)
def improve((ins1, ins2)): if ins1.classdef is None: resdef = ins2.classdef elif ins2.classdef is None: resdef = ins1.classdef else: basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is ins1.classdef: resdef = ins2.classdef elif basedef is ins2.classdef: resdef = ins1.classdef else: if ins1.can_be_None and ins2.can_be_None: return s_None else: return s_ImpossibleValue res = SomeInstance( resdef, can_be_None=ins1.can_be_None and ins2.can_be_None) if ins1.contains(res) and ins2.contains(res): return res # fine else: # this case can occur in the presence of 'const' attributes, # which we should try to preserve. Fall-back... thistype = pairtype(SomeInstance, SomeInstance) return super(thistype, pair(ins1, ins2)).improve()
def getinteriorfield(hs_v1, *offsets_hs): hs_container = hs_v1._getinterior(*offsets_hs[:-1]) hs_lastofs = offsets_hs[-1] if hs_lastofs.concretetype is lltype.Signed: return pair(hs_container, hs_lastofs).getarrayitem() else: return hs_container.getfield(hs_lastofs)
def union((hs_v1, hs_v2)): if hs_v1.deepfrozen != hs_v2.deepfrozen: hs_v1 = deepunfreeze(hs_v1) hs_v2 = deepunfreeze(hs_v2) if hs_v1 == hs_v2: return hs_v1 return pair(hs_v1, hs_v2).union_frozen_equal()
def improve((ins1, ins2)): if ins1.classdef is None: resdef = ins2.classdef elif ins2.classdef is None: resdef = ins1.classdef else: basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is ins1.classdef: resdef = ins2.classdef elif basedef is ins2.classdef: resdef = ins1.classdef else: if ins1.can_be_None and ins2.can_be_None: return s_None else: return s_ImpossibleValue res = SomeInstance(resdef, can_be_None=ins1.can_be_None and ins2.can_be_None) if ins1.contains(res) and ins2.contains(res): return res # fine else: # this case can occur in the presence of 'const' attributes, # which we should try to preserve. Fall-back... thistype = pairtype(SomeInstance, SomeInstance) return super(thistype, pair(ins1, ins2)).improve()
def unionof(*somevalues): "The most precise SomeValue instance that contains all the values." try: s1, s2 = somevalues except ValueError: s1 = s_ImpossibleValue for s2 in somevalues: if s1 != s2: s1 = pair(s1, s2).union() else: # this is just a performance shortcut if s1 != s2: s1 = pair(s1, s2).union() if DEBUG: if s1.caused_by_merge is None and len(somevalues) > 1: s1.caused_by_merge = somevalues return s1
class __extend__(pairtype(BaseListRepr, BaseListRepr)): def rtype_is_((r_lst1, r_lst2), hop): if r_lst1.lowleveltype != r_lst2.lowleveltype: # obscure logic, the is can be true only if both are None v_lst1, v_lst2 = hop.inputargs(r_lst1, r_lst2) return hop.gendirectcall(ll_both_none, v_lst1, v_lst2) return pairtype(Repr, Repr).rtype_is_(pair(r_lst1, r_lst2), hop)
def _getinterior(hs_v1, *offsets_hs): hs_container = hs_v1 for hs_offset in offsets_hs: if hs_offset.concretetype is lltype.Signed: hs_container = pair(hs_container,hs_offset).getarraysubstruct() else: hs_container = hs_container.getsubstruct(hs_offset) return hs_container
def getitem((s_array, s_index)): ndim = pair(s_array, s_index).get_leftover_dim() if len(s_index.items)>s_array.ndim: raise AnnotatorError("invalid index") if s_array.ndim == 0 and len(s_index.items): raise AnnotatorError("indexing rank zero array with nonempty tuple") if ndim > 0: return SomeArray(s_array.typecode, ndim) return s_array.get_item_type()
def _getinterior(hs_v1, *offsets_hs): hs_container = hs_v1 for hs_offset in offsets_hs: if hs_offset.concretetype is lltype.Signed: hs_container = pair(hs_container, hs_offset).getarraysubstruct() else: hs_container = hs_container.getsubstruct(hs_offset) return hs_container
def getitem((s_array, s_index)): ndim = pair(s_array, s_index).get_leftover_dim() if len(s_index.items) > s_array.ndim: raise AnnotatorError("invalid index") if s_array.ndim == 0 and len(s_index.items): raise AnnotatorError( "indexing rank zero array with nonempty tuple") if ndim > 0: return SomeArray(s_array.typecode, ndim) return s_array.get_item_type()
def is_((pbc1, pbc2)): thistype = pairtype(SomePBC, SomePBC) s = super(thistype, pair(pbc1, pbc2)).is_() if not s.is_constant(): if not pbc1.can_be_None or not pbc2.can_be_None: for desc in pbc1.descriptions: if desc in pbc2.descriptions: break else: s.const = False # no common desc in the two sets return s
def convertvar(self, v, r_from, r_to): assert isinstance(v, (Variable, Constant)) if r_from != r_to: v = pair(r_from, r_to).convert_from_to(v, self) if v is NotImplemented: raise TyperError("don't know how to convert from %r to %r" % (r_from, r_to)) if v.concretetype != r_to.lowleveltype: raise TyperError("bug in conversion from %r to %r: " "returned a %r" % (r_from, r_to, v.concretetype)) return v
def contains(self, other): if self == other: return True try: TLS.no_side_effects_in_union += 1 except AttributeError: TLS.no_side_effects_in_union = 1 try: try: return pair(self, other).union() == self except UnionError: return False finally: TLS.no_side_effects_in_union -= 1
def test_binop(): ### Binary operation example class __extend__(pairtype(int, int)): def add((x, y)): return 'integer: %s+%s' % (x, y) def sub((x, y)): return 'integer: %s-%s' % (x, y) class __extend__(pairtype(bool, bool)): def add((x, y)): return 'bool: %s+%s' % (x, y) assert pair(3,4).add() == 'integer: 3+4' assert pair(3,4).sub() == 'integer: 3-4' assert pair(3,True).add() == 'integer: 3+True' assert pair(3,True).sub() == 'integer: 3-True' assert pair(False,4).add() == 'integer: False+4' assert pair(False,4).sub() == 'integer: False-4' assert pair(False,True).add() == 'bool: False+True' assert pair(False,True).sub() == 'integer: False-True'
class __extend__(pairtype(SomeArray, SomeTuple)): def get_leftover_dim((s_array, s_index)): ndim = s_array.ndim for s_item in s_index.items: if isinstance(s_item, SomeInteger): ndim -= 1 elif isinstance(s_item, SomeSlice): pass else: raise AnnotatorError("cannot index with %s" % s_item) return ndim def setitem((s_array, s_index), s_value): ndim = pair(s_array, s_index).get_leftover_dim() if len(s_index.items) > s_array.ndim: raise AnnotatorError("invalid index") if isinstance(s_value, SomeArray): if s_value.ndim > ndim: raise AnnotatorError("shape mismatch")
def inplace_mul((obj1, obj2)): return pair(obj1, obj2).mul() def inplace_truediv((obj1, obj2)): return pair(obj1, obj2).truediv()
def inplace_add((obj1, obj2)): return pair(obj1, obj2).add() def inplace_sub((obj1, obj2)): return pair(obj1, obj2).sub()
def union((obj, p2)): return pair(p2, obj).union()
def union((pbc, gencall)): return pair(gencall, pbc).union()
def _getitem_can_only_throw(s_c1, s_o2): impl = pair(s_c1, s_o2).getitem return read_can_only_throw(impl, s_c1, s_o2)
def divmod((obj1, obj2)): getbookkeeper().count("divmod", obj1, obj2) return SomeTuple([pair(obj1, obj2).div(), pair(obj1, obj2).mod()])
def makerepr(self, s_obj): return pair(self.type_system, s_obj).rtyper_makerepr(self)
def inplace_xor((obj1, obj2)): return pair(obj1, obj2).xor()
def coerce((obj1, obj2)): getbookkeeper().count("coerce", obj1, obj2) return pair(obj1, obj2).union() # reasonable enough
class __extend__(pairtype(C_Generator, Block)): def emit((gen, block), inputvars): gen.lines.append("C code for block") outputvars = inputvars + ['v4', 'v5'] pair(gen, block.exit).emit(outputvars)
def translate_op_contains(self, hop): r_arg1 = hop.args_r[0] r_arg2 = hop.args_r[1] return pair(r_arg1, r_arg2).rtype_contains(hop)
def inplace_xor((obj1, obj2)): return pair(obj1, obj2).xor() for name, func in locals().items():
def translate_op_extend_with_str_slice(self, hop): r_arg1 = hop.args_r[0] r_arg2 = hop.args_r[3] return pair(r_arg1, r_arg2).rtype_extend_with_str_slice(hop)
def translate_op_extend_with_char_count(self, hop): r_arg1 = hop.args_r[0] r_arg2 = hop.args_r[1] return pair(r_arg1, r_arg2).rtype_extend_with_char_count(hop)
def getitem_idx_key((s_c1, s_o2)): impl = pair(s_c1, s_o2).getitem return impl()
exits = [link for link in exits if link.exitcase == s_exitswitch.const] # mapping (exitcase, variable) -> s_annotation # that can be attached to booleans, exitswitches knowntypedata = getattr(self.bindings.get(block.exitswitch), "knowntypedata", {}) # filter out those exceptions which cannot # occour for this specific, typed operation. if block.exitswitch == c_last_exception: op = block.operations[-1] if op.opname in annmodel.BINARY_OPERATIONS: arg1 = self.binding(op.args[0]) arg2 = self.binding(op.args[1]) binop = getattr(pair(arg1, arg2), op.opname, None) can_only_throw = annmodel.read_can_only_throw(binop, arg1, arg2) elif op.opname in annmodel.UNARY_OPERATIONS: arg1 = self.binding(op.args[0]) opname = op.opname if opname == 'contains': opname = 'op_contains' unop = getattr(arg1, opname, None) can_only_throw = annmodel.read_can_only_throw(unop, arg1) else: can_only_throw = None if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits exits = [] for link in candidate_exits:
def union((obj, r2)): return pair(r2, obj).union()
class __extend__(pairtype(C_Generator, Block)): def emit((gen, block), inputvars): gen.lines.append("C code for block") outputvars = inputvars + ['v4', 'v5'] pair(gen, block.exit).emit(outputvars) class __extend__(pairtype(C_Generator, Jump)): def emit((gen, jump), inputvars): gen.lines.append("goto xyz") class __extend__(pairtype(C_Generator, Switch)): def emit((gen, jump), inputvars): gen.lines.append("switch (%s) { ... }" % inputvars[-1]) g = C_Generator() pair(g, Block(Switch())).emit(['v1', 'v2']) assert g.lines == ["C code for block", "switch (v5) { ... }"] class Lisp_Generator: def __init__(self): self.progn = [] class __extend__(pairtype(Lisp_Generator, Block)): def emit((gen, block), inputvars): gen.progn.append("(do 'something)") g = Lisp_Generator() pair(g, Block(Switch())).emit(['v1', 'v2']) assert g.progn == ["(do 'something)"] def test_multiple_extend():
def inplace_sub((obj1, obj2)): return pair(obj1, obj2).sub() def inplace_mul((obj1, obj2)): return pair(obj1, obj2).mul()
def inplace_and((obj1, obj2)): return pair(obj1, obj2).and_() def inplace_or((obj1, obj2)): return pair(obj1, obj2).or_()
def inplace_truediv((obj1, obj2)): return pair(obj1, obj2).truediv() def inplace_floordiv((obj1, obj2)): return pair(obj1, obj2).floordiv()
def inplace_or((obj1, obj2)): return pair(obj1, obj2).or_() def inplace_xor((obj1, obj2)): return pair(obj1, obj2).xor()
def inplace_rshift((obj1, obj2)): return pair(obj1, obj2).rshift() def inplace_and((obj1, obj2)): return pair(obj1, obj2).and_()
def write((pickler, x)): for item in x: pair(pickler, item).write() pickler.emit('L%d' % len(x))
if link.exitcase == s_exitswitch.const ] # mapping (exitcase, variable) -> s_annotation # that can be attached to booleans, exitswitches knowntypedata = getattr(self.bindings.get(block.exitswitch), "knowntypedata", {}) # filter out those exceptions which cannot # occour for this specific, typed operation. if block.exitswitch == c_last_exception: op = block.operations[-1] if op.opname in annmodel.BINARY_OPERATIONS: arg1 = self.binding(op.args[0]) arg2 = self.binding(op.args[1]) binop = getattr(pair(arg1, arg2), op.opname, None) can_only_throw = annmodel.read_can_only_throw( binop, arg1, arg2) elif op.opname in annmodel.UNARY_OPERATIONS: arg1 = self.binding(op.args[0]) unop = getattr(arg1, op.opname, None) can_only_throw = annmodel.read_can_only_throw(unop, arg1) else: can_only_throw = None if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits exits = [] for link in candidate_exits: case = link.exitcase