1- #!/usr/bin/env python3
21# -*- coding: utf-8 -*-
32
43import re
109import typing
1110from typing import Any , cast
1211
12+ from mathics .version import __version__ # noqa used in loading to check consistency.
13+
1314from mathics .core .definitions import Definition
1415from mathics .core .parser .util import SystemDefinitions , PyMathicsDefinitions
1516from mathics .core .rules import Rule , BuiltinRule , Pattern
2728)
2829from mathics .core .numbers import get_precision , PrecisionValueError
2930
31+
3032def get_option (options , name , evaluation , pop = False , evaluate = True ):
3133 # we do not care whether an option X is given as System`X,
3234 # Global`X, or with any prefix from $ContextPath for that
@@ -83,6 +85,7 @@ def __init__(self, *args, **kwargs):
8385
8486 def contribute (self , definitions , is_pymodule = False ):
8587 from mathics .core .parser import parse_builtin_rule
88+
8689 # Set the default context
8790 if not self .context :
8891 self .context = "Pymathics`" if is_pymodule else "System`"
@@ -146,9 +149,7 @@ def check_options(options_to_check, evaluation):
146149
147150 for pattern , function in self .get_functions (is_pymodule = is_pymodule ):
148151 rules .append (
149- BuiltinRule (
150- name , pattern , function , check_options , system = True
151- )
152+ BuiltinRule (name , pattern , function , check_options , system = True )
152153 )
153154 for pattern , replace in self .rules .items ():
154155 if not isinstance (pattern , BaseExpression ):
@@ -269,7 +270,7 @@ def contextify_form_name(f):
269270 attributes = attributes ,
270271 options = options ,
271272 defaultvalues = defaults ,
272- builtin = self
273+ builtin = self ,
273274 )
274275 if is_pymodule :
275276 definitions .pymathics [name ] = definition
@@ -365,7 +366,7 @@ def get_option_string(self, *params):
365366 return None , s
366367
367368
368- class InstancableBuiltin (Builtin ):
369+ class InstanceableBuiltin (Builtin ):
369370 def __new__ (cls , * args , ** kwargs ):
370371 new_kwargs = kwargs .copy ()
371372 new_kwargs ["expression" ] = False
@@ -378,7 +379,7 @@ def __new__(cls, *args, **kwargs):
378379 try :
379380 instance .init (* args , ** kwargs )
380381 except TypeError :
381- # TypeError occurs when unpickling instance, e.g. PatterObject ,
382+ # TypeError occurs when unpickling instance, e.g. PatternObject ,
382383 # because parameter expr is not given. This should no be a
383384 # problem, as pickled objects need their init-method not
384385 # being called.
@@ -540,7 +541,7 @@ def get_constant(self, precision, evaluation, have_mpmath=False):
540541
541542 sympy_fn = self .to_sympy ()
542543 if d is None :
543- result = self .get_mpmath_function ()if have_mpmath else sympy_fn ()
544+ result = self .get_mpmath_function () if have_mpmath else sympy_fn ()
544545 return MachineReal (result )
545546 else :
546547 return PrecisionReal (sympy_fn .n (d ))
@@ -593,11 +594,105 @@ class BoxConstructError(Exception):
593594 pass
594595
595596
596- class BoxConstruct (Builtin ):
597- def get_option_values (self , leaves , evaluation = None , ** options ):
598- default = evaluation .definitions .get_options (self .get_name ()).copy ()
599- options = Expression ("List" , * leaves ).get_option_values (evaluation )
600- default .update (options )
597+ class BoxConstruct (InstanceableBuiltin ):
598+ def __new__ (cls , * leaves , ** kwargs ):
599+ instance = super ().__new__ (cls , * leaves , ** kwargs )
600+ instance ._leaves = leaves
601+ return instance
602+
603+ def evaluate (self , evaluation ):
604+ # THINK about: Should we evaluate the leaves here?
605+ return
606+
607+ def get_head_name (self ):
608+ return self .get_name ()
609+
610+ def get_lookup_name (self ):
611+ return self .get_name ()
612+
613+ def get_string_value (self ):
614+ return "-@" + self .get_head_name () + "@-"
615+
616+ def same (self , expr ):
617+ return expr .same (self )
618+
619+ def is_atom (self ):
620+ return False
621+
622+ def do_format (self , evaluation , format ):
623+ return self
624+
625+ def format (self , evaluation , fmt ):
626+ return self
627+
628+ def get_head (self ):
629+ return Symbol (self .get_name ())
630+
631+ @property
632+ def head (self ):
633+ return self .get_head ()
634+
635+ @head .setter
636+ def head (self , value ):
637+ raise ValueError ("BoxConstruct.head is write protected." )
638+
639+ @property
640+ def leaves (self ):
641+ return self ._leaves
642+
643+ @leaves .setter
644+ def leaves (self , value ):
645+ raise ValueError ("BoxConstruct.leaves is write protected." )
646+
647+ # I need to repeat this, because this is not
648+ # an expression...
649+ def has_form (self , heads , * leaf_counts ):
650+ """
651+ leaf_counts:
652+ (,): no leaves allowed
653+ (None,): no constraint on number of leaves
654+ (n, None): leaf count >= n
655+ (n1, n2, ...): leaf count in {n1, n2, ...}
656+ """
657+
658+ head_name = self .get_name ()
659+ if isinstance (heads , (tuple , list , set )):
660+ if head_name not in [ensure_context (h ) for h in heads ]:
661+ return False
662+ else :
663+ if head_name != ensure_context (heads ):
664+ return False
665+ if not leaf_counts :
666+ return False
667+ if leaf_counts and leaf_counts [0 ] is not None :
668+ count = len (self ._leaves )
669+ if count not in leaf_counts :
670+ if (
671+ len (leaf_counts ) == 2
672+ and leaf_counts [1 ] is None # noqa
673+ and count >= leaf_counts [0 ]
674+ ):
675+ return True
676+ else :
677+ return False
678+ return True
679+
680+ def flatten_pattern_sequence (self , evaluation ) -> "BoxConstruct" :
681+ return self
682+
683+ def get_option_values (self , leaves , ** options ):
684+ evaluation = options .get ("evaluation" , None )
685+ if evaluation :
686+ default = evaluation .definitions .get_options (self .get_name ()).copy ()
687+ options = Expression ("List" , * leaves ).get_option_values (evaluation )
688+ default .update (options )
689+ else :
690+ from mathics .core .parser import parse_builtin_rule
691+
692+ default = {}
693+ for option , value in self .options .items ():
694+ option = ensure_context (option )
695+ default [option ] = parse_builtin_rule (value )
601696 return default
602697
603698 def boxes_to_text (self , leaves , ** options ) -> str :
@@ -620,7 +715,7 @@ def __init__(self, name, count, expected):
620715 super ().__init__ (None , None )
621716
622717
623- class PatternObject (InstancableBuiltin , Pattern ):
718+ class PatternObject (InstanceableBuiltin , Pattern ):
624719 needs_verbatim = True
625720
626721 arg_counts : typing .List [int ] = []
0 commit comments