diff --git a/mathics/builtin/mainloop.py b/mathics/builtin/mainloop.py index 2c69b6dd2..9570c56f0 100644 --- a/mathics/builtin/mainloop.py +++ b/mathics/builtin/mainloop.py @@ -82,17 +82,17 @@ class In(Builtin): >> Definition[In] = Attributes[In] = {Listable, Protected} . - . In[6] = Definition[In] - . - . In[5] = In[-1] + . In[1] = x = 1 . - . In[4] = x + . In[2] = x = x + 1 . . In[3] = Do[In[2], {3}] . - . In[2] = x = x + 1 + . In[4] = x . - . In[1] = x = 1 + . In[5] = In[-1] + . + . In[6] = Definition[In] . """ @@ -226,3 +226,4 @@ class Line(Builtin): name = "$Line" summary_text = "current line number" + rules = {"$Line": "1"} diff --git a/mathics/core/definitions.py b/mathics/core/definitions.py index ad78468b2..c6f3dc813 100644 --- a/mathics/core/definitions.py +++ b/mathics/core/definitions.py @@ -481,7 +481,7 @@ def get_history_length(self) -> int: def get_line_no(self) -> int: """Get $Line, the current input line number""" - return self.get_config_value("$Line", 0) or 0 + return self.get_config_value("$Line", 1) or 1 def get_matching_names(self, pattern: Union[str, re.Pattern]) -> List[str]: """ @@ -666,7 +666,7 @@ def increment_line_no(self, increment: int = 1) -> None: """Increment $Line, the current input line number""" line_number = self.get_line_no() if line_number is not None: - self.set_config_value("$Line", +increment) + self.set_config_value("$Line", line_number + increment) def is_uncertain_final_value(self, last_evaluated_time: int, symbols: set) -> bool: """ diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index 81dac118d..e256eb8c9 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -229,8 +229,6 @@ def evaluate(self, query, timeout=None, format=None): output_forms = self.definitions.outputforms line_no = self.definitions.get_line_no() - line_no += 1 - self.definitions.set_line_no(line_no) history_length = self.definitions.get_history_length() @@ -242,7 +240,8 @@ def check_io_hook(hook): def evaluate(): if history_length > 0: self.definitions.add_rule( - "In", RewriteRule(to_expression("In", line_no), query) + "In", + RewriteRule(to_expression("In", line_no), query, evaluation=self), ) if check_io_hook("System`$Pre"): self.last_eval = Expression(SymbolPre, query).evaluate(self) @@ -261,8 +260,13 @@ def evaluate(): stored_result = self.get_stored_result(out_result, output_forms) self.definitions.add_rule( "Out", - RewriteRule(Expression(SymbolOut, Integer(line_no)), stored_result), + RewriteRule( + Expression(SymbolOut, Integer(line_no)), + stored_result, + evaluation=self, + ), ) + if self.last_eval != self.SymbolNull: if check_io_hook("System`$PrePrint"): self.last_eval = Expression( @@ -345,10 +349,14 @@ def evaluate(): self.out = [] finally: self.stop() + # $Line could have changed during the evaluation. + line_no = self.definitions.get_line_no() + line_no += 1 + self.definitions.set_line_no(line_no) history_length = self.definitions.get_history_length() - line = line_no - history_length + line = line_no - history_length - 1 while line > 0: unset_in = self.definitions.unset("In", Expression(SymbolIn, Integer(line))) unset_out = self.definitions.unset( diff --git a/mathics/session.py b/mathics/session.py index 6c14f5e47..e54c09b5f 100644 --- a/mathics/session.py +++ b/mathics/session.py @@ -190,18 +190,22 @@ def reset(self, add_builtin=True, catch_interrupt=False): """ reset the definitions and the evaluation objects. """ - try: - self.definitions = Definitions(add_builtin) - except KeyError: - from mathics.core.load_builtin import import_and_load_builtins + if add_builtin: + from mathics.core.load_builtin import ( + import_and_load_builtins, + mathics3_builtins_modules, + ) - import_and_load_builtins() - self.definitions = Definitions(add_builtin) + if not mathics3_builtins_modules: + import_and_load_builtins() + definitions = Definitions(add_builtin) self.evaluation = Evaluation( - definitions=self.definitions, catch_interrupt=catch_interrupt + definitions=definitions, catch_interrupt=catch_interrupt ) self.last_result = None + definitions.set_line_no(1) + self.definitions = definitions def evaluate(self, str_expression, timeout=None, form=None): """Parse str_expression and evaluate using the `evaluate` method of the Expression""" diff --git a/test/test_session.py b/test/test_session.py index 08d779a1f..03744d9f4 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -29,24 +29,25 @@ def test_session_evaluation(): Expression(Symbol("Global`F"), Symbol("Global`x")) ) assert len(session.evaluation.out) == 0 - assert session.evaluate("$Line") is Symbol("$Line") + assert session.evaluate("$Line") is Integer1 def test_session_evaluation_as_in_cli(): # `evaluation_as_in_cli` returns a `Result` object session.reset() - assert session.evaluate("$Line") is Symbol("$Line") + assert session.evaluate("$Line") is Integer1 result = session.evaluate_as_in_cli('Print["Hola"]') assert isinstance(result, Result) assert len(result.out) == 1 and result.out[0].text == "Hola" # Use session.evaluate(...) does not modify the `$Line` or # `Out` definitions, while `evaluate_as_in_cli` does: - assert session.evaluate("$Line") is Integer1 + assert session.evaluate("$Line") is Integer2 assert session.evaluate_as_in_cli("$Line", form="unformatted").result == Integer2 assert session.evaluate("Out[1]") is SymbolNull assert session.evaluate_as_in_cli("Out[1]").result is None session.reset() - assert session.evaluate("$Line") is Symbol("$Line") + # After reset, `$Line` takes the value `1`. + assert session.evaluate("$Line") is Integer1 def test_session_format_evaluation():