# HG changeset patch # User Paul Boddie # Date 1476999602 -7200 # Node ID 900d641f42d605763bb459030d7dbaef44969f08 # Parent 83d261448283a15686e6fc2500d1d08f73b22539 Added some more support for generating invocation code, distinguishing between static invocation targets that are identified and whose functions can be obtained directly and other kinds of targets whose functions must be obtained via the special attribute. diff -r 83d261448283 -r 900d641f42d6 optimiser.py --- a/optimiser.py Thu Oct 20 22:43:48 2016 +0200 +++ b/optimiser.py Thu Oct 20 23:40:02 2016 +0200 @@ -506,15 +506,38 @@ remaining -= 1 + # Define or emit the means of accessing the actual target. + if final_method == "static-assign": - emit(("__store_member", origin, "")) + parent, attrname = origin.rsplit(".", 1) + emit(("__store_via_object", parent, attrname, "")) + elif final_method == "static": accessor = ("__load_static", origin) + elif final_method == "static-invoke": + kind = self.importer.get_object(origin).get_kind() + accessor = ("__encode_callable", origin, kind) + + # Wrap accesses in context operations. + if context_test == "test": emit(("__test_context", context_var, accessor)) + elif context_test == "replace": - emit(("__replace_context", context_var, accessor)) + + # Static invocation targets have a context added but no other + # transformation performed. + + if final_method == "static-invoke": + emit(("__update_context", context_var, accessor)) + + # Other invocation targets gain a context and have the bound + # version of the callable activated. + + else: + emit(("__replace_context", context_var, accessor)) + elif final_method not in ("assign", "static-assign"): emit(accessor) diff -r 83d261448283 -r 900d641f42d6 results.py --- a/results.py Thu Oct 20 22:43:48 2016 +0200 +++ b/results.py Thu Oct 20 23:40:02 2016 +0200 @@ -29,9 +29,13 @@ def is_name(self): return False + def get_origin(self): return None + def reference(self): + return None + class AccessRef(Result): """ @@ -44,9 +48,6 @@ self.attrnames = attrnames self.number = number - def reference(self): - return None - def __repr__(self): return "AccessRef(%r, %r, %r)" % (self.original_name, self.attrnames, self.number) @@ -78,9 +79,6 @@ def is_name(self): return True - def reference(self): - return None - def final(self): return None diff -r 83d261448283 -r 900d641f42d6 translator.py --- a/translator.py Thu Oct 20 22:43:48 2016 +0200 +++ b/translator.py Thu Oct 20 23:40:02 2016 +0200 @@ -128,6 +128,14 @@ def get_origin(self): return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() + def has_kind(self, kinds): + if not self.refs: + return False + for ref in self.refs: + if ref.has_kind(kinds): + return True + return False + def __repr__(self): return "AttrResult(%r, %r)" % (self.s, self.origin) @@ -228,6 +236,14 @@ class_name, method_name = path.rsplit(".", 1) return self.importer.classes.has_key(class_name) and class_name + def reset_invocations(self): + + "Reset offsets within each namespace's arguments array." + + self.invocation_depth = 0 + self.invocation_argument_depth = 0 + self.invocation_kw_argument_depth = 0 + # Namespace recording. def record_namespaces(self, node): @@ -329,9 +345,7 @@ self.process_function_body_node(node) else: self.in_function = False - self.invocation_depth = 0 - self.invocation_argument_depth = 0 - self.invocation_kw_argument_depth = 0 + self.reset_invocations() self.start_module() self.process_structure(node) self.end_module() @@ -633,9 +647,7 @@ # Process the function body. - self.invocation_depth = 0 - self.invocation_argument_depth = 0 - self.invocation_kw_argument_depth = 0 + self.reset_invocations() in_conditional = self.in_conditional self.in_conditional = False @@ -756,14 +768,25 @@ expr = self.process_structure_node(n.node) objpath = expr.get_origin() + target = None # Obtain details of the callable. if objpath: parameters = self.importer.function_parameters.get(objpath) + if expr.has_kind(""): + target = encode_instantiator_pointer(objpath) + elif expr.has_kind(""): + target = encode_function_pointer(objpath) else: parameters = None + # Obtain details of the argument storage, updating the offsets to allow + # calls in the argument list. + + argstart = self.invocation_argument_depth + # self.invocation_argument_depth += len(parameters) + stages = [] # Arguments are presented in a temporary frame array at the current @@ -771,15 +794,20 @@ # may be omitted for invocations where it would be unused). stages.append("__tmp_target = %s" % expr) - stages.append("__tmp_args[...] = __tmp_target.context") + stages.append("__tmp_args[%d] = __tmp_target.context" % argstart) # Keyword arguments are positioned within the frame. # Defaults are added to the frame where arguments are missing. - # The callable member of the callable is then obtained. + # Any identified target is stated. - if self.always_callable: + if target: + get_fn = "__tmp_target.fn" + + # The callable member of any callable is then obtained. + + elif self.always_callable: get_fn = "__load_via_object(__tmp_target, %s).fn" % \ encode_symbol("pos", "__fn__") else: @@ -788,7 +816,7 @@ stages.append(get_fn) - output = "(\n%s\n)(__tmp_frame)" % ",\n".join(stages) + output = "(\n%s\n)(&__tmp_args[%d])" % (",\n".join(stages), argstart) return make_expression("".join(output))