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
16 changes: 10 additions & 6 deletions mathics/builtin/list/constructing.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,12 +566,16 @@ class Table(IterationFunction):
summary_text = "make a table of values of an expression"

def get_result(self, elements, is_uniform=False) -> ListExpression:
return ListExpression(
*elements,
elements_properties=ElementsProperties(
elements_fully_evaluated=True, is_uniform=is_uniform
),
)
# The elements have just been evaluated, but that does not make them
# "fully evaluated": that would keep the list from ever being evaluated
# again, so that in
# l = Table[x, {1}]; x = 1; l
# l would stay {x}. Only a list of literal elements, like a list of
# numbers, is fully evaluated, and that is settled here, at creation.
result = ListExpression(*elements)
if result.is_literal:
result._build_elements_properties()
return result


class Tuples(Builtin):
Expand Down
9 changes: 7 additions & 2 deletions mathics/core/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,13 @@ def _build_elements_properties(self):
element._build_elements_properties()

# and now possibly adjust self.elements_properties.elements_fully_evaluted
# A literal element (e.g. {}, which Map over an empty list
# gives with pessimistic properties) is fully evaluated
# whatever its own properties say.
if self.elements_properties.elements_fully_evaluated:
self.elements_properties.elements_fully_evaluated = (
element.elements_properties.elements_fully_evaluated
element.is_literal
or element.elements_properties.elements_fully_evaluated
)

if element.is_literal:
Expand Down Expand Up @@ -2149,7 +2153,8 @@ def convert_expression_elements(

if elements_properties.elements_fully_evaluated:
elements_properties.elements_fully_evaluated = (
converted_elt.elements_properties.elements_fully_evaluated
converted_elt.is_literal
or converted_elt.elements_properties.elements_fully_evaluated
)

if elements_properties.is_ordered and last_converted_elt is not None:
Expand Down
57 changes: 57 additions & 0 deletions test/builtin/list/test_constructing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
Unit tests for mathics.builtins.list.constructing
"""

from test.helper import check_evaluation

import pytest
Expand Down Expand Up @@ -72,3 +73,59 @@ def test_range(str_expr, str_expected, failure_message):
)
def test_table(str_expr, str_expected, failure_message):
check_evaluation(str_expr, str_expected, failure_message)


@pytest.mark.parametrize(
("str_expr", "str_expected", "failure_message"),
[
(None, None, None),
(
"ClearAll[l, x]; l = Table[x, {1}]; x = 1; l",
"{1}",
"A table sees a definition made after it.",
),
(
"ClearAll[l, f, y]; l = Table[f[y], {1}]; f[y_] := 7; l",
"{7}",
"A table sees a rule defined after it.",
),
(
"ClearAll[t, x]; t = Table[i + x, {i, 2}]; x = 1; t",
"{2, 3}",
None,
),
("{f /@ {}}", "{{}}", "A list of literals with pessimistic properties."),
("Table[f /@ {}, {2}]", "{{}, {}}", None),
("ClearAll[l, t, f, x, y]", "Null", None),
],
)
def test_table_is_evaluated_again(str_expr, str_expected, failure_message):
check_evaluation(str_expr, str_expected, failure_message)


def test_table_fully_evaluated_at_creation():
"""A table of literal elements, like a list of numbers, is known to be
fully evaluated as soon as Table builds it; a table with other elements
is not."""
from mathics.builtin.list.constructing import Table
from mathics.core.atoms import Integer1, Integer2
from mathics.core.expression import Expression
from mathics.core.list import ListExpression
from mathics.core.symbols import Symbol
from mathics.core.systemsymbols import SymbolTimes

numbers = Table.get_result(None, [Integer1, Integer2])
assert numbers.elements_properties is not None
assert numbers.elements_properties.elements_fully_evaluated

pairs = Table.get_result(
None, [ListExpression(Integer1, Integer2), ListExpression(Integer2, Integer1)]
)
assert pairs.elements_properties.elements_fully_evaluated

x = Symbol("Global`x")
symbolic = Table.get_result(None, [x, Expression(SymbolTimes, Integer2, x)])
assert not (
symbolic.elements_properties
and symbolic.elements_properties.elements_fully_evaluated
)
Loading