Skip to content

Commit 61e7b9c

Browse files
committed
More Python linting around Rules; document (weird) Rules Python code better.
1 parent 3d5001a commit 61e7b9c

4 files changed

Lines changed: 48 additions & 11 deletions

File tree

mathics/builtin/list/associations.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from mathics.eval.lists import list_boxes
2727

2828

29-
class Association(Builtin):
29+
class Association_(Builtin):
3030
"""
3131
<url>
3232
:WMA link:
@@ -57,10 +57,11 @@ class Association(Builtin):
5757
= {1, 3}
5858
"""
5959

60-
error_idx = 0
61-
6260
attributes = A_HOLD_ALL_COMPLETE | A_PROTECTED
6361

62+
error_idx = 0
63+
64+
name = "Association"
6465
summary_text = "make an association between keys and values"
6566

6667
def eval_makeboxes(self, rules, f, evaluation: Evaluation):

mathics/builtin/patterns/rules.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def eval_list(
140140
return result
141141

142142
def eval(
143-
self, rules: Expression, evaluation: Evaluation
143+
self, rules: BaseElement, evaluation: Evaluation
144144
) -> OptionalType[BaseElement]:
145145
"""Dispatch[rules_]"""
146146
if not isinstance(rules, Expression):
@@ -489,6 +489,8 @@ def eval_list(
489489
return result
490490

491491

492+
# rocky: I don't know why, but this class seems to need a lot of
493+
# things that handled differently from normal practice.
492494
class Rule_(InfixOperator):
493495
"""
494496
@@ -510,20 +512,39 @@ class Rule_(InfixOperator):
510512
"""
511513

512514
attributes = A_SEQUENCE_HOLD | A_PROTECTED
515+
516+
# For some mysterious reason, the below does not work and
517+
# we have to do argument checking as code in eval().
518+
# eval_error = Builtin.generic_argument_error
519+
# expected_args = 2
520+
513521
grouping = "Right"
514522
name = "Rule"
515523
needs_verbatim = True
516524

517-
# FIXME: if we remove this we have problems.
518-
# We should be able to get this from JSON.
525+
# FIXME: We should be able to get the operator from the JSON operator tables.
526+
# However, if we remove the operator class variable assignment, is we have problems.
527+
# Run test/format/test_format.py::test_makeboxes_text for details.
519528
operator = "->"
529+
520530
summary_text = "a replacement rule"
521531

522-
def eval_rule(self, elems, evaluation):
532+
def eval(self, elems, evaluation: Evaluation):
523533
"""Rule[elems___]"""
534+
524535
num_parms = len(elems.get_sequence())
525536
if num_parms != 2:
526537
evaluation.message("Rule", "argrx", "Rule", Integer(num_parms), Integer2)
538+
539+
# "Rule" is a somewhat generic term in WMA and thus Mathics3.
540+
# Rule semantics and its implementation change depending on the context that the Rule appears in.
541+
# Inside a Set, RuleDelayed, or ReplaceAll expression, the left-hand side of a Rule is a pattern.
542+
# But inside an Association or an Option, it is a key-value pair, with no pattern matching applied
543+
# to the left-hand side.
544+
# As a result, at this point we don't know which context Rule[] might appear, so we have to return
545+
# "None" which keeps the Expression the same. Returning "elems" which you might think would be the
546+
# same thing, is not correct, since the Head symbol "Rule" can get replaced with "Sequence" symbol
547+
# coming into this code.
527548
return None
528549

529550

mathics/core/pattern.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def create(
203203
Otherwise, if ``expr`` is an ``Atom``, create and return ``AtomPattern`` for ``expr``.
204204
Otherwise, create and return and ``ExpressionPattern`` for ``expr``.
205205
"""
206+
206207
name = expr.get_head_name()
207208
pattern_object = pattern_objects.get(name)
208209
if pattern_object is not None:

mathics/core/rules.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
arguments, and then apply a Python "evaluation" function to a Mathics3 Expression.
1010
These kinds of rules are handled by objects in the `FunctionApplyRule` class.
1111
12-
This module contains the classes for these two types of rules.
12+
Finally, Rules are used as KeyValue pairs in an Association or an Options list.
13+
Here, no pattern matching is applied to the left-hand side.
14+
15+
This module contains the classes for the first two non-KeyValue types of rules.
1316
1417
In a `FunctionApplyRule` rule, the match status of a rule depends on the evaluation return.
1518
@@ -236,13 +239,24 @@ def element_order(self) -> tuple:
236239
# True used to be self.system. Can we remove True?
237240
return tuple((True, self.pattern.element_order))
238241

242+
# The below routines might be needed in the future, if BaseRule becomes
243+
# more BaseElement-like. Right now that's not the situation, probably
244+
# due to the nature of the generality of Rule which causes
245+
# special casing lots of places in the Expression code.
246+
247+
# def get_head_name(self, short=False) -> str:
248+
# return "Rule" if short else "System`Rule"
249+
250+
# def get_lookup_name(self) -> str:
251+
# return "System`Rule"
252+
239253
def get_replace_value(self) -> BaseElement:
240254
raise ValueError
241255

242256
@property
243-
def lhs(self) -> BasePattern:
257+
def lhs(self) -> BasePattern | Expression:
244258
"""
245-
Lefthand side of a rule. Also known as its "pattern".
259+
Left-hand side of a rule. Also known, in this context, as its "pattern".
246260
"""
247261
return self.pattern
248262

@@ -351,7 +365,7 @@ def get_replace_value(self) -> BaseElement:
351365
"""return the replace value"""
352366
return self.replace
353367

354-
# This will probably be needed when we use with builtin Rule_
368+
# # This might be needed in the future.
355369
# @property
356370
# def is_literal(self):
357371
# """

0 commit comments

Comments
 (0)