Skip to content

Commit

Permalink
Rule do not behave like RuleDelayed
Browse files Browse the repository at this point in the history
  • Loading branch information
mmatera committed Nov 15, 2022
1 parent 66de818 commit 2d37839
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 13 deletions.
11 changes: 9 additions & 2 deletions mathics/builtin/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ def create_rules(rules_expr, expr, name, evaluation, extra_args=[]):
else:
result = []
for rule in rules:
if rule.get_head_name() not in ("System`Rule", "System`RuleDelayed"):
head_name = rule.get_head_name()
if head_name not in ("System`Rule", "System`RuleDelayed"):
evaluation.message(name, "reps", rule)
return None, True
elif len(rule.elements) != 2:
Expand All @@ -186,7 +187,13 @@ def create_rules(rules_expr, expr, name, evaluation, extra_args=[]):
)
return None, True
else:
result.append(Rule(rule.elements[0], rule.elements[1]))
result.append(
Rule(
rule.elements[0],
rule.elements[1],
delayed=(head_name == "System`RuleDelayed"),
)
)
return result, False


Expand Down
16 changes: 9 additions & 7 deletions mathics/core/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,20 @@ class Rule(BaseRule):
``G[1.^2, a^2]``
"""

def __init__(self, pattern, replace, system=False) -> None:
def __init__(self, pattern, replace, delayed=True, system=False) -> None:
super(Rule, self).__init__(pattern, system=system)
self.replace = replace
self.delayed = delayed

def do_replace(self, expression, vars, options, evaluation):
replace = self.replace
while replace.has_form("System`Condition", 2):
replace, cond = replace.elements
cond = cond.replace_vars(vars)
cond = cond.evaluate(evaluation)
if cond is not SymbolTrue:
return None
if self.delayed:
while replace.has_form("System`Condition", 2):
replace, cond = replace.elements
cond = cond.replace_vars(vars)
cond = cond.evaluate(evaluation)
if cond is not SymbolTrue:
return None

new = replace.replace_vars(vars)
new.options = options
Expand Down
22 changes: 18 additions & 4 deletions test/builtin/test_patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,27 @@ def test_replace_all():

def test_rule_repl_cond():
for str_expr, str_expected, message in (
("f[x]/.(f[u_]->u^2/; u>3/; u>2)", "f[x]", "conditions are not evaluated"),
("f[4]/.(f[u_]->u^2/; u>3/; u>2)", "16", "both conditions are True"),
# For Rules, replacement is not evaluated
(
"f[2.5]/.(f[u_]->u^2/; u>3/; u>2)",
"f[x]/.(f[u_]->u^2/; u>3/; u>2)",
"x^2/; x>3/; x>2",
"conditions are not evaluated in Rule",
),
(
"f[4]/.(f[u_]->u^2/; u>3/; u>2)",
"16 /; 4 > 3 /; 4 > 2",
"still not evaluated, even if values are provided, due to the HoldAll attribute.",
),
# However, for delayed rules, the behavior is different:
# Conditions defines if the rule is applied
# and do not appears in the result.
("f[x]/.(f[u_]:>u^2/; u>3/; u>2)", "f[x]", "conditions are not evaluated"),
("f[4]/.(f[u_]:>u^2/; u>3/; u>2)", "16", "both conditions are True"),
(
"f[2.5]/.(f[u_]:>u^2/; u>3/; u>2)",
"f[2.5]",
"just the first condition is True",
),
("f[1.]/.(f[u_]->u^2/; u>3/; u>2)", "f[1.]", "Both conditions are False"),
("f[1.]/.(f[u_]:>u^2/; u>3/; u>2)", "f[1.]", "Both conditions are False"),
):
check_evaluation(str_expr, str_expected, message)

0 comments on commit 2d37839

Please sign in to comment.