Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions mathics/builtin/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@
from mathics.core.symbols import Symbol, SymbolNull
from mathics.core.systemsymbols import (
SymbolClearAttributes,
SymbolFailed,
SymbolProtected,
SymbolSetAttributes,
)
from mathics.eval.attributes import (
eval_Attributes,
eval_ClearAttributes,
eval_SetAttributes,
eval_SetOperator_Attributes,
eval_Unset_Attributes,
)

# This tells documentation how to sort this module
Expand Down Expand Up @@ -66,7 +69,7 @@ class Attributes(Builtin):

'Attributes' does not evaluate over expressions:
>> Attributes[a + b + c]
: Argument a + b + c at position 1 is expected to be a symbol.
: Symbol, string, HoldPattern[symbol] or a List of them is expected at position 1 in Attributes[a + b + c].
= Attributes[a + b + c]

You can assign values to 'Attributes' to set attributes:
Expand All @@ -77,34 +80,54 @@ class Attributes(Builtin):
= f[a, b, c]
Attributes must be symbols:
>> Attributes[f] := {a + b}
: Argument a + b at position 1 is expected to be a symbol.
: a + b is not a known attribute.
= $Failed
Use 'Symbol' to convert strings to symbols:
>> Attributes[f] = Symbol["Listable"]
= Listable
>> Attributes[f]
= {Listable}
In the LHS, 'Attributes' accepts a 'String' as its argument,
if the symbol already exists in the context:
>> Attributes["undefinedsymbol"] := Orderless
: Symbol undefinedsymbol not found.
= $Failed
On the other hand, if the symbol already exists,
>> Attributes["f"] := Orderless; Attributes[f]
= {Orderless}

