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
3 changes: 2 additions & 1 deletion mathics/core/parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
MathicsMultiLineFeeder,
MathicsSingleLineFeeder,
)
from mathics.core.parser.operators import all_operator_names
from mathics.core.parser.operators import all_operator_names, operator_precedences
from mathics.core.parser.util import parse, parse_builtin_rule

__all__ = [
Expand All @@ -29,6 +29,7 @@
"MathicsSingleLineFeeder",
"all_operator_names",
"is_symbol_name",
"operator_precedences",
"parse",
"parse_builtin_rule",
]
2 changes: 1 addition & 1 deletion mathics/eval/makeboxes/makeboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def eval_makeboxes_outputform(expr, evaluation, form, **kwargs):
Build a 2D representation of the expression using only keyboard characters.
"""
from mathics.builtin.box.layout import PaneBox
from mathics.format.outputform import expression_to_outputform_text
from mathics.form.outputform import expression_to_outputform_text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the right place for outputform.py would be inside eval/makeboxes, like inputform.py. mathics.format contains modules to convert (Boxed) expressions into strings in different representations (plane text, latex, mathml). OutputForm (and InputForm) does something similar, but on (norma) expressions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some level, it does not matter that much other than "Form" handling and rendering are different concepts and levels; so mathics.format is definitely the wrong place.

Personally, I think of mathics.eval having code to implement the primitives of built-in functions.

Of course, there are primitives for boxing. So, sure, this fits into this category. However...

Boxing is considered its own phase. And while it is a kind of evaluation too, it is not the kind of primitive used for addition and multiplication, which must be implemented in Python, SymPy, etc.

In theory, Boxing could be written purely as Mathics3 or WMA code. And there is enough of it that, in my opinion, we'd be better off just putting that in its own place.

But again, other than it not being part of mathics.format, I don't have a strong feeling like this. Aesthetically, I think it is just better put in mathics.form.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some level, it does not matter that much other than "Form" handling and rendering are different concepts and levels; so mathics.format is definitely the wrong place.

At this point, I agree.

Personally, I think of mathics.eval having code to implement the primitives of built-in functions.

Of course, there are primitives for boxing. So, sure, this fits into this category. However...

Boxing is considered its own phase. And while it is a kind of evaluation too, it is not the kind of primitive used for addition and multiplication, which must be implemented in Python, SymPy, etc.

OK, but we have a specific submodule for Box evaluations

In theory, Boxing could be written purely as Mathics3 or WMA code. And there is enough of it that, in my opinion, we'd be better off just putting that in its own place.

If in principle that is true, it is also true that we could implement in WL most of the code inside "eval". However, would be unnecesarily complicated and very slow.

But again, other than it not being part of mathics.format, I don't have a strong feeling like this. Aesthetically, I think it is just better put in mathics.form.

I do not have strong feelings about this either, just an argument: from the point of view of code organization, it appears that we would have a lot of space for the different steps of formatting. On the other hand, the complexity inside would not be comparable with the one in core, builtin or eval.

Copy link
Member Author

@rocky rocky Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some level, it does not matter that much other than "Form" handling and rendering are different concepts and levels; so mathics.format is definitely the wrong place.

At this point, I agree.

Personally, I think of mathics.eval having code to implement the primitives of built-in functions.
Of course, there are primitives for boxing. So, sure, this fits into this category. However...
Boxing is considered its own phase. And while it is a kind of evaluation too, it is not the kind of primitive used for addition and multiplication, which must be implemented in Python, SymPy, etc.

OK, but we have a specific submodule for Box evaluations

Personally, I'd like the boxing and form stuff put somewhere else, since I think of eval as more of the kind of stuff that a compiler would work on.

In theory, Boxing could be written purely as Mathics3 or WMA code. And there is enough of it that, in my opinion, we'd be better off just putting that in its own place.

If in principle that is true, it is also true that we could implement in WL most of the code inside "eval". However, would be unnecesarily complicated and very slow.

So, again this is the kind of thing, in my view of the code organization that should distinguish eval from other parts. Stuff that really has to be done in Python (Sympy, numpy, etc.) is definitely in eval. Stuff that could easily be done in WMA, is somewhere else; especially if it is a well-defined "phase". There may be gray areas in the middle.

Analogy: think of "eval" as "physics". But there is "chemistry" and "organic chemistry" as more like "boxing" and "forms". While this could be put under the category of "physics", typically we don't do it in that way

But again, other than it not being part of mathics.format, I don't have a strong feeling like this. Aesthetically, I think it is just better put in mathics.form.

I do not have strong feelings about this either, just an argument: from the point of view of code organization, it appears that we would have a lot of space for the different steps of formatting. On the other hand, the complexity inside would not be comparable with the one in core, builtin or eval.

If you don't have a strong feeling, would you mind catering again to my idiosyncracies, and let's put this in either "mathics.form" or "mathics.box" or have two modules?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rocky, OK, let's do as you proposed here and see how this evolve.


text_outputform = str(
expression_to_outputform_text(expr, evaluation, form, **kwargs)
Expand Down
Empty file added mathics/form/__init__.py
Empty file.
31 changes: 18 additions & 13 deletions mathics/format/outputform.py → mathics/form/outputform.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""
This module builts the string associated to the OutputForm.

OutputForm produce a pretty-print-like output, suitable for CLI
and text terminals.
This module implements the "OutputForm" textual representation of expressions.

OutputForm is two-dimensional keyboard-character-only output, suitable for CLI
and text terminals.
"""

