Skip to content
Merged
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
28 changes: 10 additions & 18 deletions mathics/builtin/assignments/clear.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,13 @@
)
from mathics.core.builtin import Builtin, PostfixOperator
from mathics.core.expression import Expression
from mathics.core.symbols import Atom, Symbol, SymbolNull, symbol_set
from mathics.core.symbols import Atom, Symbol, SymbolNull
from mathics.core.systemsymbols import (
SYSTEM_SYMBOL_VALUES,
SymbolContext,
SymbolContextPath,
SymbolDownValues,
SymbolFailed,
SymbolMessages,
SymbolNValues,
SymbolOptions,
SymbolOwnValues,
SymbolSubValues,
SymbolUpValues,
)


Expand Down Expand Up @@ -258,7 +253,6 @@ class Unset(PostfixOperator):

def eval(self, expr, evaluation):
"Unset[expr_]"

head = expr.get_head()
if head in SYSTEM_SYMBOL_VALUES:
if len(expr.elements) != 1:
Expand All @@ -284,13 +278,11 @@ def eval(self, expr, evaluation):
return SymbolFailed
return SymbolNull


SYSTEM_SYMBOL_VALUES = symbol_set(
SymbolDownValues,
SymbolMessages,
SymbolNValues,
SymbolOptions,
SymbolOwnValues,
SymbolSubValues,
SymbolUpValues,
)
def eval_unset_makeboxes(self, expr, evaluation):
"Unset[expr:MakeBoxes[_, _]]"
if not evaluation.definitions.unset_format(
"System`MakeBoxes", "_MakeBoxes", expr
):
evaluation.message("Unset", "norep", expr, Symbol("System`MakeBoxes"))
return SymbolFailed
return SymbolNull
5 changes: 3 additions & 2 deletions mathics/builtin/forms/print.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from mathics.core.expression import Expression
from mathics.core.symbols import SymbolFalse, SymbolTrue
from mathics.core.systemsymbols import SymbolInputForm, SymbolOutputForm
from mathics.format.box.formatvalues import do_format_element
from mathics.format.box.makeboxes import is_print_form_callback
from mathics.format.form import render_input_form, render_output_form

