1.1 --- a/translator.py Sat Jun 23 18:01:56 2018 +0200
1.2 +++ b/translator.py Sun Jun 24 00:09:33 2018 +0200
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Translate programs.
1.6
1.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -25,7 +25,8 @@
1.13 from encoders import encode_access_instruction, encode_access_instruction_arg, \
1.14 encode_function_pointer, encode_literal_instantiator, \
1.15 encode_instantiator_pointer, encode_path, encode_symbol, \
1.16 - encode_type_attribute, is_type_attribute
1.17 + encode_type_attribute, is_type_attribute, \
1.18 + type_ops, typename_ops
1.19 from errors import InspectError, TranslateError
1.20 from os.path import exists, join
1.21 from os import makedirs
1.22 @@ -120,10 +121,6 @@
1.23 self.in_try_finally = False
1.24 self.in_try_except = False
1.25
1.26 - # Invocation adjustments.
1.27 -
1.28 - self.in_argument_list = False
1.29 -
1.30 # Attribute access and accessor counting.
1.31
1.32 self.attr_accesses = {}
1.33 @@ -317,7 +314,9 @@
1.34 else:
1.35 self.in_function = False
1.36 self.function_target = 0
1.37 - self.max_function_targets = 0
1.38 + self.max_function_target = 0
1.39 + self.context_index = 0
1.40 + self.max_context_index = 0
1.41 self.start_module()
1.42 self.process_structure(node)
1.43 self.end_module()
1.44 @@ -555,10 +554,11 @@
1.45 # The context set or retrieved will be that used by any enclosing
1.46 # invocation.
1.47
1.48 - context_index = self.function_target - 1
1.49 + context_index = self.context_index
1.50 context_identity = None
1.51 context_identity_verified = False
1.52 final_identity = None
1.53 + accessor_test = False
1.54
1.55 # Obtain encoded versions of each instruction, accumulating temporary
1.56 # variables.
1.57 @@ -579,6 +579,12 @@
1.58 final_identity = instruction[1]
1.59 continue
1.60
1.61 + # Modify test instructions.
1.62 +
1.63 + elif instruction[0] in typename_ops or instruction[0] in type_ops:
1.64 + instruction = ("__to_error", instruction)
1.65 + accessor_test = True
1.66 +
1.67 # Collect the encoded instruction, noting any temporary variables
1.68 # required by it.
1.69
1.70 @@ -599,7 +605,7 @@
1.71 refs = [ref]
1.72
1.73 del self.attrs[0]
1.74 - return AttrResult(output, refs, location, context_identity, context_identity_verified)
1.75 + return AttrResult(output, refs, location, context_identity, context_identity_verified, accessor_test)
1.76
1.77 def init_substitutions(self):
1.78
1.79 @@ -837,7 +843,9 @@
1.80 in_conditional = self.in_conditional
1.81 self.in_conditional = False
1.82 self.function_target = 0
1.83 - self.max_function_targets = 0
1.84 + self.max_function_target = 0
1.85 + self.context_index = 0
1.86 + self.max_context_index = 0
1.87
1.88 # Volatile locals for exception handling.
1.89
1.90 @@ -1040,23 +1048,10 @@
1.91
1.92 "Process the given invocation node 'n'."
1.93
1.94 - # Any invocations in the expression will store target details in a
1.95 - # different location.
1.96 -
1.97 - self.next_target()
1.98 -
1.99 - in_argument_list = self.in_argument_list
1.100 - self.in_argument_list = False
1.101 -
1.102 # Process the expression.
1.103
1.104 expr = self.process_structure_node(n.node)
1.105
1.106 - # Reference the current target again.
1.107 -
1.108 - self.in_argument_list = in_argument_list
1.109 - self.function_target -= 1
1.110 -
1.111 # Obtain details of the invocation expression.
1.112
1.113 objpath = expr.get_origin()
1.114 @@ -1083,6 +1078,7 @@
1.115 have_access_context = isinstance(expr, AttrResult)
1.116 context_identity = have_access_context and expr.context()
1.117 context_verified = have_access_context and expr.context_verified()
1.118 + tests_accessor = have_access_context and expr.tests_accessor()
1.119 parameters = None
1.120 num_parameters = None
1.121 num_defaults = None
1.122 @@ -1204,28 +1200,61 @@
1.123 len(self.importer.function_parameters[_objpath]),
1.124 _objpath)
1.125
1.126 + # Logical statement about available parameter information.
1.127 +
1.128 + known_parameters = num_parameters is not None
1.129 +
1.130 + # The source of context information: target or temporary.
1.131 +
1.132 + need_context_target = context_required and not have_access_context
1.133 +
1.134 + need_context_stored = context_required and context_identity and \
1.135 + context_identity.startswith("__get_context")
1.136 +
1.137 # Determine any readily-accessible target identity.
1.138
1.139 target_named = expr.is_name() and str(expr) or None
1.140 + target_identity = target or target_named
1.141 +
1.142 + # Use of target information to populate defaults.
1.143 +
1.144 + defaults_target_var = not (parameters and function_defaults is not None) and \
1.145 + known_parameters and len(n.args) < num_parameters
1.146 +
1.147 + # Use of a temporary target variable in these situations:
1.148 + #
1.149 + # A target provided by an expression needed for defaults.
1.150 + #
1.151 + # A target providing the context but not using a name to do so.
1.152 + #
1.153 + # A target expression involving the definition of a context which may
1.154 + # then be evaluated and stored to ensure that the context is available
1.155 + # during argument evaluation.
1.156 + #
1.157 + # An expression featuring an accessor test.
1.158 +
1.159 + need_target_stored = defaults_target_var and not target_identity or \
1.160 + need_context_target and not target_named or \
1.161 + need_context_stored or \
1.162 + tests_accessor and not target
1.163 +
1.164 + # Define stored target details.
1.165 +
1.166 target_stored = "__tmp_targets[%d]" % self.function_target
1.167
1.168 - target_identity = target or target_named
1.169 - target_var = target_identity or target_stored
1.170 - context_var = target_named or target_stored
1.171 -
1.172 - if not target_identity:
1.173 + target_var = need_target_stored and target_stored or target_identity
1.174 + context_var = need_target_stored and target_stored or target_named
1.175 +
1.176 + if need_target_stored:
1.177 self.record_temp("__tmp_targets")
1.178
1.179 - if context_identity:
1.180 - if context_identity.startswith("__tmp_contexts"):
1.181 - self.record_temp("__tmp_contexts")
1.182 + if need_context_stored:
1.183 + self.record_temp("__tmp_contexts")
1.184
1.185 # Arguments are presented in a temporary frame array with any context
1.186 # always being the first argument. Where it would be unused, it may be
1.187 # set to null.
1.188
1.189 - known_parameters = num_parameters is not None
1.190 -
1.191 if context_required:
1.192 if have_access_context:
1.193 args = [context_identity]
1.194 @@ -1245,12 +1274,13 @@
1.195 # different location.
1.196
1.197 function_target = self.function_target
1.198 -
1.199 - if not target_identity:
1.200 + context_index = self.context_index
1.201 +
1.202 + if need_target_stored:
1.203 self.next_target()
1.204
1.205 - in_argument_list = self.in_argument_list
1.206 - self.in_argument_list = True
1.207 + if need_context_stored:
1.208 + self.next_context()
1.209
1.210 for i, arg in enumerate(n.args):
1.211 argexpr = self.process_structure_node(arg)
1.212 @@ -1290,10 +1320,8 @@
1.213
1.214 # Reference the current target again.
1.215
1.216 - self.in_argument_list = in_argument_list
1.217 -
1.218 - if not self.in_argument_list:
1.219 - self.function_target = function_target
1.220 + self.function_target = function_target
1.221 + self.context_index = context_index
1.222
1.223 # Defaults are added to the frame where arguments are missing.
1.224
1.225 @@ -1343,27 +1371,31 @@
1.226 # First, the invocation expression is presented.
1.227
1.228 stages = []
1.229 -
1.230 - # Without a known specific callable, the expression provides the target.
1.231 -
1.232 - if not target or context_required:
1.233 -
1.234 - # The context is set in the expression.
1.235 -
1.236 - if target and not target_named:
1.237 -
1.238 - # Test whether the expression provides anything.
1.239 -
1.240 - if expr:
1.241 - stages.append(str(expr))
1.242 -
1.243 - elif not target_identity:
1.244 - stages.append("%s = %s" % (target_var, expr))
1.245 + emit = stages.append
1.246 +
1.247 + # Assign and yield any stored target.
1.248 + # The context may be set in the expression.
1.249 +
1.250 + if need_target_stored:
1.251 + emit("%s = %s" % (target_var, expr))
1.252 + target_expr = target_var
1.253 +
1.254 + # Otherwise, retain the expression for later use.
1.255 +
1.256 + else:
1.257 + target_expr = str(expr)
1.258
1.259 # Any specific callable is then obtained for invocation.
1.260
1.261 if target:
1.262 - stages.append(target)
1.263 +
1.264 + # An expression involving a test of the accessor providing the target.
1.265 + # This must be emitted in order to perform the test.
1.266 +
1.267 + if tests_accessor:
1.268 + emit(str(expr))
1.269 +
1.270 + emit(target)
1.271
1.272 # Methods accessed via unidentified accessors are obtained for
1.273 # invocation.
1.274 @@ -1372,15 +1404,15 @@
1.275 if context_required:
1.276 if have_access_context:
1.277 if context_verified:
1.278 - stages.append("__get_function_member(%s)" % target_var)
1.279 + emit("__get_function_member(%s)" % target_expr)
1.280 else:
1.281 - stages.append("__get_function(%s, %s)" % (
1.282 - context_identity, target_var))
1.283 + emit("__get_function(%s, %s)" % (
1.284 + context_identity, target_expr))
1.285 else:
1.286 - stages.append("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
1.287 - context_var, target_var))
1.288 + emit("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
1.289 + context_var, target_expr))
1.290 else:
1.291 - stages.append("_get_function_member(%s)" % target_var)
1.292 + emit("_get_function_member(%s)" % target_expr)
1.293
1.294 # With known parameters, the target can be tested.
1.295
1.296 @@ -1388,11 +1420,11 @@
1.297 context_arg = context_required and args[0] or "__NULL"
1.298 if self.always_callable(refs):
1.299 if context_verified:
1.300 - stages.append("__get_function_member(%s)" % target_var)
1.301 + emit("__get_function_member(%s)" % target_expr)
1.302 else:
1.303 - stages.append("__get_function(%s, %s)" % (context_arg, target_var))
1.304 + emit("__get_function(%s, %s)" % (context_arg, target_expr))
1.305 else:
1.306 - stages.append("__check_and_get_function(%s, %s)" % (context_arg, target_var))
1.307 + emit("__check_and_get_function(%s, %s)" % (context_arg, target_expr))
1.308
1.309 # With a known target, the function is obtained directly and called.
1.310 # By putting the invocation at the end of the final element in the
1.311 @@ -1411,8 +1443,8 @@
1.312 # the callable and argument collections.
1.313
1.314 else:
1.315 - stages.append("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (
1.316 - target_var,
1.317 + emit("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (
1.318 + target_expr,
1.319 self.always_callable(refs) and 1 or 0,
1.320 len(kwargs), kwcodestr, kwargstr,
1.321 len(args), "__ARGS(%s)" % argstr))
1.322 @@ -1423,7 +1455,14 @@
1.323 "Allocate the next function target storage."
1.324
1.325 self.function_target += 1
1.326 - self.max_function_targets = max(self.function_target, self.max_function_targets)
1.327 + self.max_function_target = max(self.function_target, self.max_function_target)
1.328 +
1.329 + def next_context(self):
1.330 +
1.331 + "Allocate the next context value storage."
1.332 +
1.333 + self.context_index += 1
1.334 + self.max_context_index = max(self.context_index, self.max_context_index)
1.335
1.336 def always_callable(self, refs):
1.337
1.338 @@ -2061,12 +2100,15 @@
1.339
1.340 # Provide space for the given number of targets.
1.341
1.342 - targets = self.max_function_targets
1.343 + targets = self.max_function_target
1.344
1.345 if self.uses_temp(name, "__tmp_targets"):
1.346 self.writeline("__attr __tmp_targets[%d];" % targets)
1.347 +
1.348 + index = self.max_context_index
1.349 +
1.350 if self.uses_temp(name, "__tmp_contexts"):
1.351 - self.writeline("__attr __tmp_contexts[%d];" % targets)
1.352 + self.writeline("__attr __tmp_contexts[%d];" % index)
1.353
1.354 # Add temporary variable usage details.
1.355