1.1 --- a/translator.py Mon Jul 16 23:00:47 2018 +0200
1.2 +++ b/translator.py Sat Jul 21 23:19:26 2018 +0200
1.3 @@ -115,6 +115,7 @@
1.4
1.5 self.namespaces = []
1.6 self.in_conditional = False
1.7 + self.in_parameter_list = False
1.8
1.9 # Exception raising adjustments.
1.10
1.11 @@ -317,6 +318,8 @@
1.12 self.max_function_target = 0
1.13 self.context_index = 0
1.14 self.max_context_index = 0
1.15 + self.accessor_index = 0
1.16 + self.max_accessor_index = 0
1.17 self.start_module()
1.18 self.process_structure(node)
1.19 self.end_module()
1.20 @@ -554,11 +557,13 @@
1.21 # The context set or retrieved will be that used by any enclosing
1.22 # invocation.
1.23
1.24 + accessor_index = self.accessor_index
1.25 context_index = self.context_index
1.26 context_identity = None
1.27 context_identity_verified = False
1.28 final_identity = None
1.29 accessor_test = False
1.30 + accessor_stored = False
1.31
1.32 # Obtain encoded versions of each instruction, accumulating temporary
1.33 # variables.
1.34 @@ -568,7 +573,9 @@
1.35 # Intercept a special instruction identifying the context.
1.36
1.37 if instruction[0] in ("<context_identity>", "<context_identity_verified>"):
1.38 - context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index)
1.39 + context_identity, _substituted = \
1.40 + encode_access_instruction_arg(instruction[1], subs, instruction[0],
1.41 + accessor_index, context_index)
1.42 context_identity_verified = instruction[0] == "<context_identity_verified>"
1.43 continue
1.44
1.45 @@ -585,10 +592,16 @@
1.46 instruction = ("__to_error", instruction)
1.47 accessor_test = True
1.48
1.49 + # Intercept accessor storage.
1.50 +
1.51 + elif instruction[0] == "<set_accessor>":
1.52 + accessor_stored = True
1.53 +
1.54 # Collect the encoded instruction, noting any temporary variables
1.55 # required by it.
1.56
1.57 - encoded, _substituted = encode_access_instruction(instruction, subs, context_index)
1.58 + encoded, _substituted = encode_access_instruction(instruction, subs,
1.59 + accessor_index, context_index)
1.60 output.append(encoded)
1.61 substituted.update(_substituted)
1.62
1.63 @@ -604,7 +617,9 @@
1.64 refs = set([self.importer.identify(final_identity)])
1.65
1.66 del self.attrs[0]
1.67 - return AttrResult(output, refs, location, context_identity, context_identity_verified, accessor_test)
1.68 + return AttrResult(output, refs, location,
1.69 + context_identity, context_identity_verified,
1.70 + accessor_test, accessor_stored)
1.71
1.72 def init_substitutions(self):
1.73
1.74 @@ -619,21 +634,22 @@
1.75 # Substitutions used by instructions.
1.76
1.77 "<private_context>" : "__tmp_private_context",
1.78 - "<accessor>" : "__tmp_value",
1.79 "<target_accessor>" : "__tmp_target_value",
1.80
1.81 # Mappings to be replaced by those given below.
1.82
1.83 + "<accessor>" : "__tmp_values",
1.84 "<context>" : "__tmp_contexts",
1.85 "<test_context_revert>" : "__tmp_contexts",
1.86 "<test_context_static>" : "__tmp_contexts",
1.87 "<set_context>" : "__tmp_contexts",
1.88 "<set_private_context>" : "__tmp_private_context",
1.89 - "<set_accessor>" : "__tmp_value",
1.90 + "<set_accessor>" : "__tmp_values",
1.91 "<set_target_accessor>" : "__tmp_target_value",
1.92 }
1.93
1.94 self.op_subs = {
1.95 + "<accessor>" : "__get_accessor",
1.96 "<context>" : "__get_context",
1.97 "<test_context_revert>" : "__test_context_revert",
1.98 "<test_context_static>" : "__test_context_static",
1.99 @@ -840,6 +856,8 @@
1.100 self.max_function_target = 0
1.101 self.context_index = 0
1.102 self.max_context_index = 0
1.103 + self.accessor_index = 0
1.104 + self.max_accessor_index = 0
1.105
1.106 # Volatile locals for exception handling.
1.107
1.108 @@ -1082,6 +1100,7 @@
1.109 # With such operations present, the expression cannot be eliminated.
1.110
1.111 tests_accessor = have_access_context and expr.tests_accessor()
1.112 + stores_accessor = have_access_context and expr.stores_accessor()
1.113
1.114 # Parameter details and parameter list dimensions.
1.115
1.116 @@ -1258,6 +1277,9 @@
1.117 if need_context_stored:
1.118 self.record_temp("__tmp_contexts")
1.119
1.120 + if stores_accessor:
1.121 + self.record_temp("__tmp_values")
1.122 +
1.123 # Arguments are presented in a temporary frame array with any context
1.124 # always being the first argument. Where it would be unused, it may be
1.125 # set to null.
1.126 @@ -1284,6 +1306,7 @@
1.127
1.128 function_target = self.function_target
1.129 context_index = self.context_index
1.130 + accessor_index = self.accessor_index
1.131
1.132 if need_target_stored:
1.133 self.next_target()
1.134 @@ -1291,6 +1314,12 @@
1.135 if need_context_stored:
1.136 self.next_context()
1.137
1.138 + if stores_accessor:
1.139 + self.next_accessor()
1.140 +
1.141 + in_parameter_list = self.in_parameter_list
1.142 + self.in_parameter_list = True
1.143 +
1.144 for i, arg in enumerate(n.args):
1.145 argexpr = self.process_structure_node(arg)
1.146
1.147 @@ -1329,8 +1358,12 @@
1.148
1.149 # Reference the current target again.
1.150
1.151 - self.function_target = function_target
1.152 - self.context_index = context_index
1.153 + self.in_parameter_list = in_parameter_list
1.154 +
1.155 + if not self.in_parameter_list:
1.156 + self.function_target = function_target
1.157 + self.context_index = context_index
1.158 + self.accessor_index = accessor_index
1.159
1.160 # Defaults are added to the frame where arguments are missing.
1.161
1.162 @@ -1473,6 +1506,13 @@
1.163 self.context_index += 1
1.164 self.max_context_index = max(self.context_index, self.max_context_index)
1.165
1.166 + def next_accessor(self):
1.167 +
1.168 + "Allocate the next accessor value storage."
1.169 +
1.170 + self.accessor_index += 1
1.171 + self.max_accessor_index = max(self.accessor_index, self.max_accessor_index)
1.172 +
1.173 def always_callable(self, refs):
1.174
1.175 "Determine whether all 'refs' are callable."
1.176 @@ -1527,8 +1567,9 @@
1.177
1.178 name = self.get_lambda_name()
1.179 function_name = self.get_object_path(name)
1.180 -
1.181 - defaults = self.process_function_defaults(n, name, function_name, "__tmp_value")
1.182 + instance_name = "__get_accessor(%d)" % self.accessor_index
1.183 +
1.184 + defaults = self.process_function_defaults(n, name, function_name, instance_name)
1.185
1.186 # Without defaults, produce an attribute referring to the function.
1.187
1.188 @@ -1539,11 +1580,16 @@
1.189 # copy.
1.190
1.191 else:
1.192 - self.record_temp("__tmp_value")
1.193 - return make_expression("(__tmp_value = __ATTRVALUE(__COPY(&%s, sizeof(%s))), %s, __tmp_value)" % (
1.194 + self.record_temp("__tmp_values")
1.195 + return make_expression("""\
1.196 +(__set_accessor(%d, __ATTRVALUE(__COPY(&%s, sizeof(%s)))),
1.197 + %s,
1.198 + __get_accessor(%d))""" % (
1.199 + self.accessor_index,
1.200 encode_path(function_name),
1.201 encode_symbol("obj", function_name),
1.202 - ", ".join(defaults)))
1.203 + ", ".join(defaults),
1.204 + self.accessor_index))
1.205
1.206 def process_logical_node(self, n):
1.207
1.208 @@ -2119,24 +2165,21 @@
1.209
1.210 "Write temporary storage employed by 'name'."
1.211
1.212 - # Provide space for the given number of targets.
1.213 -
1.214 - targets = self.max_function_target
1.215 + # Provide space for the recorded number of temporary variables.
1.216
1.217 if self.uses_temp(name, "__tmp_targets"):
1.218 - self.writeline("__attr __tmp_targets[%d];" % targets)
1.219 -
1.220 - index = self.max_context_index
1.221 + self.writeline("__attr __tmp_targets[%d];" % self.max_function_target)
1.222
1.223 if self.uses_temp(name, "__tmp_contexts"):
1.224 - self.writeline("__attr __tmp_contexts[%d];" % index)
1.225 + self.writeline("__attr __tmp_contexts[%d];" % self.max_context_index)
1.226 +
1.227 + if self.uses_temp(name, "__tmp_values"):
1.228 + self.writeline("__attr __tmp_values[%d];" % self.max_accessor_index)
1.229
1.230 # Add temporary variable usage details.
1.231
1.232 if self.uses_temp(name, "__tmp_private_context"):
1.233 self.writeline("__attr __tmp_private_context;")
1.234 - if self.uses_temp(name, "__tmp_value"):
1.235 - self.writeline("__attr __tmp_value;")
1.236 if self.uses_temp(name, "__tmp_target_value"):
1.237 self.writeline("__attr __tmp_target_value;")
1.238 if self.uses_temp(name, "__tmp_result"):