Expand Down Expand Up @@ -256,8 +257,8 @@ def eval_makeboxes_outputform(expr: BaseElement, evaluation: Evaluation, **kwarg
"""
Build a 2D representation of the expression using only keyboard characters.
"""

text_outputform = str(render_output_form(expr, evaluation, **kwargs))
f_expr = do_format_element(expr, evaluation, SymbolOutputForm)
text_outputform = str(render_output_form(f_expr, evaluation, **kwargs))
pane = PaneBox(String('"' + text_outputform + '"'))
return InterpretationBox(
pane, Expression(SymbolOutputForm, expr), **{"System`Editable": SymbolFalse}
Expand Down
15 changes: 12 additions & 3 deletions mathics/core/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,22 @@ def get_symbol_values(
except KeyError:
return ListExpression()

elements = []
elements: list[BaseElement] = []

if position == "formatvalues":
format_rules = definition.formatvalues
for key, rules in format_rules.items():
if key == "System`MakeBoxes":
elements.extend(rules)
if key == "_MakeBoxes":
elements.extend(
(
Expression(
SymbolRuleDelayed,
Expression(SymbolHoldPattern, rule.pattern.expr),
rule.replace,
)
for rule in rules
)
)
continue
if key:
elements.extend(
Expand Down
18 changes: 18 additions & 0 deletions mathics/core/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ def add_rule(self, rule: BaseRule) -> bool:
return self.add_rule_at(rule, pos)
return False

def remove_format_rule(self, lhs: BaseElement, form: str) -> bool:
"""Remove a rule"""
format_rule_list = self.formatvalues.get(form, [])
for index, existing in enumerate(format_rule_list):
if existing.pattern.expr.sameQ(lhs):
del format_rule_list[index]
return True
return False

def remove_rule(self, lhs: BaseElement) -> bool:
"""Remove a rule"""
position = get_tag_position(lhs, self.name)
Expand Down Expand Up @@ -810,6 +819,15 @@ def unset(self, name: str, expr: BaseElement) -> bool:
self.clear_definitions_cache(name)
return result

def unset_format(self, name: str, form: str, expr: BaseElement) -> bool:
"""Remove the rule corresponding to the expression `expr` in
the format `form` of the Definition `name`"""
definition = self.get_user_definition(self.lookup_name(name))
result = definition.remove_format_rule(expr, form)
self.mark_changed(definition)
self.clear_definitions_cache(name)
return result

def get_config_value(
self, name: str, default: Optional[int] = None
) -> Optional[int]:
Expand Down
10 changes: 10 additions & 0 deletions mathics/core/systemsymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,13 @@
SymbolRepeated,
SymbolRepeatedNull,
)

SYSTEM_SYMBOL_VALUES = symbol_set(
SymbolDownValues,
SymbolMessages,
SymbolNValues,
SymbolOptions,
SymbolOwnValues,
SymbolSubValues,
SymbolUpValues,
)
20 changes: 13 additions & 7 deletions mathics/format/box/formatvalues.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
SymbolRepeatedNull,
SymbolTimes,
)
from mathics.core.systemsymbols import SymbolMinus
from mathics.core.systemsymbols import SymbolInputForm, SymbolMinus, SymbolOutputForm

# These Strings are used in Boxing output
StringElipsis = String("...")
Expand Down Expand Up @@ -74,12 +74,18 @@ def do_format_element(
head = element.get_head() # use element.head
elements = element.get_elements()
include_form = False
# If the expression is enclosed by a Format
# takes the form from the expression and
# removes the format from the expression.
if head in OUTPUT_FORMS and len(elements) == 1 and isinstance(head, Symbol):
expr = elements[0]
if not form.sameQ(head):

if elements is not None and len(elements) == 1:
# Special cases: SymbolInputForm and SymbolOutputForm
# are only processed from MakeBoxes, using the explicit
# form parameter.
if head in (SymbolInputForm, SymbolOutputForm):
return expr
# If the expression is enclosed by other Format
# takes the form from the expression and
# removes the format from the expression.
if head in OUTPUT_FORMS and isinstance(head, Symbol):
expr = elements[0]
form = head
include_form = True

Expand Down
9 changes: 8 additions & 1 deletion mathics/format/box/makeboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from mathics.core.systemsymbols import ( # SymbolRule, SymbolRuleDelayed,
SymbolAborted,
SymbolComplex,
SymbolInputForm,
SymbolOutputForm,
SymbolParentForm,
SymbolRational,
SymbolStandardForm,
Expand Down Expand Up @@ -332,7 +334,12 @@ def format_element(
"""
was_boxing = evaluation.is_boxing
evaluation.is_boxing = True
formatted_expr = do_format(element, evaluation, form)
# InputForm and OutputForm do format in the MakeBoxes implementation.
if form in (SymbolInputForm, SymbolOutputForm):
formatted_expr = element
else:
formatted_expr = do_format(element, evaluation, form)

if form not in evaluation.definitions.boxforms:
formatted_expr = Expression(form, formatted_expr)
form = SymbolStandardForm
Expand Down
9 changes: 9 additions & 0 deletions mathics/format/form/inputform.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ def _infix_expression_to_inputform_text(
return result


@register_inputform("System`OutputForm")
def outputform(expr: Expression, evaluation: Evaluation, **kwargs):
from .outputform import render_output_form

if len(expr.elements) != 1:
raise _WrongFormattedExpression
return render_output_form(expr.elements[0], evaluation, **kwargs)


@register_inputform("System`Prefix")
def _prefix_expression_to_inputform_text(
expr: Expression, evaluation: Evaluation, **kwargs
Expand Down
4 changes: 3 additions & 1 deletion mathics/format/form/outputform.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,9 @@ def _infix_outputform_text(expr: Expression, evaluation: Evaluation, **kwargs) -

@register_outputform("System`InputForm")
def inputform(expr: Expression, evaluation: Evaluation, **kwargs):
return render_input_form(expr, evaluation, **kwargs)
if len(expr.elements) != 1:
raise _WrongFormattedExpression
return render_input_form(expr.elements[0], evaluation, **kwargs)


@register_outputform("System`List")
Expand Down
10 changes: 6 additions & 4 deletions test/format/test_makeboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ def test_makeboxes_others_fail(str_expr, str_expected, msg):
@pytest.mark.parametrize(
("str_expr", "str_expected", "msg"),
[
(None, None, None),
(
r"MakeBoxes[G[F[2.]], StandardForm]",
r'RowBox[{"G","[",RowBox[{"F","[","2.`","]"}],"]"}]',
Expand Down Expand Up @@ -199,7 +200,7 @@ def test_makeboxes_others_fail(str_expr, str_expected, msg):
),
(
r"MakeBoxes[OutputForm[G[F[3.002]]], StandardForm]",
r'InterpretationBox[PaneBox["\"G[{Formatted f, {3.002}, Standard}]\""], G[{Formatted f, {3.002}, Standard}], Editable -> False]',
r'InterpretationBox[PaneBox["\"G[{Formatted f, {3.002}, Standard}]\""], OutputForm[G[F[3.002]]], Editable -> False]',
"with the defined OutputForm",
),
(
Expand All @@ -215,7 +216,7 @@ def test_makeboxes_others_fail(str_expr, str_expected, msg):
# InterpretationBox is now used here... = InterpretationBox[PaneBox["\"G[{Formatted f, {3.002}, Output}]\""], OutputForm[G[F[3.002`]]], Rule[Editable, False]]
(
r"MakeBoxes[OutputForm[G[F[3.002]]], StandardForm]",
r'RowBox[{"G","[",RowBox[{"{",RowBox[{"\"Formatted f\"",", ",RowBox[{"{","3.002","}"}],", ","\"Standard\""}],"}"}],"]"}]',
r'InterpretationBox[PaneBox["\"G[{Formatted f, {3.002}, Output}]\""], OutputForm[G[F[3.002]]], Rule[Editable, False]]',
"Test Custom OutputForm",
),
(
Expand All @@ -225,8 +226,8 @@ def test_makeboxes_others_fail(str_expr, str_expected, msg):
),
(
r"MakeBoxes[F[x_], fmt_]=.; MakeBoxes[G[F[2.]], StandardForm]",
r'RowBox[{"G","[",RowBox[{"F","[","2.","]"}],"]"}]',
"Clear MakeBoxes rule",
r'RowBox[{"G", "[", RowBox[{"F", "[", "2.`", "]"}], "]"}]',
"Clear MakeBoxes rule - Fails because <<MakeBoxes[F[x_], fmt_]>> does not clear the rule.",
),
],
)
Expand Down Expand Up @@ -260,6 +261,7 @@ def test_makeboxes_custom(str_expr, str_expected, msg):
@pytest.mark.parametrize(
("str_expr", "str_expected", "msg"),
[
(None, None, None),
(
r'MakeBoxes[F[x__], fmt_] := RowBox[{"F", "<~", RowBox[MakeBoxes[#1, fmt] & /@ List[x]], "~>"}]',
"Null",
Expand Down
Loading