# HG changeset patch # User Paul Boddie # Date 1490475614 -3600 # Node ID 6d614f6725d562849a18be41fda360dfa6fb18db # Parent c8ba74a474eb705a3c97eddd12edc40eed01474b Permit direct access to callable function members if the context is verified. diff -r c8ba74a474eb -r 6d614f6725d5 deducer.py --- a/deducer.py Sat Mar 25 21:58:51 2017 +0100 +++ b/deducer.py Sat Mar 25 22:00:14 2017 +0100 @@ -2908,7 +2908,10 @@ # Produce an advisory instruction regarding the context. if context_var: - emit(("", context_var)) + if context_test in ("ignore", "replace"): + emit(("", context_var)) + else: + emit(("", context_var)) # Produce an advisory instruction regarding the final attribute. diff -r c8ba74a474eb -r 6d614f6725d5 results.py --- a/results.py Sat Mar 25 21:58:51 2017 +0100 +++ b/results.py Sat Mar 25 22:00:14 2017 +0100 @@ -48,6 +48,9 @@ def context(self): return None + def context_verified(self): + return None + def discards_temporary(self, test=True): return None diff -r c8ba74a474eb -r 6d614f6725d5 templates/ops.c --- a/templates/ops.c Sat Mar 25 21:58:51 2017 +0100 +++ b/templates/ops.c Sat Mar 25 22:00:14 2017 +0100 @@ -335,11 +335,16 @@ or type instance contexts for type methods. */ if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target)) - return __load_via_object(__VALUE(target), __fn__).fn; + return __get_function_member(target); else return __unbound_method; } +__attr (*__get_function_member(__attr target))() +{ + return __load_via_object(__VALUE(target), __fn__).fn; +} + __attr (*__check_and_get_function(__attr context, __attr target))() { return __check_and_get_function_unwrapped(context, __unwrap_callable(target)); diff -r c8ba74a474eb -r 6d614f6725d5 templates/ops.h --- a/templates/ops.h Sat Mar 25 21:58:51 2017 +0100 +++ b/templates/ops.h Sat Mar 25 22:00:14 2017 +0100 @@ -115,6 +115,7 @@ __attr (*__get_function_unchecked(__attr target))(); __attr (*__get_function(__attr context, __attr target))(); __attr (*__get_function_unwrapped(__attr context, __attr target))(); +__attr (*__get_function_member(__attr target))(); __attr (*__check_and_get_function(__attr context, __attr target))(); __attr (*__check_and_get_function_unwrapped(__attr context, __attr target))(); diff -r c8ba74a474eb -r 6d614f6725d5 translator.py --- a/translator.py Sat Mar 25 21:58:51 2017 +0100 +++ b/translator.py Sat Mar 25 22:00:14 2017 +0100 @@ -557,6 +557,7 @@ context_index = self.function_target - 1 context_identity = None + context_identity_verified = False final_identity = None # Obtain encoded versions of each instruction, accumulating temporary @@ -566,14 +567,15 @@ # Intercept a special instruction identifying the context. - if instruction[0] == "": + if instruction[0] in ("", ""): context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index) + context_identity_verified = instruction[0] == "" continue # Intercept a special instruction identifying the target. The value # is not encoded since it is used internally. - if instruction[0] == "": + elif instruction[0] == "": final_identity = instruction[1] continue @@ -597,7 +599,7 @@ refs = [ref] del self.attrs[0] - return AttrResult(output, refs, location, context_identity) + return AttrResult(output, refs, location, context_identity, context_identity_verified) def init_substitutions(self): @@ -1065,6 +1067,7 @@ context_required = True have_access_context = isinstance(expr, AttrResult) context_identity = have_access_context and expr.context() + context_verified = have_access_context and expr.context_verified() parameters = None num_parameters = None num_defaults = None @@ -1353,20 +1356,26 @@ elif function: if context_required: if have_access_context: - stages.append("__get_function(%s, %s)" % ( - context_identity, target_var)) + if context_verified: + stages.append("__get_function_member(%s)" % target_var) + else: + stages.append("__get_function(%s, %s)" % ( + context_identity, target_var)) else: stages.append("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % ( context_var, target_var)) else: - stages.append("__load_via_object(__VALUE(%s), __fn__).fn" % target_var) + stages.append("_get_function_member(%s)" % target_var) # With known parameters, the target can be tested. elif known_parameters: context_arg = context_required and args[0] or "__NULL" if self.always_callable(refs): - stages.append("__get_function(%s, %s)" % (context_arg, target_var)) + if context_verified: + stages.append("__get_function_member(%s)" % target_var) + else: + stages.append("__get_function(%s, %s)" % (context_arg, target_var)) else: stages.append("__check_and_get_function(%s, %s)" % (context_arg, target_var)) diff -r c8ba74a474eb -r 6d614f6725d5 transresults.py --- a/transresults.py Sat Mar 25 21:58:51 2017 +0100 +++ b/transresults.py Sat Mar 25 22:00:14 2017 +0100 @@ -178,11 +178,12 @@ "A translation result for an attribute access." - def __init__(self, instructions, refs, location, context_identity): + def __init__(self, instructions, refs, location, context_identity, context_identity_verified): InstructionSequence.__init__(self, instructions) self.refs = refs self.location = location self.context_identity = context_identity + self.context_identity_verified = context_identity_verified def references(self): return self.refs @@ -193,6 +194,9 @@ def context(self): return self.context_identity + def context_verified(self): + return self.context_identity_verified and self.context() or None + def get_origin(self): return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()