1.1 --- a/optimiser.py Thu Oct 20 22:43:48 2016 +0200
1.2 +++ b/optimiser.py Thu Oct 20 23:40:02 2016 +0200
1.3 @@ -506,15 +506,38 @@
1.4
1.5 remaining -= 1
1.6
1.7 + # Define or emit the means of accessing the actual target.
1.8 +
1.9 if final_method == "static-assign":
1.10 - emit(("__store_member", origin, "<assexpr>"))
1.11 + parent, attrname = origin.rsplit(".", 1)
1.12 + emit(("__store_via_object", parent, attrname, "<assexpr>"))
1.13 +
1.14 elif final_method == "static":
1.15 accessor = ("__load_static", origin)
1.16
1.17 + elif final_method == "static-invoke":
1.18 + kind = self.importer.get_object(origin).get_kind()
1.19 + accessor = ("__encode_callable", origin, kind)
1.20 +
1.21 + # Wrap accesses in context operations.
1.22 +
1.23 if context_test == "test":
1.24 emit(("__test_context", context_var, accessor))
1.25 +
1.26 elif context_test == "replace":
1.27 - emit(("__replace_context", context_var, accessor))
1.28 +
1.29 + # Static invocation targets have a context added but no other
1.30 + # transformation performed.
1.31 +
1.32 + if final_method == "static-invoke":
1.33 + emit(("__update_context", context_var, accessor))
1.34 +
1.35 + # Other invocation targets gain a context and have the bound
1.36 + # version of the callable activated.
1.37 +
1.38 + else:
1.39 + emit(("__replace_context", context_var, accessor))
1.40 +
1.41 elif final_method not in ("assign", "static-assign"):
1.42 emit(accessor)
1.43
2.1 --- a/results.py Thu Oct 20 22:43:48 2016 +0200
2.2 +++ b/results.py Thu Oct 20 23:40:02 2016 +0200
2.3 @@ -29,9 +29,13 @@
2.4
2.5 def is_name(self):
2.6 return False
2.7 +
2.8 def get_origin(self):
2.9 return None
2.10
2.11 + def reference(self):
2.12 + return None
2.13 +
2.14 class AccessRef(Result):
2.15
2.16 """
2.17 @@ -44,9 +48,6 @@
2.18 self.attrnames = attrnames
2.19 self.number = number
2.20
2.21 - def reference(self):
2.22 - return None
2.23 -
2.24 def __repr__(self):
2.25 return "AccessRef(%r, %r, %r)" % (self.original_name, self.attrnames, self.number)
2.26
2.27 @@ -78,9 +79,6 @@
2.28 def is_name(self):
2.29 return True
2.30
2.31 - def reference(self):
2.32 - return None
2.33 -
2.34 def final(self):
2.35 return None
2.36
3.1 --- a/translator.py Thu Oct 20 22:43:48 2016 +0200
3.2 +++ b/translator.py Thu Oct 20 23:40:02 2016 +0200
3.3 @@ -128,6 +128,14 @@
3.4 def get_origin(self):
3.5 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()
3.6
3.7 + def has_kind(self, kinds):
3.8 + if not self.refs:
3.9 + return False
3.10 + for ref in self.refs:
3.11 + if ref.has_kind(kinds):
3.12 + return True
3.13 + return False
3.14 +
3.15 def __repr__(self):
3.16 return "AttrResult(%r, %r)" % (self.s, self.origin)
3.17
3.18 @@ -228,6 +236,14 @@
3.19 class_name, method_name = path.rsplit(".", 1)
3.20 return self.importer.classes.has_key(class_name) and class_name
3.21
3.22 + def reset_invocations(self):
3.23 +
3.24 + "Reset offsets within each namespace's arguments array."
3.25 +
3.26 + self.invocation_depth = 0
3.27 + self.invocation_argument_depth = 0
3.28 + self.invocation_kw_argument_depth = 0
3.29 +
3.30 # Namespace recording.
3.31
3.32 def record_namespaces(self, node):
3.33 @@ -329,9 +345,7 @@
3.34 self.process_function_body_node(node)
3.35 else:
3.36 self.in_function = False
3.37 - self.invocation_depth = 0
3.38 - self.invocation_argument_depth = 0
3.39 - self.invocation_kw_argument_depth = 0
3.40 + self.reset_invocations()
3.41 self.start_module()
3.42 self.process_structure(node)
3.43 self.end_module()
3.44 @@ -633,9 +647,7 @@
3.45
3.46 # Process the function body.
3.47
3.48 - self.invocation_depth = 0
3.49 - self.invocation_argument_depth = 0
3.50 - self.invocation_kw_argument_depth = 0
3.51 + self.reset_invocations()
3.52
3.53 in_conditional = self.in_conditional
3.54 self.in_conditional = False
3.55 @@ -756,14 +768,25 @@
3.56
3.57 expr = self.process_structure_node(n.node)
3.58 objpath = expr.get_origin()
3.59 + target = None
3.60
3.61 # Obtain details of the callable.
3.62
3.63 if objpath:
3.64 parameters = self.importer.function_parameters.get(objpath)
3.65 + if expr.has_kind("<class>"):
3.66 + target = encode_instantiator_pointer(objpath)
3.67 + elif expr.has_kind("<function>"):
3.68 + target = encode_function_pointer(objpath)
3.69 else:
3.70 parameters = None
3.71
3.72 + # Obtain details of the argument storage, updating the offsets to allow
3.73 + # calls in the argument list.
3.74 +
3.75 + argstart = self.invocation_argument_depth
3.76 + # self.invocation_argument_depth += len(parameters)
3.77 +
3.78 stages = []
3.79
3.80 # Arguments are presented in a temporary frame array at the current
3.81 @@ -771,15 +794,20 @@
3.82 # may be omitted for invocations where it would be unused).
3.83
3.84 stages.append("__tmp_target = %s" % expr)
3.85 - stages.append("__tmp_args[...] = __tmp_target.context")
3.86 + stages.append("__tmp_args[%d] = __tmp_target.context" % argstart)
3.87
3.88 # Keyword arguments are positioned within the frame.
3.89
3.90 # Defaults are added to the frame where arguments are missing.
3.91
3.92 - # The callable member of the callable is then obtained.
3.93 + # Any identified target is stated.
3.94
3.95 - if self.always_callable:
3.96 + if target:
3.97 + get_fn = "__tmp_target.fn"
3.98 +
3.99 + # The callable member of any callable is then obtained.
3.100 +
3.101 + elif self.always_callable:
3.102 get_fn = "__load_via_object(__tmp_target, %s).fn" % \
3.103 encode_symbol("pos", "__fn__")
3.104 else:
3.105 @@ -788,7 +816,7 @@
3.106
3.107 stages.append(get_fn)
3.108
3.109 - output = "(\n%s\n)(__tmp_frame)" % ",\n".join(stages)
3.110 + output = "(\n%s\n)(&__tmp_args[%d])" % (",\n".join(stages), argstart)
3.111
3.112 return make_expression("".join(output))
3.113