# HG changeset patch # User Paul Boddie # Date 1693589720 -7200 # Node ID 2957d8a7ccfb343e7eb4fcd9f24682d428e3afc3 # Parent 560f520d8446f6ea4df20a4d1e314342d4d04830 Introduce special well-defined instances, similar to predefined constants, to support loop exit conditions without having to raise a new instance as an exception on every occasion. diff -r 560f520d8446 -r 2957d8a7ccfb common.py --- a/common.py Sun Jan 15 17:37:00 2023 +0100 +++ b/common.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb inspector.py --- a/inspector.py Sun Jan 15 17:37:00 2023 +0100 +++ b/inspector.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb lib/__builtins__/__init__.py --- a/lib/__builtins__/__init__.py Sun Jan 15 17:37:00 2023 +0100 +++ b/lib/__builtins__/__init__.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb lib/__builtins__/exception/__init__.py --- a/lib/__builtins__/exception/__init__.py Sun Jan 15 17:37:00 2023 +0100 +++ b/lib/__builtins__/exception/__init__.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb lib/__builtins__/exception/base.py --- a/lib/__builtins__/exception/base.py Sun Jan 15 17:37:00 2023 +0100 +++ b/lib/__builtins__/exception/base.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb referencing.py --- a/referencing.py Sun Jan 15 17:37:00 2023 +0100 +++ b/referencing.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb resolving.py --- a/resolving.py Sun Jan 15 17:37:00 2023 +0100 +++ b/resolving.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb results.py --- a/results.py Sun Jan 15 17:37:00 2023 +0100 +++ b/results.py Fri Sep 01 19:35:20 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 560f520d8446 -r 2957d8a7ccfb translator.py --- a/translator.py Sun Jan 15 17:37:00 2023 +0100 +++ b/translator.py Fri Sep 01 19:35:20 2023 +0200 @@ -1619,7 +1619,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) @@ -1736,7 +1737,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)