Attributes can be eliminated using the unset operator:
>> Attributes[f] = .
>> Attributes[f]
= {}
"""

attributes = A_HOLD_ALL | A_LISTABLE | A_PROTECTED
eval_error = Builtin.generic_argument_error
expected_args = 1
messages = {
"attnf": "`1` is not a known attribute.",
"fnsym": "First argument in Attributes[`1`] is not a symbol or a string naming a symbol.",
"notfound": "Symbol `1` not found.",
"ssle": "Symbol, string, HoldPattern[symbol] or a List of them is expected at position 1 in Attributes[`1`].",
"locked": "Symbol `1` is locked.",
"tag": "Rule for Attributes of Attributes[`1`] can only be attached to `1`.",
}
summary_text = "find the attributes of a symbol"

def eval(self, expr, evaluation):
"Attributes[expr_]"
evaluation.message("Attributes", "sym", expr, 1)
evaluation.message("Attributes", "ssle", expr, 1)
return None

def eval_symbol(self, expr, evaluation):
"Attributes[expr_Symbol]"
return eval_Attributes(expr, evaluation)

def eval_holdpattern(self, expr, evaluation):
"Attributes[HoldPattern[expr_Symbol]]"
return eval_Attributes(expr, evaluation)

def eval_string(self, expr, evaluation):
"Attributes[expr_String]"
try:
Expand All @@ -120,6 +143,32 @@ def eval_list(self, expr, evaluation):
*(self.eval_list(elem, evaluation) for elem in expr.elements)
)

def eval_set(self, operator, symb, rhs, evaluation):
"operator:(Set|UpSet)[Attributes[symb_],rhs_]"
return eval_SetOperator_Attributes(symb, rhs, False, evaluation)

def eval_set_delayed(self, operator, symb, rhs, evaluation):
"operator:(SetDelayed|UpSetDelayed)[Attributes[symb_],rhs_]"
return eval_SetOperator_Attributes(symb, rhs, True, evaluation)

def eval_tagset(self, operator, tag, symb, rhs, evaluation):
"operator:TagSet[tag_Symbol, Attributes[symb_], rhs_]"
if tag is not symb:
evaluation.message("Attributes", "tag", symb)
return SymbolFailed
return eval_SetOperator_Attributes(symb, rhs, False, evaluation)

def eval_tagset_delayed(self, operator, tag, symb, rhs, evaluation):
"operator:TagSetDelayed[tag_Symbol, Attributes[symb_], rhs_]"
if tag is not symb:
evaluation.message("Attributes", "tag", symb)
return SymbolFailed
return eval_SetOperator_Attributes(symb, rhs, True, evaluation)

def eval_unset(self, expr, evaluation):
"Unset[Attributes[expr_]]"
return eval_Unset_Attributes(expr, evaluation)


class ClearAttributes(Builtin):
"""
Expand Down
7 changes: 4 additions & 3 deletions mathics/core/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ def get_symbol_list(
Otherwise, error_callback is called with the wrong argument
as a parameter.



Parameters
----------
expr : Expression
Expand Down Expand Up @@ -81,7 +79,10 @@ def get_symbol_list(
for item in list_expr:
if isinstance(item, String):
name = valid_name(item.value)
if name is not None:
if name is None:
if stop_on_failure:
return None
else:
values.append(name)
elif isinstance(item, Symbol):
values.append(item.get_name())
Expand Down
86 changes: 0 additions & 86 deletions mathics/eval/assignments/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from mathics.core.assignment import is_protected, rejected_because_protected, unwrap_lhs
from mathics.core.atoms import Integer, Integer1
from mathics.core.attributes import A_LOCKED
from mathics.core.definitions import BOX_FORMS
from mathics.core.element import BaseElement, EvalMixin
from mathics.core.evaluation import (
Expand Down Expand Up @@ -47,7 +46,6 @@
SymbolPatternTest,
SymbolVerbatim,
)
from mathics.eval.attributes import attributes_to_bitcode
from mathics.eval.list.eol import eval_Part

# Head Symbols of expressions that may need unwrapping in an assignment.
Expand Down Expand Up @@ -155,89 +153,6 @@ def eval_assign(
return False


def eval_assign_attributes(
op_name: str,
lhs: BaseElement,
lhs_unwrapped: BaseElement,
rhs: BaseElement,
evaluation: Evaluation,
target_symbol_names: list[str],
upset: bool,
) -> bool:
"""
Process the case where lhs is of the form
`Attribute[symbol]`

Parameters
----------
op_name : str
The built-in assignment operator name.
lhs : BaseElement
The pattern of the rule to be assigned.
lhs_unwrapped : BaseElement
The head of the expression after BLANK_PATTERN_HEADS
expressions have been are removed by unwrapping.
rhs : BaseElement
the expression representing the replacement.
evaluation : Evaluation
DESCRIPTION.
target_symbol_names : list[str]
the list of symbol names to be associated with the rule.
upset : bool
`True` if the rule is an Up value.

Raises
------
AssignmentException

Returns
-------
bool
True if the assignment was successful.

"""
# UpSet and Target_symbol_nameset for this symbol are handled in
# the standard way. The same if the expression is wrapped:
if lhs.get_head() is not lhs_unwrapped:
return eval_assign_store_rules_by_tag(
op_name, lhs, lhs_unwrapped, rhs, evaluation
)

name = lhs_unwrapped.get_head_name()
if len(lhs.elements) != 1:
evaluation.message_args(name, len(lhs.elements), 1)
raise AssignmentException(lhs, rhs)

target_symbol = unwrap_expression(lhs.elements[0])
tag = target_symbol.get_symbol_definition_name()
if not tag:
evaluation.message(op_name, "sym", lhs.elements[0], 1)
raise AssignmentException(lhs, rhs)
if target_symbol_names is not None and target_symbol_names != [tag]:
evaluation.message(op_name, "tag", Symbol(name), Symbol(tag))
raise AssignmentException(lhs, rhs)

attributes: Optional[int] = attributes_to_bitcode(
rhs, lambda item: evaluation.message(op_name, "sym", item, 1)
)
# If one of the attributes in the RHS is wrong, the assignment fails.
# Notice that this is different to what happens with SetAttributes.
if attributes is None:
raise AssignmentException(lhs, rhs)

defs = evaluation.definitions
definition = defs.get_definition(tag)
if A_LOCKED & definition.attributes:
evaluation.message(op_name, "locked", Symbol(tag))
raise AssignmentException(lhs, rhs)

definition.attributes = attributes
defs.mark_changed(definition)
defs.clear_definitions_cache(tag)

return True


def eval_assign_boxforms(
op_name: str, lhs: BaseElement, rhs: BaseElement, evaluation: Evaluation
) -> bool:
Expand Down Expand Up @@ -1714,7 +1629,6 @@ def get_symbol_definition_name(expr) -> Optional[str]:

# Below is a mapping from Symbol name (as a string) into an assignment eval function.
ASSIGNMENT_FUNCTION_MAP = {
"System`Attributes": eval_assign_attributes,
"System`Default": eval_assign_default,
"System`DefaultValues": eval_assign_definition_values,
"System`DownValues": eval_assign_definition_values,
Expand Down
Loading
Loading