Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SYMBOLS_MANIFEST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ System`Brown
System`ButtonBox
System`Byte
System`ByteArray
System`ByteArrayQ
System`ByteCount
System`ByteOrdering
System`C
Expand Down
7 changes: 2 additions & 5 deletions mathics/builtin/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
SymbolTable,
SymbolUndefined,
)
from mathics.eval.arithmetic import eval_RealValuedNumberQ
from mathics.eval.inference import get_assumptions_list
from mathics.eval.nevaluator import eval_N
from mathics.eval.numeric import eval_Sign
Expand Down Expand Up @@ -961,11 +962,7 @@ class RealValuedNumberQ(Test):
summary_text = "test whether an expression is a real number"

def test(self, expr) -> bool:
return (
isinstance(expr, (Integer, Rational, Real))
or expr.has_form("Underflow", 0)
or expr.has_form("Overflow", 0)
)
return eval_RealValuedNumberQ(expr)


class Sum(IterationFunction, SympyFunction, PrefixOperator):
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/atomic/atomic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""

from mathics.core.builtin import Builtin, Test
from mathics.core.symbols import Atom
from mathics.eval.atomic.atomic import eval_AtomQ


class AtomQ(Test):
Expand Down Expand Up @@ -57,7 +57,7 @@ class AtomQ(Test):
summary_text = "test whether an expression is an atom"

def test(self, expr) -> bool:
return isinstance(expr, Atom)
return eval_AtomQ(expr)


class Head(Builtin):
Expand Down
9 changes: 5 additions & 4 deletions mathics/builtin/atomic/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
or namespace, and can have a variety of type of values and attributes.
"""
import re
from typing import Callable, List, Optional
from typing import Callable, Optional

from mathics_scanner.tokeniser import NAMES_WILDCARDS, is_symbol_name

Expand Down Expand Up @@ -45,20 +45,21 @@
SymbolGrid,
SymbolInputForm,
SymbolLeft,
SymbolMissing,
SymbolOptions,
SymbolRule,
SymbolSet,
)
from mathics.doc.online import online_doc_string
from mathics.eval.atomic.symbols import eval_SymbolQ
from mathics.eval.stackframe import get_eval_Expression

SymbolMissing = Symbol("System`Missing")
SymbolUnknownSymbol = Symbol("System`UnknownSymbol")


def gather_and_format_definition_rules(
symbol: Symbol, evaluation: Evaluation
) -> Optional[List[Expression]]:
) -> Optional[list[Expression]]:
"""Return a list of lines describing the definition of `symbol`"""
lines = []

Expand Down Expand Up @@ -727,7 +728,7 @@ class SymbolQ(Test):
summary_text = "test whether is a symbol"

def test(self, expr) -> bool:
return isinstance(expr, Symbol)
return eval_SymbolQ(expr)


class ValueQ(Builtin):
Expand Down
1 change: 0 additions & 1 deletion mathics/builtin/binary/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-

"""
Binary Data

Expand Down
37 changes: 35 additions & 2 deletions mathics/builtin/binary/bytearray.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from typing import Optional

from mathics.core.atoms import ByteArray, Integer, String
from mathics.core.builtin import Builtin
from mathics.core.attributes import A_PROTECTED
from mathics.core.builtin import Builtin, Test
from mathics.core.convert.expression import to_mathics_list
from mathics.core.evaluation import Evaluation
from mathics.core.list import ListExpression
from mathics.eval.binary.bytearray import eval_ByteArrayQ


class ByteArray_(Builtin):
Expand Down Expand Up @@ -54,6 +56,8 @@ class ByteArray_(Builtin):
),
}

expected_args = 1
eval_error = Builtin.generic_argument_error
name = "ByteArray"
summary_text = "array of bytes"

Expand Down Expand Up @@ -88,4 +92,33 @@ def eval_list(self, values, evaluation) -> Optional[ByteArray]:
return ba


# TODO: BaseEncode, BaseDecode, ByteArrayQ, ByteArrayToString, StringToByteArray, ImportByteArray, ExportByteArray
class ByteArrayQ(Test):
r"""
<url>:WMA link:
https://reference.wolfram.com/language/ref/ByteArrayQ.html</url>

<dl>
<dt>'ByteArrayQ'[{$expr$}]
<dd> returns True if $expr$ is a ByteArray object, and False otherwise.
</dl>

>> ByteArrayQ[ByteArray[Range[16]]]
= True

>> ByteArrayQ[Range[3]]
= False

>> ByteArrayQ[ByteArray["xyz"]]
: The argument at position 1 in ByteArray[xyz] should be a vector of unsigned byte values or a Base64-encoded string.
= False
"""

attributes = A_PROTECTED
summary_text = "test whether an expression is a ByteArray"

def test(self, expr) -> bool:
"""Return True if expr is a ByteArray atom."""
return eval_ByteArrayQ(expr)


# TODO: BaseEncode, BaseDecode, ByteArrayToString, StringToByteArray, ImportByteArray, ExportByteArray
44 changes: 18 additions & 26 deletions mathics/core/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,7 @@
from functools import total_ordering
from itertools import chain
from types import ModuleType
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Optional,
Sequence,
Tuple,
Union,
cast,
)
from typing import Any, Callable, Iterable, List, Optional, Sequence, Tuple, Union, cast

import mpmath
import sympy
Expand Down Expand Up @@ -205,16 +194,16 @@ def eval_with_options(x, evaluation: Evaluation, options: dict):
_is_numeric: bool = False
attributes: int = A_PROTECTED
context: str = ""
defaults: Dict[Optional[int], str] = {}
defaults: dict[Optional[int], str] = {}

# Number of arguments expected. -1 is used for an arbitrary number.
expected_args: Union[int, Tuple[int, int], range] = -1

