1.1 --- a/translator.py Sun Oct 23 00:37:13 2016 +0200
1.2 +++ b/translator.py Sun Oct 23 00:38:30 2016 +0200
1.3 @@ -236,14 +236,6 @@
1.4 class_name, method_name = path.rsplit(".", 1)
1.5 return self.importer.classes.has_key(class_name) and class_name
1.6
1.7 - def reset_invocations(self):
1.8 -
1.9 - "Reset offsets within each namespace's arguments array."
1.10 -
1.11 - self.invocation_depth = 0
1.12 - self.invocation_argument_depth = 0
1.13 - self.invocation_kw_argument_depth = 0
1.14 -
1.15 # Namespace recording.
1.16
1.17 def record_namespaces(self, node):
1.18 @@ -345,7 +337,6 @@
1.19 self.process_function_body_node(node)
1.20 else:
1.21 self.in_function = False
1.22 - self.reset_invocations()
1.23 self.start_module()
1.24 self.process_structure(node)
1.25 self.end_module()
1.26 @@ -647,8 +638,6 @@
1.27
1.28 # Process the function body.
1.29
1.30 - self.reset_invocations()
1.31 -
1.32 in_conditional = self.in_conditional
1.33 self.in_conditional = False
1.34
1.35 @@ -781,44 +770,100 @@
1.36 else:
1.37 parameters = None
1.38
1.39 - # Obtain details of the argument storage, updating the offsets to allow
1.40 - # calls in the argument list.
1.41 -
1.42 - argstart = self.invocation_argument_depth
1.43 - # self.invocation_argument_depth += len(parameters)
1.44 -
1.45 stages = []
1.46
1.47 - # Arguments are presented in a temporary frame array at the current
1.48 - # position with any context always being the first argument (although it
1.49 - # may be omitted for invocations where it would be unused).
1.50 + # First, the invocation target is presented.
1.51
1.52 stages.append("__tmp_target = %s" % expr)
1.53 - stages.append("__tmp_args[%d] = __tmp_target.context" % argstart)
1.54 +
1.55 + # Arguments are presented in a temporary frame array with any context
1.56 + # always being the first argument (although it may be set to null for
1.57 + # invocations where it would be unused).
1.58 +
1.59 + args = ["__CONTEXT_AS_VALUE(__tmp_target)"]
1.60 + args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0)
1.61 + kwcodes = []
1.62 + kwargs = []
1.63 +
1.64 + for i, arg in enumerate(n.args):
1.65 + argexpr = self.process_structure_node(arg)
1.66 +
1.67 + # Store a keyword argument, either in the argument list or
1.68 + # in a separate keyword argument list for subsequent lookup.
1.69 +
1.70 + if isinstance(arg, compiler.ast.Keyword):
1.71
1.72 - # Keyword arguments are positioned within the frame.
1.73 + # With knowledge of the target, store the keyword
1.74 + # argument directly.
1.75 +
1.76 + if parameters:
1.77 + argnum = parameters.index(arg.name)
1.78 + args[argnum+1] = str(argexpr)
1.79 +
1.80 + # Otherwise, store the details in a separate collection.
1.81 +
1.82 + else:
1.83 + kwargs.append(str(argexpr))
1.84 + kwcodes.append("{%s, %s}" % (
1.85 + encode_symbol("ppos", arg.name),
1.86 + encode_symbol("pcode", arg.name)))
1.87 +
1.88 + else:
1.89 + args[i+1] = str(argexpr)
1.90
1.91 # Defaults are added to the frame where arguments are missing.
1.92
1.93 - # Any identified target is stated.
1.94 + if parameters:
1.95 + function_defaults = self.importer.function_defaults.get(objpath)
1.96 + if function_defaults:
1.97 +
1.98 + # Visit each default and set any missing arguments.
1.99 +
1.100 + for i, (argname, default) in enumerate(function_defaults):
1.101 + argnum = parameters.index(argname)
1.102 + if not args[argnum+1]:
1.103 + args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target, i)
1.104 +
1.105 + if None in args:
1.106 + print self.get_namespace_path()
1.107 + print n
1.108 + print expr
1.109 + print target
1.110 + print args
1.111 +
1.112 + argstr = "__ARGS(%s)" % ", ".join(args)
1.113 + kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"
1.114 + kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"
1.115 +
1.116 + # The callable is then obtained.
1.117
1.118 if target:
1.119 - get_fn = "__tmp_target.fn"
1.120 -
1.121 - # The callable member of any callable is then obtained.
1.122 + callable = "__tmp_target"
1.123
1.124 elif self.always_callable:
1.125 - get_fn = "__load_via_object(__tmp_target, %s).fn" % \
1.126 + callable = "__load_via_object(__tmp_target, %s)" % \
1.127 encode_symbol("pos", "__fn__")
1.128 else:
1.129 - get_fn = "__check_and_load_via_object(__tmp_target, %s, %s).fn" % (
1.130 + callable = "__check_and_load_via_object(__tmp_target, %s, %s)" % (
1.131 encode_symbol("pos", "__fn__"), encode_symbol("code", "__fn__"))
1.132
1.133 - stages.append(get_fn)
1.134 + stages.append(callable)
1.135 +
1.136 + # With a known target, the function is obtained directly and called.
1.137 +
1.138 + if target:
1.139 + output = "(\n%s.fn\n)(%s)" % (",\n".join(stages), argstr)
1.140
1.141 - output = "(\n%s\n)(&__tmp_args[%d])" % (",\n".join(stages), argstart)
1.142 + # With unknown targets, the generic invocation function is applied to
1.143 + # the callable and argument collections.
1.144
1.145 - return make_expression("".join(output))
1.146 + else:
1.147 + output = "__invoke(\n(\n%s\n),\n%d, %s, %s,\n%d, %s\n)" % (
1.148 + ",\n".join(stages),
1.149 + len(kwargs), kwcodestr, kwargstr,
1.150 + len(args), argstr)
1.151 +
1.152 + return make_expression(output)
1.153
1.154 def always_callable(self, refs):
1.155
1.156 @@ -1025,7 +1070,6 @@
1.157 print >>self.out, "void __main_%s()" % encode_path(self.name)
1.158 print >>self.out, "{"
1.159 self.indent += 1
1.160 - self.emit_invocation_storage(self.name)
1.161
1.162 def end_module(self):
1.163 self.indent -= 1
1.164 @@ -1058,8 +1102,6 @@
1.165 names.sort()
1.166 self.writeline("__attr %s;" % ", ".join(names))
1.167
1.168 - self.emit_invocation_storage(name)
1.169 -
1.170 # Generate any self reference.
1.171
1.172 if self.in_method(name):
1.173 @@ -1096,16 +1138,6 @@
1.174 self.indent -= 1
1.175 self.writeline("}")
1.176
1.177 - def emit_invocation_storage(self, name):
1.178 -
1.179 - "Emit invocation temporary storage."
1.180 -
1.181 - if self.importer.function_targets.has_key(name):
1.182 - self.writeline("__attr __tmp_targets[%d];" % self.importer.function_targets[name])
1.183 -
1.184 - if self.importer.function_arguments.has_key(name):
1.185 - self.writeline("__attr __tmp_args[%d];" % self.importer.function_arguments[name])
1.186 -
1.187 def statement(self, expr):
1.188 # NOTE: Should never be None.
1.189 if not expr:
1.190 @@ -1128,7 +1160,7 @@
1.191 out.append(levels * self.tabstop + line)
1.192 if line.endswith("("):
1.193 levels += 1
1.194 - elif line.endswith(")"):
1.195 + elif line.startswith(")"):
1.196 levels -= 1
1.197 return "\n".join(out)
1.198