diff --git a/mathics/core/symbols.py b/mathics/core/symbols.py index 75c7f1b51..cb434f855 100644 --- a/mathics/core/symbols.py +++ b/mathics/core/symbols.py @@ -465,9 +465,14 @@ def evaluate(self, evaluation): from mathics.core.systemsymbols import SymbolAborted return SymbolAborted + # iteration_count is the length of the current chain of + # rewrites (x -> y -> ...), not a total for the whole + # evaluation: each finished lookup gives its step back. evaluation.iteration_count += 1 - - return result.evaluate(evaluation) + try: + return result.evaluate(evaluation) + finally: + evaluation.iteration_count -= 1 return self def get_head(self) -> "Symbol": diff --git a/test/builtin/test_evaluation.py b/test/builtin/test_evaluation.py index 1d635991d..e0a8c4169 100644 --- a/test/builtin/test_evaluation.py +++ b/test/builtin/test_evaluation.py @@ -3,7 +3,6 @@ Unit tests from mathics.builtin.evaluation. """ - import sys from test.helper import check_evaluation_as_in_cli @@ -55,6 +54,32 @@ None, ), ("ClearAll[f];", None, None, None), + # $IterationLimit bounds one chain of rewrites, not the number of + # times symbols are looked up during the whole evaluation. + ( + "Block[{$IterationLimit = 20, itlimX = {itlimA}}, Do[itlimX, {30}]; itlimX]", + None, + "{itlimA}", + "Many separate lookups of a symbol do not add up", + ), + ( + 'Do[Evaluate[Symbol["c" <> ToString[k]]] = Symbol["c" <> ToString[k + 1]], {k, 0, 29}]; Block[{$IterationLimit = 40}, c0]', + None, + "c30", + "A chain of 30 rewrites is within the limit of 40", + ), + ( + "Block[{$IterationLimit = 20}, c0]", + ("Iteration limit of 20 exceeded.",), + "$Aborted", + "A chain of 30 rewrites exceeds the limit of 20", + ), + ( + 'ClearAll[c0, c30]; Do[ClearAll[Evaluate[Symbol["c" <> ToString[k]]]], {k, 1, 29}];', + None, + None, + None, + ), ( "Attributes[h] = Flat;h[items___] := Plus[items];h[1, Unevaluated[Sequence[Unevaluated[2], 3]], Sequence[4, Unevaluated[5]]]", None,