2.1 --- a/translator.py Thu Mar 09 21:48:59 2017 +0100
2.2 +++ b/translator.py Thu Mar 09 21:53:55 2017 +0100
2.3 @@ -33,7 +33,7 @@
2.4 from results import Result
2.5 from transresults import TrConstantValueRef, TrInstanceRef, \
2.6 TrLiteralSequenceRef, TrResolvedNameRef, \
2.7 - AttrResult, Expression, InstantiationResult, \
2.8 + AliasResult, AttrResult, Expression, InstantiationResult, \
2.9 InvocationResult, LogicalOperationResult, \
2.10 LogicalResult, NegationResult, PredefinedConstantRef, \
2.11 ReturnRef
2.12 @@ -631,8 +631,10 @@
2.13
2.14 access_location = self.deducer.const_accesses.get(location)
2.15 refs = []
2.16 - for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]:
2.17 - refs.append(attr)
2.18 + l = self.deducer.referenced_attrs.get(access_location or location)
2.19 + if l:
2.20 + for attrtype, objpath, attr in l:
2.21 + refs.append(attr)
2.22 return refs
2.23
2.24 def get_referenced_attribute_invocations(self, location):
2.25 @@ -645,11 +647,16 @@
2.26 access_location = self.deducer.const_accesses.get(location)
2.27 return self.deducer.reference_invocations_unsuitable.get(access_location or location)
2.28
2.29 - def get_accessor_kinds(self, location):
2.30 -
2.31 - "Return the accessor kinds for 'location'."
2.32 -
2.33 - return self.deducer.accessor_kinds.get(location)
2.34 + def get_accessor_kinds(self, locations):
2.35 +
2.36 + "Return the accessor kinds for 'locations'."
2.37 +
2.38 + accessor_kinds = set()
2.39 + for location in locations:
2.40 + kinds = self.deducer.accessor_kinds.get(location)
2.41 + if kinds:
2.42 + accessor_kinds.update(kinds)
2.43 + return accessor_kinds
2.44
2.45 def get_access_location(self, name, attrnames=None):
2.46
2.47 @@ -1018,6 +1025,7 @@
2.48
2.49 objpath = expr.get_origin()
2.50 location = expr.access_location()
2.51 + locations = expr.access_locations()
2.52
2.53 # Identified target details.
2.54
2.55 @@ -1071,7 +1079,10 @@
2.56 # Test for functions and methods.
2.57
2.58 context_required = self.is_method(objpath)
2.59 - accessor_kinds = self.get_accessor_kinds(location)
2.60 +
2.61 + accessor_kinds = location and self.get_accessor_kinds([location]) or \
2.62 + locations and self.get_accessor_kinds(locations)
2.63 +
2.64 instance_accessor = accessor_kinds and \
2.65 len(accessor_kinds) == 1 and \
2.66 first(accessor_kinds) == "<instance>"
2.67 @@ -1105,8 +1116,12 @@
2.68
2.69 # Determine any readily-accessible target identity.
2.70
2.71 - target_identity = target or expr.is_name() and str(expr) or None
2.72 - target_var = target_identity or "__tmp_targets[%d]" % self.function_target
2.73 + target_named = expr.is_name() and str(expr) or None
2.74 + target_stored = "__tmp_targets[%d]" % self.function_target
2.75 +
2.76 + target_identity = target or target_named
2.77 + target_var = target_identity or target_stored
2.78 + context_var = target_named or target_stored
2.79
2.80 if not target_identity:
2.81 self.record_temp("__tmp_targets")
2.82 @@ -1122,7 +1137,7 @@
2.83 if have_access_context:
2.84 args = ["__ATTRVALUE(%s)" % context_identity]
2.85 else:
2.86 - args = ["__CONTEXT_AS_VALUE(%s)" % target_var]
2.87 + args = ["__CONTEXT_AS_VALUE(%s)" % context_var]
2.88 else:
2.89 args = ["__NULL"]
2.90
2.91 @@ -1227,18 +1242,26 @@
2.92 # Without a known specific callable, the expression provides the target.
2.93
2.94 if not target or context_required:
2.95 - if target:
2.96 +
2.97 + # The context is set in the expression.
2.98 +
2.99 + if target and not target_named:
2.100 +
2.101 + # Test whether the expression provides anything.
2.102 +
2.103 if expr:
2.104 stages.append(str(expr))
2.105 +
2.106 elif not target_identity:
2.107 stages.append("%s = %s" % (target_var, expr))
2.108
2.109 - # Any specific callable is then obtained.
2.110 + # Any specific callable is then obtained for invocation.
2.111
2.112 if target:
2.113 stages.append(target)
2.114
2.115 - # Methods accessed via unidentified accessors are obtained.
2.116 + # Methods accessed via unidentified accessors are obtained for
2.117 + # invocation.
2.118
2.119 elif function:
2.120 if context_required:
2.121 @@ -1247,7 +1270,7 @@
2.122 context_identity, target_var))
2.123 else:
2.124 stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % (
2.125 - target_var, target_var))
2.126 + context_var, target_var))
2.127 else:
2.128 stages.append("__load_via_object(%s.value, __fn__).fn" % target_var)
2.129
2.130 @@ -1412,10 +1435,10 @@
2.131 parameter = n.name == "self" and self.in_method() or \
2.132 parameters and n.name in parameters
2.133
2.134 - # Find any invocation details.
2.135 + # Find any invocation or alias details.
2.136
2.137 name = self.get_name_for_tracking(n.name, is_global=is_global)
2.138 - location = self.get_access_location(name)
2.139 + location = not expr and self.get_access_location(name)
2.140
2.141 # Mark any local assignments as volatile in exception blocks.
2.142
2.143 @@ -1426,7 +1449,32 @@
2.144 # static namespace members. The reference should be configured to return
2.145 # such names.
2.146
2.147 - return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location)
2.148 + name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global,
2.149 + parameter=parameter, location=location)
2.150 + result = self.get_aliases(name_ref)
2.151 + return result or name_ref
2.152 +
2.153 + def get_aliases(self, name_ref):
2.154 +
2.155 + "Return alias references for the given 'name_ref'."
2.156 +
2.157 + location = name_ref.access_location()
2.158 +
2.159 + accessor_locations = location and self.deducer.get_accessors_for_access(location)
2.160 + alias_refs = set()
2.161 + access_locations = set()
2.162 +
2.163 + if accessor_locations:
2.164 + for accessor_location in accessor_locations:
2.165 + aliased_accesses = self.deducer.alias_index.get(accessor_location)
2.166 + if not aliased_accesses:
2.167 + continue
2.168 + access_locations.update(aliased_accesses)
2.169 + refs = self.deducer.referenced_objects.get(accessor_location)
2.170 + if refs:
2.171 + alias_refs.update(refs)
2.172 +
2.173 + return AliasResult(name_ref, alias_refs, access_locations)
2.174
2.175 def make_volatile(self, name):
2.176
3.1 --- a/transresults.py Thu Mar 09 21:48:59 2017 +0100
3.2 +++ b/transresults.py Thu Mar 09 21:53:55 2017 +0100
3.3 @@ -21,7 +21,7 @@
3.4
3.5 from common import first, InstructionSequence
3.6 from encoders import encode_instructions, encode_literal_constant, encode_path
3.7 -from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, \
3.8 +from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, NameRef, \
3.9 ResolvedNameRef, Result
3.10
3.11 # Classes representing intermediate translation results.
3.12 @@ -71,6 +71,9 @@
3.13 def access_location(self):
3.14 return self.location
3.15
3.16 + def access_locations(self):
3.17 + return self.location and [self.location]
3.18 +
3.19 def __str__(self):
3.20
3.21 "Return an output representation of the referenced name."
3.22 @@ -95,7 +98,7 @@
3.23
3.24 # Eliminate assignments between constants.
3.25
3.26 - if ref and isinstance(self.expr, ResolvedNameRef) and self.expr.static():
3.27 + if ref and self.expr.static():
3.28 return ""
3.29
3.30 # Qualified names must be converted into parent-relative assignments.
3.31 @@ -177,6 +180,9 @@
3.32 def access_location(self):
3.33 return self.location
3.34
3.35 + def access_locations(self):
3.36 + return self.location and [self.location]
3.37 +
3.38 def context(self):
3.39 return self.context_identity
3.40
3.41 @@ -200,6 +206,62 @@
3.42 def __repr__(self):
3.43 return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.location)
3.44
3.45 +class AliasResult(NameRef, Result):
3.46 +
3.47 + "An alias for other values."
3.48 +
3.49 + def __init__(self, name_ref, refs, locations):
3.50 + NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name())
3.51 + self.name_ref = name_ref
3.52 + self.refs = refs
3.53 + self.locations = locations
3.54 +
3.55 + def references(self):
3.56 + ref = self.name_ref.reference()
3.57 + return self.refs or ref and [ref] or None
3.58 +
3.59 + def reference(self):
3.60 + refs = self.references()
3.61 + return len(refs) == 1 and first(refs) or None
3.62 +
3.63 + def access_location(self):
3.64 + return len(self.locations) == 1 and first(self.locations) or None
3.65 +
3.66 + def access_locations(self):
3.67 + return self.locations
3.68 +
3.69 + def get_name(self):
3.70 + ref = self.reference()
3.71 + return ref and ref.get_name()
3.72 +
3.73 + def get_origin(self):
3.74 + ref = self.reference()
3.75 + return ref and ref.get_origin()
3.76 +
3.77 + def static(self):
3.78 + ref = self.reference()
3.79 + return ref and ref.static()
3.80 +
3.81 + def final(self):
3.82 + ref = self.reference()
3.83 + return ref and ref.final()
3.84 +
3.85 + def has_kind(self, kinds):
3.86 + if not self.refs:
3.87 + return self.name_ref.has_kind(kinds)
3.88 +
3.89 + for ref in self.refs:
3.90 + if ref.has_kind(kinds):
3.91 + return True
3.92 +
3.93 + return False
3.94 +
3.95 + def __str__(self):
3.96 + return str(self.name_ref)
3.97 +
3.98 + def __repr__(self):
3.99 + return "AliasResult(%r, %r)" % (self.name_ref, self.refs)
3.100 +
3.101 class InvocationResult(Result, InstructionSequence):
3.102
3.103 "A translation result for an invocation."