diff --git a/CHANGES.rst b/CHANGES.rst index 4156b4251..2f2b844f1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -62,7 +62,7 @@ API incompatibility * ``Matcher`` now requires an additional ``evaluation`` parameter * ``Romberg`` removed as an ``NIntegrate[]`` method. It is depcrecated in SciPy and is to be removed by SciPy 1.15. - +* `Definitions.get_ownvalue` now returns a `BaseElement` instead of a `BaseRule` object. Bugs ---- diff --git a/mathics/builtin/makeboxes.py b/mathics/builtin/makeboxes.py index 06733f516..9e713bef3 100644 --- a/mathics/builtin/makeboxes.py +++ b/mathics/builtin/makeboxes.py @@ -516,9 +516,7 @@ def format_operator(operator) -> Union[String, BaseElement]: encoding_rule = evaluation.definitions.get_ownvalue( "$CharacterEncoding" ) - encoding = ( - "UTF8" if encoding_rule is None else encoding_rule.replace.value - ) + encoding = "UTF8" if encoding_rule is None else encoding_rule.value op_str = ( operator.value if isinstance(operator, String) diff --git a/mathics/core/builtin.py b/mathics/core/builtin.py index 96bc141fd..faa88c880 100644 --- a/mathics/core/builtin.py +++ b/mathics/core/builtin.py @@ -262,7 +262,7 @@ def contribute(self, definitions: Definitions, is_pymodule=False): # Otherwise it'll be created in Global` when it's # used, so it won't work. if option not in definitions.builtin: - definitions.builtin[option] = Definition(name=name) + definitions.builtin[option] = Definition(name=option) # Check if the given options are actually supported by the # Builtin. If not, we might issue an "optx" error and diff --git a/mathics/core/definitions.py b/mathics/core/definitions.py index 732ea7910..d07107afd 100644 --- a/mathics/core/definitions.py +++ b/mathics/core/definitions.py @@ -219,7 +219,7 @@ def is_pattern_a_kind_of(pattern: BaseElement, pattern_name: str) -> bool: return None -def insert_rule(values: list, rule: BaseRule) -> None: +def insert_rule(values: List[BaseRule], rule: BaseRule) -> None: """ Add a new rule inside a list of values. Rules are sorted in a way that the first elements @@ -326,14 +326,14 @@ def __init__( if not self.add_rule(rule): print(f"{rule.pattern.expr} could not be associated with {self.name}") - def get_values_list(self, pos: str) -> list: + def get_values_list(self, pos: str) -> List[BaseRule]: """Return one of the value lists""" assert pos.isalpha() if pos == "messages": return self.messages return getattr(self, f"{pos}values") - def set_values_list(self, pos: str, rules: list) -> None: + def set_values_list(self, pos: str, rules: List[BaseRule]) -> None: """Set one of the value lists""" assert pos.isalpha() if pos == "messages": @@ -847,23 +847,23 @@ def get_attributes(self, name: str) -> int: """ return self.get_definition(name).attributes - def get_ownvalues(self, name: str) -> list: + def get_ownvalues(self, name: str) -> List[BaseRule]: """Return the list of ownvalues""" return self.get_definition(name).ownvalues - def get_downvalues(self, name: str) -> list: + def get_downvalues(self, name: str) -> List[BaseRule]: """Return the list of downvalues""" return self.get_definition(name).downvalues - def get_subvalues(self, name: str) -> list: + def get_subvalues(self, name: str) -> List[BaseRule]: """Return the list of subvalues""" return self.get_definition(name).subvalues - def get_upvalues(self, name: str) -> list: + def get_upvalues(self, name: str) -> List[BaseRule]: """Return the list of upvalues""" return self.get_definition(name).upvalues - def get_formats(self, name: str, format_name="") -> list: + def get_formats(self, name: str, format_name="") -> List[BaseRule]: """ Return a list of format rules associated with `name`. if `format_name` is given, looks to the rules associated @@ -874,11 +874,11 @@ def get_formats(self, name: str, format_name="") -> list: result.sort() return result - def get_nvalues(self, name: str) -> list: + def get_nvalues(self, name: str) -> List[BaseRule]: """Return the list of nvalues""" return self.get_definition(name).nvalues - def get_defaultvalues(self, name: str) -> list: + def get_defaultvalues(self, name: str) -> List[BaseRule]: """Return the list of defaultvalues""" return self.get_definition(name).defaultvalues @@ -1042,7 +1042,7 @@ def add_message(self, name: str, rule: BaseRule) -> None: self.mark_changed(definition) self.clear_definitions_cache(name) - def set_values(self, name: str, values, rules) -> None: + def set_values(self, name: str, values: str, rules: List[BaseRule]) -> None: """Set a list of rules associated with the Symbol `name`""" pos = valuesname(values) definition = self.get_user_definition(self.lookup_name(name)) @@ -1075,9 +1075,16 @@ def set_user_definitions(self, definitions: str) -> None: def get_ownvalue(self, name: str) -> BaseElement: """Get ownvalue associated with `name`""" - ownvalues = self.get_definition(self.lookup_name(name)).ownvalues - if ownvalues: - return ownvalues[0] + lookup_name = self.lookup_name(name) + ownvalues = self.get_definition(lookup_name).ownvalues + + for ownvalue in ownvalues: + if not isinstance(ownvalue.pattern.expr, Symbol): + continue + try: + return ownvalue.get_replace_value() + except ValueError: + continue raise ValueError # return None @@ -1108,20 +1115,15 @@ def get_config_value( self, name: str, default: Optional[int] = None ) -> Optional[int]: "Infinity -> None, otherwise returns integer." - value = self.get_definition(name).ownvalues - if value: - try: - value = value[0].replace - except AttributeError: - return None - if value.get_name() == "System`Infinity" or value.has_form( - "DirectedInfinity", 1 - ): - return None - - return int(value.get_int_value()) - - return default + try: + value = self.get_ownvalue(name) + except ValueError: + return default + if value.get_name() == "System`Infinity" or value.has_form( + "DirectedInfinity", 1 + ): + return None + return int(value.to_python()) # .get_int_value()) def set_config_value(self, name: str, new_value: int) -> None: """Set the (own)value of an integer variable""" diff --git a/mathics/core/element.py b/mathics/core/element.py index 7dc8c3211..1b4971bb3 100644 --- a/mathics/core/element.py +++ b/mathics/core/element.py @@ -416,7 +416,7 @@ def is_free(self, form, evaluation) -> bool: def is_inexact(self) -> bool: return self.get_precision() is not None - def sameQ(self, rhs: "BaseElement") -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" return id(self) == id(rhs) diff --git a/mathics/core/pattern.py b/mathics/core/pattern.py index 9ae9ab4df..7e44b2c71 100644 --- a/mathics/core/pattern.py +++ b/mathics/core/pattern.py @@ -16,7 +16,17 @@ from abc import ABC from itertools import chain -from typing import TYPE_CHECKING, Callable, Dict, Optional, Sequence, Tuple, Type, Union +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + Optional, + Sequence, + Tuple, + Type, + Union, + overload, +) from mathics.core.atoms import Integer from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_ORDERLESS @@ -314,11 +324,19 @@ def get_match_candidates_count( """Return the number of candidates that match with the pattern.""" return len(self.get_match_candidates(elements, pattern_context)) + @overload + def sameQ(self, other: "BasePattern") -> bool: + ... + + @overload def sameQ(self, other: BaseElement) -> bool: + ... + + def sameQ(self, other) -> bool: """Mathics SameQ""" - if not isinstance(other, BasePattern): - return False - return self.expr.sameQ(other.expr) + if isinstance(other, BasePattern): + return self.expr.sameQ(other.expr) + return self.expr.sameQ(other) class AtomPattern(BasePattern): diff --git a/mathics/core/rules.py b/mathics/core/rules.py index 7c5764d7b..568bb52df 100644 --- a/mathics/core/rules.py +++ b/mathics/core/rules.py @@ -197,6 +197,9 @@ def apply_function( ): raise NotImplementedError + def get_replace_value(self) -> BaseElement: + raise ValueError + def get_sort_key(self, pattern_sort=True) -> tuple: # FIXME: check if this makes sense: return tuple((self.system, self.pattern.get_sort_key(pattern_sort))) @@ -269,6 +272,10 @@ def apply_rule( return new + def get_replace_value(self) -> BaseElement: + """return the replace value""" + return self.replace + def __repr__(self) -> str: return " %s>" % (self.pattern, self.replace) diff --git a/mathics/doc/online.py b/mathics/doc/online.py index 4a28de5fc..666db58ef 100644 --- a/mathics/doc/online.py +++ b/mathics/doc/online.py @@ -20,8 +20,11 @@ def online_doc_string( # First look at user definitions: for rulemsg in ruleusage: - if rulemsg.pattern.expr.elements[1].__str__() == '"usage"': - usagetext = rulemsg.replace.value + if rulemsg.pattern.expr.get_elements()[1].__str__() == '"usage"': + # mypy complains about the plane conversion, but + # to_python() returns a string wrapped in quotes. + # So, let's get ride the quotes... + usagetext = rulemsg.get_replace_value().to_python(string_quotes=False) if not is_long_form and usagetext: return usagetext diff --git a/mathics/eval/assignments/assignment.py b/mathics/eval/assignments/assignment.py index d6beef206..f6875bc38 100644 --- a/mathics/eval/assignments/assignment.py +++ b/mathics/eval/assignments/assignment.py @@ -1101,12 +1101,13 @@ def eval_assign_part( if is_protected(name, defs): evaluation.message(self.get_name(), "wrsym", symbol) return False - rule = defs.get_ownvalue(name) - if rule is None: + try: + rule = defs.get_ownvalue(name) + except ValueError: evaluation.message(self.get_name(), "noval", symbol) return False indices = lhs.elements[1:] - return eval_Part([rule.replace], indices, evaluation, rhs) + return eval_Part([rule], indices, evaluation, rhs) def eval_assign_random_state( diff --git a/mathics/main.py b/mathics/main.py index 30749903d..ad03b7181 100755 --- a/mathics/main.py +++ b/mathics/main.py @@ -48,7 +48,7 @@ def get_srcdir(): def show_echo(query, evaluation): - echovar = evaluation.definitions.get_ownvalue("System`$Echo").replace + echovar = evaluation.definitions.get_ownvalue("System`$Echo") if not isinstance(echovar, Expression) or not echovar.has_form("List", None): return