# HG changeset patch # User Paul Boddie # Date 1636846969 -3600 # Node ID d1fe5052f9565f5b4e46a411079998ac95cd8e6c # Parent 67c3c5ec69889b379b0a9784ae4637f95cfde482 Introduced copyable and mutable flags in the tagged region of attribute values. Such flags are set when new integer and floating point values are created, but the mutable flag is cleared when such attributes are propagated between functions in order to prevent values being replaced upon assignment to parameter names, this being a concern when value copying is introduced. diff -r 67c3c5ec6988 -r d1fe5052f956 templates/types.h --- a/templates/types.h Sun Nov 14 00:37:32 2021 +0100 +++ b/templates/types.h Sun Nov 14 00:42:49 2021 +0100 @@ -130,12 +130,15 @@ /* Attribute interpretation. */ -#define __NUM_TAG_BITS 1 -#define __TAG_MUTABLE 0b1 -#define __TAG_MASK 0b1 +#define __NUM_TAG_BITS 2 +#define __TAG_COPYABLE 0b01UL +#define __TAG_MUTABLE 0b10UL +#define __TAG_MASK 0b11UL -#define __MUTABLE(ATTR) (((ATTR).rawvalue & __TAG_MASK) == __TAG_MUTABLE) -#define __TO_MUTABLE(ATTR) ((__attr) (((ATTR).rawvalue & (~__TAG_MASK)) | __TAG_MUTABLE)) +#define __COPYABLE(ATTR) ((ATTR).rawvalue & __TAG_COPYABLE) +#define __MUTABLE(ATTR) ((ATTR).rawvalue & __TAG_MUTABLE) +#define __TO_IMMUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue & (~__TAG_MUTABLE)}) +#define __TO_MUTABLE(ATTR) ((__attr) {.rawvalue=(ATTR).rawvalue | __TAG_MASK}) /* Attribute value setting. */ diff -r 67c3c5ec6988 -r d1fe5052f956 translator.py --- a/translator.py Sun Nov 14 00:37:32 2021 +0100 +++ b/translator.py Sun Nov 14 00:42:49 2021 +0100 @@ -1324,6 +1324,13 @@ for i, arg in enumerate(n.args): argexpr = self.process_structure_node(arg) + # Obtain an appropriate argument representation. This prevents + # copyable values from being mutable, but care must be taken to + # prevent special internal attribute values represented using + # attributes from being modified. + + argrepr = argexpr.as_arg() + # Store a keyword argument, either in the argument list or # in a separate keyword argument list for subsequent lookup. @@ -1338,12 +1345,12 @@ except ValueError: raise TranslateError("Argument %s is not recognised." % arg.name, self.get_namespace_path(), n) - args[argnum + reserved_args] = str(argexpr) + args[argnum + reserved_args] = argrepr # Otherwise, store the details in a separate collection. else: - kwargs.append(str(argexpr)) + kwargs.append(argrepr) kwcodes.append("{%s, %s}" % ( encode_ppos(arg.name), encode_pcode(arg.name))) @@ -1352,7 +1359,7 @@ else: try: - args[i + reserved_args] = str(argexpr) + args[i + reserved_args] = argrepr except IndexError: raise TranslateError("Too many arguments specified.", self.get_namespace_path(), n) diff -r 67c3c5ec6988 -r d1fe5052f956 transresults.py --- a/transresults.py Sun Nov 14 00:37:32 2021 +0100 +++ b/transresults.py Sun Nov 14 00:42:49 2021 +0100 @@ -59,6 +59,12 @@ def __repr__(self): return "Expression(%r)" % self.s + def as_arg(self): + + "Return the expression without any mutable tag." + + return self.s + class TrResolvedNameRef(ResolvedNameRef): "A reference to a name in the translation." @@ -132,6 +138,21 @@ else: return "(%s)" % self.attrname + def as_arg(self): + + "Return the expression without any mutable tag." + + s = self.__str__() + + # NOTE: This is a superficial test for internal attributes that relies + # NOTE: on such attributes being used directly and passed to native + # NOTE: code. + + if self.attrname in ("__data__", "__size__"): + return s + else: + return "__TO_IMMUTABLE(%s)" % s + class TrConstantValueRef(ConstantValueRef): "A constant value reference in the translation." @@ -139,6 +160,9 @@ def __str__(self): return encode_literal_constant(self.number) + def as_arg(self): + return self.__str__() + class TrLiteralSequenceRef(LiteralSequenceRef): "A reference representing a sequence of values." @@ -146,6 +170,9 @@ def __str__(self): return str(self.node) + def as_arg(self): + return self.__str__() + class TrInstanceRef(InstanceRef): "A reference representing instantiation of a class." @@ -166,6 +193,9 @@ def __repr__(self): return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr) + def as_arg(self): + return self.__str__() + class AttrResult(Result, InstructionSequence): "A translation result for an attribute access." @@ -222,6 +252,9 @@ self.context_identity, self.context_identity_verified, self.accessor_test, self.accessor_stored) + def as_arg(self): + return self.__str__() + class AliasResult(NameRef, Result): "An alias for other values." @@ -275,6 +308,9 @@ def __repr__(self): return "AliasResult(%r, %r)" % (self.name_ref, self.refs) + def as_arg(self): + return self.__str__() + class InvocationResult(Result, InstructionSequence): "A translation result for an invocation." @@ -285,6 +321,9 @@ def __repr__(self): return "InvocationResult(%r)" % self.instructions + def as_arg(self): + return self.__str__() + class InstantiationResult(InvocationResult, TrInstanceRef): "An instantiation result acting like an invocation result." @@ -325,6 +364,9 @@ def __repr__(self): return "PredefinedConstantRef(%r)" % self.value + def as_arg(self): + return self.__str__() + class LogicalResult(Result): "A logical expression result." @@ -370,6 +412,9 @@ def __repr__(self): return "NegationResult(%r)" % self.expr + def as_arg(self): + return self.__str__() + class LogicalOperationResult(LogicalResult): "A logical operation result." @@ -442,4 +487,7 @@ def __repr__(self): return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction) + def as_arg(self): + return self.__str__() + # vim: tabstop=4 expandtab shiftwidth=4