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