-
-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathbasic.py
More file actions
205 lines (169 loc) · 6.19 KB
/
Copy pathbasic.py
File metadata and controls
205 lines (169 loc) · 6.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# -*- coding: utf-8 -*-
"""
Basic Pattern Objects
"""
from abc import ABC
from typing import Optional as OptionalType
from mathics.core.builtin import PatternObject
from mathics.core.evaluation import Evaluation
from mathics.core.expression import Expression
from mathics.core.symbols import BaseElement
# This tells documentation how to sort this module
sort_order = "mathics.builtin.rules-and-patterns.basic"
class _Blank(PatternObject, ABC):
arg_counts = [0, 1]
_instance = None
def __new__(cls, *args, **kwargs):
if kwargs.get("expression", None) is False:
return super().__new__(cls, *args, **kwargs)
num_elem = len(args[0].elements)
assert num_elem < 2, f"{cls} should have at most an element."
if num_elem != 0:
return super().__new__(cls, *args, **kwargs)
# no arguments. Use the singleton
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
def init(
self, expr: Expression, evaluation: OptionalType[Evaluation] = None
) -> None:
super().init(expr, evaluation=evaluation)
if expr.elements:
self.head = expr.elements[0]
else:
# FIXME: elswhere, some code wants to
# get the attributes of head.
# So is this really the best thing to do here?
self.head = None
class Blank(_Blank):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/Blank.html</url>
<dl>
<dt>'Blank[]'
<dt>'_'
<dd>represents any single expression in a pattern.
<dt>'Blank'[$h$]
<dt>'_$h$'
<dd>represents any expression with head $h$.
</dl>
>> MatchQ[a + b, _]
= True
Patterns of the form '_'$h$ can be used to test the types of \
objects:
>> MatchQ[42, _Integer]
= True
>> MatchQ[1.0, _Integer]
= False
>> {42, 1.0, x} /. {_Integer -> "integer", _Real -> "real"} // InputForm
= {"integer", "real", x}
'Blank' only matches a single expression:
>> MatchQ[f[1, 2], f[_]]
= False
"""
rules = {
(
"MakeBoxes[Verbatim[Blank][], "
"f:StandardForm|TraditionalForm|OutputForm|InputForm]"
): '"_"',
(
"MakeBoxes[Verbatim[Blank][head_Symbol], "
"f:StandardForm|TraditionalForm|OutputForm|InputForm]"
): ('"_" <> MakeBoxes[head, f]'),
}
summary_text = "match to any single expression"
def match(self, expression: BaseElement, pattern_context: dict):
vars_dict = pattern_context["vars_dict"]
yield_func = pattern_context["yield_func"]
if not expression.has_form("Sequence", 0):
if self.head is not None:
if expression.get_head().sameQ(self.head):
yield_func(vars_dict, None)
else:
yield_func(vars_dict, None)
class BlankNullSequence(_Blank):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/BlankNullSequence.html</url>
<dl>
<dt>'BlankNullSequence[]'
<dt>'___'
<dd>represents any sequence of expression elements in a pattern, \
including an empty sequence.
</dl>
'BlankNullSequence' is like 'BlankSequence', except it can match an \
empty sequence:
>> MatchQ[f[], f[___]]
= True
"""
rules = {
"MakeBoxes[Verbatim[BlankNullSequence][], f:StandardForm|TraditionalForm|OutputForm|InputForm]": '"___"',
"MakeBoxes[Verbatim[BlankNullSequence][head_Symbol], f:StandardForm|TraditionalForm|OutputForm|InputForm]": '"___" <> MakeBoxes[head, f]',
}
summary_text = "match to a sequence of zero or more elements"
def match(self, expression: Expression, pattern_context: dict):
"""Match with a BlankNullSequence"""
vars_dict = pattern_context["vars_dict"]
yield_func = pattern_context["yield_func"]
elements = expression.get_sequence()
if self.head:
ok = True
for element in elements:
if element.get_head() != self.head:
ok = False
break
if ok:
yield_func(vars_dict, None)
else:
yield_func(vars_dict, None)
def get_match_count(self, vars_dict: OptionalType[dict] = None) -> tuple:
return (0, None)
class BlankSequence(_Blank):
"""
<url>:WMA link:https://reference.wolfram.com/language/ref/BlankSequence.html</url>
<dl>
<dt>'BlankSequence[]'
<dt>'__'
<dd>represents any non-empty sequence of expression elements in \
a pattern.
<dt>'BlankSequence'[$h$]
<dt>'__$h$'
<dd>represents any sequence of elements, all of which have head $h$.
</dl>
Use a 'BlankSequence' pattern to stand for a non-empty sequence of \
arguments:
>> MatchQ[f[1, 2, 3], f[__]]
= True
>> MatchQ[f[], f[__]]
= False
'__'$h$ will match only if all elements have head $h$:
>> MatchQ[f[1, 2, 3], f[__Integer]]
= True
>> MatchQ[f[1, 2.0, 3], f[__Integer]]
= False
The value captured by a named 'BlankSequence' pattern is a \
'Sequence' object:
>> f[1, 2, 3] /. f[x__] -> x
= Sequence[1, 2, 3]
"""
rules = {
"MakeBoxes[Verbatim[BlankSequence][], f:StandardForm|TraditionalForm|OutputForm|InputForm]": '"__"',
"MakeBoxes[Verbatim[BlankSequence][head_Symbol], f:StandardForm|TraditionalForm|OutputForm|InputForm]": '"__" <> MakeBoxes[head, f]',
}
summary_text = "match to a non-empty sequence of elements"
def match(self, expression: Expression, pattern_context: dict):
vars_dict = pattern_context["vars_dict"]
yield_func = pattern_context["yield_func"]
elements = expression.get_sequence()
if not elements:
return
if self.head:
ok = True
for element in elements:
if element.get_head() != self.head:
ok = False
break
if ok:
yield_func(vars_dict, None)
else:
yield_func(vars_dict, None)
def get_match_count(self, vars_dict: OptionalType[dict] = None) -> tuple:
return (1, None)