diff --git a/mathics/builtin/assignments/assignment.py b/mathics/builtin/assignments/assignment.py
index 955ecd474..84fe47288 100644
--- a/mathics/builtin/assignments/assignment.py
+++ b/mathics/builtin/assignments/assignment.py
@@ -355,10 +355,6 @@ class UpSet(InfixOperator, _SetOperator):
>> UpValues[b]
= {HoldPattern[a[b]] :> 3}
- >> a ^= 3
- : Nonatomic expression expected.
- = 3
-
You can use 'UpSet' to specify special values like format values.
However, these values will not be saved in 'UpValues':
>> Format[r] ^= "custom";
diff --git a/mathics/builtin/atomic/symbols.py b/mathics/builtin/atomic/symbols.py
index 7ca6c32fd..95107b8dc 100644
--- a/mathics/builtin/atomic/symbols.py
+++ b/mathics/builtin/atomic/symbols.py
@@ -11,7 +11,7 @@
from mathics_scanner.tokeniser import is_symbol_name
from mathics.core.assignment import get_symbol_values
-from mathics.core.atoms import String
+from mathics.core.atoms import Integer1, String
from mathics.core.attributes import (
A_HOLD_ALL,
A_HOLD_FIRST,
@@ -39,6 +39,7 @@
)
from mathics.core.systemsymbols import (
SymbolAttributes,
+ SymbolContext,
SymbolDefinition,
SymbolFormat,
SymbolGrid,
@@ -122,7 +123,9 @@ def eval(self, symbol, evaluation):
name = symbol.get_name()
if not name:
- evaluation.message("Context", "normal")
+ evaluation.message(
+ "Context", "normal", Integer1, Expression(SymbolContext, symbol)
+ )
return
assert "`" in name
context = name[: name.rindex("`") + 1]
diff --git a/mathics/builtin/exp_structure/general.py b/mathics/builtin/exp_structure/general.py
index f5f1720e2..f99f20dc5 100644
--- a/mathics/builtin/exp_structure/general.py
+++ b/mathics/builtin/exp_structure/general.py
@@ -3,14 +3,14 @@
Structural Expression Functions
"""
-from mathics.core.atoms import Integer
+from mathics.core.atoms import Integer, Integer1
from mathics.core.builtin import Builtin, InfixOperator, Predefined
from mathics.core.exceptions import InvalidLevelspecError
from mathics.core.expression import Evaluation, Expression
from mathics.core.list import ListExpression
from mathics.core.rules import BasePattern
from mathics.core.symbols import Atom, SymbolFalse, SymbolTrue
-from mathics.core.systemsymbols import SymbolMap
+from mathics.core.systemsymbols import SymbolMap, SymbolSortBy
from mathics.eval.parts import python_levelspec, walk_levels
@@ -265,7 +265,9 @@ def eval(self, li, f, evaluation: Evaluation):
"SortBy[li_, f_]"
if isinstance(li, Atom):
- evaluation.message("Sort", "normal")
+ evaluation.message(
+ "Sort", "normal", Integer1, Expression(SymbolSortBy, li, f)
+ )
return
elif li.get_head_name() != "System`List":
expr = Expression(SymbolSortBy, li, f)
diff --git a/mathics/builtin/intfns/combinatorial.py b/mathics/builtin/intfns/combinatorial.py
index 33b7333f2..de1b5c5e4 100644
--- a/mathics/builtin/intfns/combinatorial.py
+++ b/mathics/builtin/intfns/combinatorial.py
@@ -14,7 +14,7 @@
from itertools import combinations
-from mathics.core.atoms import Integer
+from mathics.core.atoms import Integer, Integer1
from mathics.core.attributes import (
A_LISTABLE,
A_N_HOLD_FIRST,
@@ -536,7 +536,6 @@ class Subsets(Builtin):
messages = {
"nninfseq": "Position 2 of `1` must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.",
- "normal": "Nonatomic expression expected at position 1 in `1`.",
}
rules = {
@@ -549,7 +548,9 @@ def eval_list(self, list, evaluation):
"Subsets[list_]"
if isinstance(list, Atom):
- evaluation.message("Subsets", "normal", Expression(SymbolSubsets, list))
+ evaluation.message(
+ "Subsets", "normal", Integer1, Expression(SymbolSubsets, list)
+ )
else:
return self.eval_list_n(list, Integer(len(list.elements)), evaluation)
@@ -558,7 +559,7 @@ def eval_list_n(self, list, n, evaluation):
expr = Expression(SymbolSubsets, list, n)
if isinstance(list, Atom):
- evaluation.message("Subsets", "normal", expr)
+ evaluation.message("Subsets", "normal", Integer1, expr)
return
else:
head_t = list.head
@@ -584,7 +585,7 @@ def eval_list_pattern(self, list, n, evaluation):
expr = Expression(SymbolSubsets, list, n)
if isinstance(list, Atom):
- evaluation.message("Subsets", "normal", expr)
+ evaluation.message("Subsets", "normal", Integer1, expr)
return
else:
head_t = list.head
@@ -663,7 +664,7 @@ def eval_atom_pattern(self, list, n, spec, evaluation):
"Subsets[list_?AtomQ, Pattern[n,_List|All|DirectedInfinity[1]], spec_]"
evaluation.message(
- "Subsets", "normal", Expression(SymbolSubsets, list, n, spec)
+ "Subsets", "normal", Integer1, Expression(SymbolSubsets, list, n, spec)
)
diff --git a/mathics/builtin/layout.py b/mathics/builtin/layout.py
index bfa4bcaa8..5f40f5838 100644
--- a/mathics/builtin/layout.py
+++ b/mathics/builtin/layout.py
@@ -179,9 +179,6 @@ class Infix(Builtin):
= a + b - c
"""
- messages = {
- "normal": "Nonatomic expression expected at position `1`",
- }
summary_text = "infix form"
diff --git a/mathics/builtin/list/constructing.py b/mathics/builtin/list/constructing.py
index 998278df9..278b5d9d7 100644
--- a/mathics/builtin/list/constructing.py
+++ b/mathics/builtin/list/constructing.py
@@ -13,7 +13,7 @@
from typing import Optional, Tuple
from mathics.builtin.box.layout import RowBox
-from mathics.core.atoms import Integer, is_integer_rational_or_real
+from mathics.core.atoms import Integer, Integer1, is_integer_rational_or_real
from mathics.core.attributes import A_HOLD_FIRST, A_LISTABLE, A_LOCKED, A_PROTECTED
from mathics.core.builtin import BasePattern, Builtin, IterationFunction
from mathics.core.convert.expression import to_expression
@@ -23,7 +23,7 @@
from mathics.core.expression import Expression, structure
from mathics.core.list import ListExpression
from mathics.core.symbols import Atom, Symbol
-from mathics.core.systemsymbols import SymbolNormal
+from mathics.core.systemsymbols import SymbolNormal, SymbolTuples
from mathics.eval.lists import get_tuples, list_boxes
@@ -607,7 +607,7 @@ def eval_n(self, expr, n: Integer, evaluation: Evaluation):
"Tuples[expr_, n_Integer]"
if isinstance(expr, Atom):
- evaluation.message("Tuples", "normal")
+ evaluation.message("Tuples", "normal", Integer1, Expression(expr, n))
return
py_n = n.value
if py_n is None or py_n < 0:
@@ -633,10 +633,12 @@ def eval_lists(self, exprs, evaluation: Evaluation):
exprs = exprs.get_sequence()
items = []
- for expr in exprs:
+ for i, expr in enumerate(exprs):
evaluation.check_stopped()
if isinstance(expr, Atom):
- evaluation.message("Tuples", "normal")
+ evaluation.message(
+ "Tuples", "normal", Integer(i + 1), Expression(SymbolTuples)
+ )
return
items.append(expr.elements)
diff --git a/mathics/builtin/list/eol.py b/mathics/builtin/list/eol.py
index da89bba37..cfd208c6b 100644
--- a/mathics/builtin/list/eol.py
+++ b/mathics/builtin/list/eol.py
@@ -93,7 +93,9 @@ def eval(self, expr, item, evaluation):
"Append[expr_, item_]"
if isinstance(expr, Atom):
- evaluation.message("Append", "normal")
+ evaluation.message(
+ "Append", "normal", Integer1, Expression(SymbolAppend, expr, item)
+ )
return
return expr.restructure(
@@ -145,7 +147,9 @@ def eval(self, s, element, evaluation):
)
return result.evaluate(evaluation)
- evaluation.message("AppendTo", "normal", Expression(SymbolAppendTo, s, element))
+ evaluation.message(
+ "AppendTo", "normal", Integer1, Expression(SymbolAppendTo, s, element)
+ )
class Cases(Builtin):
@@ -441,7 +445,12 @@ def eval_ls_n(self, items, pattern, levelspec, n, evaluation):
"DeleteCases[items_, pattern_, levelspec_:1, n_:System`Infinity]"
if isinstance(items, Atom):
- evaluation.message("Select", "normal")
+ evaluation.message(
+ "DeleteCases",
+ "normal",
+ Integer1,
+ Expression(SymbolDeleteCases, items, pattern, levelspec, n),
+ )
return
# If levelspec is specified to a non-trivial value,
# we need to proceed with this complicate procedure
@@ -496,28 +505,29 @@ def condn(element):
return items.filter("List", condn, evaluation)
-class _DeleteDuplicatesBin:
- def __init__(self, item):
- self._item = item
- self.add_to = lambda elem: None
-
- def from_python(self):
- return self._item
-
-
class Drop(Builtin):
"""
:WMA link:https://reference.wolfram.com/language/ref/Drop.html
- - 'Drop[$expr$, $n$]'
-
- returns $expr$ with the first $n$ elements removed.
+
- 'Drop[$list$, $n$]'
+
- returns $list$ with the first $n$ elements removed.
+
- 'Drop[$list$, -$n$]'
+
- returns $list$ with its last $n$ elements removed.
+
- 'Drop[$list$, {$m$, $n$}]'
+
- returns $list$ with elements $m$ though $n$ removed.
+ Drop up intil the 3rd item from the beginning of a list:
+
>> Drop[{a, b, c, d}, 3]
= {d}
+
+ Drop until the second item from the end of that list:
>> Drop[{a, b, c, d}, -2]
= {a, b}
+
+ Drop from the second item to the second-to-the-end item:
>> Drop[{a, b, c, d, e}, {2, -2}]
= {a, e}
@@ -526,27 +536,41 @@ class Drop(Builtin):
= {{11, 12, 13, 14}, {21, 22, 23, 24}, {31, 32, 33, 34}, {41, 42, 43, 44}}
>> Drop[A, {2, 3}, {2, 3}]
= {{11, 14}, {41, 44}}
+
+ Dropping the 0th element does nothing and returns the list unmodified:
+
+ >> Drop[{a, b, c, d}, 0]
+ = {a, b, c, d}
+
+ Even if the list is empty:
+
+ >> Drop[{}, 0]
+ = {}
"""
messages = {
- "normal": "Nonatomic expression expected at position `1` in `2`.",
"drop": "Cannot drop positions `1` through `2` in `3`.",
}
summary_text = "remove a number of elements from a list"
- def eval(self, items, seqs, evaluation):
+ def eval(self, items, seqs, evaluation: Evaluation):
"Drop[items_, seqs___]"
- seqs = seqs.get_sequence()
+ if seqs is Integer0:
+ return items
+
+ seq_tuple = seqs.get_sequence()
if isinstance(items, Atom):
evaluation.message(
- "Drop", "normal", 1, Expression(SymbolDrop, items, *seqs)
+ "Drop", "normal", Integer1, Expression(SymbolDrop, items, *seq_tuple)
)
return
try:
- return parts(items, [_drop_span_selector(seq) for seq in seqs], evaluation)
+ return parts(
+ items, [_drop_span_selector(seq) for seq in seq_tuple], evaluation
+ )
except MessageException as e:
e.message(evaluation)
@@ -626,7 +650,6 @@ class First(Builtin):
attributes = A_HOLD_REST | A_PROTECTED
messages = {
"argt": "First called with `1` arguments; 1 or 2 arguments are expected.",
- "normal": "Nonatomic expression expected at position 1 in `1`.",
"nofirst": "`1` has zero length and no first element.",
}
summary_text = "first element of a list or expression"
@@ -636,7 +659,7 @@ def eval(self, expr, evaluation: Evaluation, expression: Expression):
"First[expr__]"
if isinstance(expr, Atom):
- evaluation.message("First", "normal", expression)
+ evaluation.message("First", "normal", Integer1, expression)
return
expr_len = len(expr.elements)
if expr_len == 0:
@@ -895,7 +918,6 @@ class Last(Builtin):
attributes = A_HOLD_REST | A_PROTECTED
messages = {
"argt": "Last called with `1` arguments; 1 or 2 arguments are expected.",
- "normal": "Nonatomic expression expected at position 1 in `1`.",
"nolast": "`1` has zero length and no last element.",
}
summary_text = "last element of a list or expression"
@@ -905,7 +927,7 @@ def eval(self, expr, evaluation: Evaluation, expression: Expression):
"Last[expr__]"
if isinstance(expr, Atom):
- evaluation.message("Last", "normal", expression)
+ evaluation.message("Last", "normal", Integer1, expression)
return
expr_len = len(expr.elements)
if expr_len == 0:
@@ -982,17 +1004,13 @@ class Most(Builtin):
= Most[x]
"""
- messages = {
- "normal": "Nonatomic expression expected at position 1 in `1`.",
- }
-
summary_text = "remove the last element"
def eval(self, expr, evaluation: Evaluation, expression: Expression):
"Most[expr_]"
if isinstance(expr, Atom):
- evaluation.message("Most", "normal", expression)
+ evaluation.message("Most", "normal", Integer1, expression)
return
return expr.slice(expr.head, slice(0, -1), evaluation)
@@ -1299,7 +1317,9 @@ def eval(self, expr, item, evaluation):
"Prepend[expr_, item_]"
if isinstance(expr, Atom):
- evaluation.message("Prepend", "normal")
+ evaluation.message(
+ "Prepend", "normal", Integer1, Expression(SymbolPrepend, expr, item)
+ )
return
return expr.restructure(
@@ -1341,9 +1361,6 @@ class PrependTo(Builtin):
attributes = A_HOLD_FIRST | A_PROTECTED
- messages = {
- "normal": "Nonatomic expression expected at position 1 in `1`.",
- }
summary_text = "add an element at the beginning of an stored list or expression"
def eval(self, s, item, evaluation):
@@ -1359,7 +1376,9 @@ def eval(self, s, item, evaluation):
)
return result.evaluate(evaluation)
- evaluation.message("PrependTo", "normal", Expression(SymbolPrependTo, s, item))
+ evaluation.message(
+ "PrependTo", "normal", Integer1, Expression(SymbolPrependTo, s, item)
+ )
class ReplacePart(Builtin):
@@ -1478,7 +1497,6 @@ class Rest(Builtin):
"""
messages = {
- "normal": "Nonatomic expression expected at position 1 in `1`.",
"norest": "Cannot take Rest of expression `1` with length zero.",
}
summary_text = "remove the first element"
@@ -1487,7 +1505,7 @@ def eval(self, expr, evaluation: Evaluation, expression: Expression):
"Rest[expr_]"
if isinstance(expr, Atom):
- evaluation.message("Rest", "normal", expression)
+ evaluation.message("Rest", "normal", Integer1, expression)
return
if len(expr.elements) == 0:
evaluation.message("Rest", "norest", expr)
@@ -1551,7 +1569,9 @@ def eval_with_n(self, items, expr, n, evaluation: Evaluation):
return
if isinstance(items, Atom):
- evaluation.message("Select", "normal")
+ evaluation.message(
+ "Select", "normal", Integer1, Expression(SymbolSelect, items, expr, n)
+ )
return
def cond(element):
@@ -1610,9 +1630,6 @@ class Take(Builtin):
= {{b}, {e}}
"""
- messages = {
- "normal": "Nonatomic expression expected at position `1` in `2`.",
- }
summary_text = "pick a range of elements"
def eval(self, items, seqs, evaluation):
@@ -1622,7 +1639,7 @@ def eval(self, items, seqs, evaluation):
if isinstance(items, Atom):
evaluation.message(
- "Take", "normal", 1, Expression(SymbolTake, items, *seqs)
+ "Take", "normal", Integer1, Expression(SymbolTake, items, *seqs)
)
return
diff --git a/mathics/builtin/list/rearrange.py b/mathics/builtin/list/rearrange.py
index a01c9a448..683ec4cf6 100644
--- a/mathics/builtin/list/rearrange.py
+++ b/mathics/builtin/list/rearrange.py
@@ -10,7 +10,7 @@
from itertools import chain
from typing import Callable, Optional
-from mathics.core.atoms import Integer, Integer0, Number
+from mathics.core.atoms import Integer, Integer0, Integer1, Number
from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED
from mathics.core.builtin import Builtin, MessageException
from mathics.core.element import BaseElement
@@ -77,7 +77,6 @@ def __init__(self, level):
class _Pad(Builtin):
messages = {
- "normal": "Expression at position 1 in `` must not be an atom.",
"level": "Cannot pad list `3` which has `4` using padding `1` which specifies `2`.",
"ilsm": "Expected an integer or a list of integers at position `1` in `2`.",
}
@@ -176,7 +175,7 @@ def padding(amount, sign):
def _pad(self, in_l, in_n, in_x, in_m, evaluation, expr):
if not isinstance(in_l, Expression):
- evaluation.message(self.get_name(), "normal", expr())
+ evaluation.message(self.get_name(), "normal", Integer1, expr())
return
py_n = None
@@ -300,7 +299,6 @@ class _GatherOperation(Builtin):
rules = {"%(name)s[list_]": "%(name)s[list, SameQ]"}
messages = {
- "normal": "Nonatomic expression expected at position `1` in `2`.",
"list": "List expected at position `2` in `1`.",
"smtst": (
"Application of the SameTest yielded `1`, which evaluates "
@@ -324,7 +322,7 @@ def eval(self, values, test, evaluation: Evaluation):
def _check_list(self, values, arg2, evaluation: Evaluation):
if isinstance(values, Atom):
expr = Expression(Symbol(self.get_name()), values, arg2)
- evaluation.message(self.get_name(), "normal", 1, expr)
+ evaluation.message(self.get_name(), "normal", Integer1, expr)
return False
if values.get_head_name() != "System`List":
@@ -398,7 +396,6 @@ def eval(self, expr, n, evaluation: Evaluation):
class _SetOperation(Builtin):
messages = {
- "normal": "Non-atomic expression expected at position `1` in `2`.",
"heads": (
"Heads `1` and `2` at positions `3` and `4` are expected " "to be the same."
),
@@ -432,7 +429,7 @@ def eval(self, lists, evaluation, options={}):
evaluation.message(
self.get_name(),
"normal",
- pos + 1,
+ Integer(pos + 1),
Expression(Symbol(self.get_name()), *seq),
)
return
@@ -656,7 +653,6 @@ class Flatten(Builtin):
"Level `1` specified in `2` exceeds the levels, `3`, "
"which can be flattened together in `4`."
),
- "normal": "Nonatomic expression expected at position `1` in `2`.",
}
rules = {
@@ -776,7 +772,7 @@ def eval(self, expr: BaseElement, n: Number, h, evaluation):
return
if not isinstance(expr, Expression):
- evaluation.message("Flatten", "normal", 1, expr)
+ evaluation.message("Flatten", "normal", Integer1, expr)
return
return expr.flatten_with_respect_to_head(h, level=n_int)
@@ -1262,9 +1258,6 @@ class Split(Builtin):
"Split[list_]": "Split[list, SameQ]",
}
- messages = {
- "normal": "Nonatomic expression expected at position `1` in `2`.",
- }
summary_text = "split into runs of identical elements"
def eval(self, mlist, test, evaluation: Evaluation):
@@ -1273,7 +1266,7 @@ def eval(self, mlist, test, evaluation: Evaluation):
expr = Expression(SymbolSplit, mlist, test)
if isinstance(mlist, Atom):
- evaluation.message("Select", "normal", 1, expr)
+ evaluation.message("Select", "normal", Integer1, expr)
return
if not mlist.elements:
@@ -1311,10 +1304,6 @@ class SplitBy(Builtin):
= {{{1}}, {{2}}, {{1}, {1.2}}}
"""
- messages = {
- "normal": "Nonatomic expression expected at position `1` in `2`.",
- }
-
rules = {
"SplitBy[list_]": "SplitBy[list, Identity]",
}
@@ -1327,7 +1316,7 @@ def eval(self, mlist, func, evaluation: Evaluation):
expr = Expression(SymbolSplit, mlist, func)
if isinstance(mlist, Atom):
- evaluation.message("Select", "normal", 1, expr)
+ evaluation.message("Select", "normal", Integer1, expr)
return
plist = [t for t in mlist.elements]
@@ -1351,7 +1340,7 @@ def eval_multiple(self, mlist, funcs, evaluation: Evaluation):
expr = Expression(SymbolSplit, mlist, funcs)
if isinstance(mlist, Atom):
- evaluation.message("Select", "normal", 1, expr)
+ evaluation.message("Select", "normal", Integer1, expr)
return
result = mlist
diff --git a/mathics/builtin/messages.py b/mathics/builtin/messages.py
index 75996aebf..e65f55fff 100644
--- a/mathics/builtin/messages.py
+++ b/mathics/builtin/messages.py
@@ -211,7 +211,7 @@ class General(Builtin):
"newpkg": "In WL, there is a new package for this.",
"noopen": "Cannot open `1`.",
"nord": "Invalid comparison with `1` attempted.",
- "normal": "Nonatomic expression expected.",
+ "normal": "Nonatomic expression expected at position `1` in `2`.",
"noval": ("Symbol `1` in part assignment does not have an immediate value."),
"obspkg": "In WL, this package is obsolete.",
"openx": "`1` is not open.",
diff --git a/mathics/builtin/statistics/orderstats.py b/mathics/builtin/statistics/orderstats.py
index c0806a542..8d5139945 100644
--- a/mathics/builtin/statistics/orderstats.py
+++ b/mathics/builtin/statistics/orderstats.py
@@ -17,18 +17,20 @@
from mathics.algorithm.introselect import introselect
from mathics.builtin.list.math import _RankedTakeLargest, _RankedTakeSmallest
-from mathics.core.atoms import Atom, Integer, Symbol, SymbolTrue
+from mathics.core.atoms import Atom, Integer, Integer1, SymbolTrue
from mathics.core.attributes import A_PROTECTED, A_READ_PROTECTED
from mathics.core.builtin import Builtin
from mathics.core.expression import Evaluation, Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import SymbolFloor, SymbolPlus, SymbolTimes
-from mathics.core.systemsymbols import SymbolSubtract
+from mathics.core.systemsymbols import (
+ SymbolRankedMax,
+ SymbolRankedMin,
+ SymbolSort,
+ SymbolSubtract,
+)
from mathics.eval.numerify import numerify
-SymbolRankedMax = Symbol("RankedMax")
-SymbolRankedMin = Symbol("RankedMin")
-
class Quantile(Builtin):
"""
@@ -325,7 +327,7 @@ def eval(self, list, evaluation: Evaluation):
"Sort[list_]"
if isinstance(list, Atom):
- evaluation.message("Sort", "normal")
+ evaluation.message("Sort", "normal", Integer1, Expression(SymbolSort, list))
else:
new_elements = sorted(list.elements)
return list.restructure(list.head, new_elements, evaluation)
@@ -334,7 +336,7 @@ def eval_predicate(self, list, p, evaluation: Evaluation):
"Sort[list_, p_]"
if isinstance(list, Atom):
- evaluation.message("Sort", "normal")
+ evaluation.message("Sort", "normal", Integer1, Expression(SymbolSort, list))
else:
class Key:
diff --git a/mathics/builtin/testing_expressions/list_oriented.py b/mathics/builtin/testing_expressions/list_oriented.py
index 1de7f15ad..f7619b4d0 100644
--- a/mathics/builtin/testing_expressions/list_oriented.py
+++ b/mathics/builtin/testing_expressions/list_oriented.py
@@ -288,7 +288,6 @@ class SubsetQ(Builtin):
"argr": "SubsetQ called with 1 argument; 2 arguments are expected.",
"argrx": "SubsetQ called with `1` arguments; 2 arguments are expected.",
"heads": "Heads `1` and `2` at positions 1 and 2 are expected to be the same.",
- "normal": "Nonatomic expression expected at position `1` in `2`.",
}
summary_text = "test if a list is a subset of another list"
diff --git a/mathics/core/assignment.py b/mathics/core/assignment.py
index a268414cb..d1bb3a2e6 100644
--- a/mathics/core/assignment.py
+++ b/mathics/core/assignment.py
@@ -6,7 +6,7 @@
from functools import reduce
from typing import Optional, Tuple
-from mathics.core.atoms import Atom, Integer
+from mathics.core.atoms import Atom, Integer, Integer1
from mathics.core.attributes import A_LOCKED, A_PROTECTED, attribute_string_to_number
from mathics.core.element import BaseElement
from mathics.core.evaluation import (
@@ -645,8 +645,8 @@ def eval_assign_other(
into account.
Otherwise, the value is False.
"""
- tags, focus = process_tags_and_upset_allow_custom(
- tags, upset, self, lhs, evaluation
+ tags, _ = process_tags_and_upset_allow_custom(
+ tags, upset, self, lhs, rhs, evaluation
)
lhs_name = lhs.get_name()
if lhs_name == "System`$RecursionLimit":
@@ -772,7 +772,7 @@ def process_tags_and_upset_dont_allow_custom(
def process_tags_and_upset_allow_custom(
- tags, upset, self, lhs: BaseElement, evaluation: Evaluation
+ tags, upset, self, lhs: BaseElement, rhs: BaseElement, evaluation: Evaluation
):
name = lhs.get_head_name()
focus = lhs
@@ -787,7 +787,13 @@ def process_tags_and_upset_allow_custom(
elif upset:
tags = []
if isinstance(focus, Atom):
- evaluation.message(self.get_name(), "normal")
+ symbol_name = self.get_name()
+ evaluation.message(
+ symbol_name,
+ "normal",
+ Integer1,
+ Expression(Symbol(symbol_name), lhs, rhs),
+ )
raise AssignmentException(lhs, None)
for element in focus.get_elements():
name = element.get_lookup_name()
diff --git a/mathics/core/systemsymbols.py b/mathics/core/systemsymbols.py
index 1798a9bb8..a8a8faade 100644
--- a/mathics/core/systemsymbols.py
+++ b/mathics/core/systemsymbols.py
@@ -127,6 +127,7 @@
SymbolInequality = Symbol("System`Inequality")
SymbolInfinity = Symbol("System`Infinity")
SymbolInfix = Symbol("System`Infix")
+SymbolInner = Symbol("System`Inner")
SymbolInputForm = Symbol("System`InputForm")
SymbolInputStream = Symbol("System`InputStream")
SymbolInteger = Symbol("System`Integer")
@@ -184,6 +185,7 @@
SymbolOut = Symbol("System`Out")
SymbolOutputForm = Symbol("System`OutputForm")
SymbolOutputStream = Symbol("System`OutputStream")
+SymbolOuter = Symbol("System`Outer")
SymbolOverflow = Symbol("System`Overflow")
SymbolOwnValues = Symbol("System`OwnValues")
SymbolPackages = Symbol("System`$Packages")
@@ -208,6 +210,8 @@
SymbolRGBColor = Symbol("System`RGBColor")
SymbolRandomComplex = Symbol("System`RandomComplex")
SymbolRandomReal = Symbol("System`RandomReal")
+SymbolRankedMax = Symbol("RankedMax")
+SymbolRankedMin = Symbol("RankedMin")
SymbolRational = Symbol("System`Rational")
SymbolRe = Symbol("System`Re")
SymbolReal = Symbol("System`Real")
@@ -236,6 +240,7 @@
SymbolSin = Symbol("System`Sin")
SymbolSinh = Symbol("System`Sinh")
SymbolSlot = Symbol("System`Slot")
+SymbolSort = Symbol("System`Sort")
SymbolSortBy = Symbol("System`SortBy")
SymbolSparseArray = Symbol("System`SparseArray")
SymbolSplit = Symbol("System`Split")
@@ -270,6 +275,7 @@
SymbolToString = Symbol("System`ToString")
SymbolTotal = Symbol("System`Total")
SymbolTraditionalForm = Symbol("System`TraditionalForm")
+SymbolTuples = Symbol("System`Tuples")
SymbolUndefined = Symbol("System`Undefined")
SymbolUnequal = Symbol("System`Unequal")
SymbolUnevaluated = Symbol("System`Unevaluated")
diff --git a/mathics/eval/tensors.py b/mathics/eval/tensors.py
index 35e11208d..a579fa386 100644
--- a/mathics/eval/tensors.py
+++ b/mathics/eval/tensors.py
@@ -18,7 +18,9 @@
)
from mathics.core.systemsymbols import (
SymbolAutomatic,
+ SymbolInner,
SymbolNormal,
+ SymbolOuter,
SymbolRule,
SymbolSparseArray,
)
@@ -171,7 +173,9 @@ def eval_Inner(f, list1, list2, g, evaluation: Evaluation):
n = get_dimensions(list2)
if not m or not n:
- evaluation.message("Inner", "normal")
+ evaluation.message(
+ "Inner", "normal", Integer1, Expression(SymbolInner, list1, list2)
+ )
return
if list1.get_head() != list2.get_head():
evaluation.message("Inner", "heads", list1.get_head(), list2.get_head())
@@ -213,7 +217,7 @@ def eval_Outer(f, lists, evaluation: Evaluation):
"Evaluates recursively the outer product of lists"
if isinstance(lists, Atom):
- evaluation.message("Outer", "normal")
+ evaluation.message("Outer", "normal", Integer1, Expression(SymbolOuter, lists))
return
# If f=!=Times, or lists contain both SparseArray and List, then convert all SparseArrays to Lists
@@ -222,6 +226,7 @@ def eval_Outer(f, lists, evaluation: Evaluation):
sparse_to_list = f != SymbolTimes
contain_sparse = False
contain_list = False
+ new_lists = []
for _list in lists:
if _list.head.sameQ(SymbolSparseArray):
contain_sparse = True
@@ -230,11 +235,11 @@ def eval_Outer(f, lists, evaluation: Evaluation):
sparse_to_list = sparse_to_list or (contain_sparse and contain_list)
if sparse_to_list:
break
- if sparse_to_list:
- new_lists = []
- for _list in lists:
+ for i, _list in enumerate(lists):
if isinstance(_list, Atom):
- evaluation.message("Outer", "normal")
+ evaluation.message(
+ "Outer", "normal", Integer(i + 1), Expression(SymbolOuter, lists)
+ )
return
if sparse_to_list:
if _list.head.sameQ(SymbolSparseArray):
@@ -245,6 +250,7 @@ def eval_Outer(f, lists, evaluation: Evaluation):
elif not _list.head.sameQ(head):
evaluation.message("Outer", "heads", head, _list.head)
return
+
if sparse_to_list:
lists = new_lists
@@ -277,7 +283,7 @@ def cond_next_list(item, level) -> bool:
def sparse_cond_next_list(item, level) -> bool:
return isinstance(item, Atom) or not item.head.sameQ(head)
- def sparse_apply_Rule(current) -> tuple:
+ def sparse_apply_Rule(current) -> Expression:
return Expression(SymbolRule, ListExpression(*current[0]), current[1])
def sparse_join_elem(current, item) -> tuple:
diff --git a/mathics/packages/DiscreteMath/CombinatoricaV0.9.m b/mathics/packages/DiscreteMath/CombinatoricaV0.9.m
deleted file mode 120000
index 0c713bf82..000000000
--- a/mathics/packages/DiscreteMath/CombinatoricaV0.9.m
+++ /dev/null
@@ -1 +0,0 @@
-../Combinatorica-repo/Combinatorica/CombinatoricaV0.9.m
\ No newline at end of file
diff --git a/test/builtin/assignments/test_assignment.py b/test/builtin/assignments/test_assignment.py
new file mode 100644
index 000000000..68a70658d
--- /dev/null
+++ b/test/builtin/assignments/test_assignment.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+"""
+Unit tests for mathics.builtins.assignments.assignment
+"""
+
+from test.helper import check_evaluation
+
+
+def test_upset():
+ """
+ Test UpSet[] builtin
+ """
+ check_evaluation(
+ "a ^= 3",
+ "a ^= 3",
+ failure_message="Should not be able to use UpSet on a Symbol",
+ expected_messages=("Nonatomic expression expected at position 1 in a ^= 3.",),
+ )
+ check_evaluation(
+ "f[g, a + b, h] ^= 2",
+ "2",
+ failure_message="UpSet on a protected value should fail",
+ expected_messages=("Tag Plus in f[g, a + b, h] is Protected.",),
+ )
+ check_evaluation("UpValues[h]", "{HoldPattern[f[g, a + b, h]] :> 2}")
diff --git a/test/builtin/list/test_eol.py b/test/builtin/list/test_eol.py
index 8ae460746..51338375a 100644
--- a/test/builtin/list/test_eol.py
+++ b/test/builtin/list/test_eol.py
@@ -10,7 +10,12 @@
@pytest.mark.parametrize(
("str_expr", "expected_messages", "str_expected", "assert_message"),
[
- ("Append[a, b]", ("Nonatomic expression expected.",), "Append[a, b]", None),
+ (
+ "Append[a, b]",
+ ("Nonatomic expression expected at position 1 in Append[a, b].",),
+ "Append[a, b]",
+ None,
+ ),
(
"AppendTo[{}, 1]",
("{} is not a variable with a value, so its value cannot be changed.",),
@@ -185,7 +190,7 @@
),
(
"a=.;b=.;Prepend[a, b]",
- ("Nonatomic expression expected.",),
+ ("Nonatomic expression expected at position 1 in Prepend[a, b].",),
"Prepend[a, b]",
"Prepend works with non-atomic expressions",
),
@@ -230,7 +235,9 @@
("{a ;; b ;; c ;; d}", None, "{a ;; b ;; c, 1 ;; d}", ";; association"),
(
"Select[a, True]",
- ("Nonatomic expression expected.",),
+ (
+ "Nonatomic expression expected at position 1 in Select[a, True, Infinity].",
+ ),
"Select[a, True]",
None,
),
diff --git a/test/builtin/list/test_list.py b/test/builtin/list/test_list.py
index f0adfa807..f8d6b520a 100644
--- a/test/builtin/list/test_list.py
+++ b/test/builtin/list/test_list.py
@@ -12,7 +12,7 @@
[
(
"Complement[a, b]",
- ("Non-atomic expression expected at position 1 in Complement[a, b].",),
+ ("Nonatomic expression expected at position 1 in Complement[a, b].",),
"Complement[a, b]",
None,
),
diff --git a/test/builtin/test_assignment.py b/test/builtin/test_assignment.py
index acea25312..32a1e7d4b 100644
--- a/test/builtin/test_assignment.py
+++ b/test/builtin/test_assignment.py
@@ -395,17 +395,17 @@ def test_process_assign_other():
check_evaluation(
f"{prefix}{limit} = 2",
"2",
- expected_messages=[
- f"Cannot set {limit} to 2; value must be an integer between 20 and {suffix}."
- ],
+ expected_messages=(
+ f"Cannot set {limit} to 2; value must be an integer between 20 and {suffix}.",
+ ),
)
check_evaluation(f"{prefix}$ModuleNumber = 3", "3")
check_evaluation(
f"{prefix}$ModuleNumber = -1",
"-1",
- expected_messages=[
- "Cannot set $ModuleNumber to -1; value must be a positive integer."
- ],
+ expected_messages=(
+ "Cannot set $ModuleNumber to -1; value must be a positive integer.",
+ ),
)
@@ -428,14 +428,6 @@ def test_process_assign_other():
],
"Unset Message",
),
- # From assignent
- (
- "f[g, a + b, h] ^= 2",
- "2",
- ("Tag Plus in f[g, a + b, h] is Protected.",),
- "Upset to protected symbols fails",
- ),
- ("UpValues[h]", "{HoldPattern[f[g, a + b, h]] :> 2}", None, None),
(" g[a+b] ^:= 2", "$Failed", ("Tag Plus in g[a + b] is Protected.",), None),
(" g[a+b]", "g[a + b]", None, None),
],