diff --git a/mathics/builtin/assignments/upvalues.py b/mathics/builtin/assignments/upvalues.py
deleted file mode 100644
index e62dd9108..000000000
--- a/mathics/builtin/assignments/upvalues.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-UpValue-related assignments
-
-An UpValue is a definition associated with a symbols that does not appear directly its head.
-
-See
-:Associating Definitions with Different Symbols:
-https://reference.wolfram.com/language/tutorial/TransformationRulesAndDefinitions.html#6972.
-"""
-
-from mathics.core.assignment import get_symbol_values
-from mathics.core.attributes import A_HOLD_ALL, A_PROTECTED
-from mathics.core.builtin import Builtin
-
-
-# In Mathematica 5, this appears under "Types of Values".
-class UpValues(Builtin):
- """
- :WMA link: https://reference.wolfram.com/language/ref/UpValues.html
-
- - 'UpValues'[$symbol$]
-
- gives the list of transformation rules corresponding to upvalues \
- define with $symbol$.
-
-
- >> a + b ^= 2
- = 2
- >> UpValues[a]
- = {HoldPattern[a + b] ⧴ 2}
- >> UpValues[b]
- = {HoldPattern[a + b] ⧴ 2}
-
- You can assign values to 'UpValues':
- >> UpValues[pi] := {Sin[pi] :> 0}
- >> Sin[pi]
- = 0
- """
-
- attributes = A_HOLD_ALL | A_PROTECTED
- summary_text = "give a list of transformation rules corresponding to upvalues defined for a symbol"
-
- def eval(self, symbol, evaluation):
- "UpValues[symbol_]"
-
- return get_symbol_values(symbol, "UpValues", "upvalues", evaluation)
diff --git a/mathics/builtin/atomic/__init__.py b/mathics/builtin/atomic/__init__.py
index 57cc0acd2..c1b200002 100644
--- a/mathics/builtin/atomic/__init__.py
+++ b/mathics/builtin/atomic/__init__.py
@@ -3,4 +3,6 @@
Atomic Elements of Expressions
Expressions are ultimately built from a small number of distinct types of atomic elements.
+
+See also :Symbols:/doc/reference-of-built-in-symbols/symbols/.
"""
diff --git a/mathics/builtin/attributes.py b/mathics/builtin/attributes.py
index 424ed9b23..88e7f0a1b 100644
--- a/mathics/builtin/attributes.py
+++ b/mathics/builtin/attributes.py
@@ -22,20 +22,21 @@
A_LOCKED,
A_PROTECTED,
attribute_string_to_number,
- attributes_bitset_to_list,
)
from mathics.core.builtin import Builtin, Predefined
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import Symbol, SymbolNull
+from mathics.core.systemsymbols import (
+ SymbolClearAttributes,
+ SymbolProtected,
+ SymbolSetAttributes,
+)
+from mathics.eval.attributes import eval_Attributes
# This tells documentation how to sort this module
sort_order = "mathics.builtin.definition-attributes"
-SymbolClearAttributes = Symbol("ClearAttributes")
-SymbolSetAttributes = Symbol("SetAttributes")
-SymbolProtected = Symbol("Protected")
-
class Attributes(Builtin):
"""
@@ -89,16 +90,7 @@ class Attributes(Builtin):
def eval(self, expr, evaluation):
"Attributes[expr_]"
-
- if isinstance(expr, String):
- expr = Symbol(expr.value)
- name = expr.get_lookup_name()
-
- attributes = attributes_bitset_to_list(
- evaluation.definitions.get_attributes(name)
- )
- attributes_symbols = [Symbol(attribute) for attribute in attributes]
- return ListExpression(*attributes_symbols)
+ return eval_Attributes(expr, evaluation)
class ClearAttributes(Builtin):
@@ -780,12 +772,18 @@ def eval(self, symbols, evaluation):
names = evaluation.definitions.get_matching_names(pattern)
for defn in names:
symbol = Symbol(defn)
- if not A_LOCKED & evaluation.definitions.get_attributes(defn):
+ attributes = evaluation.definitions.get_attributes(defn)
+ if not A_LOCKED & attributes:
items.append(symbol)
- Expression(
- SymbolClearAttributes,
- ListExpression(*items),
- protected,
- ).evaluate(evaluation)
+ changed_list = ListExpression(*items)
+ if items:
+ Expression(
+ SymbolClearAttributes,
+ changed_list,
+ protected,
+ ).evaluate(evaluation)
+
+ # FIXME this is wrong we should return those attributes that got changed only.
+ # return changed_list
return SymbolNull
diff --git a/mathics/builtin/options.py b/mathics/builtin/options.py
index 61dcb82d5..99f84a66d 100644
--- a/mathics/builtin/options.py
+++ b/mathics/builtin/options.py
@@ -12,7 +12,6 @@
"""
from typing import Callable, Optional
-from mathics.builtin.image.base import Image
from mathics.core.atoms import Integer1, String
from mathics.core.builtin import Builtin, Predefined, Test, get_option
from mathics.core.evaluation import Evaluation
@@ -20,7 +19,8 @@
from mathics.core.list import ListExpression
from mathics.core.parser import parse_builtin_rule
from mathics.core.symbols import Symbol, SymbolList, ensure_context, strip_context
-from mathics.core.systemsymbols import SymbolDefault, SymbolRule, SymbolRuleDelayed
+from mathics.core.systemsymbols import SymbolDefault, SymbolRule
+from mathics.eval.options import eval_Options
from mathics.eval.patterns import Matcher, get_default_value
@@ -358,23 +358,7 @@ class Options(Builtin):
def eval(self, f, evaluation):
"Options[f_]"
-
- name = f.get_name()
- if not name:
- if isinstance(f, Image):
- # FIXME ColorSpace, MetaInformation
- options = f.metadata
- else:
- evaluation.message("Options", "sym", f, Integer1)
- return
- else:
- options = evaluation.definitions.get_options(name)
- result = []
- for option, value in sorted(options.items(), key=lambda item: item[0]):
- # Don't use HoldPattern, since the returned List should be
- # assignable to Options again!
- result.append(Expression(SymbolRuleDelayed, Symbol(option), value))
- return ListExpression(*result)
+ return eval_Options(f, evaluation)
class OptionValue(Builtin):
diff --git a/mathics/builtin/symbol/__init__.py b/mathics/builtin/symbol/__init__.py
new file mode 100644
index 000000000..1316d7769
--- /dev/null
+++ b/mathics/builtin/symbol/__init__.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+"""
+Symbols
+
+Symbols are the atoms of symbolic data. A symbol has a unique name, exists in a Language context or namespace, \
+and can have a variety of types of values and attributes.
+
+Expressions are built from a small number of distinct types of atomic elements.
+"""
diff --git a/mathics/builtin/atomic/symbols.py b/mathics/builtin/symbol/properties.py
similarity index 69%
rename from mathics/builtin/atomic/symbols.py
rename to mathics/builtin/symbol/properties.py
index f541b5bbf..a6e7a621d 100644
--- a/mathics/builtin/atomic/symbols.py
+++ b/mathics/builtin/symbol/properties.py
@@ -1,34 +1,26 @@
-# -*- coding: utf-8 -*-
"""
-Symbol Handling
-
-Symbolic data. Every symbol has a unique name, exists in a certain context \
-or namespace, and can have a variety of types of values and attributes.
+Symbol properties
"""
-import re
+
from typing import Callable, Optional
-from mathics_scanner.tokeniser import NAMES_WILDCARDS, is_symbol_name
+from mathics_scanner.tokeniser import NAMES_WILDCARDS
-from mathics.core.assignment import get_symbol_values
-from mathics.core.atoms import Integer1, String
+from mathics.core.atoms import String
from mathics.core.attributes import (
A_HOLD_ALL,
A_HOLD_FIRST,
- A_LOCKED,
A_PROTECTED,
A_READ_PROTECTED,
- A_SEQUENCE_HOLD,
attributes_bitset_to_list,
)
from mathics.core.builtin import Builtin, PrefixOperator, Test
from mathics.core.convert.expression import to_mathics_list
-from mathics.core.convert.regex import to_regex
from mathics.core.element import BaseElement
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
-from mathics.core.rules import RewriteRule
+from mathics.core.rules import RewriteRule, is_rule
from mathics.core.symbols import (
Symbol,
SymbolFalse,
@@ -36,7 +28,6 @@
SymbolNull,
SymbolTrue,
SymbolUpSet,
- strip_context,
)
from mathics.core.systemsymbols import (
SymbolAttributes,
@@ -49,14 +40,19 @@
SymbolOptions,
SymbolRule,
SymbolSet,
+ SymbolUnknownSymbol,
)
from mathics.doc.online import online_doc_string
from mathics.eval.atomic.symbols import eval_SymbolQ
-from mathics.eval.stackframe import get_eval_Expression
-
-SymbolUnknownSymbol = Symbol("System`UnknownSymbol")
+from mathics.eval.symbol.properties import (
+ eval_Information_with_property,
+ eval_values,
+ missing_symbol,
+)
+# FIXME: gather_and_format_definition_rules is crap and needs to be revised, rewritten and put in
+# mathics.eval.symbols.properties
def gather_and_format_definition_rules(
symbol: Symbol, evaluation: Evaluation
) -> Optional[list[Expression]]:
@@ -175,45 +171,6 @@ def lhs_format(expr):
return lines
-class Context(Builtin):
- r"""
- :WMA link:
- https://reference.wolfram.com/language/ref/Context.html
-
- - 'Context'[$symbol$]
-
- yields the name of the context where $symbol$ is defined in.
-
-
- 'Context[]'
-
- returns the value of '$Context'.
-
-
- >> Context[a]
- = Global`
- >> Context[b`c]
- = b`
-
- >> InputForm[Context[]]
- = "Global`"
- """
-
- attributes = A_HOLD_FIRST | A_PROTECTED
-
- rules = {"Context[]": "$Context"}
-
- summary_text = "give the name of the context of a symbol"
-
- def eval(self, symbol, evaluation):
- "Context[symbol_]"
-
- name = symbol.get_name()
- if not name:
- evaluation.message("Context", "normal", Integer1, get_eval_Expression())
- return
- assert "`" in name
- context = name[: name.rindex("`") + 1]
- return String(context)
-
-
class Definition(Builtin):
"""
:WMA link:
@@ -396,42 +353,32 @@ class DownValues(Builtin):
attributes = A_HOLD_ALL | A_PROTECTED
summary_text = "give a list of transformation rules corresponding to all downvalues defined for a symbol"
- def eval(self, symbol, evaluation):
- "DownValues[symbol_]"
-
- return get_symbol_values(symbol, "DownValues", "downvalues", evaluation)
+ def eval(self, name, evaluation):
+ "DownValues[name_]"
+ return eval_values(name, evaluation, "DownValues")
-# In Mathematica 5, this appears under "Types of Values".
-class FormatValues(Builtin):
+class SymbolQ(Test):
"""
- :WMA link:https://reference.wolfram.com/language/tutorial/PatternsAndTransformationRules.html#6025
+ :WMA link:
+ https://resources.wolframcloud.com/FunctionRepository/resources/SymbolQ
- - 'FormatValues'[$symbol$]
-
- gives the list of format rules associated with $symbol$.
+
- 'SymbolQ'[$x$]
+
- is 'True' if $x$ is a symbol, or 'False' otherwise.
- First, use 'Format' to set a formatting rule for a form:
-
- >> Format[F[x_], OutputForm]:= Subscript[x, F]
-
- Now, to see the rules, we can use 'FormatValues':
-
- >> FormatValues[F]
- = {HoldPattern[Subscript[x_, F]] ⧴ Subscript[x, F]}
-
- The replacement pattern on the right in the delayed rule is formatted according to the top-level form. To see the rule input, we can use 'InputForm':
- >> FormatValues[F] //InputForm
- = {HoldPattern[Format[F[x_], OutputForm]] :> Subscript[x, F]}
+ >> SymbolQ[a]
+ = True
+ >> SymbolQ[1]
+ = False
+ >> SymbolQ[a + b]
+ = False
"""
- summary_text = (
- "give a list of formatting transformation rules associated with a symbol."
- )
+ summary_text = "test whether is a symbol"
- def eval(self, symbol, evaluation):
- """FormatValues[symbol_]"""
- return get_symbol_values(symbol, "FormatValues", "formatvalues", evaluation)
+ def test(self, expr) -> bool:
+ return eval_SymbolQ(expr)
class Information(PrefixOperator):
@@ -448,12 +395,16 @@ class Information(PrefixOperator):
'Information' uses 'InputForm' to format values.
"""
- attributes = A_HOLD_ALL | A_SEQUENCE_HOLD | A_PROTECTED | A_READ_PROTECTED
+ attributes = A_PROTECTED | A_READ_PROTECTED
eval_error = Builtin.generic_argument_error
expected_args = (1, 2)
messages = {"notfound": "Expression `1` is not a symbol"}
+
+ # FIXME: the only valid option is ResolveContextAliases.
+ # LongForm is *not* an option.
options = {
"LongForm": "True",
+ "ResolveContextAliases": "True",
}
summary_text = "get information about all assignments for a symbol"
@@ -461,8 +412,9 @@ def build_missing(self, expression: BaseElement) -> Expression:
"""Evaluate ?? F[x][y].. as -> Missing[UnknownSymbol, F][x][y]"""
if isinstance(expression, Expression):
return Expression(self.build_missing(expression.head), *expression.elements)
- return Expression(SymbolMissing, SymbolUnknownSymbol, expression)
+ return missing_symbol(expression)
+ # FIXME: this is crap and needs to be moved to eval and rewritten.
def build_list_of_matching_symbols(
self, symbol_pat: str, evaluation: Evaluation, options: dict, grid: bool = True
):
@@ -488,6 +440,16 @@ def build_list_of_matching_symbols(
result = Expression(Symbol("System`TableForm"), ListExpression(*rows))
return result
+ def eval_with_property(self, expr, prop, evaluation: Evaluation, options: dict):
+ "Information[expr_, prop_, OptionsPattern[Information]]"
+ if is_rule(prop):
+ # FIXME we have an option here.
+ return
+ if not isinstance(prop, String):
+ return Expression(SymbolMissing, SymbolUnknownSymbol, prop)
+
+ return eval_Information_with_property(expr, prop.value, evaluation)
+
# This implementation mixes the current behavior of WMA >=12.0 with the old behavior
# (WMA 4.0).
# TODO: the formatting part of this must be moved to `InformationData`
@@ -501,8 +463,8 @@ def format_information_generic(
grid: bool = True,
) -> Symbol:
"(StandardForm,TraditionalForm,InputForm,OutputForm,): Information[expr_, OptionsPattern[Information]]"
- evaluation.message("Information", "notfound", expr)
- return self.build_missing(expr)
+ # expr is not a Symbol. We should leave unchanged and let other formatting rules kick in.
+ return None
def format_information_string(
self, strpat: String, evaluation: Evaluation, options: dict, grid: bool = True
@@ -553,184 +515,6 @@ def format_information_symbol(
return infoshow
-class Names(Builtin):
- """
- :WMA link:
- https://reference.wolfram.com/language/ref/Names.html
-
- - 'Names'["$pattern$"]
-
- returns the list of names matching $pattern$.
-
-
- >> Names["List"]
- = {List}
-
- The wildcard '*' matches any character:
- >> Names["List*"]
- = {List, ListLinePlot, ListLogPlot, ListPlot, ListQ, ListStepPlot, Listable}
-
- The wildcard '@' matches only lowercase characters:
- >> Names["List@"]
- = {Listable}
-
- >> x = 5;
- >> Names["Global`*"]
- = {x}
-
- The number of built-in symbols:
- >> Length[Names["System`*"]]
- = ...
- """
-
- summary_text = "find a list of symbols with names matching a pattern"
-
- def eval(self, pattern, evaluation: Evaluation):
- "Names[pattern_]"
- headname = pattern.get_head_name()
- if headname == "System`StringExpression":
- pattern = re.compile(to_regex(pattern, show_message=evaluation.message))
- else:
- pattern = pattern.get_string_value()
-
- if pattern is None:
- return
-
- names = set()
- for full_name in evaluation.definitions.get_matching_names(pattern):
- short_name = strip_context(full_name)
- names.add(short_name if short_name not in names else full_name)
-
- # TODO: Mathematica ignores contexts when it sorts the list of
- # names.
- return to_mathics_list(*sorted(names), elements_conversion_fn=String)
-
-
-# In Mathematica 5, this appears under "Types of Values".
-class OwnValues(Builtin):
- """
- :WMA link:
- https://reference.wolfram.com/language/ref/OwnValues.html
-
- - 'OwnValues'[$symbol$]
-
- gives the list of ownvalue associated with $symbol$.
-
-
- >> x = 3;
- >> x = 2;
- >> OwnValues[x]
- = {HoldPattern[x] ⧴ 2}
- >> x := y
- >> OwnValues[x]
- = {HoldPattern[x] ⧴ y}
- >> y = 5;
- >> OwnValues[x]
- = {HoldPattern[x] ⧴ y}
- >> Hold[x] /. OwnValues[x]
- = Hold[y]
- >> Hold[x] /. OwnValues[x] // ReleaseHold
- = 5
- """
-
- attributes = A_HOLD_ALL | A_PROTECTED
- summary_text = "give the rule corresponding to any ownvalue defined for a symbol"
-
- def eval(self, symbol, evaluation):
- "OwnValues[symbol_]"
-
- return get_symbol_values(symbol, "OwnValues", "ownvalues", evaluation)
-
-
-class Symbol_(Builtin):
- """
- :WMA link:
- https://reference.wolfram.com/language/ref/Symbol.html
-
- - 'Symbol'
-
- is the head of symbols.
-
-
- >> Head[x]
- = Symbol
- You can use 'Symbol' to create symbols from strings:
- >> Symbol["x"] + Symbol["x"]
- = 2 x
- """
-
- attributes = A_LOCKED | A_PROTECTED
- eval_error = Builtin.generic_argument_error
- expected_args = 1
-
- messages = {
- "symname": (
- "The string `1` cannot be used for a symbol name. "
- "A symbol name must start with a letter "
- "followed by letters and numbers."
- ),
- }
-
- name = "Symbol"
-
- summary_text = "the head of a symbol; create a symbol from a name"
-
- def eval(self, string, evaluation):
- "Symbol[string_String]"
-
- text = string.value
- if is_symbol_name(text):
- return Symbol(evaluation.definitions.lookup_name(string.value))
- else:
- evaluation.message("Symbol", "symname", string)
-
-
-class SymbolName(Builtin):
- """
- :WMA link:
- https://reference.wolfram.com/language/ref/SymbolName.html
-
- - 'SymbolName'[$s$]
-
- returns the name of the symbol $s$ (without any leading \
- context name).
-
-
- >> SymbolName[x] // InputForm
- = "x"
- """
-
- eval_error = Builtin.generic_argument_error
- expected_args = 1
- summary_text = "give the name of a symbol as a string"
-
- def eval(self, symbol, evaluation):
- "SymbolName[symbol_Symbol]"
-
- # MMA docs say "SymbolName always give the short name,
- # without any context"
- return String(strip_context(symbol.get_name()))
-
-
-class SymbolQ(Test):
- """
- :WMA link:
- https://resources.wolframcloud.com/FunctionRepository/resources/SymbolQ
-
- - 'SymbolQ'[$x$]
-
- is 'True' if $x$ is a symbol, or 'False' otherwise.
-
-
- >> SymbolQ[a]
- = True
- >> SymbolQ[1]
- = False
- >> SymbolQ[a + b]
- = False
- """
-
- summary_text = "test whether is a symbol"
-
- def test(self, expr) -> bool:
- return eval_SymbolQ(expr)
-
-
class ValueQ(Builtin):
"""
:WMA link:
@@ -758,3 +542,34 @@ def eval(self, expr, evaluation):
if expr.sameQ(evaluated_expr):
return SymbolFalse
return SymbolTrue
+
+
+# In Mathematica 5, this appears under "Types of Values".
+class UpValues(Builtin):
+ """
+ :WMA link: https://reference.wolfram.com/language/ref/UpValues.html
+
+ - 'UpValues'[$symbol$]
+
- gives the list of transformation rules corresponding to upvalues \
+ define with $symbol$.
+
+
+ >> a + b ^= 2
+ = 2
+ >> UpValues[a]
+ = {HoldPattern[a + b] ⧴ 2}
+ >> UpValues[b]
+ = {HoldPattern[a + b] ⧴ 2}
+
+ You can assign values to 'UpValues':
+ >> UpValues[pi] := {Sin[pi] :> 0}
+ >> Sin[pi]
+ = 0
+ """
+
+ attributes = A_HOLD_ALL | A_PROTECTED
+ summary_text = "give a list of transformation rules corresponding to upvalues defined for a symbol"
+
+ def eval(self, name, evaluation):
+ "UpValues[name_]"
+ return eval_values(name, evaluation, "UpValues")
diff --git a/mathics/builtin/symbol/symbols.py b/mathics/builtin/symbol/symbols.py
new file mode 100644
index 000000000..24e561c7b
--- /dev/null
+++ b/mathics/builtin/symbol/symbols.py
@@ -0,0 +1,243 @@
+# -*- coding: utf-8 -*-
+"""
+Basic Symbol components
+"""
+import re
+
+from mathics_scanner.tokeniser import is_symbol_name
+
+from mathics.core.assignment import get_symbol_values
+from mathics.core.atoms import Integer1, String
+from mathics.core.attributes import A_HOLD_ALL, A_HOLD_FIRST, A_LOCKED, A_PROTECTED
+from mathics.core.builtin import Builtin
+from mathics.core.convert.expression import to_mathics_list
+from mathics.core.convert.regex import to_regex
+from mathics.core.evaluation import Evaluation
+from mathics.core.symbols import Symbol, strip_context
+from mathics.eval.stackframe import get_eval_Expression
+
+
+class Context(Builtin):
+ r"""
+ :WMA link:
+ https://reference.wolfram.com/language/ref/Context.html
+
+ - 'Context'[$symbol$]
+
- yields the name of the context where $symbol$ is defined in.
+
+
- 'Context[]'
+
- returns the value of '$Context'.
+
+
+ >> Context[a]
+ = Global`
+ >> Context[b`c]
+ = b`
+
+ >> InputForm[Context[]]
+ = "Global`"
+ """
+
+ attributes = A_HOLD_FIRST | A_PROTECTED
+
+ rules = {"Context[]": "$Context"}
+
+ summary_text = "give the name of the context of a symbol"
+
+ def eval(self, symbol, evaluation):
+ "Context[symbol_]"
+
+ name = symbol.get_name()
+ if not name:
+ evaluation.message("Context", "normal", Integer1, get_eval_Expression())
+ return
+ assert "`" in name
+ context = name[: name.rindex("`") + 1]
+ return String(context)
+
+
+# In Mathematica 5, this appears under "Types of Values".
+class FormatValues(Builtin):
+ """
+ :WMA link:https://reference.wolfram.com/language/tutorial/PatternsAndTransformationRules.html#6025
+
+ - 'FormatValues'[$symbol$]
+
- gives the list of format rules associated with $symbol$.
+
+
+ First, use 'Format' to set a formatting rule for a form:
+
+ >> Format[F[x_], OutputForm]:= Subscript[x, F]
+
+ Now, to see the rules, we can use 'FormatValues':
+
+ >> FormatValues[F]
+ = {HoldPattern[Subscript[x_, F]] ⧴ Subscript[x, F]}
+
+ The replacement pattern on the right in the delayed rule is formatted according to the top-level form. To see the rule input, we can use 'InputForm':
+ >> FormatValues[F] //InputForm
+ = {HoldPattern[Format[F[x_], OutputForm]] :> Subscript[x, F]}
+ """
+
+ summary_text = (
+ "give a list of formatting transformation rules associated with a symbol."
+ )
+
+ def eval(self, symbol, evaluation):
+ """FormatValues[symbol_]"""
+ return get_symbol_values(symbol, "FormatValues", "formatvalues", evaluation)
+
+
+class Names(Builtin):
+ """
+ :WMA link:
+ https://reference.wolfram.com/language/ref/Names.html
+
+ - 'Names'["$pattern$"]
+
- returns the list of names matching $pattern$.
+
+
+ >> Names["List"]
+ = {List}
+
+ The wildcard '*' matches any character:
+ >> Names["List*"]
+ = {List, ListLinePlot, ListLogPlot, ListPlot, ListQ, ListStepPlot, Listable}
+
+ The wildcard '@' matches only lowercase characters:
+ >> Names["List@"]
+ = {Listable}
+
+ >> x = 5;
+ >> Names["Global`*"]
+ = {x}
+
+ The number of built-in symbols:
+ >> Length[Names["System`*"]]
+ = ...
+ """
+
+ summary_text = "find a list of symbols with names matching a pattern"
+
+ def eval(self, pattern, evaluation: Evaluation):
+ "Names[pattern_]"
+ headname = pattern.get_head_name()
+ if headname == "System`StringExpression":
+ pattern = re.compile(to_regex(pattern, show_message=evaluation.message))
+ else:
+ pattern = pattern.get_string_value()
+
+ if pattern is None:
+ return
+
+ names = set()
+ for full_name in evaluation.definitions.get_matching_names(pattern):
+ short_name = strip_context(full_name)
+ names.add(short_name if short_name not in names else full_name)
+
+ # TODO: Mathematica ignores contexts when it sorts the list of
+ # names.
+ return to_mathics_list(*sorted(names), elements_conversion_fn=String)
+
+
+# In Mathematica 5, this appears under "Types of Values".
+class OwnValues(Builtin):
+ """
+ :WMA link:
+ https://reference.wolfram.com/language/ref/OwnValues.html
+
+ - 'OwnValues'[$symbol$]
+
- gives the list of ownvalue associated with $symbol$.
+
+
+ >> x = 3;
+ >> x = 2;
+ >> OwnValues[x]
+ = {HoldPattern[x] ⧴ 2}
+ >> x := y
+ >> OwnValues[x]
+ = {HoldPattern[x] ⧴ y}
+ >> y = 5;
+ >> OwnValues[x]
+ = {HoldPattern[x] ⧴ y}
+ >> Hold[x] /. OwnValues[x]
+ = Hold[y]
+ >> Hold[x] /. OwnValues[x] // ReleaseHold
+ = 5
+ """
+
+ attributes = A_HOLD_ALL | A_PROTECTED
+ summary_text = "give the rule corresponding to any ownvalue defined for a symbol"
+
+ def eval(self, symbol, evaluation):
+ "OwnValues[symbol_]"
+
+ return get_symbol_values(symbol, "OwnValues", "ownvalues", evaluation)
+
+
+class Symbol_(Builtin):
+ """
+ :WMA link:
+ https://reference.wolfram.com/language/ref/Symbol.html
+
+ - 'Symbol'
+
- is the head of symbols.
+
+
+ >> Head[x]
+ = Symbol
+ You can use 'Symbol' to create symbols from strings:
+ >> Symbol["x"] + Symbol["x"]
+ = 2 x
+ """
+
+ attributes = A_LOCKED | A_PROTECTED
+ eval_error = Builtin.generic_argument_error
+ expected_args = 1
+
+ messages = {
+ "symname": (
+ "The string `1` cannot be used for a symbol name. "
+ "A symbol name must start with a letter "
+ "followed by letters and numbers."
+ ),
+ }
+
+ name = "Symbol"
+
+ summary_text = "the head of a symbol; create a symbol from a name"
+
+ def eval(self, string, evaluation):
+ "Symbol[string_String]"
+
+ text = string.value
+ if is_symbol_name(text):
+ return Symbol(evaluation.definitions.lookup_name(string.value))
+ else:
+ evaluation.message("Symbol", "symname", string)
+
+
+class SymbolName(Builtin):
+ """
+ :WMA link:
+ https://reference.wolfram.com/language/ref/SymbolName.html
+
+ - 'SymbolName'[$s$]
+
- returns the name of the symbol $s$ (without any leading \
+ context name).
+
+
+ >> SymbolName[x] // InputForm
+ = "x"
+ """
+
+ eval_error = Builtin.generic_argument_error
+ expected_args = 1
+ summary_text = "give the name of a symbol as a string"
+
+ def eval(self, symbol, evaluation):
+ "SymbolName[symbol_Symbol]"
+
+ # MMA docs say "SymbolName always give the short name,
+ # without any context"
+ return String(strip_context(symbol.get_name()))
diff --git a/mathics/core/assignment.py b/mathics/core/assignment.py
index a75fcd28a..6dad5e0bc 100644
--- a/mathics/core/assignment.py
+++ b/mathics/core/assignment.py
@@ -7,6 +7,7 @@
from typing import Callable, List, Optional, Tuple
+from mathics.core.atoms import Integer1
from mathics.core.attributes import A_PROTECTED
from mathics.core.builtin import Builtin
from mathics.core.definitions import Definitions
@@ -102,7 +103,7 @@ def get_symbol_values(
"""
if not isinstance(symbol, Symbol):
- evaluation.message(func_name, "sym", symbol, 1)
+ evaluation.message(func_name, "sym", symbol, Integer1)
return None
name = symbol.get_name()
definitions = evaluation.definitions
diff --git a/mathics/core/systemsymbols.py b/mathics/core/systemsymbols.py
index 4e936bb97..95f0934a0 100644
--- a/mathics/core/systemsymbols.py
+++ b/mathics/core/systemsymbols.py
@@ -68,6 +68,7 @@
SymbolCases = Symbol("System`Cases")
SymbolCatalan = Symbol("System`Catalan")
SymbolCeiling = Symbol("System`Ceiling")
+SymbolClearAttributes = Symbol("System`ClearAttributes")
SymbolClipPlanes = Symbol("System`ClipPlanes")
SymbolClipPlanesStyle = Symbol("System`ClipPlanesStyle")
SymbolClusteringComponents = Symbol("System`ClusteringComponents")
@@ -145,6 +146,7 @@
SymbolFunction = Symbol("System`Function")
SymbolGamma = Symbol("System`Gamma")
SymbolGet = Symbol("System`Get")
+SymbolGlaisher = Symbol("System`Glaisher")
SymbolGoldenRatio = Symbol("System`GoldenRatio")
SymbolGraphics = Symbol("System`Graphics")
SymbolGraphics3D = Symbol("System`Graphics3D")
@@ -283,6 +285,7 @@
SymbolPrefix = Symbol("System`Prefix")
SymbolPreserveImageOptions = Symbol("System`PreserveImageOptions")
SymbolProlog = Symbol("System`Prolog")
+SymbolProtected = Symbol("System`Protected")
SymbolQuantity = Symbol("System`Quantity")
SymbolQuiet = Symbol("System`Quiet")
SymbolQuotient = Symbol("System`Quotient")
@@ -318,6 +321,7 @@
SymbolSeries = Symbol("System`Series")
SymbolSeriesData = Symbol("System`SeriesData")
SymbolSet = Symbol("System`Set")
+SymbolSetAttributes = Symbol("System`SetAttributes")
SymbolSign = Symbol("System`Sign")
SymbolSimplify = Symbol("System`Simplify")
SymbolSin = Symbol("System`Sin")
@@ -377,6 +381,8 @@
SymbolUndefined = Symbol("System`Undefined")
SymbolUnequal = Symbol("System`Unequal")
SymbolUnevaluated = Symbol("System`Unevaluated")
+SymbolUnknownProperty = Symbol("System`UnknownProperty")
+SymbolUnknownSymbol = Symbol("System`UnknownSymbol")
SymbolUpValues = Symbol("System`UpValues")
SymbolVariance = Symbol("System`Variance")
SymbolVerbatim = Symbol("Verbatim")
diff --git a/mathics/eval/attributes.py b/mathics/eval/attributes.py
new file mode 100644
index 000000000..fe0aa7446
--- /dev/null
+++ b/mathics/eval/attributes.py
@@ -0,0 +1,19 @@
+"""
+Evaluation functions for builtins in mathics.core.builtin.attributes
+"""
+
+from mathics.core.atoms import String
+from mathics.core.attributes import attributes_bitset_to_list
+from mathics.core.evaluation import Evaluation
+from mathics.core.list import ListExpression
+from mathics.core.symbols import Symbol
+
+
+def eval_Attributes(expr, evaluation: Evaluation):
+ if isinstance(expr, String):
+ expr = Symbol(expr.value)
+ name = expr.get_lookup_name()
+
+ attributes = attributes_bitset_to_list(evaluation.definitions.get_attributes(name))
+ attributes_symbols = [Symbol(attribute) for attribute in attributes]
+ return ListExpression(*attributes_symbols)
diff --git a/mathics/eval/options.py b/mathics/eval/options.py
new file mode 100644
index 000000000..2ba895745
--- /dev/null
+++ b/mathics/eval/options.py
@@ -0,0 +1,28 @@
+from typing import Optional
+
+from mathics.builtin.image.base import Image
+from mathics.core.atoms import Integer1
+from mathics.core.evaluation import Evaluation
+from mathics.core.expression import Expression
+from mathics.core.list import ListExpression
+from mathics.core.symbols import Symbol
+from mathics.core.systemsymbols import SymbolRuleDelayed
+
+
+def eval_Options(f, evaluation: Evaluation) -> Optional[ListExpression]:
+ name = f.get_name()
+ if not name:
+ if isinstance(f, Image):
+ # FIXME ColorSpace, MetaInformation
+ options = f.metadata
+ else:
+ evaluation.message("Options", "sym", f, Integer1)
+ return
+ else:
+ options = evaluation.definitions.get_options(name)
+ result = []
+ for option, value in sorted(options.items(), key=lambda item: item[0]):
+ # Don't use HoldPattern, since the returned List should be
+ # assignable to Options again!
+ result.append(Expression(SymbolRuleDelayed, Symbol(option), value))
+ return ListExpression(*result)
diff --git a/mathics/eval/symbol/__init__.py b/mathics/eval/symbol/__init__.py
new file mode 100644
index 000000000..1932a0a62
--- /dev/null
+++ b/mathics/eval/symbol/__init__.py
@@ -0,0 +1,4 @@
+"""
+Evaluation routines and associated code for Built-in functions found under module
+mathics.builtins.symbol.properties.
+"""
diff --git a/mathics/eval/symbol/properties.py b/mathics/eval/symbol/properties.py
new file mode 100644
index 000000000..401027ebe
--- /dev/null
+++ b/mathics/eval/symbol/properties.py
@@ -0,0 +1,326 @@
+"""
+Evaluation routines for builtin function in mathics.core.builtin.symbol.properties.
+"""
+
+from functools import cache
+from typing import Final
+
+from mathics.core.assignment import get_symbol_values
+from mathics.core.atoms import String
+from mathics.core.attributes import A_READ_PROTECTED
+from mathics.core.evaluation import Evaluation
+from mathics.core.expression import Expression
+from mathics.core.list import ListExpression
+from mathics.core.symbols import Symbol
+from mathics.core.systemsymbols import (
+ SymbolMissing,
+ SymbolNone,
+ SymbolUnknownProperty,
+ SymbolUnknownSymbol,
+)
+from mathics.eval.attributes import eval_Attributes
+from mathics.eval.options import eval_Options
+
+ALL_PROPERTIES: Final[ListExpression] = ListExpression(
+ String("Attributes"),
+ String("DefaultValues"),
+ # String("Definitions"),
+ String("DownValues"),
+ String("FormatValues"),
+ String("FullName"),
+ String("NValues"),
+ String("Options"),
+ String("Ownvalues"),
+ String("SubValues"),
+ String("UpValues"),
+ # String("Usage"),
+)
+
+
+def eval_Information_with_property(expr, property: str, evaluation: Evaluation):
+ match property:
+ case "Attributes":
+ return eval_Attributes(expr, evaluation)
+ case (
+ "DefaultValues"
+ | "DownValues"
+ | "FormatValues"
+ | "NValues"
+ | "OwnValues"
+ | "SubValues"
+ | "UpValues"
+ ):
+ return information_values(expr, evaluation, property)
+ # case "Definitions":
+ # return information_values(expr, evaluation.definitions, "defaultvalues")
+ return information_fullname(expr)
+ case "Options":
+ return eval_Options(expr, evaluation)
+ case "Properties":
+ return ALL_PROPERTIES
+ # case "Usage":
+ # return information_values(expr, evaluation.definitions, "upvalues")
+ case _:
+ return missing_property(property)
+ return
+
+
+def eval_values(name: Symbol | String, evaluation: Evaluation, attribute: str):
+ """
+ Evaluation function for xxxValues, e.g. DownValues, UpValues, ...
+ """
+ name_symbol = (
+ Symbol(evaluation.definitions.lookup_name(name.value))
+ if isinstance(name, String)
+ else name
+ )
+ return get_symbol_values(name_symbol, attribute, attribute.lower(), evaluation)
+
+
+def information_values(name: Symbol | String, evaluation, value_type: str):
+ """
+ Evaluation function for Information[name, xxxValues].
+ This is similar to eval_values, however the results change slightly
+ 1. 'None' returned in the key is not found
+ 2. The READ_PROTECTED attribute is is respected
+ 3. Empty values return 'None' instead of {}.
+
+ """
+ if isinstance(name, String):
+ name_str = name.value
+ name_symbol = Symbol(evaluation.definitions.lookup_name(name.value))
+ else:
+ name_str = name.name
+ name_symbol = name
+
+ definitions = evaluation.definitions
+ name = definitions.lookup_name(name_str)
+ try:
+ definition = definitions.get_definition(name_str, only_if_exists=True)
+ except KeyError:
+ return SymbolNone
+
+ attributes = definition.attributes
+ if not A_READ_PROTECTED & attributes:
+ return SymbolNone
+ values = get_symbol_values(name_symbol, value_type, value_type.lower(), evaluation)
+ return SymbolNone if not values else values
+
+
+# FIXME there should be an eval_Fullname for this.
+def information_fullname(symbol: Symbol):
+ return String(symbol)
+
+
+@cache
+def missing_property(property) -> Expression:
+ return Expression(SymbolMissing, SymbolUnknownProperty, Symbol(property))
+
+
+@cache
+def missing_symbol(expression) -> Expression:
+ return Expression(SymbolMissing, SymbolUnknownSymbol, expression)
+
+
+# The stuff below is from old Mathics code and needs to be revised
+# and rewritten.
+
+# def gather_and_format_definition_rules(
+# symbol: Symbol, evaluation: Evaluation
+# ) -> Optional[list[Expression]]:
+# """Return a list of lines describing the definition of `symbol`"""
+# lines = []
+
+# def rhs_format(expr):
+# if expr.has_form("Infix", None):
+# expr = Expression(Expression(SymbolHoldForm, expr.head), *expr.elements)
+# return expr
+
+# def format_rule(
+# rule: RewriteRule,
+# up: bool = False,
+# lhs: Callable = lambda k: k,
+# rhs: Callable = lambda r: r,
+# ):
+# """
+# Add a line showing `rule`
+# """
+# evaluation.check_stopped()
+# if isinstance(rule, RewriteRule):
+# lhs_pat = Expression(SymbolInputForm, lhs(rule.pattern.expr))
+# repl_expr = rhs(
+# rule.replace.replace_vars(
+# {"System`Definition": Expression(SymbolHoldForm, SymbolDefinition)}
+# )
+# )
+# repl_expr = Expression(SymbolInputForm, repl_expr)
+# lines.append(
+# Expression(
+# SymbolHoldForm,
+# Expression(up and SymbolUpSet or SymbolSet, lhs_pat, repl_expr),
+# )
+# )
+
+# def gather_rules(definition: Definition):
+# """
+# Add to the description all the rules associated
+# to a definition object
+# """
+# for rule in definition.ownvalues:
+# format_rule(rule)
+# for rule in definition.downvalues:
+# format_rule(rule)
+# for rule in definition.subvalues:
+# format_rule(rule)
+# for rule in definition.upvalues:
+# format_rule(rule, up=True)
+# for rule in definition.nvalues:
+# format_rule(rule)
+# formats = sorted(definition.formatvalues.items())
+# for form_name, rules in formats:
+# for rule in rules:
+
+# def lhs_format(expr):
+# return Expression(SymbolFormat, expr, Symbol(form_name))
+
+# format_rule(rule, lhs=lhs_format, rhs=rhs_format)
+
+# name = symbol.get_name()
+# if not name:
+# evaluation.message("Definition", "sym", symbol, 1)
+# return
+
+# try:
+# all = evaluation.definitions.get_definition(name)
+# attributes = all.attributes
+# all_options = all.options
+# all_defaultvalues = all.defaultvalues
+
+# if attributes:
+# attributes_list = attributes_bitset_to_list(attributes)
+# lines.append(
+# Expression(
+# SymbolHoldForm,
+# Expression(
+# SymbolSet,
+# Expression(SymbolAttributes, symbol),
+# to_mathics_list(
+# *attributes_list, elements_conversion_fn=Symbol
+# ),
+# ),
+# )
+# )
+# except KeyError:
+# attributes = 0
+# all_options = {}
+# all_defaultvalues = []
+
+# if not A_READ_PROTECTED & attributes:
+# try:
+# gather_rules(evaluation.definitions.get_user_definition(name, create=False))
+# except KeyError:
+# pass
+
+# for rule in all_defaultvalues:
+# format_rule(rule)
+# if all_options:
+# options = sorted(all_options.items())
+# lines.append(
+# Expression(
+# SymbolHoldForm,
+# Expression(
+# SymbolSet,
+# Expression(SymbolOptions, symbol),
+# ListExpression(
+# *(
+# Expression(SymbolRule, Symbol(name), value)
+# for name, value in options
+# )
+# ),
+# ),
+# )
+# )
+# return lines
+
+
+# def build_list_of_matching_symbols(
+# self, symbol_pat: str, evaluation: Evaluation, options: dict, grid: bool = True
+# ):
+# """Return a list of symbols compatible with symbol_pat"""
+# definitions = evaluation.definitions
+# names = definitions.get_matching_names(symbol_pat)
+# if len(names) == 1:
+# return self.format_information_symbol(
+# Symbol(definitions.lookup_name(names[0])), evaluation, options
+# )
+# rows = []
+# curr_row = []
+# for name in names:
+# curr_row.append(String(definitions.shorten_name(name)))
+# if len(curr_row) == 3:
+# rows.append(ListExpression(*curr_row))
+# curr_row = []
+# if curr_row:
+# curr_row = curr_row + (3 - len(curr_row)) * [String("")]
+# rows.append(ListExpression(*curr_row))
+
+# # Build Association with Information fields for each matching symbol
+# associations = []
+# for name in names:
+# symbol = Symbol(definitions.lookup_name(name))
+
+# # Get symbol definition to extract attributes and values
+# try:
+# definition = definitions.get_definition(name)
+# except KeyError:
+# definition = None
+
+# # Extract components for Association
+# assoc_items = [
+# Expression(SymbolRule, String("FullName"), String(name)),
+# ]
+
+# # Add Attributes
+# if definition and definition.attributes:
+# attributes_list = attributes_bitset_to_list(definition.attributes)
+# assoc_items.append(
+# Expression(
+# SymbolRule,
+# String("Attributes"),
+# to_mathics_list(
+# *attributes_list, elements_conversion_fn=Symbol
+# ),
+# )
+# )
+
+# # Add Definitions (downvalues, ownvalues, upvalues)
+# definition_rules = gather_and_format_definition_rules(symbol, evaluation)
+# if definition_rules:
+# assoc_items.append(
+# Expression(
+# SymbolRule,
+# String("Definitions"),
+# ListExpression(*definition_rules),
+# )
+# )
+
+# # Add OwnValues
+# ownvalues = get_symbol_values(symbol, "OwnValues", "ownvalues", evaluation)
+# if ownvalues:
+# assoc_items.append(
+# Expression(SymbolRule, String("OwnValues"), ownvalues)
+# )
+
+# # Add DownValues
+# downvalues = get_symbol_values(
+# symbol, "DownValues", "downvalues", evaluation
+# )
+# if downvalues:
+# assoc_items.append(
+# Expression(SymbolRule, String("DownValues"), downvalues)
+# )
+
+# associations.append(Expression(SymbolAssociation, *assoc_items))
+
+# result = ListExpression(*associations)
+# return result
diff --git a/test/builtin/assignments/test_assignment.py b/test/builtin/assignments/test_assignment.py
index 288a378c0..a6f1243fa 100644
--- a/test/builtin/assignments/test_assignment.py
+++ b/test/builtin/assignments/test_assignment.py
@@ -435,35 +435,6 @@ def test_process_assign_other():
)
-@pytest.mark.parametrize(
- ("str_expr", "str_expected", "msgs", "failure_msg"),
- [
- (None, None, None, None),
- # From Clear
- ("x = 2;OwnValues[x]=.;x", "x", None, "Erase Ownvalues"),
- ("f[a][b] = 3; SubValues[f] =.;f[a][b]", "f[a][b]", None, "Erase Subvalues"),
- ("PrimeQ[p] ^= True; PrimeQ[p]", "True", None, "Subvalues"),
- ("UpValues[p]=.; PrimeQ[p]", "False", None, "Erase Subvalues"),
- ("a + b ^= 5; a =.; a + b", "5", None, None),
- ("{UpValues[a], UpValues[b]} =.; a+b", "a+b", None, None),
- (
- "Unset[Messages[1]]",
- "$Failed",
- [
- "First argument in Messages[1] is not a symbol or a string naming a symbol."
- ],
- "Unset Message",
- ),
- (" g[a+b] ^:= 2", "$Failed", ("Tag Plus in g[a + b] is Protected.",), None),
- (" g[a+b]", "g[a + b]", None, None),
- ],
-)
-def test_upvalues_ownvalues(str_expr, str_expected, msgs, failure_msg):
- check_evaluation(
- str_expr, str_expected, expected_messages=msgs, failure_message=failure_msg
- )
-
-
@pytest.mark.parametrize(
["expr", "expect", "fail_msg", "expected_msgs"],
[
diff --git a/test/builtin/symbol/__init__.py b/test/builtin/symbol/__init__.py
new file mode 100644
index 000000000..40a96afc6
--- /dev/null
+++ b/test/builtin/symbol/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/test/builtin/symbol/test_properties.py b/test/builtin/symbol/test_properties.py
new file mode 100644
index 000000000..9de1ff186
--- /dev/null
+++ b/test/builtin/symbol/test_properties.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""
+Unit tests from mathics.builtin.symbol.properties
+"""
+from test.helper import check_evaluation
+
+import pytest
+
+
+def test_downvalues():
+ for str_expr, str_expected, assert_fail_message in (
+ (
+ "DownValues[foo]={x_^2:>y}",
+ "{x_ ^ 2 :> y}",
+ "Issue #1251 part 1",
+ ),
+ (
+ "DownValues[foo]",
+ "{HoldPattern[x_ ^ 2] :> y}",
+ "Check that we get the DownValue just assigned.",
+ ),
+ (
+ 'DownValues["foo"]',
+ "{HoldPattern[x_ ^ 2] :> y}",
+ "A string is allowed in as a DownValues argument.",
+ ),
+ (
+ "PrependTo[DownValues[foo], {x_^3:>z}]",
+ "{{x_ ^ 3 :> z}, HoldPattern[x_ ^ 2] :> y}",
+ "Issue #1251 part 2",
+ ),
+ (
+ "DownValues[foo]={x_^3:>y}",
+ "{x_ ^ 3 :> y}",
+ "Issue #1251 part 3",
+ ),
+ ):
+ check_evaluation(
+ str_expr,
+ str_expected,
+ assert_fail_message,
+ to_string_expr=False,
+ to_string_expected=False,
+ )
+
+
+@pytest.mark.parametrize(
+ ("str_expr", "str_expected", "msgs", "failure_msg"),
+ [
+ (None, None, None, None),
+ # From Clear
+ ("x = 2;OwnValues[x]=.;x", "x", None, "Erase Ownvalues"),
+ ("f[a][b] = 3; SubValues[f] =.;f[a][b]", "f[a][b]", None, "Erase Subvalues"),
+ ("PrimeQ[p] ^= True; PrimeQ[p]", "True", None, "Subvalues"),
+ ("UpValues[p]=.; PrimeQ[p]", "False", None, "Erase Subvalues"),
+ ("a + b ^= 5; a =.; a + b", "5", None, None),
+ ("{UpValues[a], UpValues[b]} =.; a+b", "a+b", None, None),
+ (
+ "Unset[Messages[1]]",
+ "$Failed",
+ [
+ "First argument in Messages[1] is not a symbol or a string naming a symbol."
+ ],
+ "Unset Message",
+ ),
+ (" g[a+b] ^:= 2", "$Failed", ("Tag Plus in g[a + b] is Protected.",), None),
+ (" g[a+b]", "g[a + b]", None, None),
+ ],
+)
+def test_upvalues_ownvalues(str_expr, str_expected, msgs, failure_msg):
+ check_evaluation(
+ str_expr, str_expected, expected_messages=msgs, failure_message=failure_msg
+ )
diff --git a/test/builtin/atomic/test_symbols.py b/test/builtin/symbol/test_symbols.py
similarity index 79%
rename from test/builtin/atomic/test_symbols.py
rename to test/builtin/symbol/test_symbols.py
index 6c9180289..46c4e8038 100644
--- a/test/builtin/atomic/test_symbols.py
+++ b/test/builtin/symbol/test_symbols.py
@@ -1,33 +1,12 @@
# -*- coding: utf-8 -*-
"""
-Unit tests from mathics.builtin.atomic.symbols.
+Unit tests from mathics.builtin.symbol.symbols.
"""
from test.helper import check_arg_counts, check_evaluation
import pytest
-def test_downvalues():
- for str_expr, str_expected, message in (
- (
- "DownValues[foo]={x_^2:>y}",
- "{x_ ^ 2 :> y}",
- "Issue #1251 part 1",
- ),
- (
- "PrependTo[DownValues[foo], {x_^3:>z}]",
- "{{x_ ^ 3 :> z}, HoldPattern[x_ ^ 2] :> y}",
- "Issue #1251 part 2",
- ),
- (
- "DownValues[foo]={x_^3:>y}",
- "{x_ ^ 3 :> y}",
- "Issue #1251 part 3",
- ),
- ):
- check_evaluation(str_expr, str_expected, message)
-
-
@pytest.mark.parametrize(
("str_expr", "warnings", "str_expected", "fail_msg"),
[
@@ -39,8 +18,19 @@ def test_downvalues():
("a`x === b`x", None, "False", None),
## awkward parser cases
("FullForm[a`b_]", None, "Pattern[a`b, Blank[]]", None),
- ("a = 2;", None, "Null", None),
- ("Information[a]", tuple(), "Global`a\n\na = 2\n", None),
+ (
+ "Clear[a]; Information[a]",
+ tuple(),
+ "Global`a\n",
+ "When a symbol is not bound, Information[] of that symbol should return the context and name.",
+ ),
+ (
+ "a = 2;",
+ None,
+ "Null",
+ "When a symbol is bound, Information[] of that symbol do anything.",
+ ),
+ ("Information[a]", tuple(), "Information[2]", None),
(
"{?? q, ?? q}",
tuple(),
diff --git a/test/builtin/symbolic_history/test_stack.py b/test/builtin/symbolic_history/test_stack.py
index 8966d9d1e..aeeb23646 100644
--- a/test/builtin/symbolic_history/test_stack.py
+++ b/test/builtin/symbolic_history/test_stack.py
@@ -13,7 +13,7 @@ def test_trace():
"Trace with Constant - no intermediate values",
),
(
- "Trace[a]",
+ "Clear[a]; Trace[a]",
"{}",
"Trace with Symbol - no intermediate values",
),