Skip to content

Commit

Permalink
Add SyntaxQ and add String Tests section...
Browse files Browse the repository at this point in the history
of a new "Testing Expressions" Guide Section
  • Loading branch information
rocky committed Dec 28, 2024
1 parent 22c2d90 commit b005dbc
Show file tree
Hide file tree
Showing 9 changed files with 354 additions and 301 deletions.
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ repos:
hooks:
- id: check-merge-conflict
- id: debug-statements
stages: [commit]
stages: [pre-commit]
- id: end-of-file-fixer
stages: [commit]
stages: [pre-commit]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
stages: [commit]
stages: [pre-commit]
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
language_version: python3
stages: [commit]
stages: [pre-commit]
78 changes: 4 additions & 74 deletions mathics/builtin/atomic/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,22 @@

from mathics.core.atoms import Integer, Integer0, Integer1, String
from mathics.core.attributes import A_LISTABLE, A_PROTECTED
from mathics.core.builtin import Builtin, Predefined, PrefixOperator, Test
from mathics.core.builtin import Builtin, Predefined, PrefixOperator
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.list import ListExpression
from mathics.core.parser import MathicsFileLineFeeder, parse
from mathics.core.symbols import Symbol, SymbolTrue
from mathics.core.systemsymbols import (
SymbolFailed,
SymbolInputForm,
SymbolNone,
SymbolOutputForm,
SymbolToExpression,
)
from mathics.eval.strings import eval_ToString
from mathics.eval.strings import eval_StringContainsQ, eval_ToString
from mathics.settings import SYSTEM_CHARACTER_ENCODING

SymbolToExpression = Symbol("ToExpression")

# covers all of the variations. Here we just give some minimal basics

# Data taken from:
Expand Down Expand Up @@ -130,48 +126,6 @@ def push(i, iter, form):
push(i, iter, form)


def _pattern_search(name, string, patt, evaluation, options, matched):
# Get the pattern list and check validity for each
if patt.has_form("List", None):
patts = patt.elements
else:
patts = [patt]
re_patts = []
for p in patts:
py_p = to_regex(p, show_message=evaluation.message)
if py_p is None:
evaluation.message("StringExpression", "invld", p, patt)
return
re_patts.append(py_p)

flags = re.MULTILINE
if options["System`IgnoreCase"] is SymbolTrue:
flags = flags | re.IGNORECASE

def _search(patts, str, flags, matched):
if any(re.search(p, str, flags=flags) for p in patts):
return from_bool(matched)
return from_bool(not matched)

# Check string validity and perform regex searchhing
if string.has_form("List", None):
py_s = [s.get_string_value() for s in string.elements]
if any(s is None for s in py_s):
evaluation.message(
name, "strse", Integer1, Expression(Symbol(name), string, patt)
)
return
return to_mathics_list(*[_search(re_patts, s, flags, matched) for s in py_s])
else:
py_s = string.get_string_value()
if py_s is None:
evaluation.message(
name, "strse", Integer1, Expression(Symbol(name), string, patt)
)
return
return _search(re_patts, py_s, flags, matched)


def anchor_pattern(patt):
"""
anchors a regex in order to force matching against an entire string.
Expand Down Expand Up @@ -691,35 +645,11 @@ class StringContainsQ(Builtin):

def eval(self, string, patt, evaluation: Evaluation, options: dict):
"StringContainsQ[string_, patt_, OptionsPattern[%(name)s]]"
return _pattern_search(
return eval_StringContainsQ(
self.__class__.__name__, string, patt, evaluation, options, True
)


class StringQ(Test):
"""
<url>
:WMA link:
https://reference.wolfram.com/language/ref/StringQ.html</url>
<dl>
<dt>'StringQ[$expr$]'
<dd>returns 'True' if $expr$ is a 'String', or 'False' otherwise.
</dl>
>> StringQ["abc"]
= True
>> StringQ[1.5]
= False
>> Select[{"12", 1, 3, 5, "yz", x, y}, StringQ]
= {12, yz}
"""

summary_text = "test whether an expression is a string"

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


class StringRepeat(Builtin):
"""
<url>
Expand Down
1 change: 1 addition & 0 deletions mathics/builtin/string/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
Strings and Characters
"""
# FIXME: Redo this is a Tech note, not a Guide secition.
82 changes: 9 additions & 73 deletions mathics/builtin/string/characters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""
Characters in Strings
"""

