diff --git a/mathics/builtin/trace.py b/mathics/builtin/trace.py index eb5968045..517e7ba03 100644 --- a/mathics/builtin/trace.py +++ b/mathics/builtin/trace.py @@ -29,7 +29,7 @@ from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression -from mathics.core.rules import BuiltinRule +from mathics.core.rules import FunctionApplyRule from mathics.core.symbols import SymbolFalse, SymbolNull, SymbolTrue, strip_context @@ -240,11 +240,11 @@ def sort_by_name(tup: tuple): @staticmethod def enable_trace(evaluation) -> None: if TraceBuiltins.traced_definitions is None: - TraceBuiltins.apply_function_copy = BuiltinRule.apply_function + TraceBuiltins.apply_function_copy = FunctionApplyRule.apply_function TraceBuiltins.definitions_copy = evaluation.definitions # Replaces apply_function by the custom one - BuiltinRule.apply_function = traced_apply_function + FunctionApplyRule.apply_function = traced_apply_function # Create new definitions uses the new apply_function evaluation.definitions = Definitions(add_builtin=True) else: @@ -252,7 +252,7 @@ def enable_trace(evaluation) -> None: @staticmethod def disable_trace(evaluation) -> None: - BuiltinRule.apply_function = TraceBuiltins.apply_function_copy + FunctionApplyRule.apply_function = TraceBuiltins.apply_function_copy evaluation.definitions = TraceBuiltins.definitions_copy def eval(self, expr, evaluation, options={}): diff --git a/mathics/core/builtin.py b/mathics/core/builtin.py index f287a5fac..2a7c0cf46 100644 --- a/mathics/core/builtin.py +++ b/mathics/core/builtin.py @@ -55,7 +55,7 @@ from mathics.core.number import PrecisionValueError, dps, get_precision, min_prec from mathics.core.parser.util import PyMathicsDefinitions, SystemDefinitions from mathics.core.pattern import Pattern -from mathics.core.rules import BuiltinRule, Rule +from mathics.core.rules import FunctionApplyRule, Rule from mathics.core.symbols import ( BaseElement, BooleanType, @@ -121,7 +121,7 @@ def eval(x, evaluation): return Expression(Symbol("G"), x*2) ``` - adds a ``BuiltinRule`` to the symbol's definition object that implements + adds a ``FunctionApplyRule`` to the symbol's definition object that implements ``F[x_]->G[x*2]``. As shown in the example above, leading argument names of the @@ -269,11 +269,11 @@ def contribute(self, definitions, is_pymodule=False): prefix="eval", is_pymodule=is_pymodule ): rules.append( - BuiltinRule(name, pattern, function, check_options, system=True) + FunctionApplyRule(name, pattern, function, check_options, system=True) ) for pattern, function in self.get_functions(is_pymodule=is_pymodule): rules.append( - BuiltinRule(name, pattern, function, check_options, system=True) + FunctionApplyRule(name, pattern, function, check_options, system=True) ) for pattern_str, replace_str in self.rules.items(): pattern_str = pattern_str % {"name": name} @@ -325,7 +325,7 @@ def contextify_form_name(f): if form not in formatvalues: formatvalues[form] = [] formatvalues[form].append( - BuiltinRule(name, pattern, function, None, system=True) + FunctionApplyRule(name, pattern, function, None, system=True) ) for pattern, replace in self.formats.items(): forms, pattern = extract_forms(pattern) diff --git a/mathics/core/rules.py b/mathics/core/rules.py index 6823f29b1..4285b72c6 100644 --- a/mathics/core/rules.py +++ b/mathics/core/rules.py @@ -1,11 +1,15 @@ # -*- coding: utf-8 -*- """Rules are a core part of the way WMA and Mathics3 executes a -program. Expressions can be transformed by rewrite rules (AKA -transformation rules); builtin functions get matched and applied via a -function signature specified using a BuiltinRule. +program. -This module contains the classes for these two types of rules. +Expressions which are transformed by rewrite rules (AKA transformation +rules) are handed by the Rule class. + +There are also rules for how to match, assign parameter arguments, and +apply Mathics3 functions that are implemented in Python code. The +FunctionApplyRule class handles this. +This module contains the classes for these two types of rules. """ @@ -38,16 +42,15 @@ class StopGenerator_BaseRule(StopGenerator): class BaseRule(KeyComparable, ABC): - """ - This is the base class from which BuiltinRule and Rule classes - are derived from. + """This is the base class from which the FunctionApplyRule and + Rule classes are derived from. Rules are part of the rewriting system of Mathics3. See https://en.wikipedia.org/wiki/Rewriting - This class is not complete in of itself and subclasses should - adapt or fill in what is needed. In particular either ``apply_rule()`` - or ``apply_function()`` need to be implemented. + This class is not complete in of itself; subclasses must adapt or + fill in what is needed. In particular either ``apply_rule()`` or + ``apply_function()`` need to be implemented. Note: we want Rules to be serializable so that we can dump and restore Rules in order to make startup time faster. @@ -89,7 +92,7 @@ def yield_match(vars, rest): del vars[name] apply_fn = ( self.apply_function - if isinstance(self, BuiltinRule) + if isinstance(self, FunctionApplyRule) else self.apply_rule ) new_expression = apply_fn(expression, vars, options, evaluation) @@ -137,10 +140,14 @@ def yield_match(vars, rest): else: return None - def apply_rule(self): + def apply_rule( + self, expression: BaseElement, vars: dict, options: dict, evaluation: Evaluation + ): raise NotImplementedError - def apply_function(self): + def apply_function( + self, expression: BaseElement, vars: dict, options: dict, evaluation: Evaluation + ): raise NotImplementedError def get_sort_key(self) -> tuple: @@ -216,11 +223,10 @@ def __repr__(self) -> str: return " %s>" % (self.pattern, self.replace) -# FIXME: the class name would be better called FunctionCallRule. -class BuiltinRule(BaseRule): - """ - A BuiltinRule is a rule that has a replacement term that is associated - a Python function rather than a Mathics Expression as happens in a Rule. +class FunctionApplyRule(BaseRule): + """A FunctionApplyRule is a rule that has a replacement term that + is associated a Python function rather than a Mathics Expression + as happens in a transformation Rule. Each time the Pattern part of the Rule matches an Expression, the matching subexpression is replaced by the expression returned @@ -229,7 +235,7 @@ class BuiltinRule(BaseRule): Parameters for the function are bound to parameters matched by the pattern. Here is an example taken from the symbol ``System`Plus``. - It has has associated a BuiltinRule:: + It has has associated a FunctionApplyRule:: Plus[items___] -> mathics.builtin.arithfns.basic.Plus.apply @@ -242,8 +248,8 @@ class BuiltinRule(BaseRule): The return value of this function is ``Times[2, a]`` (or more compactly: ``2*a``). When replaced in the original expression, the result is: ``F[2*a]``. - In contrast to Rule, BuiltinRules can change the state of definitions - in the the system. + In contrast to (transformation) Rules, FunctionApplyRules can + change the state of definitions in the the system. For example, the rule:: @@ -256,6 +262,7 @@ class BuiltinRule(BaseRule): This will cause `Expression.evalate() to perform an additional ``rewrite_apply_eval()`` step. + """ def __init__( @@ -267,7 +274,9 @@ def __init__( system: bool = False, evaluation: Optional[Evaluation] = None, ) -> None: - super(BuiltinRule, self).__init__(pattern, system=system, evaluation=evaluation) + super(FunctionApplyRule, self).__init__( + pattern, system=system, evaluation=evaluation + ) self.name = name self.function = function self.check_options = check_options @@ -293,7 +302,7 @@ def apply_function( return self.function(evaluation=evaluation, **vars_noctx) def __repr__(self) -> str: - return " %s>" % (self.pattern, self.function) + return " %s>" % (self.pattern, self.function) def __getstate__(self): odict = self.__dict__.copy() diff --git a/mathics/main.py b/mathics/main.py index 3e6270b4c..3dcfc8069 100755 --- a/mathics/main.py +++ b/mathics/main.py @@ -27,7 +27,7 @@ from mathics.core.load_builtin import import_and_load_builtins from mathics.core.parser import MathicsFileLineFeeder, MathicsLineFeeder from mathics.core.read import channel_to_stream -from mathics.core.rules import BuiltinRule +from mathics.core.rules import FunctionApplyRule from mathics.core.streams import stream_manager from mathics.core.symbols import SymbolNull, strip_context from mathics.eval.files_io.files import set_input_var @@ -385,7 +385,7 @@ def main() -> int: extension_modules = default_pymathics_modules if args.trace_builtins: - BuiltinRule.apply_rule = traced_apply_function + FunctionApplyRule.apply_rule = traced_apply_function def dump_tracing_stats(): TraceBuiltins.dump_tracing_stats(sort_by="count", evaluation=None)