# HG changeset patch # User Paul Boddie # Date 1487027859 -3600 # Node ID 87f11937a8e860c0f8f50d6cb2d1aff6cd7ab581 # Parent 3481d146208c0dca64ba13bdaa2d7989f8d65730 Record the context for accesses that are immediately invoked so that it may be used by the invocation operation. diff -r 3481d146208c -r 87f11937a8e8 deducer.py --- a/deducer.py Mon Feb 13 21:49:59 2017 +0100 +++ b/deducer.py Tue Feb 14 00:17:39 2017 +0100 @@ -2088,7 +2088,9 @@ # All other methods of access involve traversal. else: - final_method = is_assignment and "assign" or "access" + final_method = is_assignment and "assign" or \ + is_invocation and "access-invoke" or \ + "access" origin = None # First attribute accessed at a known position via the accessor. diff -r 3481d146208c -r 87f11937a8e8 optimiser.py --- a/optimiser.py Mon Feb 13 21:49:59 2017 +0100 +++ b/optimiser.py Tue Feb 14 00:17:39 2017 +0100 @@ -371,7 +371,7 @@ # Perform the first access explicitly if at least one operation # requires it. - access_first_attribute = final_method in ("access", "assign") or traversed or attrnames + access_first_attribute = final_method in ("access", "access-invoke", "assign") or traversed or attrnames # Determine whether the first access involves assignment. @@ -388,8 +388,12 @@ # Prevent re-evaluation of any dynamic expression by storing it. if original_accessor == "": - emit((set_accessor, original_accessor)) - accessor = context_var = (stored_accessor,) + if final_method in ("access-invoke", "static-invoke"): + emit(("", original_accessor)) + accessor = context_var = ("",) + else: + emit((set_accessor, original_accessor)) + accessor = context_var = (stored_accessor,) else: accessor = context_var = (original_accessor,) @@ -462,12 +466,12 @@ # Set the context, if appropriate. if remaining == 1 and final_method != "assign" and context == "final-accessor": - emit(("__set_context", accessor)) + emit(("", accessor)) accessor = context_var = "" # Perform the access only if not achieved directly. - if remaining > 1 or final_method in ("access", "assign"): + if remaining > 1 or final_method in ("access", "access-invoke", "assign"): if traversal_mode == "class": if assigning: @@ -489,12 +493,12 @@ # Set the context, if appropriate. if remaining == 1 and final_method != "assign" and context == "final-accessor": - emit(("__set_context", accessor)) + emit(("", accessor)) accessor = context_var = "" # Perform the access only if not achieved directly. - if remaining > 1 or final_method in ("access", "assign"): + if remaining > 1 or final_method in ("access", "access-invoke", "assign"): if assigning: emit(("__check_and_store_via_any", accessor, attrname, "")) @@ -505,10 +509,14 @@ # Define or emit the means of accessing the actual target. + # Assignments to known attributes. + if final_method == "static-assign": parent, attrname = origin.rsplit(".", 1) emit(("__store_via_object", parent, attrname, "")) + # Invoked attributes employ a separate context. + elif final_method in ("static", "static-invoke"): accessor = ("__load_static_ignore", origin) @@ -521,10 +529,19 @@ emit(("__test_context", context_var, accessor)) elif context_test == "replace": - if final_method in ("static", "static-invoke"): + + # Produce an object with updated context. + + if final_method == "static": emit(("__load_static_replace", context_var, origin)) + + # Only update any context if no separate context is used. + + elif final_method not in ("access-invoke", "static-invoke"): + emit(("__update_context", context_var, accessor)) + else: - emit(("__update_context", context_var, accessor)) + emit(accessor) elif final_method not in ("assign", "static-assign"): emit(accessor) diff -r 3481d146208c -r 87f11937a8e8 translator.py --- a/translator.py Mon Feb 13 21:49:59 2017 +0100 +++ b/translator.py Tue Feb 14 00:17:39 2017 +0100 @@ -740,6 +740,7 @@ temp_subs = { "" : "__tmp_context", + "" : "__tmp_context", "" : "__tmp_value", "" : "__tmp_target_value", "" : "__tmp_value", @@ -747,6 +748,7 @@ } op_subs = { + "" : "__set_context", "" : "__set_accessor", "" : "__set_target_accessor", } @@ -1165,6 +1167,7 @@ # Invocation requirements. context_required = True + have_access_context = isinstance(expr, AttrResult) parameters = None # Obtain details of the callable and of its parameters. @@ -1235,8 +1238,11 @@ # set to null. if context_required: - self.record_temp("__tmp_targets") - args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] + if have_access_context: + args = ["(__attr) {.value=__tmp_context}"] + else: + self.record_temp("__tmp_targets") + args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] else: args = ["__NULL"] @@ -1347,8 +1353,12 @@ self.record_temp("__tmp_targets") if context_required: - stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % ( - self.function_target, self.function_target)) + if have_access_context: + stages.append("__get_function(__tmp_context, __tmp_targets[%d])" % ( + self.function_target)) + else: + stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % ( + self.function_target, self.function_target)) else: stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( self.function_target, encode_symbol("pos", "__fn__")))