55
66from mathics .core .element import KeyComparable
77from mathics .core .expression import Expression
8- from mathics .core .symbols import strip_context
8+ from mathics .core .symbols import strip_context , SymbolTrue
99from mathics .core .pattern import Pattern , StopGenerator
1010
1111from itertools import chain
@@ -19,6 +19,10 @@ def function_arguments(f):
1919 return _python_function_arguments (f )
2020
2121
22+ class StopMatchConditionFailed (StopGenerator ):
23+ pass
24+
25+
2226class StopGenerator_BaseRule (StopGenerator ):
2327 pass
2428
@@ -59,7 +63,11 @@ def yield_match(vars, rest):
5963 if name .startswith ("_option_" ):
6064 options [name [len ("_option_" ) :]] = value
6165 del vars [name ]
62- new_expression = self .do_replace (expression , vars , options , evaluation )
66+ try :
67+ new_expression = self .do_replace (expression , vars , options , evaluation )
68+ except StopMatchConditionFailed :
69+ return
70+
6371 if new_expression is None :
6472 new_expression = expression
6573 if rest [0 ] or rest [1 ]:
@@ -107,7 +115,7 @@ def yield_match(vars, rest):
107115 def do_replace (self ):
108116 raise NotImplementedError
109117
110- def get_sort_key (self ) -> tuple :
118+ def get_sort_key (self , pattern_sort = False ) -> tuple :
111119 # FIXME: check if this makes sense:
112120 return tuple ((self .system , self .pattern .get_sort_key (True )))
113121
@@ -131,12 +139,131 @@ class Rule(BaseRule):
131139 ``G[1.^2, a^2]``
132140 """
133141
134- def __init__ (self , pattern , replace , system = False ) -> None :
142+ def __ge__ (self , other ):
143+ if isinstance (other , Rule ):
144+ sys , key , rhs_cond = self .get_sort_key ()
145+ sys_other , key_other , rhs_cond_other = other .get_sort_key ()
146+ if sys != sys_other :
147+ return sys > sys_other
148+ if key != key_other :
149+ return key > key_other
150+
151+ # larger and more complex conditions come first
152+ len_cond , len_cond_other = len (rhs_cond ), len (rhs_cond_other )
153+ if len_cond != len_cond_other :
154+ return len_cond_other > len_cond
155+ if len_cond == 0 :
156+ return False
157+ for me_cond , other_cond in zip (rhs_cond , rhs_cond_other ):
158+ me_sk = me_cond .get_sort_key (True )
159+ o_sk = other_cond .get_sort_key (True )
160+ if me_sk > o_sk :
161+ return False
162+ return True
163+ # Follow the usual rule
164+ return self .get_sort_key (True ) >= other .get_sort_key (True )
165+
166+ def __gt__ (self , other ):
167+ if isinstance (other , Rule ):
168+ sys , key , rhs_cond = self .get_sort_key ()
169+ sys_other , key_other , rhs_cond_other = other .get_sort_key ()
170+ if sys != sys_other :
171+ return sys > sys_other
172+ if key != key_other :
173+ return key > key_other
174+
175+ # larger and more complex conditions come first
176+ len_cond , len_cond_other = len (rhs_cond ), len (rhs_cond_other )
177+ if len_cond != len_cond_other :
178+ return len_cond_other > len_cond
179+ if len_cond == 0 :
180+ return False
181+
182+ for me_cond , other_cond in zip (rhs_cond , rhs_cond_other ):
183+ me_sk = me_cond .get_sort_key (True )
184+ o_sk = other_cond .get_sort_key (True )
185+ if me_sk > o_sk :
186+ return False
187+ return me_sk > o_sk
188+ # Follow the usual rule
189+ return self .get_sort_key (True ) > other .get_sort_key (True )
190+
191+ def __le__ (self , other ):
192+ if isinstance (other , Rule ):
193+ sys , key , rhs_cond = self .get_sort_key ()
194+ sys_other , key_other , rhs_cond_other = other .get_sort_key ()
195+ if sys != sys_other :
196+ return sys < sys_other
197+ if key != key_other :
198+ return key < key_other
199+
200+ # larger and more complex conditions come first
201+ len_cond , len_cond_other = len (rhs_cond ), len (rhs_cond_other )
202+ if len_cond != len_cond_other :
203+ return len_cond_other < len_cond
204+ if len_cond == 0 :
205+ return False
206+ for me_cond , other_cond in zip (rhs_cond , rhs_cond_other ):
207+ me_sk = me_cond .get_sort_key (True )
208+ o_sk = other_cond .get_sort_key (True )
209+ if me_sk < o_sk :
210+ return False
211+ return True
212+ # Follow the usual rule
213+ return self .get_sort_key (True ) <= other .get_sort_key (True )
214+
215+ def __lt__ (self , other ):
216+ if isinstance (other , Rule ):
217+ sys , key , rhs_cond = self .get_sort_key ()
218+ sys_other , key_other , rhs_cond_other = other .get_sort_key ()
219+ if sys != sys_other :
220+ return sys < sys_other
221+ if key != key_other :
222+ return key < key_other
223+
224+ # larger and more complex conditions come first
225+ len_cond , len_cond_other = len (rhs_cond ), len (rhs_cond_other )
226+ if len_cond != len_cond_other :
227+ return len_cond_other < len_cond
228+ if len_cond == 0 :
229+ return False
230+
231+ for me_cond , other_cond in zip (rhs_cond , rhs_cond_other ):
232+ me_sk = me_cond .get_sort_key (True )
233+ o_sk = other_cond .get_sort_key (True )
234+ if me_sk < o_sk :
235+ return False
236+ return me_sk > o_sk
237+ # Follow the usual rule
238+ return self .get_sort_key (True ) < other .get_sort_key (True )
239+
240+ def __init__ (self , pattern , replace , delayed = True , system = False ) -> None :
135241 super (Rule , self ).__init__ (pattern , system = system )
136242 self .replace = replace
243+ self .delayed = delayed
244+ # If delayed is True, and replace is a nested
245+ # Condition expression, stores the conditions and the
246+ # remaining stripped expression.
247+ # This is going to be used to compare and sort rules,
248+ # and also to decide if the rule matches an expression.
249+ conds = []
250+ if delayed :
251+ while replace .has_form ("System`Condition" , 2 ):
252+ replace , cond = replace .elements
253+ conds .append (cond )
254+
255+ self .rhs_conditions = sorted (conds )
256+ self .strip_replace = replace
137257
138258 def do_replace (self , expression , vars , options , evaluation ):
139- new = self .replace .replace_vars (vars )
259+ replace = self .replace if self .rhs_conditions == [] else self .strip_replace
260+ for cond in self .rhs_conditions :
261+ cond = cond .replace_vars (vars )
262+ cond = cond .evaluate (evaluation )
263+ if cond is not SymbolTrue :
264+ raise StopMatchConditionFailed
265+
266+ new = replace .replace_vars (vars )
140267 new .options = options
141268
142269 # if options is a non-empty dict, we need to ensure reevaluation of the whole expression, since 'new' will
@@ -159,6 +286,12 @@ def do_replace(self, expression, vars, options, evaluation):
159286 def __repr__ (self ) -> str :
160287 return "<Rule: %s -> %s>" % (self .pattern , self .replace )
161288
289+ def get_sort_key (self , pattern_sort = False ) -> tuple :
290+ # FIXME: check if this makes sense:
291+ return tuple (
292+ (self .system , self .pattern .get_sort_key (True ), self .rhs_conditions )
293+ )
294+
162295
163296class BuiltinRule (BaseRule ):
164297 """
0 commit comments