Skip to content

Commit

Permalink
Merge branch 'master' into arithmetic_refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
mmatera committed May 24, 2023
2 parents e6577b2 + 1c1ec6b commit f32ec04
Show file tree
Hide file tree
Showing 40 changed files with 807 additions and 401 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/consistency-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10']
python-version: ['3.11']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/isort-and-black-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.9
- name: Set up Python 3.11
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: 3.11
- name: Install click, black and isort
run: pip install 'click==8.0.4' 'black==22.3.0' 'isort==5.10.1'
- name: Run isort --check .
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/osx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
os: [macOS]
python-version: ['3.7', '3.8', '3.9']
python-version: ['3.9', '3.10']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu-cython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ['3.10']
python-version: ['3.11']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.11', '3.8', '3.9', '3.10']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [windows]
python-version: ['3.8', '3.9']
python-version: ['3.10', '3.11']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ Bugs
----

* Improved support for ``DirectedInfinity`` and ``Indeterminate``.
* ``Definitions`` is compatible with ``pickle``.


Package updates
+++++++++++++++

#. Python 3.11 is now supported


6.0.1
Expand Down
2 changes: 2 additions & 0 deletions mathics/autoload/rules/Bessel.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(*Extended rules for handling expressions with Bessel functions*)



Begin["internals`bessel`"]

Unprotect[HankelH1];
Expand Down
14 changes: 14 additions & 0 deletions mathics/autoload/rules/Limit.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(* Additions to mathics.builtin.numbers.trig that are either wrong
or not covered by SymPy.
These were culled from symja_android_library/rules/LimitRules.m.
*)


Begin["System`Limit`private`"]
Unprotect[Limit];
Limit[Tan[x_], x_Symbol->Pi/2] = Indeterminate;
Limit[Cot[x_], x_Symbol->0] = Indeterminate;
Limit[x_ Sqrt[2 Pi]^(x_^-1) (Sin[x_]/(x_!))^(x_^-1), x_Symbol->Infinity] = E;
Protect[Limit];
End[]
20 changes: 19 additions & 1 deletion mathics/builtin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,25 @@ def name_is_builtin_symbol(module, name: str) -> Optional[type]:
return None

# Skip those builtins defined in or imported from another module.
if inspect.getmodule(module_object) is not module:

# rocky: I think this is a code smell. It doesn't feel like
# we should have to do this if things are organized and modularized
# builtins and use less custom code.
# mmatera reports that we need this because of the interaction of
# * the custom Mathics3 loading/importing mechanism,
# * the builtin module hierarchy, e.g. mathics.builtin.arithmetic
# nested under mathics.builtin, and
# * our custom doc/doctest and possibly custom checking system

# Mathics3 modules modules, however, right now import all builtin modules from
# __init__
# Note Mathics3 modules do not support buitin hierarchies, e.g.
# pymathics.graph.parametric is allowed but not pymathics.graph.parametric.xxx.
# This too has to do with the custom doc/doctest that is currently used.

if inspect.getmodule(
module_object
) is not module and not module.__name__.startswith("pymathics."):
return None

# Skip objects in module mathics.builtin.base.
Expand Down
166 changes: 7 additions & 159 deletions mathics/builtin/atomic/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io
import re
import unicodedata
from binascii import hexlify, unhexlify
from binascii import unhexlify
from heapq import heappop, heappush
from typing import Any, List

Expand All @@ -17,35 +17,19 @@
from mathics.core.attributes import A_LISTABLE, A_PROTECTED
from mathics.core.convert.expression import to_mathics_list
from mathics.core.convert.python import from_bool
from mathics.core.convert.regex import to_regex
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.expression_predefined import MATHICS3_INFINITY
from mathics.core.list import ListExpression
from mathics.core.parser import MathicsFileLineFeeder, parse
from mathics.core.symbols import Symbol, SymbolTrue
from mathics.core.systemsymbols import (
SymbolBlank,
SymbolFailed,
SymbolInputForm,
SymbolOutputForm,
)
from mathics.core.systemsymbols import SymbolFailed, SymbolInputForm, SymbolOutputForm
from mathics.eval.strings import eval_ToString
from mathics.settings import SYSTEM_CHARACTER_ENCODING

SymbolToExpression = Symbol("ToExpression")

_regex_longest = {
"+": "+",
"*": "*",
}

_regex_shortest = {
"+": "+?",
"*": "*?",
}


# A better thing to do would be to write a pymathics module that
# covers all of the variations. Here we just give some minimal basics

# Data taken from:
Expand Down Expand Up @@ -97,10 +81,6 @@
}


def _encode_pname(name):
return "n" + hexlify(name.encode("utf8")).decode("utf8")


def _decode_pname(name):
return unhexlify(name[1:]).decode("utf8")

Expand Down Expand Up @@ -187,140 +167,6 @@ def _search(patts, str, flags, matched):
return _search(re_patts, py_s, flags, matched)


def to_regex(
expr, evaluation, q=_regex_longest, groups=None, abbreviated_patterns=False
):
if expr is None:
return None

if groups is None:
groups = {}

def recurse(x, quantifiers=q):
return to_regex(x, evaluation, q=quantifiers, groups=groups)

