Skip to content

Commit 9e9680f

Browse files
committed
Merge branch 'makeboxesoverhault'
2 parents 96911dd + c8d9eb7 commit 9e9680f

11 files changed

Lines changed: 190 additions & 89 deletions

File tree

mathics/builtin/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ def is_builtin(var):
8585
mathics_to_python = {} # here we have: name -> string
8686
sympy_to_mathics = {}
8787

88-
box_constructs = {}
8988
pattern_objects = {}
9089
builtins_precedence = {}
9190

@@ -101,8 +100,6 @@ def add_builtins(new_builtins):
101100
mathics_to_sympy[name] = builtin
102101
for sympy_name in builtin.get_sympy_names():
103102
sympy_to_mathics[sympy_name] = builtin
104-
if isinstance(builtin, BoxConstruct):
105-
box_constructs[name] = builtin
106103
if isinstance(builtin, Operator):
107104
builtins_precedence[name] = builtin.precedence
108105
if isinstance(builtin, PatternObject):

mathics/builtin/base.py

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -592,11 +592,101 @@ class BoxConstructError(Exception):
592592
pass
593593

594594

595-
class BoxConstruct(Builtin):
596-
def get_option_values(self, leaves, evaluation=None, **options):
597-
default = evaluation.definitions.get_options(self.get_name()).copy()
598-
options = Expression("List", *leaves).get_option_values(evaluation)
599-
default.update(options)
595+
class BoxConstruct(InstancableBuiltin):
596+
def __new__(cls, *leaves, **kwargs):
597+
instance = super().__new__(cls, *leaves, **kwargs)
598+
instance._leaves = leaves
599+
return instance
600+
601+
def evaluate(self, evaluation):
602+
# Shall here evaluate the leaves?
603+
return
604+
605+
def get_head_name(self):
606+
return self.get_name()
607+
608+
def get_lookup_name(self):
609+
return self.get_name()
610+
611+
def get_string_value(self):
612+
return "-@" + self.get_head_name() + "@-"
613+
614+
def same(self, expr):
615+
return expr.same(self)
616+
617+
def is_atom(self):
618+
return False
619+
620+
def do_format(self, evaluation, format):
621+
return self
622+
623+
def format(self, evaluation, fmt):
624+
return self
625+
626+
def get_head(self):
627+
return Symbol(self.get_name())
628+
629+
@property
630+
def head(self):
631+
return self.get_head()
632+
633+
@head.setter
634+
def head(self, value):
635+
raise ValueError('BoxConstruct.head is write protected.')
636+
637+
@property
638+
def leaves(self):
639+
return self._leaves
640+
641+
@leaves.setter
642+
def leaves(self, value):
643+
raise ValueError('BoxConstruct.leaves is write protected.')
644+
645+
# I need to repeat this, because this is not
646+
# an expression...
647+
def has_form(self, heads, *leaf_counts):
648+
"""
649+
leaf_counts:
650+
(,): no leaves allowed
651+
(None,): no constraint on number of leaves
652+
(n, None): leaf count >= n
653+
(n1, n2, ...): leaf count in {n1, n2, ...}
654+
"""
655+
656+
head_name = self.get_name()
657+
if isinstance(heads, (tuple, list, set)):
658+
if head_name not in [ensure_context(h) for h in heads]:
659+
return False
660+
else:
661+
if head_name != ensure_context(heads):
662+
return False
663+
if not leaf_counts:
664+
return False
665+
if leaf_counts and leaf_counts[0] is not None:
666+
count = len(self._leaves)
667+
if count not in leaf_counts:
668+
if (len(leaf_counts) == 2 and # noqa
669+
leaf_counts[1] is None and count >= leaf_counts[0]):
670+
return True
671+
else:
672+
return False
673+
return True
674+
675+
def flatten_pattern_sequence(self, evaluation) -> 'BoxConstruct':
676+
return self
677+
678+
def get_option_values(self, leaves, **options):
679+
evaluation = options.get("evaluation", None)
680+
if evaluation:
681+
default = evaluation.definitions.get_options(self.get_name()).copy()
682+
options = Expression("List", *leaves).get_option_values(evaluation)
683+
default.update(options)
684+
else:
685+
from mathics.core.parser import parse_builtin_rule
686+
default = {}
687+
for option, value in self.options.items():
688+
option = ensure_context(option)
689+
default[option] = parse_builtin_rule(value)
600690
return default
601691

602692
def boxes_to_text(self, leaves, **options) -> str:

mathics/builtin/compilation.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,26 @@ def __hash__(self):
149149
return hash(("CompiledCode", ctypes.addressof(self.cfunc))) # XXX hack
150150