formats: Dict[str, Any] = {}
messages: Dict[str, Any] = {}
formats: dict[str, Any] = {}
messages: dict[str, Any] = {}
name: Optional[str] = None
options: Dict[str, Any] = {}
rules: Dict[str, Any] = {}
options: dict[str, Any] = {}
rules: dict[str, Any] = {}

def __getnewargs_ex__(self):
return tuple(), {
Expand Down Expand Up @@ -363,7 +352,7 @@ def contextify_form_name(f):
forms = [""]
return forms, pattern

formatvalues: Dict[str, List[BaseRule]] = {"": []}
formatvalues: dict[str, List[BaseRule]] = {"": []}
for pattern, function in self.get_functions("format_"):
forms, pattern = extract_forms(pattern)
pat_attr = attributes if pattern.get_head_name() == name else None
Expand Down Expand Up @@ -676,7 +665,7 @@ def is_literal(self) -> bool:


class BuiltinElement(Builtin, BaseElement):
options: Dict[str, Any]
options: dict[str, Any]

def __new__(cls, *args, **kwargs):
new_kwargs = kwargs.copy()
Expand Down Expand Up @@ -707,15 +696,15 @@ def __hash__(self):
class SympyObject(Builtin):
sympy_name: Optional[str] = None

mathics_to_sympy: Dict[str, str] = {}
mathics_to_sympy: dict[str, str] = {}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.sympy_name is None:
self.sympy_name = strip_context(self.get_name()).lower()
self.mathics_to_sympy[self.__class__.__name__] = self.sympy_name

def get_sympy_names(self) -> List[str]:
def get_sympy_names(self) -> list[str]:
if self.sympy_name:
return [self.sympy_name]
return []
Expand Down Expand Up @@ -848,8 +837,8 @@ def eval(self, z, evaluation: Evaluation):


class MPMathMultiFunction(MPMathFunction):
sympy_names: Optional[Dict[int, str]] = None
mpmath_names: Optional[Dict[int, str]] = None
sympy_names: Optional[dict[int, str]] = None
mpmath_names: Optional[dict[int, str]] = None

def get_sympy_names(self):
if self.sympy_names is None:
Expand Down Expand Up @@ -972,7 +961,7 @@ def has_option(options, name, evaluation):
return get_option(options, name, evaluation, evaluate=False) is not None


mathics_to_python: Dict[str, Any] = {} # here we have: name -> string
mathics_to_python: dict[str, Any] = {} # here we have: name -> string


@total_ordering
Expand Down Expand Up @@ -1638,8 +1627,8 @@ def add_no_meaning_builtin_classes(
class PatternObject(BuiltinElement, BasePattern):
needs_verbatim = True

arg_counts: List[int] = []
options: Dict[str, Any]
arg_counts: list[int] = []
options: dict[str, Any]

def init(self, expr: Expression, evaluation: Optional[Evaluation] = None):
super().init(expr, evaluation=evaluation)
Expand Down Expand Up @@ -1705,6 +1694,9 @@ def pattern_precedence(self) -> tuple:


class Test(Builtin, ABC):
expected_args = 1
eval_error = Builtin.generic_argument_error

def eval(self, expr, evaluation: Evaluation) -> Optional[BooleanType]:
# Note: in the docstring below, we need to use %(name)s for
# subclasses like ExactNumberQ to work with function-application
Expand Down
8 changes: 8 additions & 0 deletions mathics/eval/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ def eval_negate_number(n: Number) -> Number:
return eval_multiply_numbers(IntegerM1, n)


def eval_RealValuedNumberQ(expr) -> bool:
return (
isinstance(expr, (Integer, Rational, Real))
or expr.has_form("Underflow", 0)
or expr.has_form("Overflow", 0)
)


def segregate_numbers(
*elements: BaseElement,
) -> Tuple[List[Number], List[BaseElement]]:
Expand Down
10 changes: 10 additions & 0 deletions mathics/eval/atomic/atomic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Evaluation methods for mathics.builtin.atomic.atomic.
"""

from mathics.core.symbols import Atom


def eval_AtomQ(expr) -> bool:
"""Return True if expr is an Atom."""
return isinstance(expr, Atom)
10 changes: 10 additions & 0 deletions mathics/eval/atomic/symbols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Evaluation methods for mathics.builtin.atomic.atomic.
"""

from mathics.core.symbols import Symbol


def eval_SymbolQ(expr) -> bool:
"""Return True if expr is an Symbol."""
return isinstance(expr, Symbol)
10 changes: 10 additions & 0 deletions mathics/eval/binary/bytearray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
Evaluation methods for mathics.builtin.binary.bytearray.
"""

from mathics.core.atoms import ByteArray


def eval_ByteArrayQ(expr) -> bool:
"""Return True if expr is a ByteArray atom."""
return isinstance(expr, ByteArray)
22 changes: 21 additions & 1 deletion test/builtin/test_binary.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

import sys
from test.helper import check_evaluation
from test.helper import check_arg_counts, check_evaluation

import pytest

Expand Down Expand Up @@ -456,3 +456,23 @@ def test_type_conversion():
assert expr.value.dtype == np.int64
expr = evaluate('NumericArray[{1,2}, "ComplexReal32"]')
assert expr.value.dtype == np.complex64


@pytest.mark.parametrize(
("function_name", "msg_fragment"),
[
# FIXME: ToString in check_arg_counts() is giving a traceback
# for ByteArray[].
# (
# "ByteArray",
# "1 argument is",
# ),
(
"ByteArrayQ",
"1 argument is",
),
],
)
def test_arg_count_errors(function_name, msg_fragment):
""" """
check_arg_counts(function_name, msg_fragment)
Loading