diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index 049955ad6..af2179030 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -23,6 +23,7 @@ from mathics.builtin.lists import _IterationFunction from mathics.builtin.scoping import dynamic_scoping from mathics.core.atoms import ( + SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM, Complex, Integer, Integer0, @@ -73,6 +74,7 @@ SymbolTable, SymbolUndefined, ) +from mathics.eval.makeboxes import _boxed_string, eval_makeboxes from mathics.eval.nevaluator import eval_N @@ -492,6 +494,14 @@ def eval(self, r, i, evaluation): r, i = from_sympy(r), from_sympy(i) return Complex(r, i) + def eval_makeboxes(self, c, form, evaluation): + """MakeBoxes[c_Complex, form_]""" + from mathics.eval.makeboxes import do_format_complex + + # This function can be moved to this module, or even + # added here inline. + return eval_makeboxes(do_format_complex(c, evaluation, form), evaluation, form) + class ConditionalExpression(Builtin): """ @@ -771,6 +781,13 @@ def eval(self, number, evaluation): return from_sympy(sympy.im(number.to_sympy().expand(complex=True))) + def eval_makeboxes(self, n, form, evaluation) -> "String": + """MakeBoxes[n_Integer, form_]""" + + if form in SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM: + return _boxed_string(str(n.value), number_as_text=True) + return String(str(n._value)) + class Integer_(Builtin): """ @@ -1093,6 +1110,15 @@ def eval(self, n: Integer, m: Integer, evaluation): else: return Rational(n.value, m.value) + def eval_makeboxes(self, r, form, evaluation): + """MakeBoxes[r_Rational, form_]""" + from mathics.eval.makeboxes import do_format_rational + + # This function can be moved to this module, or even + # added here inline. + result = do_format_rational(r, evaluation, form) + return eval_makeboxes(result, evaluation, form) + class Re(SympyFunction): """ @@ -1210,6 +1236,10 @@ class Real_(Builtin): summary_text = "head for real numbers" name = "Real" + def eval_makeboxes(self, r, form, evaluation): + """MakeBoxes[r_Real, form_]""" + return r.make_boxes(form.name) + class RealNumberQ(Test): """ diff --git a/mathics/builtin/atomic/strings.py b/mathics/builtin/atomic/strings.py index de4aa411e..d91e3deb1 100644 --- a/mathics/builtin/atomic/strings.py +++ b/mathics/builtin/atomic/strings.py @@ -13,7 +13,13 @@ from mathics_scanner import TranslateError from mathics.builtin.base import Builtin, Predefined, PrefixOperator, Test -from mathics.core.atoms import Integer, Integer0, Integer1, String +from mathics.core.atoms import ( + SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM, + Integer, + Integer0, + Integer1, + String, +) from mathics.core.attributes import A_LISTABLE, A_PROTECTED from mathics.core.convert.expression import to_mathics_list from mathics.core.convert.python import from_bool @@ -841,6 +847,17 @@ class String_(Builtin): name = "String" summary_text = "head for strings" + def apply_makeboxes(self, s, form, evaluation): + """MakeBoxes[s_String, + form:(InputForm|OutputForm|StandardForm|TraditionalForm|FullForm)]""" + from mathics.eval.makeboxes import _boxed_string + + inner = str(s.value) + if form in SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM: + inner = '"' + inner.replace("\\", "\\\\") + '"' + return _boxed_string(inner, **{"System`ShowStringCharacters": SymbolTrue}) + return String('"' + inner + '"') + class StringContainsQ(Builtin): """ diff --git a/mathics/builtin/atomic/symbols.py b/mathics/builtin/atomic/symbols.py index 01f1ac0ce..a2bb2bd4e 100644 --- a/mathics/builtin/atomic/symbols.py +++ b/mathics/builtin/atomic/symbols.py @@ -722,6 +722,11 @@ def eval(self, string, evaluation): else: evaluation.message("Symbol", "symname", string) + def eval_symb_makeboxes(self, s, form, evaluation) -> "String": + """MakeBoxes[s_Symbol, + form:(InputForm|OutputForm|StandardForm|TraditionalForm|FullForm)]""" + return String(evaluation.definitions.shorten_name(s.name)) + class SymbolName(Builtin): """ diff --git a/mathics/builtin/box/graphics.py b/mathics/builtin/box/graphics.py index d1d9a2eea..48eed1279 100644 --- a/mathics/builtin/box/graphics.py +++ b/mathics/builtin/box/graphics.py @@ -38,7 +38,7 @@ from mathics.core.list import ListExpression from mathics.core.symbols import Symbol, SymbolTrue from mathics.core.systemsymbols import SymbolAutomatic, SymbolTraditionalForm -from mathics.eval.makeboxes import format_element +from mathics.eval.makeboxes import eval_makeboxes, format_element SymbolRegularPolygonBox = Symbol("RegularPolygonBox") SymbolStandardForm = Symbol("StandardForm") @@ -994,8 +994,8 @@ def init( self.opos = opos if isinstance(self.content, String): - self.content = self.content.atom_to_boxes( - SymbolStandardForm, evaluation=self.graphics.evaluation + self.content = eval_makeboxes( + self.content, self.graphics.evaluation, SymbolStandardForm ) self.content_text = self.content.boxes_to_text( evaluation=self.graphics.evaluation diff --git a/mathics/builtin/box/layout.py b/mathics/builtin/box/layout.py index 74b83a2e6..86ac05e16 100644 --- a/mathics/builtin/box/layout.py +++ b/mathics/builtin/box/layout.py @@ -38,18 +38,21 @@ def to_boxes(x, evaluation: Evaluation, options={}) -> BoxElementMixin: if isinstance(x, BoxElementMixin): return x if isinstance(x, Atom): - x = x.atom_to_boxes(SymbolStandardForm, evaluation) - return to_boxes(x, evaluation, options) - if isinstance(x, Expression): - if x.has_form("MakeBoxes", None): - x_boxed = x.evaluate(evaluation) - else: - x_boxed = eval_makeboxes(x, evaluation) - if isinstance(x_boxed, BoxElementMixin): - return x_boxed - if isinstance(x_boxed, Atom): - return to_boxes(x_boxed, evaluation, options) - raise eval_makeboxes(Expression(SymbolFullForm, x), evaluation) + try: + x = x.atom_to_boxes(SymbolStandardForm, evaluation) + return to_boxes(x, evaluation, options) + except NotImplementedError: + pass + + if x.has_form("MakeBoxes", None): + x_boxed = x.evaluate(evaluation) + else: + x_boxed = eval_makeboxes(x, evaluation) + if isinstance(x_boxed, BoxElementMixin): + return x_boxed + if isinstance(x_boxed, Atom): + return to_boxes(x_boxed, evaluation, options) + return eval_makeboxes(Expression(SymbolFullForm, x), evaluation) class BoxData(Builtin): diff --git a/mathics/builtin/drawing/image.py b/mathics/builtin/drawing/image.py index f63e99465..8701c8414 100644 --- a/mathics/builtin/drawing/image.py +++ b/mathics/builtin/drawing/image.py @@ -68,6 +68,7 @@ import numpy import PIL + import PIL.Image import PIL.ImageEnhance import PIL.ImageFilter import PIL.ImageOps diff --git a/mathics/builtin/makeboxes.py b/mathics/builtin/makeboxes.py index ed906e3ef..95059b85f 100644 --- a/mathics/builtin/makeboxes.py +++ b/mathics/builtin/makeboxes.py @@ -377,7 +377,10 @@ def eval_general(self, expr, f, evaluation): if isinstance(expr, BoxElementMixin): expr = expr.to_expression() if isinstance(expr, Atom): - return expr.atom_to_boxes(f, evaluation) + try: + return expr.atom_to_boxes(f, evaluation) + except NotImplementedError: + return String(f"{str(expr)} cannot be boxed in form {f}") else: head = expr.head elements = expr.elements diff --git a/mathics/core/atoms.py b/mathics/core/atoms.py index 6daa267ca..ce17f7cd9 100644 --- a/mathics/core/atoms.py +++ b/mathics/core/atoms.py @@ -224,19 +224,9 @@ def __ne__(self, other) -> bool: def abs(self) -> "Integer": return -self if self < Integer0 else self - def atom_to_boxes(self, f, evaluation): - return self.make_boxes(f.get_name()) - def default_format(self, evaluation, form) -> str: return str(self._value) - def make_boxes(self, form) -> "String": - from mathics.eval.makeboxes import _boxed_string - - if form in ("System`InputForm", "System`FullForm"): - return _boxed_string(str(self.value), number_as_text=True) - return String(str(self._value)) - def to_sympy(self, **kwargs): return sympy.Integer(self._value) @@ -341,9 +331,6 @@ def __ne__(self, other) -> bool: # Real is a total order return not (self == other) - def atom_to_boxes(self, f, evaluation): - return self.make_boxes(f.get_name()) - def is_nan(self, d=None) -> bool: return isinstance(self.value, sympy.core.numbers.NaN) @@ -715,11 +702,6 @@ def __hash__(self): def __str__(self) -> str: return str(self.to_sympy()) - def atom_to_boxes(self, f, evaluation): - from mathics.eval.makeboxes import format_element - - return format_element(self, evaluation, f) - def to_sympy(self, **kwargs): return self.real.to_sympy() + sympy.I * self.imag.to_sympy() @@ -863,11 +845,6 @@ def __new__(cls, numerator, denominator=1) -> "Rational": def __hash__(self): return self.hash - def atom_to_boxes(self, f, evaluation): - from mathics.eval.makeboxes import format_element - - return format_element(self, evaluation, f) - def to_sympy(self, **kwargs): return self.value @@ -945,15 +922,6 @@ def __hash__(self): def __str__(self) -> str: return '"%s"' % self.value - def atom_to_boxes(self, f, evaluation): - from mathics.eval.makeboxes import _boxed_string - - inner = str(self.value) - if f in SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM: - inner = '"' + inner.replace("\\", "\\\\") + '"' - return _boxed_string(inner, **{"System`ShowStringCharacters": SymbolTrue}) - return String('"' + inner + '"') - def do_copy(self) -> "String": return String(self.value) diff --git a/mathics/core/symbols.py b/mathics/core/symbols.py index 61f70add1..af28c244b 100644 --- a/mathics/core/symbols.py +++ b/mathics/core/symbols.py @@ -431,11 +431,6 @@ def __ne__(self, other) -> bool: def __str__(self) -> str: return self.name - def atom_to_boxes(self, f, evaluation) -> "String": - from mathics.core.atoms import String - - return String(evaluation.definitions.shorten_name(self.name)) - def default_format(self, evaluation, form) -> str: return self.name diff --git a/mathics/eval/image.py b/mathics/eval/image.py index 3f78371bd..cbc84f4fd 100644 --- a/mathics/eval/image.py +++ b/mathics/eval/image.py @@ -9,6 +9,7 @@ import numpy import PIL +import PIL.Image from mathics.builtin.base import String from mathics.core.atoms import Rational diff --git a/mathics/eval/makeboxes.py b/mathics/eval/makeboxes.py index 7c51be55f..326ad7873 100644 --- a/mathics/eval/makeboxes.py +++ b/mathics/eval/makeboxes.py @@ -51,7 +51,7 @@ def _boxed_string(string: str, **options): return StyleBox(String(string), **options) -def eval_makeboxes(self, expr, evaluation, f=SymbolStandardForm): +def eval_makeboxes(expr, evaluation, f=SymbolStandardForm): """ This function takes the definitions prodived by the evaluation object, and produces a boxed form for expr. @@ -67,8 +67,7 @@ def format_element( Applies formats associated to the expression, and then calls Makeboxes """ expr = do_format(element, evaluation, form) - result = Expression(SymbolMakeBoxes, expr, form) - result_box = result.evaluate(evaluation) + result_box = eval_makeboxes(expr, evaluation, form) if isinstance(result_box, String): return result_box if isinstance(result_box, BoxElementMixin):