diff --git a/mathics/builtin/makeboxes.py b/mathics/builtin/makeboxes.py index cfcdf65c1..2cf811b3f 100644 --- a/mathics/builtin/makeboxes.py +++ b/mathics/builtin/makeboxes.py @@ -11,6 +11,7 @@ from mathics.eval.makeboxes import ( eval_generic_makeboxes, eval_infix, + eval_makeboxes_fullform, eval_postprefix, format_element, parenthesize, @@ -107,9 +108,13 @@ class MakeBoxes(Builtin): } summary_text = "settable low-level translator from expression to display boxes" + def eval_fullform(self, expr, evaluation): + """MakeBoxes[expr_, FullForm]""" + return eval_makeboxes_fullform(expr, evaluation) + def eval_general(self, expr, f, evaluation): """MakeBoxes[expr_, - f:TraditionalForm|StandardForm|OutputForm|InputForm|FullForm]""" + f:TraditionalForm|StandardForm|OutputForm|InputForm]""" return eval_generic_makeboxes(self, expr, f, evaluation) def eval_outerprecedenceform(self, expr, precedence, form, evaluation): diff --git a/mathics/eval/makeboxes/__init__.py b/mathics/eval/makeboxes/__init__.py index a6cb2a6e7..b3ca977f6 100644 --- a/mathics/eval/makeboxes/__init__.py +++ b/mathics/eval/makeboxes/__init__.py @@ -7,6 +7,7 @@ _boxed_string, eval_generic_makeboxes, eval_makeboxes, + eval_makeboxes_fullform, format_element, int_to_string_shorter_repr, to_boxes, @@ -31,6 +32,7 @@ "eval_generic_makeboxes", "eval_infix", "eval_makeboxes", + "eval_makeboxes_fullform", "eval_mathmlform", "eval_postprefix", "eval_tableform", diff --git a/mathics/eval/makeboxes/formatvalues.py b/mathics/eval/makeboxes/formatvalues.py index d6d4b0ded..acafd5b18 100644 --- a/mathics/eval/makeboxes/formatvalues.py +++ b/mathics/eval/makeboxes/formatvalues.py @@ -183,14 +183,10 @@ def do_format_rational( if not isinstance(element, Rational): return None if form is SymbolFullForm: - return do_format_expression( - Expression( - Expression(SymbolHoldForm, SymbolRational), - element.numerator(), - element.denominator(), - ), - evaluation, - form, + return Expression( + SymbolRational, + element.numerator(), + element.denominator(), ) else: numerator = element.numerator() @@ -211,12 +207,10 @@ def do_format_complex( if not isinstance(element, Complex): return None if form is SymbolFullForm: - return do_format_expression( - Expression( - Expression(SymbolHoldForm, SymbolComplex), element.real, element.imag - ), - evaluation, - form, + return Expression( + SymbolComplex, + element.real, + element.imag, ) parts: List[Any] = [] diff --git a/mathics/eval/makeboxes/makeboxes.py b/mathics/eval/makeboxes/makeboxes.py index 2d7275a2e..9cb6b684e 100644 --- a/mathics/eval/makeboxes/makeboxes.py +++ b/mathics/eval/makeboxes/makeboxes.py @@ -12,8 +12,16 @@ from mathics.core.element import BaseElement, BoxElementMixin from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression -from mathics.core.symbols import Atom, Symbol, SymbolFullForm, SymbolMakeBoxes -from mathics.core.systemsymbols import SymbolStandardForm +from mathics.core.symbols import ( + Atom, + Symbol, + SymbolFullForm, + SymbolList, + SymbolMakeBoxes, +) +from mathics.core.systemsymbols import ( # SymbolRule, SymbolRuleDelayed, + SymbolStandardForm, +) from mathics.eval.makeboxes.formatvalues import do_format from mathics.eval.makeboxes.precedence import parenthesize @@ -38,7 +46,7 @@ def to_boxes(x, evaluation: Evaluation, options={}) -> BoxElementMixin: return x_boxed if isinstance(x_boxed, Atom): return to_boxes(x_boxed, evaluation, options) - return eval_makeboxes(Expression(SymbolFullForm, x), evaluation) + return eval_makeboxes_fullform(x, evaluation) # this temporarily replaces the _BoxedString class @@ -126,23 +134,53 @@ def int_to_string_shorter_repr(value: int, form: Symbol, max_digits=640): return String(value_str) -def eval_fullform_makeboxes( - self, expr, evaluation: Evaluation, form=SymbolStandardForm -) -> Optional[BaseElement]: - """ - This function takes the definitions provided by the evaluation - object, and produces a boxed form for expr. +# TODO: evaluation is needed because `atom_to_boxes` uses it. Can we remove this +# argument? +def eval_makeboxes_fullform( + expr: BaseElement, evaluation: Evaluation +) -> BoxElementMixin: + """Same as MakeBoxes[FullForm[expr_], f_]""" + from mathics.builtin.box.layout import RowBox - Basically: MakeBoxes[expr // FullForm] - """ - # This is going to be reimplemented. - expr = Expression(SymbolFullForm, expr) - return Expression(SymbolMakeBoxes, expr, form).evaluate(evaluation) + if isinstance(expr, BoxElementMixin): + expr = expr.to_expression() + if isinstance(expr, Atom): + return expr.atom_to_boxes(SymbolFullForm, evaluation) + head, elements = expr.head, expr.elements + boxed_elements = tuple( + (eval_makeboxes_fullform(element, evaluation) for element in elements) + ) + # In some places it would be less verbose to use special outputs for + # `List`, `Rule` and `RuleDelayed`. WMA does not that, but we do it for + # `List`. + # + # if head is SymbolRule and len(elements) == 2: + # return RowBox(boxed_elements[0], String("->"), boxed_elements[1]) + # if head is SymbolRuleDelayed and len(elements) == 2: + # return RowBox(boxed_elements[0], String(":>"), boxed_elements[1]) + if head is SymbolList: + left, right, sep = (String(ch) for ch in ("{", "}", ",")) + result_elements = [left] + else: + left, right, sep = (String(ch) for ch in ("[", "]", ", ")) + result_elements = [eval_makeboxes_fullform(head, evaluation), left] + + if len(boxed_elements) > 1: + arguments = [] + for b_elem in boxed_elements: + if len(arguments) > 0: + arguments.append(sep) + arguments.append(b_elem) + result_elements.append(RowBox(*arguments)) + elif len(boxed_elements) == 1: + result_elements.append(boxed_elements[0]) + result_elements.append(right) + return RowBox(*result_elements) def eval_generic_makeboxes(self, expr, f, evaluation): """MakeBoxes[expr_, - f:TraditionalForm|StandardForm|OutputForm|InputForm|FullForm]""" + f:TraditionalForm|StandardForm|OutputForm|InputForm]""" from mathics.builtin.box.layout import RowBox if isinstance(expr, BoxElementMixin): @@ -174,7 +212,6 @@ def eval_generic_makeboxes(self, expr, f, evaluation): if f_name in ( "System`InputForm", "System`OutputForm", - "System`FullForm", ): sep = ", " else: @@ -210,6 +247,8 @@ def eval_makeboxes( Basically: MakeBoxes[expr // form] """ # This is going to be reimplemented. + if form is SymbolFullForm: + return eval_makeboxes_fullform(expr, evaluation) return Expression(SymbolMakeBoxes, expr, form).evaluate(evaluation) @@ -220,14 +259,13 @@ def format_element( Applies formats associated to the expression, and then calls Makeboxes """ evaluation.is_boxing = True - expr = do_format(element, evaluation, form) - if expr is None: + formatted_expr = do_format(element, evaluation, form) + if formatted_expr is None: return None - result = Expression(SymbolMakeBoxes, expr, form) - result_box = result.evaluate(evaluation) + result_box = eval_makeboxes(formatted_expr, evaluation, form) if isinstance(result_box, String): return result_box if isinstance(result_box, BoxElementMixin): return result_box else: - return format_element(element, evaluation, SymbolFullForm, **kwargs) + return eval_makeboxes_fullform(element, evaluation)