151151
def atom_to_boxes(self, f, evaluation):
152-
return Expression('CompiledCodeBox')
152+
return CompiledCodeBox(String("Nocode"))
153153

154154

155155
class CompiledCodeBox(BoxConstruct):
156156
"""
157157
Used internally by <i>CompileCode[]</i>.
158158
"""
159-
def boxes_to_text(self, leaves, **options):
159+
def boxes_to_text(self, leaves=None, **options):
160+
if not leaves:
161+
leaves = self._leaves
160162
return '-CompiledCode-'
161163

162-
def boxes_to_xml(self, leaves, **options):
164+
def boxes_to_xml(self, leaves=None, **options):
165+
if not leaves:
166+
leaves = self._leaves
163167
return '-CompiledCode-'
164168

165-
def boxes_to_tex(self, leaves, **options):
169+
def boxes_to_tex(self, leaves=None, **options):
170+
if not leaves:
171+
leaves = self._leaves
166172
return '-CompiledCode-'
167173

168174

mathics/builtin/graphics.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,6 @@ class Graphics(Builtin):
470470
def apply_makeboxes(self, content, evaluation, options):
471471
"""MakeBoxes[%(name)s[content_, OptionsPattern[%(name)s]],
472472
StandardForm|TraditionalForm|OutputForm]"""
473-
474473
def convert(content):
475474
head = content.get_head_name()
476475

@@ -508,8 +507,12 @@ def convert(content):
508507
for option in options:
509508
if option not in ("System`ImageSize",):
510509
options[option] = Expression("N", options[option]).evaluate(evaluation)
511-
box_name = "Graphics" + self.box_suffix
512-
return Expression(box_name, convert(content), *options_to_rules(options))
510+
#box_name = "Graphics" + self.box_suffix
511+
from mathics.builtin.graphics3d import Graphics3DBox, Graphics3D
512+
if type(self) is Graphics:
513+
return GraphicsBox(convert(content), *options_to_rules(options))
514+
elif type(self) is Graphics3D:
515+
return Graphics3DBox(convert(content), *options_to_rules(options))
513516

514517

515518
class _GraphicsElement(InstancableBuiltin):
@@ -2598,8 +2601,8 @@ def to_svg(self):
25982601
content = self.content.boxes_to_xml(evaluation=self.graphics.evaluation)
25992602
style = create_css(font_color=self.color)
26002603
svg = (
2601-
'<foreignObject x="%f" y="%f" ox="%f" oy="%f" style="%s">'
2602-
"<math>%s</math></foreignObject>"
2604+
'<foreignObject x="%f" y="%f" ox="%f" oy="%f" width="100" height="100" style="%s">'
2605+
'<math xmlns="http://www.w3.org/1998/Math/MathML">%s</math></foreignObject>'
26032606
) % (x, y, self.opos[0], self.opos[1], style, content)
26042607
return svg
26052608

@@ -2768,7 +2771,6 @@ class _GraphicsElements(object):
27682771
def __init__(self, content, evaluation):
27692772
self.evaluation = evaluation
27702773
self.elements = []
2771-
27722774
builtins = evaluation.definitions.builtin
27732775

27742776
def get_options(name):
@@ -2936,7 +2938,10 @@ class GraphicsBox(BoxConstruct):
29362938

29372939
attributes = ("HoldAll", "ReadProtected")
29382940

2939-
def boxes_to_text(self, leaves, **options):
2941+
def boxes_to_text(self, leaves=None, **options):
2942+
if not leaves:
2943+
leaves = self._leaves
2944+
29402945
self._prepare_elements(leaves, options) # to test for Box errors
29412946
return "-Graphics-"
29422947

