# HG changeset patch # User Paul Boddie # Date 1489092835 -3600 # Node ID 300df9719aec05e1bb901b46aec95721bbd1e17e # Parent 56c2fde456c81ad49dcc73e6de39b9bd7d5a8280 Obtain deduced name alias initialiser details when processing names, adjusting invocation processing to take advantage of the alias information when preparing target and context details. diff -r 56c2fde456c8 -r 300df9719aec results.py --- a/results.py Thu Mar 09 21:48:59 2017 +0100 +++ b/results.py Thu Mar 09 21:53:55 2017 +0100 @@ -42,6 +42,9 @@ def access_location(self): return None + def access_locations(self): + return None + def context_identity(self): return None diff -r 56c2fde456c8 -r 300df9719aec translator.py --- a/translator.py Thu Mar 09 21:48:59 2017 +0100 +++ b/translator.py Thu Mar 09 21:53:55 2017 +0100 @@ -33,7 +33,7 @@ from results import Result from transresults import TrConstantValueRef, TrInstanceRef, \ TrLiteralSequenceRef, TrResolvedNameRef, \ - AttrResult, Expression, InstantiationResult, \ + AliasResult, AttrResult, Expression, InstantiationResult, \ InvocationResult, LogicalOperationResult, \ LogicalResult, NegationResult, PredefinedConstantRef, \ ReturnRef @@ -631,8 +631,10 @@ access_location = self.deducer.const_accesses.get(location) refs = [] - for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: - refs.append(attr) + l = self.deducer.referenced_attrs.get(access_location or location) + if l: + for attrtype, objpath, attr in l: + refs.append(attr) return refs def get_referenced_attribute_invocations(self, location): @@ -645,11 +647,16 @@ access_location = self.deducer.const_accesses.get(location) return self.deducer.reference_invocations_unsuitable.get(access_location or location) - def get_accessor_kinds(self, location): - - "Return the accessor kinds for 'location'." - - return self.deducer.accessor_kinds.get(location) + def get_accessor_kinds(self, locations): + + "Return the accessor kinds for 'locations'." + + accessor_kinds = set() + for location in locations: + kinds = self.deducer.accessor_kinds.get(location) + if kinds: + accessor_kinds.update(kinds) + return accessor_kinds def get_access_location(self, name, attrnames=None): @@ -1018,6 +1025,7 @@ objpath = expr.get_origin() location = expr.access_location() + locations = expr.access_locations() # Identified target details. @@ -1071,7 +1079,10 @@ # Test for functions and methods. context_required = self.is_method(objpath) - accessor_kinds = self.get_accessor_kinds(location) + + accessor_kinds = location and self.get_accessor_kinds([location]) or \ + locations and self.get_accessor_kinds(locations) + instance_accessor = accessor_kinds and \ len(accessor_kinds) == 1 and \ first(accessor_kinds) == "" @@ -1105,8 +1116,12 @@ # Determine any readily-accessible target identity. - target_identity = target or expr.is_name() and str(expr) or None - target_var = target_identity or "__tmp_targets[%d]" % self.function_target + target_named = expr.is_name() and str(expr) or None + target_stored = "__tmp_targets[%d]" % self.function_target + + target_identity = target or target_named + target_var = target_identity or target_stored + context_var = target_named or target_stored if not target_identity: self.record_temp("__tmp_targets") @@ -1122,7 +1137,7 @@ if have_access_context: args = ["__ATTRVALUE(%s)" % context_identity] else: - args = ["__CONTEXT_AS_VALUE(%s)" % target_var] + args = ["__CONTEXT_AS_VALUE(%s)" % context_var] else: args = ["__NULL"] @@ -1227,18 +1242,26 @@ # Without a known specific callable, the expression provides the target. if not target or context_required: - if target: + + # The context is set in the expression. + + if target and not target_named: + + # Test whether the expression provides anything. + if expr: stages.append(str(expr)) + elif not target_identity: stages.append("%s = %s" % (target_var, expr)) - # Any specific callable is then obtained. + # Any specific callable is then obtained for invocation. if target: stages.append(target) - # Methods accessed via unidentified accessors are obtained. + # Methods accessed via unidentified accessors are obtained for + # invocation. elif function: if context_required: @@ -1247,7 +1270,7 @@ context_identity, target_var)) else: stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % ( - target_var, target_var)) + context_var, target_var)) else: stages.append("__load_via_object(%s.value, __fn__).fn" % target_var) @@ -1412,10 +1435,10 @@ parameter = n.name == "self" and self.in_method() or \ parameters and n.name in parameters - # Find any invocation details. + # Find any invocation or alias details. name = self.get_name_for_tracking(n.name, is_global=is_global) - location = self.get_access_location(name) + location = not expr and self.get_access_location(name) # Mark any local assignments as volatile in exception blocks. @@ -1426,7 +1449,32 @@ # static namespace members. The reference should be configured to return # such names. - return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location) + name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, + parameter=parameter, location=location) + result = self.get_aliases(name_ref) + return result or name_ref + + def get_aliases(self, name_ref): + + "Return alias references for the given 'name_ref'." + + location = name_ref.access_location() + + accessor_locations = location and self.deducer.get_accessors_for_access(location) + alias_refs = set() + access_locations = set() + + if accessor_locations: + for accessor_location in accessor_locations: + aliased_accesses = self.deducer.alias_index.get(accessor_location) + if not aliased_accesses: + continue + access_locations.update(aliased_accesses) + refs = self.deducer.referenced_objects.get(accessor_location) + if refs: + alias_refs.update(refs) + + return AliasResult(name_ref, alias_refs, access_locations) def make_volatile(self, name): diff -r 56c2fde456c8 -r 300df9719aec transresults.py --- a/transresults.py Thu Mar 09 21:48:59 2017 +0100 +++ b/transresults.py Thu Mar 09 21:53:55 2017 +0100 @@ -21,7 +21,7 @@ from common import first, InstructionSequence from encoders import encode_instructions, encode_literal_constant, encode_path -from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, \ +from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, NameRef, \ ResolvedNameRef, Result # Classes representing intermediate translation results. @@ -71,6 +71,9 @@ def access_location(self): return self.location + def access_locations(self): + return self.location and [self.location] + def __str__(self): "Return an output representation of the referenced name." @@ -95,7 +98,7 @@ # Eliminate assignments between constants. - if ref and isinstance(self.expr, ResolvedNameRef) and self.expr.static(): + if ref and self.expr.static(): return "" # Qualified names must be converted into parent-relative assignments. @@ -177,6 +180,9 @@ def access_location(self): return self.location + def access_locations(self): + return self.location and [self.location] + def context(self): return self.context_identity @@ -200,6 +206,62 @@ def __repr__(self): return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.location) +class AliasResult(NameRef, Result): + + "An alias for other values." + + def __init__(self, name_ref, refs, locations): + NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name()) + self.name_ref = name_ref + self.refs = refs + self.locations = locations + + def references(self): + ref = self.name_ref.reference() + return self.refs or ref and [ref] or None + + def reference(self): + refs = self.references() + return len(refs) == 1 and first(refs) or None + + def access_location(self): + return len(self.locations) == 1 and first(self.locations) or None + + def access_locations(self): + return self.locations + + def get_name(self): + ref = self.reference() + return ref and ref.get_name() + + def get_origin(self): + ref = self.reference() + return ref and ref.get_origin() + + def static(self): + ref = self.reference() + return ref and ref.static() + + def final(self): + ref = self.reference() + return ref and ref.final() + + def has_kind(self, kinds): + if not self.refs: + return self.name_ref.has_kind(kinds) + + for ref in self.refs: + if ref.has_kind(kinds): + return True + + return False + + def __str__(self): + return str(self.name_ref) + + def __repr__(self): + return "AliasResult(%r, %r)" % (self.name_ref, self.refs) + class InvocationResult(Result, InstructionSequence): "A translation result for an invocation."