diff --git a/mathics/builtin/box/layout.py b/mathics/builtin/box/layout.py index 4c1c33c55..b38ab63ab 100644 --- a/mathics/builtin/box/layout.py +++ b/mathics/builtin/box/layout.py @@ -85,6 +85,50 @@ def is_constant_list(list): return True +class FormBox(BoxExpression): + """ + + :WMA link: + https://reference.wolfram.com/language/ref/FormBox.html + +
+
'FormBox[boxes, form]' +
is a low-level box construct that displays as \ + boxes and keep information about the form used to generate \ + the box representation. +
+ """ + + attributes = A_PROTECTED | A_READ_PROTECTED + summary_text = "box with an associated form" + + def init(self, *elems, **kwargs): + self.box_options = kwargs + self.form = elems[1] + self.boxed = elems[0] + assert isinstance(self.boxed, BoxElementMixin), f"{type(self.boxes)}" + + @property + def elements(self): + if self._elements is None: + self._elements = elements_to_expressions( + self, + ( + self.boxed, + self.form, + ), + self.box_options, + ) + return self._elements + + def eval_tagbox(self, expr, form: Symbol, evaluation: Evaluation): + """FormBox[expr_, form_Symbol]""" + options = {} + expr = to_boxes(expr, evaluation, options) + assert isinstance(expr, BoxElementMixin), f"{expr}" + return FormBox(expr, form, **options) + + class FractionBox(BoxExpression): """ @@ -165,7 +209,7 @@ def elements(self): return self._elements def init(self, *elems, **kwargs): - self.options = kwargs + self.box_options = kwargs self.items = elems self._elements = elems @@ -173,7 +217,7 @@ def get_array(self, elements, evaluation): if not elements: raise BoxConstructError - options = self.options + options = self.box_options expr = elements[0] if not expr.has_form("List", None): @@ -470,8 +514,6 @@ class StyleBox(BoxExpression): """ options = { - "ShowStringCharacters": "False", - "ShowSpecialCharacters": "False", "$OptionSyntax": "Ignore", } attributes = A_PROTECTED | A_READ_PROTECTED diff --git a/mathics/builtin/forms/data.py b/mathics/builtin/forms/data.py index 6ce2f7d3f..6d042f27d 100644 --- a/mathics/builtin/forms/data.py +++ b/mathics/builtin/forms/data.py @@ -791,7 +791,7 @@ class MatrixForm(TableForm): in_printforms = False summary_text = "format as a matrix" - def eval_makeboxes_matrix(self, table, form, evaluation, options): + def eval_makeboxes(self, table, form, evaluation, options): """MakeBoxes[MatrixForm[table_, OptionsPattern[]], (form:StandardForm|TraditionalForm)]""" result = super().eval_makeboxes(table, form, evaluation, options) diff --git a/mathics/builtin/forms/print.py b/mathics/builtin/forms/print.py index 59efe7c56..01ca58e8f 100644 --- a/mathics/builtin/forms/print.py +++ b/mathics/builtin/forms/print.py @@ -12,19 +12,16 @@ below are the functions that appear in '$PrintForms' at startup. """ -from mathics.builtin.box.layout import InterpretationBox, StyleBox, TagBox +from mathics.builtin.box.layout import InterpretationBox, PaneBox, StyleBox from mathics.builtin.forms.base import FormBaseClass from mathics.core.atoms import String +from mathics.core.element import BaseElement +from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression -from mathics.core.symbols import SymbolFalse, SymbolFullForm, SymbolTrue +from mathics.core.symbols import SymbolFalse, SymbolTrue from mathics.core.systemsymbols import SymbolInputForm, SymbolOutputForm -from mathics.format.box import ( - eval_makeboxes_fullform, - eval_makeboxes_outputform, - eval_mathmlform, - eval_texform, -) -from mathics.format.form import render_input_form +from mathics.format.box.makeboxes import is_print_form_callback +from mathics.format.form import render_input_form, render_output_form sort_order = "mathics.builtin.forms.general-purpose-forms" @@ -52,19 +49,6 @@ class FullForm(FormBaseClass): in_printforms = False summary_text = "format expression in underlying M-Expression representation" - def eval_makeboxes(self, expr, fmt, evaluation): - """MakeBoxes[FullForm[expr_], fmt_]""" - fullform_box = eval_makeboxes_fullform(expr, evaluation) - style_box = StyleBox( - fullform_box, - **{ - "System`ShowSpecialCharacters": SymbolFalse, - "System`ShowStringCharacters": SymbolTrue, - "System`NumberMarks": SymbolTrue, - }, - ) - return TagBox(style_box, SymbolFullForm) - class InputForm(FormBaseClass): r""" @@ -116,26 +100,6 @@ class InputForm(FormBaseClass): in_printforms = True summary_text = "format expression suitable for Mathics3 input" - # TODO: eventually, remove OutputForm in the second argument. - def eval_makeboxes(self, expr, evaluation): - """MakeBoxes[InputForm[expr_], StandardForm|TraditionalForm]""" - - inputform = String(render_input_form(expr, evaluation)) - inputform = StyleBox( - inputform, - **{ - "System`ShowSpecialCharacters": SymbolFalse, - "System`ShowStringCharacters": SymbolTrue, - "System`NumberMarks": SymbolTrue, - }, - ) - expr = Expression(SymbolInputForm, expr) - return InterpretationBox( - inputform, - expr, - **{"System`Editable": SymbolTrue, "System`AutoDelete": SymbolTrue}, - ) - class MathMLForm(FormBaseClass): """ @@ -169,10 +133,6 @@ class MathMLForm(FormBaseClass): summary_text = "format expression as MathML commands" - def eval_mathml(self, expr, evaluation) -> Expression: - "MakeBoxes[MathMLForm[expr_], StandardForm|TraditionalForm]" - return eval_mathmlform(expr, evaluation) - class OutputForm(FormBaseClass): """ @@ -202,13 +162,6 @@ class OutputForm(FormBaseClass): formats = {"OutputForm[s_String]": "s"} summary_text = "format expression in plain text" - def eval_makeboxes(self, expr, form, evaluation): - """MakeBoxes[OutputForm[expr_], form_]""" - pane = eval_makeboxes_outputform(expr, evaluation, form) - return InterpretationBox( - pane, Expression(SymbolOutputForm, expr), **{"System`Editable": SymbolFalse} - ) - class StandardForm(FormBaseClass): """ @@ -276,8 +229,34 @@ class TeXForm(FormBaseClass): in_printforms = True summary_text = "format expression as LaTeX commands" - def eval_tex(self, expr, evaluation) -> Expression: - "MakeBoxes[TeXForm[expr_], StandardForm|TraditionalForm]" - # TeXForm by default uses `TraditionalForm` - return eval_texform(expr, evaluation) +@is_print_form_callback("System`InputForm") +def eval_makeboxes_inputform(expr: BaseElement, evaluation: Evaluation): + """MakeBoxes[InputForm[expr_], StandardForm|TraditionalForm]""" + inputform = String(render_input_form(expr, evaluation)) + inputform = StyleBox( + inputform, + **{ + "System`ShowStringCharacters": SymbolTrue, + "System`NumberMarks": SymbolTrue, + }, + ) + expr = Expression(SymbolInputForm, expr) + return InterpretationBox( + inputform, + expr, + **{"System`Editable": SymbolTrue, "System`AutoDelete": SymbolTrue}, + ) + + +@is_print_form_callback("System`OutputForm") +def eval_makeboxes_outputform(expr: BaseElement, evaluation: Evaluation, **kwargs): + """ + Build a 2D representation of the expression using only keyboard characters. + """ + + text_outputform = str(render_output_form(expr, evaluation, **kwargs)) + pane = PaneBox(String('"' + text_outputform + '"')) + return InterpretationBox( + pane, Expression(SymbolOutputForm, expr), **{"System`Editable": SymbolFalse} + ) diff --git a/mathics/builtin/layout.py b/mathics/builtin/layout.py index a3785cce3..eb9884e32 100644 --- a/mathics/builtin/layout.py +++ b/mathics/builtin/layout.py @@ -11,13 +11,19 @@ from mathics.builtin.box.layout import GridBox, PaneBox, RowBox, to_boxes from mathics.builtin.makeboxes import MakeBoxes -from mathics.core.atoms import Real, String +from mathics.core.atoms import Integer, Real, String from mathics.core.builtin import Builtin, Operator, PostfixOperator, PrefixOperator from mathics.core.expression import Evaluation, Expression from mathics.core.list import ListExpression -from mathics.core.systemsymbols import SymbolMakeBoxes, SymbolSubscriptBox +from mathics.core.symbols import Symbol +from mathics.core.systemsymbols import ( + SymbolMakeBoxes, + SymbolPostfix, + SymbolPrefix, + SymbolSubscriptBox, +) from mathics.eval.lists import list_boxes -from mathics.format.box import format_element +from mathics.format.box import eval_infix, eval_postprefix, format_element, parenthesize class Center(Builtin): @@ -172,8 +178,20 @@ class Infix(Builtin): = a + b - c """ + rules = { + ( + "MakeBoxes[Infix[head_[elements___]], " + " f:StandardForm|TraditionalForm]" + ): ('MakeBoxes[Infix[head[elements], StringForm["~`1`~", head]], f]'), + } summary_text = "infix form" + def eval_makeboxes_infix( + self, expr, operator, precedence: Integer, grouping, form: Symbol, evaluation + ): + """MakeBoxes[Infix[expr_, operator_, precedence_:None, grouping_:None], form:StandardForm|TraditionalForm]""" + return eval_infix(self, expr, operator, precedence, grouping, form, evaluation) + class Left(Builtin): """ @@ -278,6 +296,13 @@ class Postfix(PostfixOperator): operator_display = None summary_text = "postfix form" + def eval_makeboxes_postfix(self, expr, h, precedence, form, evaluation): + """MakeBoxes[Postfix[expr_, h_, precedence_:None], + form:StandardForm|TraditionalForm]""" + return eval_postprefix( + self, SymbolPostfix, expr, h, precedence, form, evaluation + ) + class Precedence(Builtin): """ @@ -332,8 +357,20 @@ class PrecedenceForm(Builtin):
'PrecedenceForm'[$expr$, $prec$]
format $expr$ parenthesized as it would be if it contained an operator of precedence $prec$. + + >> PrecedenceForm[x/y, 12] - z + = -z + (x / y) + """ + def eval_outerprecedenceform(self, expr, precedence, form, evaluation): + """MakeBoxes[PrecedenceForm[expr_, precedence_], + form:StandardForm|TraditionalForm]""" + + py_precedence = precedence.get_int_value() + boxes = format_element(expr, evaluation, form) + return parenthesize(py_precedence, expr, boxes, True) + summary_text = "parenthesize with a precedence" @@ -370,6 +407,13 @@ class Prefix(PrefixOperator): operator_display = None summary_text = "prefix form" + def eval_makeboxes_prefix(self, expr, h, precedence, form, evaluation): + """MakeBoxes[Prefix[expr_, h_, precedence_:None], + form:StandardForm|TraditionalForm]""" + return eval_postprefix( + self, SymbolPrefix, expr, h, precedence, form, evaluation + ) + class Right(Builtin): """ @@ -456,7 +500,12 @@ class Style(Builtin): summary_text = "wrapper for styles and style options to apply" options = {"ImageSizeMultipliers": "Automatic"} - + rules = { + "MakeBoxes[Style[expr_, OptionsPattern[Style]], f_]": ( + "StyleBox[MakeBoxes[expr, f], " + "ImageSizeMultipliers -> OptionValue[ImageSizeMultipliers]]" + ), + } rules = { "MakeBoxes[Style[expr_, OptionsPattern[Style]], f_]": ( "StyleBox[MakeBoxes[expr, f], " diff --git a/mathics/builtin/list/constructing.py b/mathics/builtin/list/constructing.py index 2e084b542..9bcd1b64f 100644 --- a/mathics/builtin/list/constructing.py +++ b/mathics/builtin/list/constructing.py @@ -12,7 +12,6 @@ from itertools import permutations from typing import Optional, Tuple -from mathics.builtin.box.layout import RowBox from mathics.core.atoms import ByteArray, Integer, Integer1, is_integer_rational_or_real from mathics.core.attributes import A_HOLD_FIRST, A_LISTABLE, A_LOCKED, A_PROTECTED from mathics.core.builtin import BasePattern, Builtin, IterationFunction @@ -24,7 +23,7 @@ from mathics.core.list import ListExpression from mathics.core.symbols import Atom, Symbol from mathics.core.systemsymbols import SymbolNormal, SymbolTuples -from mathics.eval.lists import get_tuples, list_boxes +from mathics.eval.lists import get_tuples class Array(Builtin): @@ -165,13 +164,6 @@ def eval(self, elements, evaluation: Evaluation): elements_part_of_elements__ = elements.get_sequence() return ListExpression(*elements_part_of_elements__) - def eval_makeboxes(self, items, f, evaluation): - """MakeBoxes[{items___}, - (f:StandardForm|TraditionalForm)]""" - - items = items.get_sequence() - return RowBox(*list_boxes(items, f, evaluation, "{", "}")) - class Normal(Builtin): """ diff --git a/mathics/builtin/makeboxes.py b/mathics/builtin/makeboxes.py index 8fea8b539..2dea6be10 100644 --- a/mathics/builtin/makeboxes.py +++ b/mathics/builtin/makeboxes.py @@ -3,19 +3,9 @@ Low-level Format definitions """ - -from mathics.core.atoms import Integer from mathics.core.attributes import A_HOLD_ALL_COMPLETE, A_READ_PROTECTED from mathics.core.builtin import Builtin, Predefined -from mathics.core.symbols import Symbol -from mathics.format.box import ( - eval_generic_makeboxes, - eval_infix, - eval_makeboxes_fullform, - eval_postprefix, - format_element, - parenthesize, -) +from mathics.format.box import format_element # TODO: Differently from the current implementation, MakeBoxes should only # accept as its format field the symbols in `$BoxForms`. This is something to @@ -91,53 +81,15 @@ class MakeBoxes(Builtin): attributes = A_HOLD_ALL_COMPLETE rules = { - "MakeBoxes[Infix[head_[elements___]], " - " f:StandardForm|TraditionalForm]": ( - 'MakeBoxes[Infix[head[elements], StringForm["~`1`~", head]], f]' - ), "MakeBoxes[expr_]": "MakeBoxes[expr, StandardForm]", # The following rule is temporal. "MakeBoxes[expr_, form:(TeXForm|MathMLForm)]": "MakeBoxes[form[expr], StandardForm]", - ( - "MakeBoxes[(form:StandardForm|TraditionalForm)" - "[expr_], StandardForm|TraditionalForm]" - ): ("MakeBoxes[expr, form]"), - # BoxForms goes as second argument - "MakeBoxes[PrecedenceForm[expr_, prec_], f_]": "MakeBoxes[expr, f]", - "MakeBoxes[Style[expr_, OptionsPattern[Style]], f_]": ( - "StyleBox[MakeBoxes[expr, f], " - "ImageSizeMultipliers -> OptionValue[ImageSizeMultipliers]]" - ), } 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]""" - return eval_generic_makeboxes(expr, f, evaluation) - - def eval_outerprecedenceform(self, expr, precedence, form, evaluation): - """MakeBoxes[PrecedenceForm[expr_, precedence_], - form:StandardForm|TraditionalForm]""" - - py_precedence = precedence.get_int_value() - boxes = MakeBoxes(expr, form) - return parenthesize(py_precedence, expr, boxes, True) - - def eval_postprefix(self, p, expr, h, precedence, form, evaluation): - """MakeBoxes[(p:Prefix|Postfix)[expr_, h_, precedence_:None], - form:StandardForm|TraditionalForm]""" - return eval_postprefix(self, p, expr, h, precedence, form, evaluation) - - def eval_infix( - self, expr, operator, precedence: Integer, grouping, form: Symbol, evaluation - ): - """MakeBoxes[Infix[expr_, operator_, precedence_:None, grouping_:None], form:StandardForm|TraditionalForm]""" - return eval_infix(self, expr, operator, precedence, grouping, form, evaluation) + """MakeBoxes[expr_, f:TraditionalForm|StandardForm]""" + return format_element(expr, evaluation, f) class ToBoxes(Builtin): @@ -169,5 +121,6 @@ def eval(self, expr, form, evaluation): form_name = form.get_name() if form_name is None: evaluation.message("ToBoxes", "boxfmt", form) + boxes = format_element(expr, evaluation, form) return boxes diff --git a/mathics/builtin/patterns/defaults.py b/mathics/builtin/patterns/defaults.py index ca38a8ea8..828771360 100644 --- a/mathics/builtin/patterns/defaults.py +++ b/mathics/builtin/patterns/defaults.py @@ -72,8 +72,29 @@ class Optional(InfixOperator, PatternObject): } grouping = "Right" rules = { - "MakeBoxes[Verbatim[Optional][Verbatim[Pattern][symbol_Symbol, Verbatim[_]]], (f:StandardForm|TraditionalForm)]": 'MakeBoxes[symbol, f] <> "_."', - "MakeBoxes[Verbatim[Optional][Verbatim[_]], (f:StandardForm|TraditionalForm)]": '"_."', + ( + "MakeBoxes[Verbatim[Optional][" + "Verbatim[Pattern][symbol_Symbol," + "(kind:(Verbatim[Blank]|Verbatim[BlankSequence]|Verbatim[BlankNullSequence])[])]], " + "(f:StandardForm|TraditionalForm)]" + ): 'MakeBoxes[symbol, f] <> ToString[kind, f] <>"."', + ( + "MakeBoxes[Verbatim[Optional][" + "(kind:(Verbatim[Blank]|Verbatim[BlankSequence]|Verbatim[BlankNullSequence])[])], " + "(f:StandardForm|TraditionalForm)]" + ): 'ToString[kind, f]<>"."', + # Two arguments + ( + "MakeBoxes[Verbatim[Optional][" + "Verbatim[Pattern][symbol_Symbol," + "(kind:(Verbatim[Blank]|Verbatim[BlankSequence]|Verbatim[BlankNullSequence])[]), value_]], " + "(f:StandardForm|TraditionalForm)]" + ): 'RowBox[{MakeBoxes[symbol, f], ToString[kind, f], ":",MakeBoxes[value, f]}]', + ( + "MakeBoxes[Verbatim[Optional][" + "(kind:(Verbatim[Blank]|Verbatim[BlankSequence]|Verbatim[BlankNullSequence])[]), value_], " + "(f:StandardForm|TraditionalForm)]" + ): 'RowBox[{ToString[kind, f], ":", MakeBoxes[value, f]}]', } summary_text = "an optional argument with a default value" diff --git a/mathics/core/atoms/strings.py b/mathics/core/atoms/strings.py index a58a0a0fe..3243bf475 100644 --- a/mathics/core/atoms/strings.py +++ b/mathics/core/atoms/strings.py @@ -9,7 +9,7 @@ from mathics.core.element import BoxElementMixin from mathics.core.keycomparable import BASIC_ATOM_STRING_ELT_ORDER -from mathics.core.symbols import Atom, Symbol, SymbolTrue, symbol_set +from mathics.core.symbols import Atom, Symbol, SymbolFalse, SymbolTrue, symbol_set from mathics.core.systemsymbols import SymbolFullForm, SymbolInputForm SymbolString = Symbol("String") @@ -41,8 +41,17 @@ def atom_to_boxes(self, f, evaluation): inner = str(self.value) if f in SYSTEM_SYMBOLS_INPUT_OR_FULL_FORM: - inner = '"' + inner.replace("\\", "\\\\") + '"' - return _boxed_string(inner, **{"System`ShowStringCharacters": SymbolTrue}) + inner = inner.replace("\\", "\\\\") + inner = inner.replace('"', '\\"') + inner = f'"{inner}"' + return _boxed_string( + inner, + **{ + "System`NumberMarks": SymbolTrue, + "System`ShowSpecialCharacters": SymbolFalse, + "System`ShowStringCharacters": SymbolTrue, + }, + ) return String('"' + inner + '"') def do_copy(self) -> "String": diff --git a/mathics/core/builtin.py b/mathics/core/builtin.py index 09d001408..dc8a9ac0e 100644 --- a/mathics/core/builtin.py +++ b/mathics/core/builtin.py @@ -347,7 +347,7 @@ def contextify_form_name(f): """Handle adding 'System`' to a form name, unless it's "" (meaning the rule applies to all forms). """ - return "" if f == "" else ensure_context(f) + return f if f in ("", "_MakeBoxes") else ensure_context(f) if isinstance(pattern, tuple): forms, pattern = pattern @@ -383,6 +383,9 @@ def contextify_form_name(f): formatvalues[form].append( Rule(pattern, parse_builtin_rule(replace), system=True) ) + + formatvalues.setdefault("_MakeBoxes", []).extend(box_rules) + for form, formatrules in formatvalues.items(): formatrules.sort(key=lambda x: x.pattern_precedence) @@ -434,10 +437,6 @@ def contextify_form_name(f): else: definitions.builtin[name] = definition - makeboxes_def = definitions.builtin["System`MakeBoxes"] - for rule in box_rules: - makeboxes_def.add_rule(rule) - # This method is used to produce generic argument mismatch errors # (tags: "argx", "argr", "argrx", "argt", or "argtu") for builtin # functions that define this as an eval method. e.g. For example diff --git a/mathics/core/load_builtin.py b/mathics/core/load_builtin.py index dfff80c10..418a7527d 100644 --- a/mathics/core/load_builtin.py +++ b/mathics/core/load_builtin.py @@ -133,11 +133,8 @@ def definition_contribute(definitions): Load the Definition objects associated to all the builtins on `Definitions` """ - # let MakeBoxes contribute first - _builtins["System`MakeBoxes"].contribute(definitions) for name, item in _builtins.items(): - if name != "System`MakeBoxes": - item.contribute(definitions) + item.contribute(definitions) from mathics.core.definitions import Definition from mathics.core.expression import ensure_context diff --git a/mathics/doc/documentation/1-Manual.mdoc b/mathics/doc/documentation/1-Manual.mdoc index f3f6ac18e..433a65c38 100644 --- a/mathics/doc/documentation/1-Manual.mdoc +++ b/mathics/doc/documentation/1-Manual.mdoc @@ -912,14 +912,13 @@ In a similar way, in the CLI, we can ask for TraditionalForm explicitly = c 'MakeBoxes' for another form: - >> MakeBoxes[TeXForm[b], form_] = "d"; >> b // TeXForm = ... You can cause a much bigger mess by overriding 'MakeBoxes' than by sticking to 'Format', e.g. generate invalid XML: - >> MakeBoxes[MathMLForm[c], form_] = "> MakeBoxes[MathMLForm[c], form_] := "> c // MathMLForm //StandardForm = RadicalBox[3, StandardForm] + if not lhs.has_form("MakeBoxes", 2): + evaluation.message("MakeBoxes", "argrx", Integer(len(lhs.elements))) + raise AssignmentException(lhs, None) + target, form = lhs.elements + # Check second argument + makeboxes_rule = Rule(lhs, rhs, system=False) + tags = [] if tags is None else tags + if upset: + tags = tags + [target.get_lookup_name()] + else: + if not tags: + tags = ["System`MakeBoxes"] + definitions = evaluation.definitions - definitions.add_rule("System`MakeBoxes", makeboxes_rule, "downvalues") - # makeboxes_defs = evaluation.definitions.builtin["System`MakeBoxes"] - # makeboxes_defs.add_rule(makeboxes_rule) + for tag in tags: + if is_protected(tag, definitions): + evaluation.message(self.get_name(), "wrsym", Symbol(tag)) + return False + definitions.add_format(tag, makeboxes_rule, "_MakeBoxes") return True diff --git a/mathics/eval/lists.py b/mathics/eval/lists.py index 130d9ffb1..f20173ed6 100644 --- a/mathics/eval/lists.py +++ b/mathics/eval/lists.py @@ -1,4 +1,3 @@ -from mathics.builtin.box.layout import RowBox from mathics.core.atoms import String from mathics.core.convert.expression import to_expression from mathics.core.exceptions import PartDepthError, PartRangeError @@ -61,6 +60,8 @@ def get_tuples(items): def list_boxes(items, f, evaluation, open=None, close=None): + from mathics.builtin.box.layout import RowBox + result = [ Expression(SymbolMakeBoxes, item, f).evaluate(evaluation) for item in items ] diff --git a/mathics/format/box/__init__.py b/mathics/format/box/__init__.py index 42d3f798c..48688dd37 100644 --- a/mathics/format/box/__init__.py +++ b/mathics/format/box/__init__.py @@ -6,9 +6,7 @@ from mathics.format.box.makeboxes import ( _boxed_string, eval_generic_makeboxes, - eval_makeboxes, eval_makeboxes_fullform, - eval_makeboxes_outputform, format_element, to_boxes, ) @@ -36,9 +34,7 @@ "eval_baseform", "eval_generic_makeboxes", "eval_infix", - "eval_makeboxes", "eval_makeboxes_fullform", - "eval_makeboxes_outputform", "eval_mathmlform", "eval_postprefix", "eval_tableform", diff --git a/mathics/format/box/makeboxes.py b/mathics/format/box/makeboxes.py index 2090080c4..e365570a7 100644 --- a/mathics/format/box/makeboxes.py +++ b/mathics/format/box/makeboxes.py @@ -9,49 +9,41 @@ from typing import List from mathics.core.atoms import Complex, Rational, String -from mathics.core.element import BaseElement, BoxElementMixin +from mathics.core.element import BaseElement, BoxElementMixin, EvalMixin from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.symbols import ( Atom, Symbol, + SymbolFalse, SymbolFullForm, SymbolList, SymbolMakeBoxes, + SymbolTrue, ) from mathics.core.systemsymbols import ( # SymbolRule, SymbolRuleDelayed, + SymbolAborted, SymbolComplex, SymbolRational, SymbolStandardForm, SymbolTraditionalForm, ) +from mathics.eval.lists import list_boxes from mathics.format.box.formatvalues import do_format from mathics.format.box.precedence import parenthesize BOX_FORMS = {SymbolStandardForm, SymbolTraditionalForm} +PRINT_FORMS_CALLBACK = {} -def to_boxes(x, evaluation: Evaluation, options={}) -> BoxElementMixin: - """ - This function takes the expression ``x`` - and tries to reduce it to a ``BoxElementMixin`` - expression using an evaluation object. - """ - 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) - return eval_makeboxes_fullform(x, evaluation) +def is_print_form_callback(head_name: str): + """Decorator for register print form callbacks""" + + def _register(func): + PRINT_FORMS_CALLBACK[head_name] = func + return func + + return _register # this temporarily replaces the _BoxedString class @@ -61,10 +53,86 @@ def _boxed_string(string: str, **options): return StyleBox(String(string), **options) +@is_print_form_callback("System`StandardForm") +def eval_makeboxes_standard_form(expr, evaluation): + from mathics.builtin.box.layout import FormBox, TagBox + + boxed = apply_makeboxes_rules(expr, evaluation, SymbolStandardForm) + boxed = FormBox(boxed, SymbolStandardForm) + boxed = TagBox(boxed, SymbolStandardForm, **{"System`Editable": SymbolTrue}) + return boxed + + +@is_print_form_callback("System`TraditionalForm") +def eval_makeboxes_traditional_form(expr, evaluation): + from mathics.builtin.box.layout import FormBox, TagBox + + boxed = apply_makeboxes_rules(expr, evaluation, SymbolTraditionalForm) + boxed = FormBox(boxed, SymbolTraditionalForm) + boxed = TagBox(boxed, SymbolTraditionalForm, **{"System`Editable": SymbolTrue}) + return boxed + + +def apply_makeboxes_rules( + expr: BaseElement, evaluation: Evaluation, form: Symbol = SymbolStandardForm +) -> BoxElementMixin: + """ + This function takes the definitions provided by the evaluation + object, and produces a boxed fullform for expr. + + Basically: MakeBoxes[expr, form] + """ + assert form in BOX_FORMS, f"{form} not in BOX_FORMS" + + def yield_rules(): + # Look + for lookup in (expr.get_lookup_name(), "System`MakeBoxes"): + definition = evaluation.definitions.get_definition(lookup) + for rule in definition.formatvalues.get("_MakeBoxes", []): + yield rule + + mb_expr = Expression(SymbolMakeBoxes, expr, form) + boxed = mb_expr + for rule in yield_rules(): + try: + boxed = rule.apply(mb_expr, evaluation, fully=False) + except OverflowError: + evaluation.message("General", "ovfl") + boxed = mb_expr + continue + if boxed is mb_expr or boxed is None or boxed.sameQ(mb_expr): + continue + if boxed is SymbolAborted: + return String("Aborted") + if isinstance(boxed, EvalMixin): + return boxed.evaluate(evaluation) + if isinstance(boxed, BoxElementMixin): + return boxed + return eval_generic_makeboxes(expr, form, evaluation) + + # TODO: evaluation is needed because `atom_to_boxes` uses it. Can we remove this # argument? +@is_print_form_callback("System`FullForm") def eval_makeboxes_fullform( - element: BaseElement, evaluation: Evaluation + element: BaseElement, evaluation: Evaluation, **kwargs +) -> BoxElementMixin: + from mathics.builtin.box.layout import StyleBox, TagBox + + result = eval_makeboxes_fullform_recursive(element, evaluation, **kwargs) + style_box = StyleBox( + result, + **{ + "System`ShowSpecialCharacters": SymbolFalse, + "System`ShowStringCharacters": SymbolTrue, + "System`NumberMarks": SymbolTrue, + }, + ) + return TagBox(style_box, SymbolFullForm) + + +def eval_makeboxes_fullform_recursive( + element: BaseElement, evaluation: Evaluation, **kwargs ) -> BoxElementMixin: """Same as MakeBoxes[FullForm[expr_], f_]""" from mathics.builtin.box.expression import BoxExpression @@ -90,7 +158,7 @@ def eval_makeboxes_fullform( head, elements = expr.head, expr.elements boxed_elements = tuple( - (eval_makeboxes_fullform(element, evaluation) for element in elements) + (eval_makeboxes_fullform_recursive(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 @@ -106,7 +174,7 @@ def eval_makeboxes_fullform( result_elements = [left] else: left, right, sep = (String(ch) for ch in ("[", "]", ",")) - result_elements = [eval_makeboxes_fullform(head, evaluation), left] + result_elements = [eval_makeboxes_fullform_recursive(head, evaluation), left] if len(boxed_elements) > 1: arguments: List[BoxElementMixin] = [] @@ -121,32 +189,24 @@ def eval_makeboxes_fullform( return RowBox(*result_elements) -def eval_makeboxes_outputform( - expr: BaseElement, evaluation: Evaluation, form: Symbol, **kwargs -): - """ - Build a 2D representation of the expression using only keyboard characters. - """ - from mathics.builtin.box.layout import PaneBox - from mathics.format.form.outputform import render_output_form - - text_outputform = str(render_output_form(expr, evaluation, **kwargs)) - elem1 = PaneBox(String('"' + text_outputform + '"')) - return elem1 - - def eval_generic_makeboxes(expr, f, evaluation): """MakeBoxes[expr_, f:TraditionalForm|StandardForm]""" from mathics.builtin.box.layout import RowBox + assert f in BOX_FORMS, f"{f} not in BOX_FORMS" if isinstance(expr, BoxElementMixin): expr = expr.to_expression() if isinstance(expr, Atom): return expr.atom_to_boxes(f, evaluation) + if expr.has_form("List", None): + return RowBox(*list_boxes(expr.elements, f, evaluation, "{", "}")) else: head = expr.head elements = expr.elements + printform_callback = PRINT_FORMS_CALLBACK.get(head.get_name(), None) + if printform_callback is not None: + return printform_callback(elements[0], evaluation) f_name = f.get_name() if f_name == "System`TraditionalForm": @@ -170,6 +230,7 @@ def eval_generic_makeboxes(expr, f, evaluation): "System`InputForm", "System`OutputForm", ): + raise ValueError sep = ", " else: sep = "," @@ -194,41 +255,41 @@ def eval_generic_makeboxes(expr, f, evaluation): return RowBox(*result) -def eval_makeboxes( - expr, evaluation: Evaluation, form=SymbolStandardForm -) -> BoxElementMixin: - """ - This function takes the definitions provided by the evaluation - object, and produces a boxed fullform for expr. - - Basically: MakeBoxes[expr // form] - """ - # This is going to be reimplemented. By now, much of the formatting - # relies in rules of the form `MakeBoxes[expr, OutputForm]` - # which is wrong. - if form is SymbolFullForm: - return eval_makeboxes_fullform(expr, evaluation) - if form not in BOX_FORMS: - # print(form, "not in", BOX_FORMS) - expr = Expression(form, expr) - form = SymbolStandardForm - mb_expr = Expression(SymbolMakeBoxes, expr, form) - # print(" evaluate", mb_expr) - return mb_expr.evaluate(evaluation) - - def format_element( element: BaseElement, evaluation: Evaluation, form: Symbol, **kwargs ) -> BoxElementMixin: """ Applies formats associated to the expression, and then calls Makeboxes """ - if form is SymbolFullForm: - return eval_makeboxes_fullform(element, evaluation) - evaluation.is_boxing = True formatted_expr = do_format(element, evaluation, form) - result_box = eval_makeboxes(formatted_expr, evaluation, form) + if form not in BOX_FORMS: + formatted_expr = Expression(form, formatted_expr) + form = SymbolStandardForm + result_box = apply_makeboxes_rules(formatted_expr, evaluation, form) if isinstance(result_box, BoxElementMixin): return result_box - return eval_makeboxes_fullform(element, evaluation) + return eval_makeboxes_fullform_recursive(element, evaluation) + + +def to_boxes(x, evaluation: Evaluation, options={}) -> BoxElementMixin: + """ + This function takes the expression ``x`` + and tries to reduce it to a ``BoxElementMixin`` + expression using an evaluation object. + """ + 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", 1, 2): + x_boxed = x.evaluate(evaluation) + if isinstance(x_boxed, BoxElementMixin): + return x_boxed + if isinstance(x_boxed, Atom): + return to_boxes(x_boxed, evaluation, options) + else: + return apply_makeboxes_rules(x, evaluation) + return eval_makeboxes_fullform_recursive(x, evaluation) diff --git a/mathics/format/box/outputforms.py b/mathics/format/box/outputforms.py index a653ee5f8..60d187f4d 100644 --- a/mathics/format/box/outputforms.py +++ b/mathics/format/box/outputforms.py @@ -1,18 +1,33 @@ import re from mathics.core.atoms import Integer, String +from mathics.core.element import BaseElement, BoxElementMixin +from mathics.core.evaluation import Evaluation from mathics.core.expression import BoxError, Expression from mathics.core.list import ListExpression -from mathics.core.symbols import SymbolFalse, SymbolFullForm, SymbolList -from mathics.core.systemsymbols import SymbolRowBox, SymbolTraditionalForm +from mathics.core.symbols import ( + Symbol, + SymbolFalse, + SymbolFullForm, + SymbolList, + SymbolTrue, +) +from mathics.core.systemsymbols import ( + SymbolMathMLForm, + SymbolTeXForm, + SymbolTraditionalForm, +) from mathics.eval.testing_expressions import expr_min -from mathics.format.box.makeboxes import format_element +from mathics.format.box.makeboxes import format_element, is_print_form_callback MULTI_NEWLINE_RE = re.compile(r"\n{2,}") -def eval_mathmlform(expr, evaluation) -> Expression: +@is_print_form_callback("System`MathMLForm") +def eval_mathmlform(expr: BaseElement, evaluation: Evaluation) -> BoxElementMixin: "MakeBoxes[MathMLForm[expr_], form_]" + from mathics.builtin.box.layout import InterpretationBox + boxes = format_element(expr, evaluation, SymbolTraditionalForm) try: mathml = boxes.boxes_to_mathml(evaluation=evaluation) @@ -34,14 +49,23 @@ def eval_mathmlform(expr, evaluation) -> Expression: mathml = '%s' % mathml mathml = '%s' % mathml # convert_box(boxes) - return Expression(SymbolRowBox, ListExpression(String(mathml))) + return InterpretationBox( + String(f'"{mathml}"'), + Expression(SymbolMathMLForm, expr), + **{"System`AutoDelete": SymbolTrue, "System`Editable": SymbolTrue}, + ) -def eval_tableform(self, table, f, evaluation, options): +def eval_tableform( + self, table: BaseElement, f: Symbol, evaluation: Evaluation, options +): """MakeBoxes[TableForm[table_], f_]""" from mathics.builtin.box.layout import GridBox from mathics.builtin.tensors import get_dimensions + if not isinstance(table, Expression): + return format_element(table, evaluation, f) + dims = len(get_dimensions(table, head=SymbolList)) depth = self.get_option(options, "TableDepth", evaluation, pop=True) options["System`TableDepth"] = depth @@ -93,7 +117,10 @@ def transform_item(item): return result -def eval_texform(expr, evaluation) -> Expression: +@is_print_form_callback("System`TeXForm") +def eval_texform(expr: BaseElement, evaluation: Evaluation) -> BoxElementMixin: + from mathics.builtin.box.layout import InterpretationBox + boxes = format_element(expr, evaluation, SymbolTraditionalForm) try: # Here we set ``show_string_characters`` to False, to reproduce @@ -114,4 +141,8 @@ def eval_texform(expr, evaluation) -> Expression: Expression(SymbolFullForm, expr).evaluate(evaluation), ) tex = "" - return Expression(SymbolRowBox, ListExpression(String(tex))) + return InterpretationBox( + String(f'"{tex}"'), + Expression(SymbolTeXForm, expr), + **{"System`AutoDelete": SymbolTrue, "System`Editable": SymbolTrue}, + ) diff --git a/mathics/format/render/latex.py b/mathics/format/render/latex.py index e432992ca..a24ee0447 100644 --- a/mathics/format/render/latex.py +++ b/mathics/format/render/latex.py @@ -17,6 +17,7 @@ from mathics.builtin.box.graphics import GraphicsBox from mathics.builtin.box.graphics3d import Graphics3DBox from mathics.builtin.box.layout import ( + FormBox, FractionBox, GridBox, InterpretationBox, @@ -663,8 +664,9 @@ def graphics3dbox(self, elements=None, **options) -> str: add_conversion_fn(Graphics3DBox, graphics3dbox) -def tag_box(self, **options): +def tag_and_form_box(self, **options): return lookup_conversion_method(self.boxed, "latex")(self.boxed, **options) -add_conversion_fn(TagBox, tag_box) +add_conversion_fn(FormBox, tag_and_form_box) +add_conversion_fn(TagBox, tag_and_form_box) diff --git a/mathics/format/render/mathml.py b/mathics/format/render/mathml.py index d48a2eb6f..e229e0c18 100644 --- a/mathics/format/render/mathml.py +++ b/mathics/format/render/mathml.py @@ -13,6 +13,7 @@ from mathics.builtin.box.graphics import GraphicsBox from mathics.builtin.box.graphics3d import Graphics3DBox from mathics.builtin.box.layout import ( + FormBox, FractionBox, GridBox, InterpretationBox, @@ -371,8 +372,9 @@ def graphics3dbox(self, elements=None, **options) -> str: add_conversion_fn(Graphics3DBox, graphics3dbox) -def tag_box(self, **options): +def tag_and_form_box(self, **options): return lookup_conversion_method(self.boxed, "mathml")(self.boxed, **options) -add_conversion_fn(TagBox, tag_box) +add_conversion_fn(FormBox, tag_and_form_box) +add_conversion_fn(TagBox, tag_and_form_box) diff --git a/mathics/format/render/text.py b/mathics/format/render/text.py index 59e9236c2..49a71a510 100644 --- a/mathics/format/render/text.py +++ b/mathics/format/render/text.py @@ -7,6 +7,7 @@ from mathics.builtin.box.graphics import GraphicsBox from mathics.builtin.box.graphics3d import Graphics3DBox from mathics.builtin.box.layout import ( + FormBox, FractionBox, GridBox, InterpretationBox, @@ -235,8 +236,9 @@ def graphics3dbox(self, elements=None, **options) -> str: add_conversion_fn(Graphics3DBox, graphics3dbox) -def tag_box(self, **options): +def tag_and_form_box(self, **options): return boxes_to_text(self.boxed, **options) -add_conversion_fn(TagBox, tag_box) +add_conversion_fn(FormBox, tag_and_form_box) +add_conversion_fn(TagBox, tag_and_form_box) diff --git a/test/builtin/box/test_custom_boxexpression.py b/test/builtin/box/test_custom_boxexpression.py index d3b36fdcb..aaac0e8d2 100644 --- a/test/builtin/box/test_custom_boxexpression.py +++ b/test/builtin/box/test_custom_boxexpression.py @@ -6,6 +6,7 @@ from mathics.core.builtin import Predefined from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression +from mathics.core.rules import BaseRule, FunctionApplyRule, Rule from mathics.core.symbols import Symbol SymbolCustomGraphicsBox = Symbol("CustomGraphicsBox") @@ -42,12 +43,28 @@ class CustomAtom(Predefined): "N[System`CustomAtom]": "37", } - def eval_to_boxes(self, evaluation): - "System`MakeBoxes[System`CustomAtom, StandardForm|TraditionalForm|OutputForm]" + # Since this is a Mathics3 Module which is loaded after + # the core symbols are loaded, it is safe to assume that `MakeBoxes` + # definition was already loaded. We can add then rules to it. + # This modified `contribute` method do that, adding specific + # makeboxes rules for this kind of atoms. + def contribute(self, definitions, is_pymodule=True): + super().contribute(definitions, is_pymodule) + # Add specific MakeBoxes rules + name = self.get_name() + + for pattern, function in self.get_functions("makeboxes_"): + mb_rule = FunctionApplyRule( + name, pattern, function, None, attributes=None, system=True + ) + definitions.add_format("System`MakeBoxes", mb_rule, "_MakeBoxes") + + def makeboxes_general(self, evaluation): + "System`MakeBoxes[System`CustomAtom, StandardForm|TraditionalForm]" return CustomBoxExpression(evaluation=evaluation) - def eval_to_boxes_inputform(self, evaluation): - "System`MakeBoxes[InputForm[System`CustomAtom], StandardForm|TraditionalForm|OutputForm]" + def makeboxes_inputform(self, evaluation): + "System`MakeBoxes[InputForm[System`CustomAtom], StandardForm|TraditionalForm]" return CustomBoxExpression(evaluation=evaluation) @@ -57,6 +74,22 @@ class CustomGraphicsBox(BoxExpression): options = GRAPHICS_OPTIONS attributes = A_HOLD_ALL | A_PROTECTED | A_READ_PROTECTED + # Since this is a Mathics3 Module which is loaded after + # the core symbols are loaded, it is safe to assume that `MakeBoxes` + # definition was already loaded. We can add then rules to it. + # This modified `contribute` method do that, adding specific + # makeboxes rules for this kind of BoxExpression. + def contribute(self, definitions, is_pymodule=True): + super().contribute(definitions, is_pymodule) + # Add specific MakeBoxes rules + name = self.get_name() + + for pattern, function in self.get_functions("makeboxes_"): + mb_rule = FunctionApplyRule( + name, pattern, function, None, attributes=None, system=True + ) + definitions.add_format("System`MakeBoxes", mb_rule, "_MakeBoxes") + def init(self, *elems, **options): self._elements = elems self.evaluation = options.pop("evaluation", None) @@ -65,16 +98,15 @@ def init(self, *elems, **options): def to_expression(self): return Expression(SymbolCustomGraphicsBox, *self.elements) - def eval_box(self, expr, evaluation: Evaluation, options: dict): + def makeboxes_graphics(self, expr, evaluation: Evaluation, options: dict): """System`MakeBoxes[System`Graphics[System`expr_, System`OptionsPattern[System`Graphics]], - System`StandardForm|System`TraditionalForm|System`OutputForm]""" + System`StandardForm|System`TraditionalForm]""" instance = CustomGraphicsBox(*(expr.elements), evaluation=evaluation) return instance - def eval_box_outputForm(self, expr, evaluation: Evaluation, options: dict): + def makeboxes_outputForm(self, expr, evaluation: Evaluation, options: dict): """System`MakeBoxes[System`OutputForm[System`Graphics[System`expr_, System`OptionsPattern[System`Graphics]]], System`StandardForm|System`TraditionalForm]""" - print("MakeBoxes OutputForm") instance = CustomGraphicsBox(*(expr.elements), evaluation=evaluation) return instance diff --git a/test/format/format_tests.yaml b/test/format/format_tests.yaml index a94ae3af1..b25b9c1f3 100644 --- a/test/format/format_tests.yaml +++ b/test/format/format_tests.yaml @@ -23,6 +23,7 @@ # because we use both in documentation and in the web interface. # + '"-7.32"': msg: A String with a number latex: @@ -813,6 +814,8 @@ TableForm[{{a,b},{c,d}}]: System`OutputForm: 'α' System`StandardForm: "α" System`TraditionalForm: "α" + + a: msg: A Symbol latex: @@ -867,3 +870,47 @@ a^4: System`OutputForm: a ^ 4 System`StandardForm: a^4 System`TraditionalForm: a^4 + + +Optional[x__]: + msg: Optional with one argument + latex: + System`OutputForm: '\text{x\_\_.}' + System`StandardForm: '\text{x\_\_.}' + mathml: + System`OutputForm: 'x__.' + System`StandardForm: 'x__.' + text: + System`InputForm: '(x__.)' + System`OutputForm: 'x__.' + System`StandardForm: 'x__.' + System`TraditionalForm: 'x__.' + + +Optional[x__, a+b]: + msg: Optional with two arguments + latex: + System`OutputForm: ' \text{x\_\_ : a + b}' + System`StandardForm: '\text{x\_\_}:a+b' + mathml: + System`OutputForm: 'x__ : a + b' + text: + System`InputForm: 'x__ : a + b' + System`OutputForm: 'x__ : a + b' + System`StandardForm: 'x__:a+b' + System`TraditionalForm: 'x__:a+b' + + +a+PrecedenceForm[b+c,10]: + msg: "PrecedenceForm" + latex: + System`OutputForm: '\text{a + (b + c)}' + System`StandardForm: 'a+\left(b+c\right)' + mathml: + System`OutputForm: 'a + (b + c)' + System`StandardForm: 'a + ( b + c )' + text: + System`InputForm: 'a + (PrecedenceForm[b + c, 10])' + System`OutputForm: 'a + (b + c)' + System`StandardForm: 'a+(b+c)' + System`TraditionalForm: 'a+(b+c)' diff --git a/test/format/makeboxes_tests.yaml b/test/format/makeboxes_tests.yaml index 23d2e5990..4363450bb 100644 --- a/test/format/makeboxes_tests.yaml +++ b/test/format/makeboxes_tests.yaml @@ -65,10 +65,10 @@ Basic Forms: Arithmetic: FullForm: - expect: TagBox[StyleBox[RowBox[{"Plus", "[", RowBox[{"a", ",", RowBox[{"Times", "[", RowBox[{RowBox[{"-", "1"}], ",", "b"}], "]"}]}], "]"}], ShowSpecialCharacters-> False, ShowStringCharacters -> True, NumberMarks -> True], FullForm] + expect: 'TagBox[StyleBox[RowBox[{"Plus", "[", RowBox[{"a", ",", RowBox[{"Times", "[", RowBox[{RowBox[{"-", "1"}], ",", "b"}], "]"}]}], "]"}], System`ShowSpecialCharacters-> False, System`ShowStringCharacters -> True, System`NumberMarks -> True], FullForm]' expr: MakeBoxes[a-b//FullForm] InputForm: - expect: InterpretationBox[StyleBox["a - b", ShowStringCharacters -> True, NumberMarks-> True], InputForm[a - b], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["a - b", System`ShowStringCharacters -> True, NumberMarks-> True], InputForm[a - b], Editable -> True, AutoDelete -> True] expr: MakeBoxes[a-b//InputForm] OutputForm: expect: InterpretationBox[PaneBox["\"a - b\""], OutputForm[a - b], Editable-> False] @@ -87,10 +87,10 @@ Basic Forms: expect: TagBox[FormBox[RowBox[List["F", "(", "x", ")"]], TraditionalForm], TraditionalForm, Editable-> True] expr: MakeBoxes[F[x]//TraditionalForm] FullForm: - expect: TagBox[StyleBox[RowBox[{"F", "[", "x", "]"}], ShowSpecialCharacters-> False, ShowStringCharacters -> True, NumberMarks -> True], FullForm] + expect: TagBox[StyleBox[RowBox[{"F", "[", "x", "]"}], ShowSpecialCharacters-> False, System`ShowStringCharacters -> True, System`NumberMarks -> True], FullForm] expr: MakeBoxes[F[x]//FullForm] InputForm: - expect: InterpretationBox[StyleBox["F[x]", ShowStringCharacters -> True, NumberMarks-> True], InputForm[F[x]], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["F[x]", System`ShowStringCharacters -> True, NumberMarks-> True], InputForm[F[x]], Editable -> True, AutoDelete -> True] expr: MakeBoxes[F[x]//InputForm] OutputForm: expect: InterpretationBox[PaneBox["\"F[x]\""], OutputForm[F[x]], Editable ->False] @@ -103,10 +103,10 @@ Basic Forms: expr: MakeBoxes[F[x]//TeXForm] Integer_negative: FullForm: - expect: TagBox[StyleBox[RowBox[{"-", "14"}], ShowSpecialCharacters-> False, ShowStringCharacters -> True, NumberMarks -> True], FullForm] + expect: TagBox[StyleBox[RowBox[{"-", "14"}], ShowSpecialCharacters-> False, System`ShowStringCharacters -> True, System`NumberMarks -> True], FullForm] expr: MakeBoxes[-14//FullForm] InputForm: - expect: InterpretationBox[StyleBox["-14", ShowStringCharacters -> True, NumberMarks -> True], InputForm[-14], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["-14", System`ShowStringCharacters -> True, System`NumberMarks -> True], InputForm[-14], Editable -> True, AutoDelete -> True] expr: MakeBoxes[-14//InputForm] OutputForm: expect: InterpretationBox[PaneBox["\"-14\""], OutputForm[-14], Editable -> False] @@ -119,10 +119,10 @@ Basic Forms: expr: MakeBoxes[-14//TeXForm] Integer_positive: FullForm: - expect: TagBox[StyleBox["14", ShowSpecialCharacters -> False, ShowStringCharacters-> True, NumberMarks -> True], FullForm] + expect: TagBox[StyleBox["14", System`ShowSpecialCharacters -> False, System`ShowStringCharacters-> True, System`NumberMarks -> True], FullForm] expr: MakeBoxes[14//FullForm] InputForm: - expect: InterpretationBox[StyleBox["14", ShowStringCharacters -> True, NumberMarks-> True], InputForm[14], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["14", System`ShowStringCharacters -> True, NumberMarks-> True], InputForm[14], Editable -> True, AutoDelete -> True] expr: MakeBoxes[14//InputForm] OutputForm: expect: InterpretationBox[PaneBox["\"14\""], OutputForm[14], Editable -> False] @@ -135,12 +135,12 @@ Basic Forms: expr: MakeBoxes[14//TeXForm] PrecisionReal: FullForm: - expect: TagBox[StyleBox[RowBox[{"-", "14.`3."}], ShowSpecialCharacters -> False, ShowStringCharacters-> True, NumberMarks -> True], FullForm] + expect: TagBox[StyleBox[RowBox[{"-", "14.`3."}], System`ShowSpecialCharacters -> False, System`ShowStringCharacters-> True, System`NumberMarks -> True], FullForm] expr: MakeBoxes[-14.`3//FullForm] msg: "In Mathics3, precision is always an integer number." InputForm: expr: MakeBoxes[-14.`3//InputForm] - expect: InterpretationBox[StyleBox["-14.`3.", ShowStringCharacters -> True, NumberMarks-> True], InputForm[-14.`3], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["-14.`3.", System`ShowStringCharacters -> True, NumberMarks-> True], InputForm[-14.`3], Editable -> True, AutoDelete -> True] OutputForm: expect: InterpretationBox[PaneBox["\"-14.\""], OutputForm[-14.0], Editable-> False] expr: MakeBoxes[-14.0//OutputForm] @@ -153,10 +153,10 @@ Basic Forms: -> True] Symbol: FullForm: - expect: TagBox[StyleBox["x", ShowSpecialCharacters -> False, ShowStringCharacters-> True, NumberMarks -> True], FullForm] + expect: TagBox[StyleBox["x", System`ShowSpecialCharacters -> False, System`ShowStringCharacters-> True, System`NumberMarks -> True], FullForm] expr: MakeBoxes[x//FullForm] InputForm: - expect: InterpretationBox[StyleBox["x", ShowStringCharacters -> True, NumberMarks-> True], InputForm[x], Editable -> True, AutoDelete -> True] + expect: InterpretationBox[StyleBox["x", System`ShowStringCharacters -> True, NumberMarks-> True], InputForm[x], Editable -> True, AutoDelete -> True] expr: MakeBoxes[x//InputForm] OutputForm: expect: InterpretationBox[PaneBox["\"x\""], OutputForm[x], Editable -> False] diff --git a/test/format/test_makeboxes.py b/test/format/test_makeboxes.py index e4a1386b1..31b39a6bf 100644 --- a/test/format/test_makeboxes.py +++ b/test/format/test_makeboxes.py @@ -28,8 +28,8 @@ def makeboxes_basic_forms_iterator(block): for key, tests in MAKEBOXES_TESTS[block].items(): for form, entry in tests.items(): msg = f"{key}, {form}" - expr = entry["expr"] - expect = entry["expect"] + expr = entry["expr"] + "//InputForm" + expect = entry["expect"] + "//InputForm" yield expr, expect, msg @@ -44,7 +44,7 @@ def test_makeboxes_basic_forms(str_expr, str_expected, fail_msg): str_expected, to_string_expr=True, to_string_expected=True, - hold_expected=True, + hold_expected=False, failure_message=fail_msg, ) @@ -62,7 +62,7 @@ def test_makeboxes_real(str_expr, str_expected, msg): str_expected, to_string_expr=True, to_string_expected=True, - hold_expected=True, + hold_expected=False, failure_message=msg, ) diff --git a/test/helper.py b/test/helper.py index f9df14b31..0baa2205c 100644 --- a/test/helper.py +++ b/test/helper.py @@ -126,10 +126,10 @@ def check_evaluation( print(time.asctime()) if failure_message: - print(f"got: {result}, expect: {expected} -- {failure_message}") + print(f"got: \n{result}\nexpect:\n{expected}\n -- {failure_message}") assert result == expected, failure_message else: - print(f"got: {result}, expect: {expected}") + print(f"got: \n{result}\nexpect:\n{expected}\n --") if isinstance(expected, re.Pattern): assert expected.match(result) else: