Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty print #1162

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions mathics/builtin/arithfns/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Integer1,
Integer3,
Integer310,
Integer400,
IntegerM1,
Number,
Rational,
Expand Down Expand Up @@ -48,6 +49,7 @@
SymbolNull,
SymbolPower,
SymbolTimes,
SymbolTrue,
)
from mathics.core.systemsymbols import (
SymbolBlank,
Expand Down Expand Up @@ -152,7 +154,7 @@ class Divide(InfixOperator):
default_formats = False

formats = {
(("InputForm", "OutputForm"), "Divide[x_, y_]"): (
("InputForm", "Divide[x_, y_]"): (
'Infix[{HoldForm[x], HoldForm[y]}, "/", 400, Left]'
),
}
Expand All @@ -166,9 +168,26 @@ class Divide(InfixOperator):
"FractionBox[MakeBoxes[x, f], MakeBoxes[y, f]]"
),
}

summary_text = "divide"

def format_outputform(self, x, y, evaluation):
"OutputForm: Divide[x_, y_]"
use_2d = (
evaluation.definitions.get_ownvalues("System`$Use2DOutputForm")[0].replace
is SymbolTrue
)
if not use_2d:
return Expression(
SymbolInfix,
ListExpression(
Expression(SymbolHoldForm, x), Expression(SymbolHoldForm, y)
),
String("/"),
Integer400,
SymbolLeft,
)
return None


class Minus(PrefixOperator):
"""
Expand Down Expand Up @@ -406,10 +425,21 @@ class Power(InfixOperator, MPMathFunction):
Expression(SymbolPattern, Symbol("x"), Expression(SymbolBlank)),
RationalOneHalf,
): "HoldForm[Sqrt[x]]",
(("InputForm", "OutputForm"), "x_ ^ y_"): (
(("InputForm",), "x_ ^ y_"): (
'Infix[{HoldForm[x], HoldForm[y]}, "^", 590, Right]'
),
("", "x_ ^ y_"): (
(("OutputForm",), "x_ ^ y_"): (
"If[$Use2DOutputForm, "
"Superscript[HoldForm[x], HoldForm[y]], "
'Infix[{HoldForm[x], HoldForm[y]}, "^", 590, Right]]'
),
(
(
"StandardForm",
"TraditionalForm",
),
"x_ ^ y_",
): (
"PrecedenceForm[Superscript[PrecedenceForm[HoldForm[x], 590],"
" HoldForm[y]], 590]"
),
Expand Down
28 changes: 28 additions & 0 deletions mathics/builtin/box/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class GridBox(BoxExpression):
# >> MathMLForm[TableForm[{{a,b},{c,d}}]]
# = ...
"""

options = {"ColumnAlignments": "Center"}
summary_text = "low-level representation of an arbitrary 2D layout"

Expand Down Expand Up @@ -211,6 +212,33 @@ def eval_display(boxexpr, evaluation):
return boxexpr.elements[0]


class PaneBox(BoxExpression):
"""
<url>
:WMA link:
https://reference.wolfram.com/language/ref/InterpretationBox.html</url>

<dl>
<dt>'PaneBox[expr]'
<dd> is a low-level box construct, used in OutputForm.
</dl>

"""

attributes = A_HOLD_ALL_COMPLETE | A_PROTECTED | A_READ_PROTECTED
summary_text = "box associated to panel"

def apply_display(boxexpr, evaluation, expression):
"""ToExpression[boxexpr_PaneBox, form_]"""
return Expression(expression.head, boxexpr.elements[0], form).evaluate(
evaluation
)

def apply_display(boxexpr, evaluation):
"""DisplayForm[boxexpr_PaneBox]"""
return boxexpr.elements[0]


class RowBox(BoxExpression):
"""
<url>
Expand Down
22 changes: 20 additions & 2 deletions mathics/builtin/forms/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
from math import ceil
from typing import Optional

from mathics.builtin.box.layout import GridBox, RowBox, to_boxes
from mathics.builtin.box.layout import (
GridBox,
InterpretationBox,
PaneBox,
RowBox,
to_boxes,
)
from mathics.builtin.forms.base import FormBaseClass
from mathics.builtin.makeboxes import MakeBoxes, NumberForm_to_String
from mathics.builtin.tensors import get_dimensions
Expand Down Expand Up @@ -54,11 +60,13 @@
SymbolOutputForm,
SymbolRowBox,
SymbolRuleDelayed,
SymbolStandardForm,
SymbolSubscriptBox,
SymbolSuperscriptBox,
)
from mathics.eval.makeboxes import StringLParen, StringRParen, format_element
from mathics.eval.testing_expressions import expr_min
from mathics.format.prettyprint import expression_to_2d_text

MULTI_NEWLINE_RE = re.compile(r"\n{2,}")

Expand Down Expand Up @@ -561,8 +569,18 @@ class OutputForm(FormBaseClass):
= -Graphics-
"""

formats = {"OutputForm[s_String]": "s"}
summary_text = "plain-text output format"

def eval_makeboxes(self, expr, form, evaluation):
"""MakeBoxes[OutputForm[expr_], form_]"""
print(" eval Makeboxes outputform")
text2d = str(expression_to_2d_text(expr, evaluation, form))
elem1 = PaneBox(String(text2d))
elem2 = Expression(SymbolOutputForm, expr)
result = InterpretationBox(elem1, elem2)
return result


