From 23ef1f040f54b990e30ad8d41211dbf5a628280d Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Nov 2022 06:17:56 -0400 Subject: [PATCH 1/7] An example of defining MakeBoxes in Mathics code We hack assigment for MakeBoxes, but ultimately this is wrong. There seems to be confusion in MakeBoxes internals with respect to Rules and delayed assignment. --- mathics/autoload/forms/StandardForm.m | 21 +++++++++++++++++++++ mathics/builtin/arithfns/basic.py | 3 --- mathics/builtin/assignments/internals.py | 16 ++++++++++++++++ mathics/builtin/base.py | 4 ++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 mathics/autoload/forms/StandardForm.m diff --git a/mathics/autoload/forms/StandardForm.m b/mathics/autoload/forms/StandardForm.m new file mode 100644 index 000000000..820e7380d --- /dev/null +++ b/mathics/autoload/forms/StandardForm.m @@ -0,0 +1,21 @@ +(* This implements StandardForm boxing rules in Mathics *) + + +Begin["System`"] + +(******************************************************************************************) +(* Common Boxing routines that are used by many forms. FIXME: place this in another file. *) +(******************************************************************************************) + +(* Change RadBox to RadicalBox. We use RadBox to make it clear that + the below code was a read-in from a file and not some pre-existing + code. *) +RadicalBox[expr_, form_] = RadBox[MakeBoxes[expr, form], 3]; + +(******************************************************************************************) +(* StandardForm Boxing Rules *) +(******************************************************************************************) + +MakeBoxes[CubeRoot[expr_], StandardForm] := RadicalBox[expr_, form_]; +(*All the other StandardForm boxing routines... *) +End[] diff --git a/mathics/builtin/arithfns/basic.py b/mathics/builtin/arithfns/basic.py index a3c39c8b5..466ae53b3 100644 --- a/mathics/builtin/arithfns/basic.py +++ b/mathics/builtin/arithfns/basic.py @@ -112,9 +112,6 @@ class CubeRoot(Builtin): rules = { "CubeRoot[n_?NumberQ]": "If[n > 0, Power[n, Divide[1, 3]], Times[-1, Power[Times[-1, n], Divide[1, 3]]]]", "CubeRoot[n_]": "Power[n, Divide[1, 3]]", - "MakeBoxes[CubeRoot[x_], f:StandardForm|TraditionalForm]": ( - "RadicalBox[MakeBoxes[x, f], 3]" - ), } summary_text = "cubed root" diff --git a/mathics/builtin/assignments/internals.py b/mathics/builtin/assignments/internals.py index 132d9e390..26a7bb42c 100644 --- a/mathics/builtin/assignments/internals.py +++ b/mathics/builtin/assignments/internals.py @@ -755,5 +755,21 @@ def assign(self, lhs, rhs, evaluation): return False indices = lhs.elements[1:] return walk_parts([rule.replace], indices, evaluation, rhs) + + # FIXME: the below is a big hack. + # Currently MakeBoxes boxing is implemented as a bunch of rules. + # See mathics.builtin.base contribute(). + # I think we want to change this so it works like normal SetDelayed + # That is: + # MakeBoxes[CubeRoot, StandardForm] := RadicalBox[3, StandardForm] + # rather than: + # MakeBoxes[CubeRoot, StandardForm] -> RadicalBox[3, StandardForm] + elif lhs.get_head_name() == "System`MakeBoxes": + makeboxes_rule = Rule(lhs, rhs, system=True) + makeboxes_defs = defs.builtin["System`MakeBoxes"] + makeboxes_defs.add_rule(makeboxes_rule) + # FIXME: what should be the result? + return makeboxes_rule + else: return self.assign_elementary(lhs, rhs, evaluation) diff --git a/mathics/builtin/base.py b/mathics/builtin/base.py index 57a8473eb..8b047d8f0 100644 --- a/mathics/builtin/base.py +++ b/mathics/builtin/base.py @@ -284,7 +284,10 @@ def check_options(options_to_check, evaluation): BuiltinRule(name, pattern, function, check_options, system=True) ) for pattern, replace in self.rules.items(): + # FIXME: sometimes pattern is a string and sometimes a BaseElement? + # This seems wrong. if not isinstance(pattern, BaseElement): + assert pattern pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern, definition_class) replace = replace % {"name": name} @@ -292,6 +295,7 @@ def check_options(options_to_check, evaluation): rules.append(Rule(pattern, parse_builtin_rule(replace), system=True)) box_rules = [] + # FIXME: Why a special case for System`MakeBoxes? Remove this if name != "System`MakeBoxes": new_rules = [] for rule in rules: From c49f4064d472a39e4eb2e9f5adf78761ecd2277c Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Nov 2022 06:28:09 -0400 Subject: [PATCH 2/7] More correct Mathics code for CuebRoot My WL skills are not that good. --- mathics/autoload/forms/StandardForm.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mathics/autoload/forms/StandardForm.m b/mathics/autoload/forms/StandardForm.m index 820e7380d..3f2806e9d 100644 --- a/mathics/autoload/forms/StandardForm.m +++ b/mathics/autoload/forms/StandardForm.m @@ -10,12 +10,15 @@ (* Change RadBox to RadicalBox. We use RadBox to make it clear that the below code was a read-in from a file and not some pre-existing code. *) -RadicalBox[expr_, form_] = RadBox[MakeBoxes[expr, form], 3]; +Attributes[CommonRadicalBox] = HoldAll; +Attributes[RadBox] = HoldAll; +CommonRadicalBox[expr_, form_] = RadBox[MakeBoxes[expr, form], 3]; (******************************************************************************************) (* StandardForm Boxing Rules *) (******************************************************************************************) -MakeBoxes[CubeRoot[expr_], StandardForm] := RadicalBox[expr_, form_]; +MakeBoxes[CubeRoot[expr_], StandardForm] := CommonRadicalBox[expr, StandardForm]; (*All the other StandardForm boxing routines... *) + End[] From aa8f7393c77e088fe0238137d70af5e75e8195ef Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 2 Nov 2022 15:41:42 -0400 Subject: [PATCH 3/7] Rmeve stray assert --- mathics/builtin/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mathics/builtin/base.py b/mathics/builtin/base.py index 8b047d8f0..10994f721 100644 --- a/mathics/builtin/base.py +++ b/mathics/builtin/base.py @@ -287,7 +287,6 @@ def check_options(options_to_check, evaluation): # FIXME: sometimes pattern is a string and sometimes a BaseElement? # This seems wrong. if not isinstance(pattern, BaseElement): - assert pattern pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern, definition_class) replace = replace % {"name": name} From 5a1d0def5edb19bdfbd13cd8ee25ecb2d68a5ee4 Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Fri, 4 Nov 2022 10:16:39 -0300 Subject: [PATCH 4/7] my suggestions (#592) --- mathics/builtin/assignments/internals.py | 58 ++++++++++++------------ mathics/builtin/base.py | 16 +++---- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/mathics/builtin/assignments/internals.py b/mathics/builtin/assignments/internals.py index 26a7bb42c..de67bd3a4 100644 --- a/mathics/builtin/assignments/internals.py +++ b/mathics/builtin/assignments/internals.py @@ -558,6 +558,21 @@ def process_assign_format(self, lhs, rhs, evaluation, tags, upset): return count > 0 +def process_assign_makeboxes(self, lhs, rhs, evaluation, tags, upset): + # FIXME: the below is a big hack. + # Currently MakeBoxes boxing is implemented as a bunch of rules. + # See mathics.builtin.base contribute(). + # I think we want to change this so it works like normal SetDelayed + # That is: + # MakeBoxes[CubeRoot, StandardForm] := RadicalBox[3, StandardForm] + # rather than: + # MakeBoxes[CubeRoot, StandardForm] -> RadicalBox[3, StandardForm] + makeboxes_rule = Rule(lhs, rhs, system=True) + makeboxes_defs = evaluation.definitions.builtin["System`MakeBoxes"] + makeboxes_defs.add_rule(makeboxes_rule) + return True + + def process_assign_messagename(self, lhs, rhs, evaluation, tags, upset): lhs, condition = unroll_conditions(lhs) lhs, rhs = unroll_patterns(lhs, rhs, evaluation) @@ -685,23 +700,24 @@ def process_tags_and_upset_allow_custom(tags, upset, self, lhs, evaluation): class _SetOperator: special_cases = { - "System`OwnValues": process_assign_definition_values, - "System`DownValues": process_assign_definition_values, - "System`SubValues": process_assign_definition_values, - "System`UpValues": process_assign_definition_values, - "System`NValues": process_assign_definition_values, - "System`DefaultValues": process_assign_definition_values, - "System`Messages": process_assign_definition_values, - "System`Attributes": process_assign_attributes, - "System`Options": process_assign_options, - "System`$RandomState": process_assign_random_state, "System`$Context": process_assign_context, "System`$ContextPath": process_assign_context_path, - "System`N": process_assign_n, - "System`NumericQ": process_assign_numericq, - "System`MessageName": process_assign_messagename, + "System`$RandomState": process_assign_random_state, + "System`Attributes": process_assign_attributes, "System`Default": process_assign_default, + "System`DefaultValues": process_assign_definition_values, + "System`DownValues": process_assign_definition_values, "System`Format": process_assign_format, + "System`MakeBoxes": process_assign_makeboxes, + "System`MessageName": process_assign_messagename, + "System`Messages": process_assign_definition_values, + "System`N": process_assign_n, + "System`NValues": process_assign_definition_values, + "System`NumericQ": process_assign_numericq, + "System`Options": process_assign_options, + "System`OwnValues": process_assign_definition_values, + "System`SubValues": process_assign_definition_values, + "System`UpValues": process_assign_definition_values, } def assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False): @@ -755,21 +771,5 @@ def assign(self, lhs, rhs, evaluation): return False indices = lhs.elements[1:] return walk_parts([rule.replace], indices, evaluation, rhs) - - # FIXME: the below is a big hack. - # Currently MakeBoxes boxing is implemented as a bunch of rules. - # See mathics.builtin.base contribute(). - # I think we want to change this so it works like normal SetDelayed - # That is: - # MakeBoxes[CubeRoot, StandardForm] := RadicalBox[3, StandardForm] - # rather than: - # MakeBoxes[CubeRoot, StandardForm] -> RadicalBox[3, StandardForm] - elif lhs.get_head_name() == "System`MakeBoxes": - makeboxes_rule = Rule(lhs, rhs, system=True) - makeboxes_defs = defs.builtin["System`MakeBoxes"] - makeboxes_defs.add_rule(makeboxes_rule) - # FIXME: what should be the result? - return makeboxes_rule - else: return self.assign_elementary(lhs, rhs, evaluation) diff --git a/mathics/builtin/base.py b/mathics/builtin/base.py index 10994f721..b6faf3aac 100644 --- a/mathics/builtin/base.py +++ b/mathics/builtin/base.py @@ -283,15 +283,13 @@ def check_options(options_to_check, evaluation): rules.append( BuiltinRule(name, pattern, function, check_options, system=True) ) - for pattern, replace in self.rules.items(): - # FIXME: sometimes pattern is a string and sometimes a BaseElement? - # This seems wrong. - if not isinstance(pattern, BaseElement): - pattern = pattern % {"name": name} - pattern = parse_builtin_rule(pattern, definition_class) - replace = replace % {"name": name} - # FIXME: Should system=True be system=not is_pymodule ? - rules.append(Rule(pattern, parse_builtin_rule(replace), system=True)) + for pattern_str, replace_str in self.rules.items(): + pattern_str = pattern_str % {"name": name} + pattern = parse_builtin_rule(pattern_str, definition_class) + replace_str = replace_str % {"name": name} + rules.append( + Rule(pattern, parse_builtin_rule(replace_str), system=not is_pymodule) + ) box_rules = [] # FIXME: Why a special case for System`MakeBoxes? Remove this From 2d616e3781fe6d805657b05b2cc5cf18d5d1d416 Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Sun, 6 Nov 2022 15:39:43 -0300 Subject: [PATCH 5/7] More suggestions and fixes (#595) * add `Remove`. Fix load definitions. Normalize assignment for MakeBoxes * support strings --- CHANGES.rst | 1 + SYMBOLS_MANIFEST.txt | 1 + mathics/autoload/forms/StandardForm.m | 2 +- mathics/builtin/assignments/clear.py | 30 ++++++++++++++++++++++++ mathics/builtin/assignments/internals.py | 9 ++++--- mathics/core/definitions.py | 9 ++++++- 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 6ce0a3587..836d64e9d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,6 +17,7 @@ New Builtins #. ``Curl`` (2-D and 3-D vector forms only) #. ``Kurtosis`` #. ``PauliMatrix`` +#. ``Remove`` #. ``SetOptions`` #. ``SixJSymbol`` #. ``Skewness`` diff --git a/SYMBOLS_MANIFEST.txt b/SYMBOLS_MANIFEST.txt index 93d85f481..7a9a64774 100644 --- a/SYMBOLS_MANIFEST.txt +++ b/SYMBOLS_MANIFEST.txt @@ -831,6 +831,7 @@ System`RegularExpression System`RegularPolygon System`RegularPolygonBox System`ReleaseHold +System`Remove System`RemoveDiacritics System`RenameDirectory System`RenameFile diff --git a/mathics/autoload/forms/StandardForm.m b/mathics/autoload/forms/StandardForm.m index 3f2806e9d..d44c7b414 100644 --- a/mathics/autoload/forms/StandardForm.m +++ b/mathics/autoload/forms/StandardForm.m @@ -12,7 +12,7 @@ code. *) Attributes[CommonRadicalBox] = HoldAll; Attributes[RadBox] = HoldAll; -CommonRadicalBox[expr_, form_] = RadBox[MakeBoxes[expr, form], 3]; +CommonRadicalBox[expr_, form_]:= RadBox[MakeBoxes[expr, form], 3]; (******************************************************************************************) (* StandardForm Boxing Rules *) diff --git a/mathics/builtin/assignments/clear.py b/mathics/builtin/assignments/clear.py index 9f64c2241..197e3cd80 100644 --- a/mathics/builtin/assignments/clear.py +++ b/mathics/builtin/assignments/clear.py @@ -166,6 +166,36 @@ def do_clear(self, definition): definition.defaultvalues = [] +class Remove(Builtin): + """ +
+
'Remove[$x$]' +
removes the definition associated to $x$. +
+ >> a := 2 + >> Names["Global`a"] + = {a} + >> Remove[a] + >> Names["Global`a"] + = {} + """ + + attributes = A_HOLD_ALL | A_LOCKED | A_PROTECTED + messages = {"ssym": "`1` is not a symbol."} + precedence = 670 + summary_text = "remove the definition of a symbol" + + def eval(self, symb, evaluation): + """Remove[symb_]""" + if isinstance(symb, Symbol): + evaluation.definitions.reset_user_definition(symb.name) + elif isinstance(symb, String): + evaluation.definitions.reset_user_definition(symb.value) + else: + evaluation.message(self.get_name(), "ssym", symb) + return SymbolNull + + class Unset(PostfixOperator): """
diff --git a/mathics/builtin/assignments/internals.py b/mathics/builtin/assignments/internals.py index de67bd3a4..2d8804a63 100644 --- a/mathics/builtin/assignments/internals.py +++ b/mathics/builtin/assignments/internals.py @@ -567,9 +567,12 @@ def process_assign_makeboxes(self, lhs, rhs, evaluation, tags, upset): # MakeBoxes[CubeRoot, StandardForm] := RadicalBox[3, StandardForm] # rather than: # MakeBoxes[CubeRoot, StandardForm] -> RadicalBox[3, StandardForm] - makeboxes_rule = Rule(lhs, rhs, system=True) - makeboxes_defs = evaluation.definitions.builtin["System`MakeBoxes"] - makeboxes_defs.add_rule(makeboxes_rule) + + makeboxes_rule = Rule(lhs, rhs, system=False) + definitions = evaluation.definitions + definitions.add_rule("System`MakeBoxes", makeboxes_rule, "down") + # makeboxes_defs = evaluation.definitions.builtin["System`MakeBoxes"] + # makeboxes_defs.add_rule(makeboxes_rule) return True diff --git a/mathics/core/definitions.py b/mathics/core/definitions.py index def6b1a93..46aa0c31c 100644 --- a/mathics/core/definitions.py +++ b/mathics/core/definitions.py @@ -169,7 +169,14 @@ def __init__( if name.startswith("Global`"): raise ValueError("autoload defined %s." % name) - self.builtin.update(self.user) + # The idea here is that all the symbols loaded in + # autoload become converted in builtin. + # For some reason, if we do not do this here, + # `Export` and `Import` fails. + # TODO: investigate why. + for name in self.user: + self.builtin[name] = self.get_definition(name) + self.user = {} self.clear_cache() From 235e77093fcfe52fa8227cca6eec584c5e92738f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 6 Nov 2022 14:52:51 -0500 Subject: [PATCH 6/7] CommonRadicalBox -> CubeRootRadicalBox --- mathics/autoload/forms/StandardForm.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mathics/autoload/forms/StandardForm.m b/mathics/autoload/forms/StandardForm.m index d44c7b414..425a50422 100644 --- a/mathics/autoload/forms/StandardForm.m +++ b/mathics/autoload/forms/StandardForm.m @@ -10,15 +10,15 @@ (* Change RadBox to RadicalBox. We use RadBox to make it clear that the below code was a read-in from a file and not some pre-existing code. *) -Attributes[CommonRadicalBox] = HoldAll; +Attributes[CubeRootRadicalBox] = HoldAll; Attributes[RadBox] = HoldAll; -CommonRadicalBox[expr_, form_]:= RadBox[MakeBoxes[expr, form], 3]; +CubeRootRadicalBox[expr_, form_]:= RadBox[MakeBoxes[expr, form], 3]; (******************************************************************************************) (* StandardForm Boxing Rules *) (******************************************************************************************) -MakeBoxes[CubeRoot[expr_], StandardForm] := CommonRadicalBox[expr, StandardForm]; +MakeBoxes[CubeRoot[expr_], StandardForm] := CubeRootRadicalBox[expr, StandardForm]; (*All the other StandardForm boxing routines... *) End[] From 21b69859d04a3926a650a06d382d1a4d89fa518a Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 6 Nov 2022 15:15:39 -0500 Subject: [PATCH 7/7] Add WMA links... also, merge accidently reverted a "ssym" removal --- mathics/builtin/assignments/clear.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mathics/builtin/assignments/clear.py b/mathics/builtin/assignments/clear.py index 197e3cd80..44f00cc59 100644 --- a/mathics/builtin/assignments/clear.py +++ b/mathics/builtin/assignments/clear.py @@ -39,6 +39,10 @@ class Clear(Builtin): """ + + :WMA link: + https://reference.wolfram.com/language/ref/Clear.html +
'Clear[$symb1$, $symb2$, ...]'
clears all values of the given symbols. The arguments can also be given as strings containing symbol names. @@ -134,6 +138,10 @@ def apply(self, symbols, evaluation): class ClearAll(Clear): """ + + :WMA link: + https://reference.wolfram.com/language/ref/ClearAll.html +
'ClearAll[$symb1$, $symb2$, ...]'
clears all values, attributes, messages and options associated with the given symbols. @@ -168,6 +176,10 @@ def do_clear(self, definition): class Remove(Builtin): """ + + :WMA link: + https://reference.wolfram.com/language/ref/Remove.html +
'Remove[$x$]'
removes the definition associated to $x$. @@ -181,7 +193,6 @@ class Remove(Builtin): """ attributes = A_HOLD_ALL | A_LOCKED | A_PROTECTED - messages = {"ssym": "`1` is not a symbol."} precedence = 670 summary_text = "remove the definition of a symbol" @@ -198,10 +209,14 @@ def eval(self, symb, evaluation): class Unset(PostfixOperator): """ + + :WMA link: + https://reference.wolfram.com/language/ref/Unset.html +
-
'Unset[$x$]' -
'$x$=.' -
removes any value belonging to $x$. +
'Unset[$x$]' +
'$x$=.' +
removes any value belonging to $x$.
>> a = 2 = 2