def register_external(function, args, result=None, export_name=None, llimpl=None, llfakeimpl=None, sandboxsafe=False): """ function: the RPython function that will be rendered as an external function (e.g.: math.floor) args: a list containing the annotation of the arguments result: surprisingly enough, the annotation of the result export_name: the name of the function as it will be seen by the backends llimpl: optional; if provided, this RPython function is called instead of the target function llfakeimpl: optional; if provided, called by the llinterpreter sandboxsafe: use True if the function performs no I/O (safe for --sandbox) """ if export_name is None: export_name = function.__name__ params_s = [annotation(arg) for arg in args] s_result = annotation(result) class FunEntry(ExtFuncEntry): _about_ = function safe_not_sandboxed = sandboxsafe signature_args = params_s signature_result = s_result name = export_name if llimpl: lltypeimpl = staticmethod(llimpl) if llfakeimpl: lltypefakeimpl = staticmethod(llfakeimpl)
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_annotation(t): from rpython.annotator.signature import annotation from rpython.annotator.model import SomeObject, SomeString, SomeUnicodeString if isinstance(t, SomeObject): return t s_result = annotation(t) if (isinstance(s_result, SomeString) or isinstance(s_result, SomeUnicodeString)): return s_result.__class__(can_be_None=True) return s_result
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 install_marshaller((tag, s_list)): def dump_list_or_none(buf, x): if x is None: dump_none(buf, x) else: buf.append(TYPE_LIST) w_long(buf, len(x)) for item in x: itemdumper(buf, item) itemdumper = get_marshaller(s_list.listdef.listitem.s_value) if s_list.listdef.listitem.dont_change_any_more: s_general_list = s_list else: s_item = get_dumper_annotation(itemdumper) s_general_list = annotation([s_item]) add_dumper(s_general_list, dump_list_or_none)
def normalize_args(self, *args_s): args = self.signature_args signature_args = [annotation(arg, None) for arg in args] assert len(args_s) == len(signature_args),\ "Argument number mismatch" for i, expected in enumerate(signature_args): arg = annmodel.unionof(args_s[i], expected) if not expected.contains(arg): name = getattr(self, 'name', None) if not name: try: name = self.instance.__name__ except AttributeError: name = '?' raise Exception("In call to external function %r:\n" "arg %d must be %s,\n" " got %s" % ( name, i+1, expected, args_s[i])) return signature_args
class FunEntry(ExtFuncEntry): _about_ = function safe_not_sandboxed = sandboxsafe if args is None: def normalize_args(self, *args_s): return args_s # accept any argument unmodified elif callable(args): # custom annotation normalizer (see e.g. os.utime()) normalize_args = staticmethod(args) else: # use common case behavior signature_args = args signature_result = annotation(result, None) name = export_name if llimpl: lltypeimpl = staticmethod(llimpl) if llfakeimpl: lltypefakeimpl = staticmethod(llfakeimpl)
def normalize_args(self, *args_s): args = self.signature_args signature_args = [annotation(arg, None) for arg in args] assert len(args_s) == len(signature_args),\ "Argument number mismatch" for i, expected in enumerate(signature_args): arg = annmodel.unionof(args_s[i], expected) if not expected.contains(arg): name = getattr(self, 'name', None) if not name: try: name = self.instance.__name__ except AttributeError: name = '?' raise Exception("In call to external function %r:\n" "arg %d must be %s,\n" " got %s" % (name, i + 1, expected, args_s[i])) return signature_args
def install_marshaller((tag, s_dict)): def dump_dict_or_none(buf, x): if x is None: dump_none(buf, x) else: buf.append(TYPE_DICT) for key, value in x.items(): keydumper(buf, key) valuedumper(buf, value) buf.append('0') # end of dict keydumper = get_marshaller(s_dict.dictdef.dictkey.s_value) valuedumper = get_marshaller(s_dict.dictdef.dictvalue.s_value) if (s_dict.dictdef.dictkey.dont_change_any_more or s_dict.dictdef.dictvalue.dont_change_any_more): s_general_dict = s_dict else: s_key = get_dumper_annotation(keydumper) s_value = get_dumper_annotation(valuedumper) s_general_dict = annotation({s_key: s_value}) add_dumper(s_general_dict, dump_dict_or_none)
def typeannotation(self, t): return signature.annotation(t, self.bookkeeper)
return x if r == TYPE_INT: return readlong(loader) raise ValueError("expected an int") add_loader(annmodel.SomeInteger(), load_int) def dump_longlong(buf, x): buf.append(TYPE_INT64) w_long(buf, intmask(x)) w_long(buf, intmask(x >> 32)) add_dumper(annotation(r_longlong), dump_longlong) r_32bits_mask = r_longlong(0xFFFFFFFF) def load_longlong_nonneg(loader): x = load_longlong(loader) if x < 0: raise ValueError("expected a non-negative longlong") return x add_loader(annmodel.SomeInteger(knowntype=r_longlong, nonneg=True), load_longlong_nonneg)
def load_int(loader): r = readchr(loader) if LONG_BIT > 32 and r == TYPE_INT64: x = readlong(loader) & 0xFFFFFFFF x |= readlong(loader) << 32 return x if r == TYPE_INT: return readlong(loader) raise ValueError("expected an int") add_loader(annmodel.SomeInteger(), load_int) def dump_longlong(buf, x): buf.append(TYPE_INT64) w_long(buf, intmask(x)) w_long(buf, intmask(x>>32)) add_dumper(annotation(r_longlong), dump_longlong) r_32bits_mask = r_longlong(0xFFFFFFFF) def load_longlong(loader): if readchr(loader) != TYPE_INT64: raise ValueError("expected a longlong") x = r_longlong(readlong(loader)) & r_32bits_mask x |= (r_longlong(readlong(loader)) << 32) return x add_loader(annotation(r_longlong), load_longlong) def dump_float(buf, x): buf.append(TYPE_FLOAT) s = formatd(x, 'g', 17) buf.append(chr(len(s)))
def get_annotation(t): from rpython.annotator.signature import annotation from rpython.annotator.model import SomeObject if isinstance(t, SomeObject): return t return annotation(t)
def annotation_to_cts(self, _tp): s_tp = annotation(_tp) TP = annotation_to_lltype(s_tp) return self.lltype_to_cts(TP)