Skip to content

Commit 2aecdb3

Browse files
authored
Add SyntaxQ and add a new "String Tests" Section (#1248)
* Add `SyntaxQ[]` * Create "String Tests" section in the "Testing Expressions" Guide section * move another eval function to `mathics.eval` `SyntaxQ[]` is used in the PacletManager.
1 parent 738992d commit 2aecdb3

File tree

9 files changed

+354
-301
lines changed

9 files changed

+354
-301
lines changed

.pre-commit-config.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ repos:
66
hooks:
77
- id: check-merge-conflict
88
- id: debug-statements
9-
stages: [commit]
9+
stages: [pre-commit]
1010
- id: end-of-file-fixer
11-
stages: [commit]
11+
stages: [pre-commit]
1212
- repo: https://github.com/pycqa/isort
1313
rev: 5.13.2
1414
hooks:
1515
- id: isort
16-
stages: [commit]
16+
stages: [pre-commit]
1717
- repo: https://github.com/psf/black
1818
rev: 23.12.1
1919
hooks:
2020
- id: black
2121
language_version: python3
22-
stages: [commit]
22+
stages: [pre-commit]

mathics/builtin/atomic/strings.py

+4-74
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,22 @@
1515

1616
from mathics.core.atoms import Integer, Integer0, Integer1, String
1717
from mathics.core.attributes import A_LISTABLE, A_PROTECTED
18-
from mathics.core.builtin import Builtin, Predefined, PrefixOperator, Test
18+
from mathics.core.builtin import Builtin, Predefined, PrefixOperator
1919
from mathics.core.convert.expression import to_mathics_list
20-
from mathics.core.convert.python import from_bool
21-
from mathics.core.convert.regex import to_regex
2220
from mathics.core.evaluation import Evaluation
2321
from mathics.core.expression import Expression
2422
from mathics.core.list import ListExpression
2523
from mathics.core.parser import MathicsFileLineFeeder, parse
26-
from mathics.core.symbols import Symbol, SymbolTrue
2724
from mathics.core.systemsymbols import (
2825
SymbolFailed,
2926
SymbolInputForm,
3027
SymbolNone,
3128
SymbolOutputForm,
29+
SymbolToExpression,
3230
)
33-
from mathics.eval.strings import eval_ToString
31+
from mathics.eval.strings import eval_StringContainsQ, eval_ToString
3432
from mathics.settings import SYSTEM_CHARACTER_ENCODING
3533

36-
SymbolToExpression = Symbol("ToExpression")
37-
3834
# covers all of the variations. Here we just give some minimal basics
3935

4036
# Data taken from:
@@ -130,48 +126,6 @@ def push(i, iter, form):
130126
push(i, iter, form)
131127

132128

133-
def _pattern_search(name, string, patt, evaluation, options, matched):
134-
# Get the pattern list and check validity for each
135-
if patt.has_form("List", None):
136-
patts = patt.elements
137-
else:
138-
patts = [patt]
139-
re_patts = []
140-
for p in patts:
141-
py_p = to_regex(p, show_message=evaluation.message)
142-
if py_p is None:
143-
evaluation.message("StringExpression", "invld", p, patt)
144-
return
145-
re_patts.append(py_p)
146-
147-
flags = re.MULTILINE
148-
if options["System`IgnoreCase"] is SymbolTrue:
149-
flags = flags | re.IGNORECASE
150-
151-
def _search(patts, str, flags, matched):
152-
if any(re.search(p, str, flags=flags) for p in patts):
153-
return from_bool(matched)
154-
return from_bool(not matched)
155-
156-
# Check string validity and perform regex searchhing
157-
if string.has_form("List", None):
158-
py_s = [s.get_string_value() for s in string.elements]
159-
if any(s is None for s in py_s):
160-
evaluation.message(
161-
name, "strse", Integer1, Expression(Symbol(name), string, patt)
162-
)
163-
return
164-
return to_mathics_list(*[_search(re_patts, s, flags, matched) for s in py_s])
165-
else:
166-
py_s = string.get_string_value()
167-
if py_s is None:
168-
evaluation.message(
169-
name, "strse", Integer1, Expression(Symbol(name), string, patt)
170-
)
171-
return
172-
return _search(re_patts, py_s, flags, matched)
173-
174-
175129
def anchor_pattern(patt):
176130
"""
177131
anchors a regex in order to force matching against an entire string.
@@ -691,35 +645,11 @@ class StringContainsQ(Builtin):
691645

692646
def eval(self, string, patt, evaluation: Evaluation, options: dict):
693647
"StringContainsQ[string_, patt_, OptionsPattern[%(name)s]]"
694-
return _pattern_search(
648+
return eval_StringContainsQ(
695649
self.__class__.__name__, string, patt, evaluation, options, True
696650
)
697651

698652

699-
class StringQ(Test):
700-
"""
701-
<url>
702-
:WMA link:
703-
https://reference.wolfram.com/language/ref/StringQ.html</url>
704-
<dl>
705-
<dt>'StringQ[$expr$]'
706-
<dd>returns 'True' if $expr$ is a 'String', or 'False' otherwise.
707-
</dl>
708-
709-
>> StringQ["abc"]
710-
= True
711-
>> StringQ[1.5]
712-
= False
713-
>> Select[{"12", 1, 3, 5, "yz", x, y}, StringQ]
714-
= {12, yz}
715-
"""
716-
717-
summary_text = "test whether an expression is a string"
718-
719-
def test(self, expr) -> bool:
720-
return isinstance(expr, String)
721-
722-
723653
class StringRepeat(Builtin):
724654
"""
725655
<url>

mathics/builtin/string/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
Strings and Characters
33
44
"""
5+
# FIXME: Redo. This is a Tech note, not a Guide Section.

mathics/builtin/string/characters.py

+9-73
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
Characters in Strings
44
"""
5-
5+
# FIXME: Redo: this is part of a Tech note, not a guide section.
66

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

7474

75-
class DigitQ(Builtin):
76-
"""
77-
<url>
78-
:WMA link:
79-
https://reference.wolfram.com/language/ref/DigitQ.html</url>
80-
81-
<dl>
82-
<dt>'DigitQ[$string$]'
83-
<dd>yields 'True' if all the characters in the $string$ are \
84-
digits, and yields 'False' otherwise.
85-
86-
</dl>
87-
88-
>> DigitQ["9"]
89-
= True
90-
91-
>> DigitQ["a"]
92-
= False
93-
94-
>> DigitQ["01001101011000010111010001101000011010010110001101110011"]
95-
= True
96-
97-
>> DigitQ["-123456789"]
98-
= False
99-
100-
"""
101-
102-
rules = {
103-
"DigitQ[string_]": (
104-
"If[StringQ[string], StringMatchQ[string, DigitCharacter...], False, False]"
105-
),
106-
}
107-
summary_text = "test whether all the characters are digits"
108-
109-
110-
class LetterQ(Builtin):
111-
"""
112-
<url>
113-
:WMA link:
114-
https://reference.wolfram.com/language/ref/LetterQ.html</url>
115-
116-
<dl>
117-
<dt>'LetterQ[$string$]'
118-
<dd> yields 'True' if all the characters in the $string$ are \
119-
letters, and yields 'False' otherwise.
120-
</dl>
121-
122-
>> LetterQ["m"]
123-
= True
124-
125-
>> LetterQ["9"]
126-
= False
127-
128-
>> LetterQ["Mathics"]
129-
= True
130-
131-
>> LetterQ["Welcome to Mathics"]
132-
= False
133-
"""
134-
135-
rules = {
136-
"LetterQ[string_]": (
137-
"If[StringQ[string], StringMatchQ[string, LetterCharacter...], False, False]"
138-
),
139-
}
140-
summary_text = "test whether all the characters are letters"
141-
142-
14375
class LowerCaseQ(Test):
14476
"""
14577
<url>:WMA link:https://reference.wolfram.com/language/ref/LowerCaseQ.html</url>
@@ -159,8 +91,10 @@ class LowerCaseQ(Test):
15991

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

162-
def test(self, s) -> bool:
163-
return isinstance(s, String) and all(c.islower() for c in s.get_string_value())
94+
def test(self, expr) -> bool:
95+
return isinstance(expr, String) and all(
96+
c.islower() for c in expr.get_string_value()
97+
)
16498

16599

166100
class ToLowerCase(Builtin):
@@ -224,5 +158,7 @@ class UpperCaseQ(Test):
224158

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

227-
def test(self, s) -> bool:
228-
return isinstance(s, String) and all(c.isupper() for c in s.get_string_value())
161+
def test(self, expr) -> bool:
162+
return isinstance(expr, String) and all(
163+
c.isupper() for c in expr.get_string_value()
164+
)

mathics/builtin/string/operations.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
_parallel_match,
1212
_StringFind,
1313
mathics_split,
14-
to_regex,
1514
)
1615
from mathics.core.atoms import Integer, Integer1, Integer3, String
1716
from mathics.core.attributes import (
@@ -23,6 +22,7 @@
2322
)
2423
from mathics.core.builtin import Builtin, InfixOperator
2524
from mathics.core.convert.python import from_python
25+
from mathics.core.convert.regex import to_regex
2626
from mathics.core.evaluation import Evaluation
2727
from mathics.core.expression import BoxError, Expression, string_list
2828
from mathics.core.expression_predefined import MATHICS3_INFINITY

0 commit comments

Comments
 (0)