@@ -2992,9 +2997,7 @@ def _get_image_size(self, options, graphics_options, max_width):
29922997
def _prepare_elements(self, leaves, options, neg_y=False, max_width=None):
29932998
if not leaves:
29942999
raise BoxConstructError
2995-
29963000
graphics_options = self.get_option_values(leaves[1:], **options)
2997-
29983001
background = graphics_options["System`Background"]
29993002
if (
30003003
isinstance(background, Symbol)
@@ -3142,7 +3145,9 @@ def get_range(min, max):
31423145

31433146
return elements, calc_dimensions
31443147

3145-
def boxes_to_tex(self, leaves, **options):
3148+
def boxes_to_tex(self, leaves=None, **options):
3149+
if not leaves:
3150+
leaves = self._leaves
31463151
elements, calc_dimensions = self._prepare_elements(
31473152
leaves, options, max_width=450
31483153
)
@@ -3195,7 +3200,9 @@ def boxes_to_tex(self, leaves, **options):
31953200

31963201
return tex
31973202

3198-
def boxes_to_xml(self, leaves, **options):
3203+
def boxes_to_xml(self, leaves=None, **options):
3204+
if not leaves:
3205+
leaves = self._leaves
31993206
elements, calc_dimensions = self._prepare_elements(leaves, options, neg_y=True)
32003207

32013208
xmin, xmax, ymin, ymax, w, h, width, height = calc_dimensions()
@@ -3229,7 +3236,7 @@ def boxes_to_xml(self, leaves, **options):
32293236
" ".join("%f" % t for t in (xmin, ymin, w, h)),
32303237
svg,
32313238
)
3232-
3239+
print("svg=", svg_xml)
32333240
return (
32343241
'<mglyph width="%dpx" height="%dpx" src="data:image/svg+xml;base64,%s"/>'
32353242
% (
@@ -3623,7 +3630,6 @@ class _ColorObject(Builtin):
36233630

36243631
def __init__(self, *args, **kwargs):
36253632
super(_ColorObject, self).__init__(*args, **kwargs)
3626-
36273633
if self.text_name is None:
36283634
text_name = strip_context(self.get_name()).lower()
36293635
else:
@@ -3660,6 +3666,7 @@ class Black(_ColorObject):
36603666
}
36613667

36623668

3669+
36633670
class White(_ColorObject):
36643671
"""
36653672
>> White
@@ -3737,6 +3744,7 @@ class Magenta(_ColorObject):
37373744
}
37383745

37393746

3747+
37403748
class Yellow(_ColorObject):
37413749
"""
37423750
>> Yellow
@@ -3860,6 +3868,7 @@ class Large(Builtin):
38603868
style_options = system_symbols_dict(
38613869
{
38623870
"FontColor": _style,
3871+
"ImageSizeMultipliers": (lambda *x: x[1])
38633872
}
38643873
)
38653874

mathics/builtin/graphics3d.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ class Graphics3D(Graphics):
154154

155155

156156
class Graphics3DBox(GraphicsBox):
157-
def boxes_to_text(self, leaves, **options):
157+
def boxes_to_text(self, leaves=None, **options):
158+
if not leaves:
159+
leaves = self._leaves
158160
return "-Graphics3D-"
159161

160162
def _prepare_elements(self, leaves, options, max_width=None):
@@ -435,7 +437,10 @@ def calc_dimensions(final_pass=True):
435437

436438
return elements, axes, ticks, calc_dimensions, boxscale
437439

438-
def boxes_to_tex(self, leaves, **options):
440+
def boxes_to_tex(self, leaves=None, **options):
441+
if not leaves:
442+
leaves = self._leaves
443+
439444
elements, axes, ticks, calc_dimensions, boxscale = self._prepare_elements(
440445
leaves, options, max_width=450
441446
)
@@ -624,7 +629,10 @@ def boxes_to_tex(self, leaves, **options):
624629
)
625630
return tex
626631

627-
def boxes_to_xml(self, leaves, **options):
632+
def boxes_to_xml(self, leaves=None, **options):
633+
if not leaves:
634+
leaves = self._leaves
635+
628636
elements, axes, ticks, calc_dimensions, boxscale = self._prepare_elements(
629637
leaves, options
630638
)

mathics/builtin/image.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,18 +2124,20 @@ def test(self, expr):
21242124

21252125

21262126
class ImageBox(BoxConstruct):
2127-
def boxes_to_text(self, leaves, **options):
2127+
def boxes_to_text(self, leaves=None, **options):
21282128
return "-Image-"
21292129

2130-
def boxes_to_xml(self, leaves, **options):
2130+
def boxes_to_xml(self, leaves=None, **options):
2131+
if leaves is None:
2132+
leaves = self._leaves
21312133
# see https://tools.ietf.org/html/rfc2397
21322134
return '<mglyph src="%s" width="%dpx" height="%dpx" />' % (
21332135
leaves[0].get_string_value(),
21342136
leaves[1].get_int_value(),
21352137
leaves[2].get_int_value(),
21362138
)
21372139

2138-
def boxes_to_tex(self, leaves, **options):
2140+
def boxes_to_tex(self, leaves=None, **options):
21392141
return "-Image-"
21402142

21412143

@@ -2259,8 +2261,7 @@ def atom_to_boxes(self, f, evaluation):
22592261
encoded = base64.b64encode(contents)
22602262
encoded = b"data:image/png;base64," + encoded
22612263

2262-
return Expression(
2263-
"ImageBox", String(encoded), Integer(scaled_width), Integer(scaled_height)
2264+
return ImageBox(String(encoded), Integer(scaled_width), Integer(scaled_height)
22642265
)
22652266

22662267
def __str__(self):

0 commit comments

Comments
 (0)