1- #!/usr/bin/env python3
21# -*- coding: utf-8 -*-
32
4- import mpmath
53import re
64import sympy
75
86from functools import total_ordering
97import importlib
108from itertools import chain
11-
129import typing
1310from typing import Any , cast
1411
12+ from mathics .version import __version__ # noqa used in loading to check consistency.
13+
1514from mathics .core .definitions import Definition
1615from mathics .core .parser .util import SystemDefinitions , PyMathicsDefinitions
1716from mathics .core .rules import Rule , BuiltinRule , Pattern
2827)
2928from mathics .core .numbers import get_precision , PrecisionValueError
3029
30+
3131def get_option (options , name , evaluation , pop = False , evaluate = True ):
3232 # we do not care whether an option X is given as System`X,
3333 # Global`X, or with any prefix from $ContextPath for that
@@ -84,6 +84,7 @@ def __init__(self, *args, **kwargs):
8484
8585 def contribute (self , definitions , is_pymodule = False ):
8686 from mathics .core .parser import parse_builtin_rule
87+
8788 # Set the default context
8889 if not self .context :
8990 self .context = "Pymathics`" if is_pymodule else "System`"
@@ -147,9 +148,7 @@ def check_options(options_to_check, evaluation):
147148
148149 for pattern , function in self .get_functions (is_pymodule = is_pymodule ):
149150 rules .append (
150- BuiltinRule (
151- name , pattern , function , check_options , system = True
152- )
151+ BuiltinRule (name , pattern , function , check_options , system = True )
153152 )
154153 for pattern , replace in self .rules .items ():
155154 if not isinstance (pattern , BaseExpression ):
@@ -270,7 +269,7 @@ def contextify_form_name(f):
270269 attributes = attributes ,
271270 options = options ,
272271 defaultvalues = defaults ,
273- builtin = self
272+ builtin = self ,
274273 )
275274 if is_pymodule :
276275 definitions .pymathics [name ] = definition
@@ -366,7 +365,7 @@ def get_option_string(self, *params):
366365 return None , s
367366
368367
369- class InstancableBuiltin (Builtin ):
368+ class InstanceableBuiltin (Builtin ):
370369 def __new__ (cls , * args , ** kwargs ):
371370 new_kwargs = kwargs .copy ()
372371 new_kwargs ["expression" ] = False
@@ -379,7 +378,7 @@ def __new__(cls, *args, **kwargs):
379378 try :
380379 instance .init (* args , ** kwargs )
381380 except TypeError :
382- # TypeError occurs when unpickling instance, e.g. PatterObject ,
381+ # TypeError occurs when unpickling instance, e.g. PatternObject ,
383382 # because parameter expr is not given. This should no be a
384383 # problem, as pickled objects need their init-method not
385384 # being called.
@@ -533,15 +532,15 @@ def apply(self, expr, evaluation) -> Symbol:
533532
534533
535534class SympyFunction (SympyObject ):
536- def get_constant (self , precision , have_mpmath = False ):
535+ def get_constant (self , precision , evaluation , have_mpmath = False ):
537536 try :
538537 d = get_precision (precision , evaluation )
539538 except PrecisionValueError :
540539 return
541540
542541 sympy_fn = self .to_sympy ()
543542 if d is None :
544- result = self .get_mpmath_function ()if have_mpmath else sympy_fn ()
543+ result = self .get_mpmath_function () if have_mpmath else sympy_fn ()
545544 return MachineReal (result )
546545 else :
547546 return PrecisionReal (sympy_fn .n (d ))
@@ -594,11 +593,105 @@ class BoxConstructError(Exception):
594593 pass
595594
596595
597- class BoxConstruct (Builtin ):
598- def get_option_values (self , leaves , evaluation = None , ** options ):
599- default = evaluation .definitions .get_options (self .get_name ()).copy ()
600- options = Expression ("List" , * leaves ).get_option_values (evaluation )
601- 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 )
602695 return default
603696
604697 def boxes_to_text (self , leaves , ** options ) -> str :
@@ -621,7 +714,7 @@ def __init__(self, name, count, expected):
621714 super ().__init__ (None , None )
622715
623716
624- class PatternObject (InstancableBuiltin , Pattern ):
717+ class PatternObject (InstanceableBuiltin , Pattern ):
625718 needs_verbatim = True
626719
627720 arg_counts : typing .List [int ] = []
0 commit comments