1.1 --- a/deducer.py Sun Sep 03 00:24:29 2023 +0200
1.2 +++ b/deducer.py Tue Sep 05 21:16:49 2023 +0200
1.3 @@ -19,6 +19,7 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 +from access_plan import AccessPlan
1.8 from common import first, get_assigned_attributes, get_attrnames, \
1.9 get_invoked_attributes, get_name_path, init_item, \
1.10 order_dependencies_partial, sorted_output, \
1.11 @@ -477,23 +478,7 @@
1.12 locations.sort()
1.13
1.14 for location in locations:
1.15 - name, test, test_type, base, \
1.16 - traversed, traversal_modes, attrnames, \
1.17 - context, context_test, \
1.18 - first_method, final_method, \
1.19 - attr, accessor_kinds = self.access_plans[location]
1.20 -
1.21 - print >>f_attrs, encode_access_location(location), \
1.22 - name or "{}", \
1.23 - test and "-".join(test) or "{}", \
1.24 - test_type or "{}", \
1.25 - base or "{}", \
1.26 - ".".join(traversed) or "{}", \
1.27 - ".".join(traversal_modes) or "{}", \
1.28 - ".".join(attrnames) or "{}", \
1.29 - context, context_test, \
1.30 - first_method, final_method, attr or "{}", \
1.31 - ",".join(accessor_kinds)
1.32 + self.access_plans[location].write(f_attrs, location)
1.33
1.34 finally:
1.35 f_attrs.close()
1.36 @@ -2637,364 +2622,18 @@
1.37 (base and "base" or "original-accessor") or \
1.38 "final-accessor"
1.39
1.40 - return name, test, test_type, base, \
1.41 - traversed, traversal_modes, remaining, \
1.42 - context, context_test, \
1.43 - first_method, final_method, \
1.44 - origin, accessor_kinds
1.45 + return AccessPlan(name, test, test_type, base,
1.46 + traversed, traversal_modes, remaining,
1.47 + context, context_test,
1.48 + first_method, final_method,
1.49 + origin, accessor_kinds)
1.50
1.51 def initialise_access_instructions(self):
1.52
1.53 "Expand access plans into instruction sequences."
1.54
1.55 for access_location, access_plan in self.access_plans.items():
1.56 -
1.57 - # Obtain the access details.
1.58 -
1.59 - name, test, test_type, base, \
1.60 - traversed, traversal_modes, attrnames, \
1.61 - context, context_test, \
1.62 - first_method, final_method, \
1.63 - origin, accessor_kinds = access_plan
1.64 -
1.65 - # Emit instructions by appending them to a list.
1.66 -
1.67 - instructions = []
1.68 - emit = instructions.append
1.69 -
1.70 - # Identify any static original accessor.
1.71 -
1.72 - if base:
1.73 - original_accessor = base
1.74 -
1.75 - # Employ names as contexts unless the context needs testing and
1.76 - # potentially updating. In such cases, temporary context storage is
1.77 - # used instead.
1.78 -
1.79 - elif name and not (context_test == "test" and
1.80 - final_method in ("access-invoke", "static-invoke")):
1.81 - original_accessor = "<name>" # refers to the name
1.82 -
1.83 - # Use a generic placeholder representing the access expression in
1.84 - # the general case.
1.85 -
1.86 - else:
1.87 - original_accessor = "<expr>"
1.88 -
1.89 - # Prepare for any first attribute access.
1.90 -
1.91 - if traversed:
1.92 - attrname = traversed[0]
1.93 - del traversed[0]
1.94 - elif attrnames:
1.95 - attrname = attrnames[0]
1.96 - del attrnames[0]
1.97 -
1.98 - # Perform the first access explicitly if at least one operation
1.99 - # requires it.
1.100 -
1.101 - access_first_attribute = final_method in ("access", "access-invoke", "assign") or traversed or attrnames
1.102 -
1.103 - # Determine whether the first access involves assignment.
1.104 -
1.105 - assigning = not traversed and not attrnames and final_method == "assign"
1.106 - set_accessor = assigning and "<set_target_accessor>" or "<set_accessor>"
1.107 - stored_accessor = assigning and "<target_accessor>" or "<accessor>"
1.108 -
1.109 - # Set the context if already available.
1.110 -
1.111 - context_var = None
1.112 -
1.113 - if context == "base":
1.114 - accessor = context_var = (base,)
1.115 - elif context == "original-accessor":
1.116 -
1.117 - # Prevent re-evaluation of any dynamic expression by storing it.
1.118 -
1.119 - if original_accessor == "<expr>":
1.120 - if final_method in ("access-invoke", "static-invoke"):
1.121 - emit(("<set_context>", original_accessor))
1.122 - accessor = context_var = ("<context>",)
1.123 - else:
1.124 - emit((set_accessor, original_accessor))
1.125 - accessor = context_var = (stored_accessor,)
1.126 - else:
1.127 - accessor = context_var = (original_accessor,)
1.128 -
1.129 - # Assigning does not set the context.
1.130 -
1.131 - elif context in ("final-accessor", "unset") and access_first_attribute:
1.132 -
1.133 - # Prevent re-evaluation of any dynamic expression by storing it.
1.134 -
1.135 - if original_accessor == "<expr>":
1.136 - emit((set_accessor, original_accessor))
1.137 - accessor = (stored_accessor,)
1.138 - else:
1.139 - accessor = (original_accessor,)
1.140 - else:
1.141 - accessor = None
1.142 -
1.143 - # Apply any test.
1.144 -
1.145 - if test[0] == "test":
1.146 - test_accessor = accessor = ("__%s_%s_%s" % test, accessor, test_type)
1.147 - else:
1.148 - test_accessor = None
1.149 -
1.150 - # Perform the first or final access.
1.151 - # The access only needs performing if the resulting accessor is used.
1.152 -
1.153 - remaining = len(traversed + attrnames)
1.154 -
1.155 - if access_first_attribute:
1.156 -
1.157 - # Access via the accessor's class.
1.158 -
1.159 - if first_method == "relative-class":
1.160 - if assigning:
1.161 - emit(("<set_attr_ref>", ("__get_class_attr_ref", accessor, attrname)))
1.162 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.163 - else:
1.164 - accessor = ("__load_via_class", accessor, attrname)
1.165 -
1.166 - # Access via the accessor itself.
1.167 -
1.168 - elif first_method == "relative-object":
1.169 - if assigning:
1.170 - emit(("<set_attr_ref>", ("__get_object_attr_ref", accessor, attrname)))
1.171 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.172 - else:
1.173 - accessor = ("__load_via_object", accessor, attrname)
1.174 -
1.175 - # Access via a class accessor or the accessor's class.
1.176 -
1.177 - elif first_method == "relative-object-class":
1.178 - if assigning:
1.179 - emit(("__raise_type_error",))
1.180 - else:
1.181 - accessor = ("__get_class_and_load", accessor, attrname)
1.182 -
1.183 - # Access via the accessor's class.
1.184 -
1.185 - elif first_method == "check-class":
1.186 - if assigning:
1.187 - emit(("__raise_type_error",))
1.188 - else:
1.189 - accessor = ("__check_and_load_via_class", accessor, attrname)
1.190 -
1.191 - # Access via the accessor itself.
1.192 -
1.193 - elif first_method == "check-object":
1.194 - if assigning:
1.195 - emit(("<set_attr_ref>", ("__check_and_get_object_attr_ref", accessor, attrname)))
1.196 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.197 - else:
1.198 - accessor = ("__check_and_load_via_object", accessor, attrname)
1.199 -
1.200 - # Access via a class accessor or the accessor's class.
1.201 - # Here, only access via the accessor is supported.
1.202 -
1.203 - elif first_method == "check-object-class":
1.204 - if assigning:
1.205 - emit(("<set_attr_ref>", ("__check_and_get_object_attr_ref", accessor, attrname)))
1.206 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.207 - else:
1.208 - accessor = ("__check_and_load_via_any", accessor, attrname)
1.209 -
1.210 - # Traverse attributes using the accessor.
1.211 -
1.212 - if traversed:
1.213 - for attrname, traversal_mode in zip(traversed, traversal_modes):
1.214 - assigning = remaining == 1 and final_method == "assign"
1.215 -
1.216 - # Set the context, if appropriate.
1.217 -
1.218 - if remaining == 1 and final_method != "assign" and context == "final-accessor":
1.219 -
1.220 - # Invoked attributes employ a separate context accessed
1.221 - # during invocation.
1.222 -
1.223 - if final_method in ("access-invoke", "static-invoke"):
1.224 - emit(("<set_context>", accessor))
1.225 - accessor = context_var = "<context>"
1.226 -
1.227 - # A private context within the access is otherwise
1.228 - # retained.
1.229 -
1.230 - else:
1.231 - emit(("<set_private_context>", accessor))
1.232 - accessor = context_var = "<private_context>"
1.233 -
1.234 - # Perform the access only if not achieved directly.
1.235 -
1.236 - if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
1.237 -
1.238 - if traversal_mode == "class":
1.239 - if assigning:
1.240 - emit(("<set_attr_ref>", ("__get_class_attr_ref", accessor, attrname)))
1.241 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.242 - else:
1.243 - accessor = ("__load_via_class", accessor, attrname)
1.244 - else:
1.245 - if assigning:
1.246 - emit(("<set_attr_ref>", ("__get_object_attr_ref", accessor, attrname)))
1.247 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.248 - else:
1.249 - accessor = ("__load_via_object", accessor, attrname)
1.250 -
1.251 - remaining -= 1
1.252 -
1.253 - if attrnames:
1.254 - for attrname in attrnames:
1.255 - assigning = remaining == 1 and final_method == "assign"
1.256 -
1.257 - # Set the context, if appropriate.
1.258 -
1.259 - if remaining == 1 and final_method != "assign" and context == "final-accessor":
1.260 -
1.261 - # Invoked attributes employ a separate context accessed
1.262 - # during invocation.
1.263 -
1.264 - if final_method in ("access-invoke", "static-invoke"):
1.265 - emit(("<set_context>", accessor))
1.266 - accessor = context_var = "<context>"
1.267 -
1.268 - # A private context within the access is otherwise
1.269 - # retained.
1.270 -
1.271 - else:
1.272 - emit(("<set_private_context>", accessor))
1.273 - accessor = context_var = "<private_context>"
1.274 -
1.275 - # Perform the access only if not achieved directly.
1.276 -
1.277 - if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
1.278 -
1.279 - # Constrain instructions involving certain special
1.280 - # attribute names.
1.281 -
1.282 - to_search = attrname != "__data__" and "any" or "object"
1.283 -
1.284 - if assigning:
1.285 - emit(("<set_attr_ref>", ("__check_and_get_object_attr_ref", accessor, attrname)))
1.286 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.287 - else:
1.288 - accessor = ("__check_and_load_via_%s" % to_search, accessor, attrname)
1.289 -
1.290 - remaining -= 1
1.291 -
1.292 - # Make any accessor test available if not emitted.
1.293 -
1.294 - test_accessor = not instructions and test_accessor or None
1.295 -
1.296 - # Define or emit the means of accessing the actual target.
1.297 -
1.298 - if final_method in ("static", "static-assign", "static-invoke"):
1.299 -
1.300 - if test_accessor:
1.301 - emit(test_accessor)
1.302 -
1.303 - # Assignments to known attributes.
1.304 -
1.305 - if final_method == "static-assign":
1.306 - parent, attrname = origin.rsplit(".", 1)
1.307 - emit(("<set_attr_ref>", ("__get_object_attr_ref", parent, attrname)))
1.308 - emit(("__store_via_attr_ref", "<attr_ref>", "<assexpr>"))
1.309 -
1.310 - # Invoked attributes employ a separate context.
1.311 -
1.312 - elif final_method in ("static", "static-invoke"):
1.313 - accessor = ("__load_static_ignore", origin)
1.314 -
1.315 - # Define any replacement context variable plus the default eventual
1.316 - # context variable.
1.317 -
1.318 - replacement_context_var = "<new_context>"
1.319 - final_context_var = context_var
1.320 -
1.321 - # Wrap accesses in context operations.
1.322 -
1.323 - if context_test == "test":
1.324 -
1.325 - # Test and combine the context with static attribute details.
1.326 -
1.327 - if final_method == "static":
1.328 - emit(("__load_static_test", replacement_context_var, context_var, origin))
1.329 - final_context_var = replacement_context_var
1.330 -
1.331 - # Test the context, storing it separately if required for the
1.332 - # immediately invoked static attribute.
1.333 -
1.334 - elif final_method == "static-invoke":
1.335 - emit(("<test_context_static>", context_var, origin))
1.336 -
1.337 - # Test the context, storing it separately if required for an
1.338 - # immediately invoked attribute.
1.339 -
1.340 - elif final_method == "access-invoke":
1.341 - emit(("<test_context_revert>", context_var, accessor))
1.342 -
1.343 - # Test the context and update the attribute details if
1.344 - # appropriate.
1.345 -
1.346 - else:
1.347 - emit(("__test_context", replacement_context_var, context_var, accessor))
1.348 - final_context_var = replacement_context_var
1.349 -
1.350 - elif context_test == "replace":
1.351 -
1.352 - # Produce an object with updated context.
1.353 -
1.354 - if final_method == "static":
1.355 - emit(("__load_static_replace", replacement_context_var, context_var, origin))
1.356 - final_context_var = replacement_context_var
1.357 -
1.358 - # Omit the context update operation where the target is static
1.359 - # and the context is recorded separately.
1.360 -
1.361 - elif final_method == "static-invoke":
1.362 - pass
1.363 -
1.364 - # If a separate context is used for an immediate invocation,
1.365 - # produce the attribute details unchanged.
1.366 -
1.367 - elif final_method == "access-invoke":
1.368 - emit(accessor)
1.369 -
1.370 - # Update the context in the attribute details.
1.371 -
1.372 - else:
1.373 - emit(("__update_context", replacement_context_var, context_var, accessor))
1.374 - final_context_var = replacement_context_var
1.375 -
1.376 - # Omit the accessor for assignments and for invocations of static
1.377 - # targets. Otherwise, emit the accessor which may involve the
1.378 - # invocation of a test.
1.379 -
1.380 - elif final_method not in ("assign", "static-assign", "static-invoke"):
1.381 - emit(accessor)
1.382 -
1.383 - # Produce an advisory instruction regarding the context.
1.384 -
1.385 - if final_context_var:
1.386 -
1.387 - # Only verify the context for invocation purposes if a suitable
1.388 - # test has been performed.
1.389 -
1.390 - if context_test in ("ignore", "replace") or \
1.391 - final_method in ("access-invoke", "static-invoke"):
1.392 -
1.393 - emit(("<context_identity_verified>", final_context_var))
1.394 - else:
1.395 - emit(("<context_identity>", final_context_var))
1.396 -
1.397 - # Produce an advisory instruction regarding the final attribute.
1.398 -
1.399 - if origin:
1.400 - emit(("<final_identity>", origin))
1.401 -
1.402 - self.access_instructions[access_location] = instructions
1.403 - self.accessor_kinds[access_location] = accessor_kinds
1.404 + self.access_instructions[access_location] = access_plan.get_instructions()
1.405 + self.accessor_kinds[access_location] = access_plan.accessor_kinds
1.406
1.407 # vim: tabstop=4 expandtab shiftwidth=4