if isinstance(expr, String):
result = expr.get_string_value()
if abbreviated_patterns:
pieces = []
i, j = 0, 0
while j < len(result):
c = result[j]
if c == "\\" and j + 1 < len(result):
pieces.append(re.escape(result[i:j]))
pieces.append(re.escape(result[j + 1]))
j += 2
i = j
elif c == "*":
pieces.append(re.escape(result[i:j]))
pieces.append("(.*)")
j += 1
i = j
elif c == "@":
pieces.append(re.escape(result[i:j]))
# one or more characters, excluding uppercase letters
pieces.append("([^A-Z]+)")
j += 1
i = j
else:
j += 1
pieces.append(re.escape(result[i:j]))
result = "".join(pieces)
else:
result = re.escape(result)
return result
if expr.has_form("RegularExpression", 1):
regex = expr.elements[0].get_string_value()
if regex is None:
return regex
try:
re.compile(regex)
# Don't return the compiled regex because it may need to composed
# further e.g. StringExpression["abc", RegularExpression[regex2]].
return regex
except re.error:
return None # invalid regex

if isinstance(expr, Symbol):
return {
"System`NumberString": r"[-|+]?(\d+(\.\d*)?|\.\d+)?",
"System`Whitespace": r"(?u)\s+",
"System`DigitCharacter": r"\d",
"System`WhitespaceCharacter": r"(?u)\s",
"System`WordCharacter": r"(?u)[^\W_]",
"System`StartOfLine": r"^",
"System`EndOfLine": r"$",
"System`StartOfString": r"\A",
"System`EndOfString": r"\Z",
"System`WordBoundary": r"\b",
"System`LetterCharacter": r"(?u)[^\W_0-9]",
"System`HexadecimalCharacter": r"[0-9a-fA-F]",
}.get(expr.get_name())

if expr.has_form("CharacterRange", 2):
(start, stop) = (element.get_string_value() for element in expr.elements)
if all(x is not None and len(x) == 1 for x in (start, stop)):
return "[{0}-{1}]".format(re.escape(start), re.escape(stop))

if expr.has_form("Blank", 0):
return r"(.|\n)"
if expr.has_form("BlankSequence", 0):
return r"(.|\n)" + q["+"]
if expr.has_form("BlankNullSequence", 0):
return r"(.|\n)" + q["*"]
if expr.has_form("Except", 1, 2):
if len(expr.elements) == 1:
# TODO: Check if this shouldn't be SymbolBlank
# instead of SymbolBlank[]
elements = [expr.elements[0], Expression(SymbolBlank)]
else:
elements = [expr.elements[0], expr.elements[1]]
elements = [recurse(element) for element in elements]
if all(element is not None for element in elements):
return "(?!{0}){1}".format(*elements)
if expr.has_form("Characters", 1):
element = expr.elements[0].get_string_value()
if element is not None:
return "[{0}]".format(re.escape(element))
if expr.has_form("StringExpression", None):
elements = [recurse(element) for element in expr.elements]
if None in elements:
return None
return "".join(elements)
if expr.has_form("Repeated", 1):
element = recurse(expr.elements[0])
if element is not None:
return "({0})".format(element) + q["+"]
if expr.has_form("RepeatedNull", 1):
element = recurse(expr.elements[0])
if element is not None:
return "({0})".format(element) + q["*"]
if expr.has_form("Alternatives", None):
elements = [recurse(element) for element in expr.elements]
if all(element is not None for element in elements):
return "|".join(elements)
if expr.has_form("Shortest", 1):
return recurse(expr.elements[0], quantifiers=_regex_shortest)
if expr.has_form("Longest", 1):
return recurse(expr.elements[0], quantifiers=_regex_longest)
if expr.has_form("Pattern", 2) and isinstance(expr.elements[0], Symbol):
name = expr.elements[0].get_name()
patt = groups.get(name, None)
if patt is not None:
if expr.elements[1].has_form("Blank", 0):
pass # ok, no warnings
elif not expr.elements[1].sameQ(patt):
evaluation.message(
"StringExpression", "cond", expr.elements[0], expr, expr.elements[0]
)
return "(?P=%s)" % _encode_pname(name)
else:
groups[name] = expr.elements[1]
return "(?P<%s>%s)" % (_encode_pname(name), recurse(expr.elements[1]))

return None


def anchor_pattern(patt):
"""
anchors a regex in order to force matching against an entire string.
Expand Down Expand Up @@ -1087,7 +933,8 @@ class ToExpression(Builtin):
>> ToExpression["2 3", InputForm]
= 6
Note that newlines are like semicolons, not blanks. So so the return value is the second-line value.
Note that newlines are like semicolons, not blanks. So so the return value is the \
second-line value.
>> ToExpression["2\[NewLine]3"]
= 3
Expand Down Expand Up @@ -1255,7 +1102,8 @@ class Transliterate(Builtin):
ASCII translateration examples:
<ul>
<li><url>:Russian language: https://en.wikipedia.org/wiki/Russian_language#Transliteration</url>
<li><url>:Russian language:
https://en.wikipedia.org/wiki/Russian_language#Transliteration</url>
<li><url>:Hiragana: https://en.wikipedia.org/wiki/Hiragana#Table_of_hiragana</url>
</ul>
"""
Expand Down
2 changes: 1 addition & 1 deletion mathics/builtin/atomic/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import re

from mathics.builtin.atomic.strings import to_regex
from mathics.builtin.base import Builtin, PrefixOperator, Test
from mathics.core.assignment import get_symbol_values
from mathics.core.atoms import String
Expand All @@ -22,6 +21,7 @@
attributes_bitset_to_list,
)
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.expression import Expression
from mathics.core.list import ListExpression
Expand Down
Loading

0 comments on commit f32ec04

Please sign in to comment.