# HG changeset patch # User Paul Boddie # Date 1693601169 -7200 # Node ID d6ffe931de37e9d409bbc502a7274d9c22dafdf3 # Parent ee9512fa0fc7d4ec613cc41e0ca5cca85355c37f# Parent 51ec9d93d6489cedf8106a7c5956a34a2c5bad1f Merged changes from the trailing-data branch. diff -r ee9512fa0fc7 -r d6ffe931de37 common.py --- a/common.py Wed Aug 30 01:49:28 2023 +0200 +++ b/common.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Common functions. -Copyright (C) 2007-2019, 2021 Paul Boddie +Copyright (C) 2007-2019, 2021, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -623,7 +623,7 @@ # raise LoopExit [(compiler.ast.Name("StopIteration"), None, - compiler.ast.Raise(compiler.ast.Name("LoopExit")))], + compiler.ast.Raise(compiler.ast.Name("$loop_exit")))], None), # ... = diff -r ee9512fa0fc7 -r d6ffe931de37 docs/tools/sign_releases.sh --- a/docs/tools/sign_releases.sh Wed Aug 30 01:49:28 2023 +0200 +++ b/docs/tools/sign_releases.sh Fri Sep 01 22:46:09 2023 +0200 @@ -31,9 +31,18 @@ fi for FILENAME in "$OUTDIR/"*".tar.bz2" ; do + + # Handle an absence of archives. + + if [ ! -e "$FILENAME" ] ; then + break + fi + OUTFILE="$FILENAME.asc" if [ ! -e "$OUTFILE" ] || [ "$FORCE" ]; then gpg --sign -a -b "$FILENAME" echo "$OUTFILE" fi done + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r ee9512fa0fc7 -r d6ffe931de37 docs/wiki/Downloads diff -r ee9512fa0fc7 -r d6ffe931de37 inspector.py --- a/inspector.py Wed Aug 30 01:49:28 2023 +0200 +++ b/inspector.py Fri Sep 01 22:46:09 2023 +0200 @@ -907,6 +907,20 @@ self.set_special(n.name, value) return value + # Special case for loops. + + elif n.name == "$loop_exit": + + # Attempt to get a reference. + + ref = self.get_builtin("__loop_exit") + + # Record the imported name and provide the resolved name reference. + + value = ResolvedNameRef(n.name, ref) + self.set_special(n.name, value) + return value + # Test for self usage, which is only allowed in methods. if n.name == "self" and not (self.in_function and self.in_class): diff -r ee9512fa0fc7 -r d6ffe931de37 lib/__builtins__/__init__.py --- a/lib/__builtins__/__init__.py Wed Aug 30 01:49:28 2023 +0200 +++ b/lib/__builtins__/__init__.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Simple built-in classes and functions. -Copyright (C) 2015, 2016, 2017, 2019, 2021 Paul Boddie +Copyright (C) 2015-2017, 2019, 2021, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -50,7 +50,8 @@ UnicodeEncodeError, UnicodeError, UnicodeTranslateError, - ValueError + ValueError, + __loop_exit ) # Classes. diff -r ee9512fa0fc7 -r d6ffe931de37 lib/__builtins__/exception/__init__.py --- a/lib/__builtins__/exception/__init__.py Wed Aug 30 01:49:28 2023 +0200 +++ b/lib/__builtins__/exception/__init__.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Exception objects. -Copyright (C) 2015, 2016, 2017, 2019 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2019, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -30,7 +30,8 @@ NotImplementedError, RuntimeError, StopIteration, - ValueError + ValueError, + __loop_exit ) from __builtins__.exception.io import ( diff -r ee9512fa0fc7 -r d6ffe931de37 lib/__builtins__/exception/base.py --- a/lib/__builtins__/exception/base.py Wed Aug 30 01:49:28 2023 +0200 +++ b/lib/__builtins__/exception/base.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Base exception objects. See __builtins__.core for the core exceptions. -Copyright (C) 2015, 2016, 2018, 2019 Paul Boddie +Copyright (C) 2015, 2016, 2018, 2019, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -87,4 +87,8 @@ pass +# Common loop exit instance. + +__loop_exit = LoopExit() + # vim: tabstop=4 expandtab shiftwidth=4 diff -r ee9512fa0fc7 -r d6ffe931de37 referencing.py --- a/referencing.py Wed Aug 30 01:49:28 2023 +0200 +++ b/referencing.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Reference abstractions. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -222,6 +222,12 @@ name = self.get_name() return name and name.rsplit(".")[-1].startswith("$c") + def is_well_defined_instance(self): + + "Return whether this reference involves a well-defined instance." + + return self.get_kind() == "" + def is_predefined_value(self): "Return whether this reference identifies a predefined value." diff -r ee9512fa0fc7 -r d6ffe931de37 resolving.py --- a/resolving.py Wed Aug 30 01:49:28 2023 +0200 +++ b/resolving.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Name resolution. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -73,7 +73,11 @@ for name, value in self.special.items(): ref, paths = value - self.special[name] = self.importer.identify(ref.get_origin()), paths + + # Handle special instances. + + origin = ref.is_well_defined_instance() and ref.get_name() or ref.get_origin() + self.special[name] = self.importer.identify(origin), paths def check_names_used(self): diff -r ee9512fa0fc7 -r d6ffe931de37 results.py --- a/results.py Wed Aug 30 01:49:28 2023 +0200 +++ b/results.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Result abstractions. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -164,6 +164,9 @@ def is_constant_alias(self): return self.ref and self.ref.is_constant_alias() + def is_well_defined_instance(self): + return self.ref and self.ref.is_well_defined_instance() + class ResolvedNameRef(ResolvedRef, NameRef): "A resolved name-based reference." diff -r ee9512fa0fc7 -r d6ffe931de37 templates/native/limits.c --- a/templates/native/limits.c Wed Aug 30 01:49:28 2023 +0200 +++ b/templates/native/limits.c Fri Sep 01 22:46:09 2023 +0200 @@ -1,6 +1,6 @@ /* Native functions for limit definition. -Copyright (C) 2016, 2017, 2023 Paul Boddie +Copyright (C) 2016, 2017, 2021, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff -r ee9512fa0fc7 -r d6ffe931de37 templates/native/list.c diff -r ee9512fa0fc7 -r d6ffe931de37 templates/native/list.h --- a/templates/native/list.h Wed Aug 30 01:49:28 2023 +0200 +++ b/templates/native/list.h Fri Sep 01 22:46:09 2023 +0200 @@ -1,6 +1,6 @@ /* Native functions for list operations. -Copyright (C) 2016, 2017, 2023 Paul Boddie +Copyright (C) 2016, 2017, 2021, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff -r ee9512fa0fc7 -r d6ffe931de37 translator.py --- a/translator.py Wed Aug 30 01:49:28 2023 +0200 +++ b/translator.py Fri Sep 01 22:46:09 2023 +0200 @@ -1314,7 +1314,7 @@ # Start with result target and context arguments for each invocation. args = [result_target, context_arg] - argstart = 2 + reserved_args = 2 # Complete the array with null values, permitting tests for a complete # set of arguments. @@ -1366,7 +1366,7 @@ except ValueError: raise TranslateError("Argument %s is not recognised." % arg.name, self.get_namespace_path(), n) - args[argnum+argstart] = argexprstr + args[argnum + reserved_args] = argexprstr # Otherwise, store the details in a separate collection. @@ -1380,7 +1380,7 @@ else: try: - args[i+argstart] = argexprstr + args[i + reserved_args] = argexprstr except IndexError: raise TranslateError("Too many arguments specified.", self.get_namespace_path(), n) @@ -1404,8 +1404,8 @@ for i, (argname, default) in enumerate(function_defaults): argnum = parameters.index(argname) - if not args[argnum+argstart]: - args[argnum+argstart] = "__GETDEFAULT(%s, %d)" % (target_structure, i) + if not args[argnum + reserved_args]: + args[argnum + reserved_args] = "__GETDEFAULT(%s, %d)" % (target_structure, i) elif known_parameters: @@ -1416,7 +1416,7 @@ i = len(n.args) pos = i - (num_parameters - num_defaults) while i < num_parameters: - args[i+argstart] = "__GETDEFAULT(%s.value, %d)" % (target_var, pos) + args[i + reserved_args] = "__GETDEFAULT(%s.value, %d)" % (target_var, pos) i += 1 pos += 1 @@ -1432,7 +1432,7 @@ # the number of values. The result target and context are excluded. if literal_instantiation: - argstr = "%d, %s" % (len(args) - 2, ", ".join(args[2:])) + argstr = "%d, %s" % (len(args) - reserved_args, ", ".join(args[reserved_args:])) else: argstr = ", ".join(args) @@ -1670,7 +1670,8 @@ # function names to references. elif n.name.startswith("$L") or n.name.startswith("$op") or \ - n.name.startswith("$seq") or n.name.startswith("$print"): + n.name.startswith("$seq") or n.name.startswith("$print") or \ + n.name == "$loop_exit": ref, paths = self.importer.get_module(self.name).special[n.name] return TrResolvedNameRef(n.name, ref) @@ -1800,7 +1801,7 @@ else: exc = self.process_structure_node(n.expr1) - if isinstance(exc, TrInstanceRef): + if isinstance(exc, TrInstanceRef) or exc.is_well_defined_instance(): self.writestmt("__Raise(%s);" % exc) else: self.writestmt("__Raise(__ensure_instance(%s));" % exc) diff -r ee9512fa0fc7 -r d6ffe931de37 transresults.py --- a/transresults.py Wed Aug 30 01:49:28 2023 +0200 +++ b/transresults.py Fri Sep 01 22:46:09 2023 +0200 @@ -3,7 +3,7 @@ """ Translation result abstractions. -Copyright (C) 2016, 2017, 2018, 2023 Paul Boddie +Copyright (C) 2016, 2017, 2018, 2021, 2023 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -68,6 +68,20 @@ ResolvedNameRef.__init__(self, name, ref, expr, is_global) self.location = location + # For sources, any identified static origin will be constant and thus + # usable directly. For targets, no constant should be assigned and thus + # the alias (or any plain name) will be used. + + self.static_ref = self.static() + origin = self.static_ref and self.get_origin() + self.static_name = origin and encode_path(origin) + + # Determine whether a qualified name is involved. + + t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1) + self.parent = len(t) > 1 and t[0] or None + self.attrname = t[-1] and encode_path(t[-1]) + def access_location(self): return self.location @@ -83,58 +97,42 @@ else: return encode_path(self.name) - # For sources, any identified static origin will be constant and thus - # usable directly. For targets, no constant should be assigned and thus - # the alias (or any plain name) will be used. - - ref = self.static() - origin = ref and self.get_origin() - static_name = origin and encode_path(origin) - - # Determine whether a qualified name is involved. - - t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1) - parent = len(t) > 1 and t[0] or None - attrname = t[-1] and encode_path(t[-1]) - # Assignments. if self.expr: # Eliminate assignments between constants. - if ref and self.expr.static(): + if self.static_ref and self.expr.static(): return "" # Qualified names must be converted into parent-relative assignments. - elif parent: + elif self.parent: return "__store_via_object(&%s, %s, %s)" % ( - encode_path(parent), attrname, self.expr) + encode_path(self.parent), self.attrname, self.expr) # All other assignments involve the names as they were given. # To support value replacement, a special operation is used. else: - return "__set_local(&%s, %s)" % (attrname, self.expr) + return "__set_local(&%s, %s)" % (self.attrname, self.expr) # Expressions. - elif static_name: - parent = ref.parent() - context = ref.has_kind("") and encode_path(parent) or None - return "__ATTRVALUE(&%s)" % static_name + elif self.static_name: + return "__ATTRVALUE(&%s)" % self.static_name # Qualified names must be converted into parent-relative accesses. - elif parent: + elif self.parent: return "__load_via_object(&%s, %s)" % ( - encode_path(parent), attrname) + encode_path(self.parent), self.attrname) # All other accesses involve the names as they were given. else: - return "(%s)" % attrname + return "(%s)" % self.attrname class TrConstantValueRef(ConstantValueRef):