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
2627)
2728from mathics .core .numbers import get_precision , PrecisionValueError
2829
30+
2931def get_option (options , name , evaluation , pop = False , evaluate = True ):
3032 # we do not care whether an option X is given as System`X,
3133 # Global`X, or with any prefix from $ContextPath for that
@@ -82,6 +84,7 @@ def __init__(self, *args, **kwargs):
8284
8385 def contribute (self , definitions , is_pymodule = False ):
8486 from mathics .core .parser import parse_builtin_rule
87+
8588 # Set the default context
8689 if not self .context :
8790 self .context = "Pymathics`" if is_pymodule else "System`"
@@ -145,9 +148,7 @@ def check_options(options_to_check, evaluation):
145148
146149 for pattern , function in self .get_functions (is_pymodule = is_pymodule ):
147150 rules .append (
148- BuiltinRule (
149- name , pattern , function , check_options , system = True
150- )
151+ BuiltinRule (name , pattern , function , check_options , system = True )
151152 )
152153 for pattern , replace in self .rules .items ():
153154 if not isinstance (pattern , BaseExpression ):
@@ -268,7 +269,7 @@ def contextify_form_name(f):
268269 attributes = attributes ,
269270 options = options ,
270271 defaultvalues = defaults ,
271- builtin = self
272+ builtin = self ,
272273 )
273274 if is_pymodule :
274275 definitions .pymathics [name ] = definition
@@ -364,7 +365,7 @@ def get_option_string(self, *params):
364365 return None , s
365366
366367
367- class InstancableBuiltin (Builtin ):
368+ class InstanceableBuiltin (Builtin ):
368369 def __new__ (cls , * args , ** kwargs ):
369370 new_kwargs = kwargs .copy ()
370371 new_kwargs ["expression" ] = False
@@ -377,7 +378,7 @@ def __new__(cls, *args, **kwargs):
377378 try :
378379 instance .init (* args , ** kwargs )
379380 except TypeError :
380- # TypeError occurs when unpickling instance, e.g. PatterObject ,
381+ # TypeError occurs when unpickling instance, e.g. PatternObject ,
381382 # because parameter expr is not given. This should no be a
382383 # problem, as pickled objects need their init-method not
383384 # being called.
@@ -539,7 +540,7 @@ def get_constant(self, precision, evaluation, have_mpmath=False):
539540
540541 sympy_fn = self .to_sympy ()
541542 if d is None :
542- result = self .get_mpmath_function ()if have_mpmath else sympy_fn ()
543+ result = self .get_mpmath_function () if have_mpmath else sympy_fn ()
543544 return MachineReal (result )
544545 else :
545546 return PrecisionReal (sympy_fn .n (d ))
@@ -592,11 +593,105 @@ class BoxConstructError(Exception):
592593 pass
593594
594595
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 )
596+ class BoxConstruct (InstanceableBuiltin ):
597+ def __new__ (cls , * leaves , ** kwargs ):
598+ instance = super ().__new__ (cls , * leaves , ** kwargs )
599+ instance ._leaves = leaves
600+ return instance
601+
602+ def evaluate (self , evaluation ):
603+ # THINK about: Should we evaluate the leaves here?
604+ return
605+
606+ def get_head_name (self ):
607+ return self .get_name ()
608+
609+ def get_lookup_name (self ):
610+ return self .get_name ()
611+
612+ def get_string_value (self ):
613+ return "-@" + self .get_head_name () + "@-"
614+
615+ def same (self , expr ):
616+ return expr .same (self )
617+
618+ def is_atom (self ):
619+ return False
620+
621+ def do_format (self , evaluation , format ):
622+ return self
623+
624+ def format (self , evaluation , fmt ):
625+ return self
626+
627+ def get_head (self ):
628+ return Symbol (self .get_name ())
629+
630+ @property
631+ def head (self ):
632+ return self .get_head ()
633+
634+ @head .setter
635+ def head (self , value ):
636+ raise ValueError ("BoxConstruct.head is write protected." )
637+
638+ @property
639+ def leaves (self ):
640+ return self ._leaves
641+
642+ @leaves .setter
643+ def leaves (self , value ):
644+ raise ValueError ("BoxConstruct.leaves is write protected." )
645+
646+ # I need to repeat this, because this is not
647+ # an expression...
648+ def has_form (self , heads , * leaf_counts ):
649+ """
650+ leaf_counts:
651+ (,): no leaves allowed
652+ (None,): no constraint on number of leaves
653+ (n, None): leaf count >= n
654+ (n1, n2, ...): leaf count in {n1, n2, ...}
655+ """
656+
657+ head_name = self .get_name ()
658+ if isinstance (heads , (tuple , list , set )):
659+ if head_name not in [ensure_context (h ) for h in heads ]:
660+ return False
661+ else :
662+ if head_name != ensure_context (heads ):
663+ return False
664+ if not leaf_counts :
665+ return False
666+ if leaf_counts and leaf_counts [0 ] is not None :
667+ count = len (self ._leaves )
668+ if count not in leaf_counts :
669+ if (
670+ len (leaf_counts ) == 2
671+ and leaf_counts [1 ] is None # noqa
672+ and count >= leaf_counts [0 ]
673+ ):
674+ return True
675+ else :
676+ return False
677+ return True
678+
679+ def flatten_pattern_sequence (self , evaluation ) -> "BoxConstruct" :
680+ return self
681+
682+ def get_option_values (self , leaves , ** options ):
683+ evaluation = options .get ("evaluation" , None )
684+ if evaluation :
685+ default = evaluation .definitions .get_options (self .get_name ()).copy ()
686+ options = Expression ("List" , * leaves ).get_option_values (evaluation )
687+ default .update (options )
688+ else :
689+ from mathics .core .parser import parse_builtin_rule
690+
691+ default = {}
692+ for option , value in self .options .items ():
693+ option = ensure_context (option )
694+ default [option ] = parse_builtin_rule (value )
600695 return default
601696
602697 def boxes_to_text (self , leaves , ** options ) -> str :
@@ -619,7 +714,7 @@ def __init__(self, name, count, expected):
619714 super ().__init__ (None , None )
620715
621716
622- class PatternObject (InstancableBuiltin , Pattern ):
717+ class PatternObject (InstanceableBuiltin , Pattern ):
623718 needs_verbatim = True
624719
625720 arg_counts : typing .List [int ] = []
0 commit comments