2.1 --- a/translator.py Sun Nov 07 01:18:51 2021 +0100
2.2 +++ b/translator.py Mon Nov 08 00:25:46 2021 +0100
2.3 @@ -1326,6 +1326,13 @@
2.4 for i, arg in enumerate(n.args):
2.5 argexpr = self.process_structure_node(arg)
2.6
2.7 + # Obtain an appropriate argument representation. This prevents
2.8 + # copyable values from being mutable, but care must be taken to
2.9 + # prevent special internal attribute values represented using
2.10 + # attributes from being modified.
2.11 +
2.12 + argrepr = argexpr.as_arg()
2.13 +
2.14 # Store a keyword argument, either in the argument list or
2.15 # in a separate keyword argument list for subsequent lookup.
2.16
2.17 @@ -1340,12 +1347,12 @@
2.18 except ValueError:
2.19 raise TranslateError("Argument %s is not recognised." % arg.name,
2.20 self.get_namespace_path(), n)
2.21 - args[argnum + reserved_args] = str(argexpr)
2.22 + args[argnum + reserved_args] = argrepr
2.23
2.24 # Otherwise, store the details in a separate collection.
2.25
2.26 else:
2.27 - kwargs.append(str(argexpr))
2.28 + kwargs.append(argrepr)
2.29 kwcodes.append("{%s, %s}" % (
2.30 encode_ppos(arg.name), encode_pcode(arg.name)))
2.31
2.32 @@ -1354,7 +1361,7 @@
2.33
2.34 else:
2.35 try:
2.36 - args[i + reserved_args] = str(argexpr)
2.37 + args[i + reserved_args] = argrepr
2.38 except IndexError:
2.39 raise TranslateError("Too many arguments specified.",
2.40 self.get_namespace_path(), n)
3.1 --- a/transresults.py Sun Nov 07 01:18:51 2021 +0100
3.2 +++ b/transresults.py Mon Nov 08 00:25:46 2021 +0100
3.3 @@ -59,6 +59,12 @@
3.4 def __repr__(self):
3.5 return "Expression(%r)" % self.s
3.6
3.7 + def as_arg(self):
3.8 +
3.9 + "Return the expression without any mutable tag."
3.10 +
3.11 + return "__TO_IMMUTABLE(%s)" % self.s
3.12 +
3.13 class TrResolvedNameRef(ResolvedNameRef):
3.14
3.15 "A reference to a name in the translation."
3.16 @@ -67,6 +73,20 @@
3.17 ResolvedNameRef.__init__(self, name, ref, expr, is_global)
3.18 self.location = location
3.19
3.20 + # For sources, any identified static origin will be constant and thus
3.21 + # usable directly. For targets, no constant should be assigned and thus
3.22 + # the alias (or any plain name) will be used.
3.23 +
3.24 + self.static_ref = self.static()
3.25 + origin = self.static_ref and self.get_origin()
3.26 + self.static_name = origin and encode_path(origin)
3.27 +
3.28 + # Determine whether a qualified name is involved.
3.29 +
3.30 + t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)
3.31 + self.parent = len(t) > 1 and t[0] or None
3.32 + self.attrname = t[-1] and encode_path(t[-1])
3.33 +
3.34 def access_location(self):
3.35 return self.location
3.36
3.37 @@ -82,55 +102,56 @@
3.38 else:
3.39 return encode_path(self.name)
3.40
3.41 - # For sources, any identified static origin will be constant and thus
3.42 - # usable directly. For targets, no constant should be assigned and thus
3.43 - # the alias (or any plain name) will be used.
3.44 -
3.45 - ref = self.static()
3.46 - origin = ref and self.get_origin()
3.47 - static_name = origin and encode_path(origin)
3.48 -
3.49 - # Determine whether a qualified name is involved.
3.50 -
3.51 - t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)
3.52 - parent = len(t) > 1 and t[0] or None
3.53 - attrname = t[-1] and encode_path(t[-1])
3.54 -
3.55 # Assignments.
3.56
3.57 if self.expr:
3.58
3.59 # Eliminate assignments between constants.
3.60
3.61 - if ref and self.expr.static():
3.62 + if self.static_ref and self.expr.static():
3.63 return ""
3.64
3.65 # Qualified names must be converted into parent-relative assignments.
3.66
3.67 - elif parent:
3.68 + elif self.parent:
3.69 return "__store_via_object(&%s, %s, %s)" % (
3.70 - encode_path(parent), attrname, self.expr)
3.71 + encode_path(self.parent), self.attrname, self.expr)
3.72
3.73 # All other assignments involve the names as they were given.
3.74
3.75 else:
3.76 - return "%s = %s" % (attrname, self.expr)
3.77 + return "%s = %s" % (self.attrname, self.expr)
3.78
3.79 # Expressions.
3.80
3.81 - elif static_name:
3.82 - return "__ATTRVALUE(&%s)" % static_name
3.83 + elif self.static_name:
3.84 + return "__ATTRVALUE(&%s)" % self.static_name
3.85
3.86 # Qualified names must be converted into parent-relative accesses.
3.87
3.88 - elif parent:
3.89 + elif self.parent:
3.90 return "__load_via_object(&%s, %s)" % (
3.91 - encode_path(parent), attrname)
3.92 + encode_path(self.parent), self.attrname)
3.93
3.94 # All other accesses involve the names as they were given.
3.95
3.96 else:
3.97 - return "(%s)" % attrname
3.98 + return "(%s)" % self.attrname
3.99 +
3.100 + def as_arg(self):
3.101 +
3.102 + "Return the expression without any mutable tag."
3.103 +
3.104 + s = self.__str__()
3.105 +
3.106 + # NOTE: This is a superficial test for internal attributes that relies
3.107 + # NOTE: on such attributes being used directly and passed to native
3.108 + # NOTE: code.
3.109 +
3.110 + if self.attrname in ("__data__", "__size__"):
3.111 + return s
3.112 + else:
3.113 + return "__TO_IMMUTABLE(%s)" % s
3.114
3.115 class TrConstantValueRef(ConstantValueRef):
3.116
3.117 @@ -139,6 +160,9 @@
3.118 def __str__(self):
3.119 return encode_literal_constant(self.number)
3.120
3.121 + def as_arg(self):
3.122 + return self.__str__()
3.123 +
3.124 class TrLiteralSequenceRef(LiteralSequenceRef):
3.125
3.126 "A reference representing a sequence of values."
3.127 @@ -146,6 +170,9 @@
3.128 def __str__(self):
3.129 return str(self.node)
3.130
3.131 + def as_arg(self):
3.132 + return self.__str__()
3.133 +
3.134 class TrInstanceRef(InstanceRef):
3.135
3.136 "A reference representing instantiation of a class."
3.137 @@ -166,6 +193,9 @@
3.138 def __repr__(self):
3.139 return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)
3.140
3.141 + def as_arg(self):
3.142 + return self.__str__()
3.143 +
3.144 class AttrResult(Result, InstructionSequence):
3.145
3.146 "A translation result for an attribute access."
3.147 @@ -222,6 +252,9 @@
3.148 self.context_identity, self.context_identity_verified,
3.149 self.accessor_test, self.accessor_stored)
3.150
3.151 + def as_arg(self):
3.152 + return self.__str__()
3.153 +
3.154 class AliasResult(NameRef, Result):
3.155
3.156 "An alias for other values."
3.157 @@ -275,6 +308,9 @@
3.158 def __repr__(self):
3.159 return "AliasResult(%r, %r)" % (self.name_ref, self.refs)
3.160
3.161 + def as_arg(self):
3.162 + return self.__str__()
3.163 +
3.164 class InvocationResult(Result, InstructionSequence):
3.165
3.166 "A translation result for an invocation."
3.167 @@ -285,6 +321,9 @@
3.168 def __repr__(self):
3.169 return "InvocationResult(%r)" % self.instructions
3.170
3.171 + def as_arg(self):
3.172 + return self.__str__()
3.173 +
3.174 class InstantiationResult(InvocationResult, TrInstanceRef):
3.175
3.176 "An instantiation result acting like an invocation result."
3.177 @@ -325,6 +364,9 @@
3.178 def __repr__(self):
3.179 return "PredefinedConstantRef(%r)" % self.value
3.180
3.181 + def as_arg(self):
3.182 + return self.__str__()
3.183 +
3.184 class LogicalResult(Result):
3.185
3.186 "A logical expression result."
3.187 @@ -370,6 +412,9 @@
3.188 def __repr__(self):
3.189 return "NegationResult(%r)" % self.expr
3.190
3.191 + def as_arg(self):
3.192 + return self.__str__()
3.193 +
3.194 class LogicalOperationResult(LogicalResult):
3.195
3.196 "A logical operation result."
3.197 @@ -442,4 +487,7 @@
3.198 def __repr__(self):
3.199 return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)
3.200
3.201 + def as_arg(self):
3.202 + return self.__str__()
3.203 +
3.204 # vim: tabstop=4 expandtab shiftwidth=4