class PythonForm(FormBaseClass):
"""
Expand Down Expand Up @@ -707,7 +725,7 @@ class TeXForm(FormBaseClass):

def eval_tex(self, expr, evaluation) -> Expression:
"MakeBoxes[expr_, TeXForm]"
boxes = MakeBoxes(expr).evaluate(evaluation)
boxes = format_element(expr, evaluation, SymbolStandardForm)
try:
# Here we set ``show_string_characters`` to False, to reproduce
# the standard behaviour in WMA. Remove this parameter to recover the
Expand Down
38 changes: 37 additions & 1 deletion mathics/builtin/forms/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,47 @@

"""

from mathics.core.attributes import A_LOCKED, A_PROTECTED
from mathics.core.attributes import A_LOCKED, A_NO_ATTRIBUTES, A_PROTECTED
from mathics.core.builtin import Predefined
from mathics.core.list import ListExpression


class Use2DOutputForm_(Predefined):
r"""
<dl>
<dt>'$Use2DOutputForm'
<dd>internal variable that controls if 'OutputForm[expr]' is shown \
in one line (standard Mathics behavior) or \
or in a prettyform-like multiline output (the standard way in WMA).
The default value is 'False', keeping the standard Mathics behavior.
</dl>

>> $Use2DOutputForm
= False
>> OutputForm[a^b]
= a ^ b
>> $Use2DOutputForm = True; OutputForm[a ^ b]
=
. b
. a

Notice that without the 'OutputForm' wrapper, we fall back to the normal
behavior:
>> a ^ b
= Superscript[a, b]
Setting the variable back to False go back to the normal behavior:
>> $Use2DOutputForm = False; OutputForm[a ^ b]
= a ^ b
"""

attributes = A_NO_ATTRIBUTES
name = "$Use2DOutputForm"
rules = {
"$Use2DOutputForm": "False",
}
summary_text = "use the 2D OutputForm"


class PrintForms_(Predefined):
r"""
<dl>
Expand Down
1 change: 1 addition & 0 deletions mathics/core/atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ def is_zero(self) -> bool:
Integer2 = Integer(2)
Integer3 = Integer(3)
Integer310 = Integer(310)
Integer400 = Integer(400)
Integer10 = Integer(10)
IntegerM1 = Integer(-1)

Expand Down
26 changes: 26 additions & 0 deletions mathics/eval/makeboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@
SymbolRepeated,
SymbolRepeatedNull,
SymbolTimes,
SymbolTrue,
)
from mathics.core.systemsymbols import (
SymbolComplex,
SymbolMinus,
SymbolOutputForm,
SymbolRational,
SymbolRowBox,
SymbolStandardForm,
SymbolTraditionalForm,
)

# An operator precedence value that will ensure that whatever operator
Expand Down Expand Up @@ -203,12 +206,35 @@ def eval_makeboxes(
return Expression(SymbolMakeBoxes, expr, form).evaluate(evaluation)


def make_output_form(expr, evaluation, form):
"""
Build a 2D text representation of the expression.
"""
from mathics.builtin.box.layout import InterpretationBox, PaneBox
from mathics.format.prettyprint import expression_to_2d_text

use_2d = (
evaluation.definitions.get_ownvalues("System`$Use2DOutputForm")[0].replace
is SymbolTrue
)
text2d = str(expression_to_2d_text(expr, evaluation, form, **{"2d": use_2d}))

if "\n" in text2d:
text2d = "\n" + text2d
elem1 = PaneBox(String(text2d))
elem2 = Expression(SymbolOutputForm, expr)
return InterpretationBox(elem1, elem2)


def format_element(
element: BaseElement, evaluation: Evaluation, form: Symbol, **kwargs
) -> Optional[BaseElement]:
"""
Applies formats associated to the expression, and then calls Makeboxes
"""
if element.has_form("OutputForm", 1):
return make_output_form(element.elements[0], evaluation, form)

expr = do_format(element, evaluation, form)
if expr is None:
return None
Expand Down
12 changes: 12 additions & 0 deletions mathics/format/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from mathics.builtin.box.layout import (
FractionBox,
GridBox,
InterpretationBox,
PaneBox,
RowBox,
SqrtBox,
StyleBox,
Expand Down Expand Up @@ -142,6 +144,16 @@ def render(format, string, in_text=False):
add_conversion_fn(String, string)


def interpretation_panebox(self, **options):
return lookup_conversion_method(self.elements[0], "latex")(
self.elements[0], **options
)


add_conversion_fn(InterpretationBox, interpretation_panebox)
add_conversion_fn(PaneBox, interpretation_panebox)


def fractionbox(self, **options) -> str:
_options = self.box_options.copy()
_options.update(options)
Expand Down
12 changes: 12 additions & 0 deletions mathics/format/mathml.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from mathics.builtin.box.layout import (
FractionBox,
GridBox,
InterpretationBox,
PaneBox,
RowBox,
SqrtBox,
StyleBox,
Expand Down Expand Up @@ -110,6 +112,16 @@ def render(format, string):
add_conversion_fn(String, string)


def interpretation_panebox(self, **options):
return lookup_conversion_method(self.elements[0], "latex")(
self.elements[0], **options
)


add_conversion_fn(InterpretationBox, interpretation_panebox)
add_conversion_fn(PaneBox, interpretation_panebox)


def fractionbox(self, **options) -> str:
_options = self.box_options.copy()
_options.update(options)
Expand Down
Loading
Loading