Skip to content

Commit

Permalink
BuiltinRule -> FunctionApplyRule
Browse files Browse the repository at this point in the history
The name Builtin is vague, since there are things that are
"builtin" (like variables and symbols) that are not functions.

Furthermore, BuiltinRule handles functions added by Mathics3 modules.
  • Loading branch information
rocky committed Sep 16, 2024
1 parent ebdc6b9 commit 5adbdc1
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 34 deletions.
8 changes: 4 additions & 4 deletions mathics/builtin/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -240,19 +240,19 @@ 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:
evaluation.definitions = TraceBuiltins.definitions_copy

@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={}):
Expand Down
10 changes: 5 additions & 5 deletions mathics/core/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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)
Expand Down
55 changes: 32 additions & 23 deletions mathics/core/rules.py
Original file line number Diff line number Diff line change
@@ -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.
"""


Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -216,11 +223,10 @@ def __repr__(self) -> str:
return "<Rule: %s -> %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
Expand All @@ -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
Expand All @@ -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::
Expand All @@ -256,6 +262,7 @@ class BuiltinRule(BaseRule):
This will cause `Expression.evalate() to perform an additional
``rewrite_apply_eval()`` step.
"""

def __init__(
Expand All @@ -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
Expand All @@ -293,7 +302,7 @@ def apply_function(
return self.function(evaluation=evaluation, **vars_noctx)

def __repr__(self) -> str:
return "<BuiltinRule: %s -> %s>" % (self.pattern, self.function)
return "<FunctionApplyRule: %s -> %s>" % (self.pattern, self.function)

def __getstate__(self):
odict = self.__dict__.copy()
Expand Down
4 changes: 2 additions & 2 deletions mathics/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 5adbdc1

Please sign in to comment.