from typing import Callable, Dict, List, Union
from typing import Callable, Dict, Final, List, Union

from mathics.core.atoms import (
Integer,
Expand All @@ -22,7 +21,7 @@
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.parser.operators import OPERATOR_DATA
from mathics.core.parser.operators import OPERATOR_DATA, box_operators
from mathics.core.symbols import Atom, Symbol, SymbolTimes
from mathics.core.systemsymbols import (
SymbolBlank,
Expand All @@ -46,11 +45,15 @@
SymbolPrefix = Symbol("System`Prefix")


PRECEDENCES = OPERATOR_DATA.get("operator-precedences")
PRECEDENCE_DEFAULT = PRECEDENCES.get("FunctionApply")
PRECEDENCE_PLUS = PRECEDENCES.get("Plus")
PRECEDENCE_TIMES = PRECEDENCES.get("Times")
PRECEDENCE_POWER = PRECEDENCES.get("Power")
PRECEDENCES: Final = OPERATOR_DATA.get("operator-precedences")
PRECEDENCE_DEFAULT: Final = PRECEDENCES.get("FunctionApply")
PRECEDENCE_PLUS: Final = PRECEDENCES.get("Plus")
PRECEDENCE_TIMES: Final = PRECEDENCES.get("Times")
PRECEDENCE_POWER: Final = PRECEDENCES.get("Power")

# When new mathics-scanner tables are updagted:
# BOX_GROUP_PRECEDENCE: Final = box_operators["BoxGroup"]
BOX_GROUP_PRECEDENCE: Final = PRECEDENCE_DEFAULT

EXPR_TO_OUTPUTFORM_TEXT_MAP: Dict[str, Callable] = {}

Expand Down Expand Up @@ -328,7 +331,8 @@ def infix_expression_to_outputform_text(
raise _WrongFormattedExpression

group = None
precedence = PRECEDENCE_DEFAULT
precedence = BOX_GROUP_PRECEDENCE

# Processing the first argument:
head = expr.get_head()
target = expr.elements[0]
Expand Down Expand Up @@ -606,7 +610,8 @@ def pre_pos_fix_expression_to_outputform_text(
raise _WrongFormattedExpression

group = None
precedence = PRECEDENCE_DEFAULT
precedence = BOX_GROUP_PRECEDENCE

# Processing the first argument:
head = expr.get_head()
target = expr.elements[0]
Expand Down
Loading