# HG changeset patch # User Paul Boddie # Date 1480950186 -3600 # Node ID 9f7a9aff1ca4cf64eaf898cd3aa84fd93d90b164 # Parent f484c01e190343edd847ad7b562a17996a35b2ea Introduced a result type that propagates instantiation details, thus supporting the detection of instances being raised, and providing the means to generate code to raise instances and other objects. Added a helper function to test for an instance and to invoke a non-instance to obtain an instance otherwise. diff -r f484c01e1903 -r 9f7a9aff1ca4 results.py --- a/results.py Mon Dec 05 13:01:21 2016 +0100 +++ b/results.py Mon Dec 05 16:03:06 2016 +0100 @@ -108,13 +108,9 @@ def __repr__(self): return "LocalNameRef(%r, %r)" % (self.name, self.number) -class ResolvedNameRef(NameRef): - - "A resolved name-based reference." +class ResolvedRef: - def __init__(self, name, ref, expr=None): - NameRef.__init__(self, name, expr) - self.ref = ref + "A resolved reference mix-in." def reference(self): return self.ref @@ -134,6 +130,14 @@ def has_kind(self, kinds): return self.ref and self.ref.has_kind(kinds) +class ResolvedNameRef(ResolvedRef, NameRef): + + "A resolved name-based reference." + + def __init__(self, name, ref, expr=None): + NameRef.__init__(self, name, expr) + self.ref = ref + def __repr__(self): return "ResolvedNameRef(%r, %r, %r)" % (self.name, self.ref, self.expr) @@ -149,7 +153,7 @@ def __repr__(self): return "ConstantValueRef(%r, %r, %r, %r)" % (self.name, self.ref, self.value, self.number) -class InstanceRef(Result): +class InstanceRef(ResolvedRef, Result): "An instance reference." diff -r f484c01e1903 -r 9f7a9aff1ca4 templates/progops.c --- a/templates/progops.c Mon Dec 05 13:01:21 2016 +0100 +++ b/templates/progops.c Mon Dec 05 16:03:06 2016 +0100 @@ -109,6 +109,25 @@ __Raise(exc); } +/* Helper for raising exception instances. */ + +__attr __ensure_instance(__attr arg) +{ + /* Reserve space for the instance. */ + + __attr args[1]; + + /* Return instances as provided. */ + + if (__is_instance(arg.value)) + return arg; + + /* Invoke non-instances to produce instances. */ + + else + return __invoke(arg, 0, 0, 0, 0, 1, args); +} + /* Generic invocation operations. */ /* Invoke the given callable, supplying keyword argument details in the given diff -r f484c01e1903 -r 9f7a9aff1ca4 templates/progops.h --- a/templates/progops.h Mon Dec 05 13:01:21 2016 +0100 +++ b/templates/progops.h Mon Dec 05 16:03:06 2016 +0100 @@ -13,10 +13,15 @@ void __newdata_mapping(__attr args[], unsigned int number); +/* Exception raising. */ + void __raise_memory_error(); void __raise_overflow_error(); void __raise_zero_division_error(); void __raise_type_error(); +__attr __ensure_instance(__attr arg); + +/* Generic invocation operations. */ __attr __invoke(__attr callable, int always_callable, unsigned int nkwargs, __param kwcodes[], __attr kwargs[], diff -r f484c01e1903 -r 9f7a9aff1ca4 translator.py --- a/translator.py Mon Dec 05 13:01:21 2016 +0100 +++ b/translator.py Mon Dec 05 16:03:06 2016 +0100 @@ -154,6 +154,26 @@ def __str__(self): return str(self.node) +class TrInstanceRef(results.InstanceRef, TranslationResult): + + "A reference representing instantiation of a class." + + def __init__(self, ref, expr): + + """ + Initialise the reference with 'ref' indicating the nature of the + reference and 'expr' being an expression used to create the instance. + """ + + results.InstanceRef.__init__(self, ref) + self.expr = expr + + def __str__(self): + return self.expr + + def __repr__(self): + return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr) + class AttrResult(Expression, TranslationResult): "A translation result for an attribute access." @@ -1022,6 +1042,7 @@ objpath = expr.get_origin() target = None function = None + instantiation = False literal_instantiation = False context_required = True @@ -1030,7 +1051,7 @@ # Literals may be instantiated specially. if expr.is_name() and expr.name.startswith("$L") and objpath: - literal_instantiation = True + instantiation = literal_instantiation = objpath parameters = None target = encode_literal_instantiator(objpath) context_required = False @@ -1043,6 +1064,7 @@ # Class invocation involves instantiators. if expr.has_kind(""): + instantiation = objpath target = encode_instantiator_pointer(objpath) target_structure = "&%s" % encode_bound_reference("%s.__init__" % objpath) context_required = False @@ -1195,7 +1217,10 @@ len(kwargs), kwcodestr, kwargstr, len(args), argstr) - return make_expression(output) + if instantiation: + return TrInstanceRef(instantiation, output) + else: + return make_expression(output) def always_callable(self, refs): @@ -1342,7 +1367,15 @@ # NOTE: Determine which raise statement variants should be permitted. if n.expr1: - self.writestmt("__Raise(%s);" % self.process_structure_node(n.expr1)) + exc = self.process_structure_node(n.expr1) + + # Raise instances, testing the kind at run-time if necessary and + # instantiating any non-instance. + + if isinstance(exc, TrInstanceRef): + self.writestmt("__Raise(%s);" % exc) + else: + self.writestmt("__Raise(__ensure_instance(%s));" % exc) else: self.writestmt("__Complete;")