# FIXME: Redo: this is part of a Tech note, not a guide section.

from mathics.core.atoms import String
from mathics.core.attributes import A_LISTABLE, A_PROTECTED, A_READ_PROTECTED
Expand Down Expand Up @@ -72,74 +72,6 @@ def eval(self, start, stop, evaluation: Evaluation):
return ListExpression(*[String(chr(code)) for code in range(start, stop + 1)])


class DigitQ(Builtin):
"""
<url>
:WMA link:
https://reference.wolfram.com/language/ref/DigitQ.html</url>
<dl>
<dt>'DigitQ[$string$]'
<dd>yields 'True' if all the characters in the $string$ are \
digits, and yields 'False' otherwise.
</dl>
>> DigitQ["9"]
= True
>> DigitQ["a"]
= False
>> DigitQ["01001101011000010111010001101000011010010110001101110011"]
= True
>> DigitQ["-123456789"]
= False
"""

rules = {
"DigitQ[string_]": (
"If[StringQ[string], StringMatchQ[string, DigitCharacter...], False, False]"
),
}
summary_text = "test whether all the characters are digits"


class LetterQ(Builtin):
"""
<url>
:WMA link:
https://reference.wolfram.com/language/ref/LetterQ.html</url>
<dl>
<dt>'LetterQ[$string$]'
<dd> yields 'True' if all the characters in the $string$ are \
letters, and yields 'False' otherwise.
</dl>
>> LetterQ["m"]
= True
>> LetterQ["9"]
= False
>> LetterQ["Mathics"]
= True
>> LetterQ["Welcome to Mathics"]
= False
"""

rules = {
"LetterQ[string_]": (
"If[StringQ[string], StringMatchQ[string, LetterCharacter...], False, False]"
),
}
summary_text = "test whether all the characters are letters"


class LowerCaseQ(Test):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/LowerCaseQ.html</url>
Expand All @@ -159,8 +91,10 @@ class LowerCaseQ(Test):

summary_text = "test whether all the characters are lower-case letters"

def test(self, s) -> bool:
return isinstance(s, String) and all(c.islower() for c in s.get_string_value())
def test(self, expr) -> bool:
return isinstance(expr, String) and all(
c.islower() for c in expr.get_string_value()
)


class ToLowerCase(Builtin):
Expand Down Expand Up @@ -224,5 +158,7 @@ class UpperCaseQ(Test):

summary_text = "test whether all the characters are upper-case letters"

def test(self, s) -> bool:
return isinstance(s, String) and all(c.isupper() for c in s.get_string_value())
def test(self, expr) -> bool:
return isinstance(expr, String) and all(
c.isupper() for c in expr.get_string_value()
)
2 changes: 1 addition & 1 deletion mathics/builtin/string/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
_parallel_match,
_StringFind,
mathics_split,
to_regex,
)
from mathics.core.atoms import Integer, Integer1, Integer3, String
from mathics.core.attributes import (
Expand All @@ -23,6 +22,7 @@
)
from mathics.core.builtin import Builtin, InfixOperator
from mathics.core.convert.python import from_python
from mathics.core.convert.regex import to_regex
from mathics.core.evaluation import Evaluation
from mathics.core.expression import BoxError, Expression, string_list
from mathics.core.expression_predefined import MATHICS3_INFINITY
Expand Down
Loading

0 comments on commit b005dbc

Please sign in to comment.