Skip to content

Commit

Permalink
Adding support for del d[...] for removing elements from dictionaries
Browse files Browse the repository at this point in the history
  • Loading branch information
hkaiser committed Apr 27, 2021
1 parent 48c7d69 commit 4e33ece
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 3 deletions.
3 changes: 3 additions & 0 deletions phylanx/ir/dictionary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ namespace phylanx { namespace ir {
std::size_t size() const;
bool empty() const;

bool has_key(
phylanx::execution_tree::primitive_argument_type const& key) const;

phylanx::execution_tree::primitive_argument_type& operator[](
phylanx::execution_tree::primitive_argument_type const& key);
phylanx::execution_tree::primitive_argument_type& operator[](
Expand Down
59 changes: 59 additions & 0 deletions phylanx/plugins/listops/delete_operation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) 2021 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

#include <phylanx/config.hpp>
#include <phylanx/execution_tree/primitives/base_primitive.hpp>
#include <phylanx/execution_tree/primitives/primitive_component_base.hpp>

#include <hpx/futures/future.hpp>

#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace phylanx { namespace execution_tree { namespace primitives {
/// \brief
/// \param
class delete_operation
: public primitive_component_base
, public std::enable_shared_from_this<delete_operation>
{
protected:
hpx::future<primitive_argument_type> eval(
primitive_arguments_type const& operands,
primitive_arguments_type const& args,
eval_context ctx) const override;

public:
static match_pattern_type const match_data;

delete_operation() = default;

delete_operation(primitive_arguments_type&& operands,
std::string const& name, std::string const& codename);

private:
primitive_argument_type delete_elements(
primitive_argument_type&& target,
primitive_argument_type&& index, eval_context ctx) const;

primitive_argument_type delete_from_dict(ir::dictionary&& target,
primitive_argument_type&& index, eval_context ctx) const;
primitive_argument_type delete_from_list(ir::range&& target,
primitive_argument_type&& index, eval_context ctx) const;
};

inline primitive create_delete_operation(hpx::id_type const& locality,
primitive_arguments_type&& operands, std::string const& name = "",
std::string const& codename = "")
{
return create_primitive_component(
locality, "delete", std::move(operands), name, codename);
}
}}} // namespace phylanx::execution_tree::primitives
3 changes: 2 additions & 1 deletion phylanx/plugins/listops/listops.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018 Hartmut Kaiser
// Copyright (c) 2018-20s21 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -8,6 +8,7 @@

#include <phylanx/plugins/listops/append_operation.hpp>
#include <phylanx/plugins/listops/car_cdr_operation.hpp>
#include <phylanx/plugins/listops/delete_operation.hpp>
#include <phylanx/plugins/listops/dictionary_operation.hpp>
#include <phylanx/plugins/listops/len_operation.hpp>
#include <phylanx/plugins/listops/make_list.hpp>
Expand Down
19 changes: 19 additions & 0 deletions python/phylanx/ast/physl.py
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,25 @@ def _Constant(self, node):
# everything that's not a string can be directly passed on
return '%s' % node.value

def _Delete(self, node):
"""class Delete(targets)
Represents a del statement.
`targets` is a list of nodes, such as Name, Attribute or Subscript nodes.
"""

if len(node.targets) > 1:
raise Exception("Phylanx does not support del operators with " + \
"more than one argument.")

if isinstance(node.targets[0], ast.Subscript):
target = self._apply_rule(node.targets[0].value)
index = self._apply_rule(node.targets[0].slice)
return ['delete', (target, index)]

return ''

def _Div(self, node):
"""Leaf node, returning raw string of the 'division' operation."""

Expand Down
6 changes: 6 additions & 0 deletions src/ir/dictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,12 @@ namespace phylanx { namespace ir {
return dict().empty();
}

bool dictionary::has_key(
phylanx::execution_tree::primitive_argument_type const& key) const
{
return dict().find(key) != dict().end();
}

phylanx::execution_tree::primitive_argument_type& dictionary::operator[](
phylanx::execution_tree::primitive_argument_type const& key)
{
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/listops/append_operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace phylanx { namespace execution_tree { namespace primitives
primitive_argument_type append_operation::handle_list_operands(
primitive_argument_type && op1, primitive_argument_type && rhs) const
{
ir::range lhs =
ir::range&& lhs =
extract_list_value_strict(std::move(op1), name_, codename_);

if (lhs.is_ref())
Expand Down
135 changes: 135 additions & 0 deletions src/plugins/listops/delete_operation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) 2021 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <phylanx/config.hpp>
#include <phylanx/ir/dictionary.hpp>
#include <phylanx/plugins/listops/delete_operation.hpp>
#include <phylanx/util/matrix_iterators.hpp>

#include <hpx/errors/throw_exception.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/util.hpp>

#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>

///////////////////////////////////////////////////////////////////////////////
namespace phylanx { namespace execution_tree { namespace primitives {

///////////////////////////////////////////////////////////////////////////
match_pattern_type const delete_operation::match_data = {
hpx::make_tuple("delete", std::vector<std::string>{"delete(_1, _2)"},
&create_delete_operation, &create_primitive<delete_operation>,
R"(target, index
Args:
target (list or dict) : the container to delete a value from
index (key or list) : the index (indices) of the element(s) to
remove from the dictionary or list
Returns:
A new list or dictionary with the element(s) removed. Note that
`target` is not modified by this operation.)")};

///////////////////////////////////////////////////////////////////////////
delete_operation::delete_operation(primitive_arguments_type&& operands,
std::string const& name, std::string const& codename)
: primitive_component_base(std::move(operands), name, codename)
{
}

///////////////////////////////////////////////////////////////////////////
primitive_argument_type delete_operation::delete_from_dict(
ir::dictionary&& target, primitive_argument_type&& index,
eval_context ctx) const
{
if (!target.has_key(index))
{
HPX_THROW_EXCEPTION(hpx::bad_parameter,
"delete_operation::delete_from_dict",
generate_error_message(
"attempting to delete a non-existing dictionary entry",
ctx));
}

target.dict().erase(index);
return primitive_argument_type{std::move(target)};
}

primitive_argument_type delete_operation::delete_from_list(
ir::range&& target, primitive_argument_type&& index,
eval_context ctx) const
{
HPX_THROW_EXCEPTION(hpx::bad_parameter,
"delete_operation::delete_from_list",
generate_error_message(
"deleting an entry from list is not supported yet", ctx));
}

primitive_argument_type delete_operation::delete_elements(
primitive_argument_type&& target, primitive_argument_type&& index,
eval_context ctx) const
{
if (is_dictionary_operand_strict(target))
{
return delete_from_dict(extract_dictionary_value_strict(
std::move(target), name_, codename_),
std::move(index), std::move(ctx));
}

if (is_list_operand_strict(target))
{
return delete_from_list(
extract_list_value_strict(std::move(target), name_, codename_),
std::move(index), std::move(ctx));
}

HPX_THROW_EXCEPTION(hpx::bad_parameter,
"delete_operation::delete_elements",
generate_error_message("the delete_operation supports removing "
"elements from lists and dictionaries only",
ctx));
}

//////////////////////////////////////////////////////////////////////////
hpx::future<primitive_argument_type> delete_operation::eval(
primitive_arguments_type const& operands,
primitive_arguments_type const& args, eval_context ctx) const
{
if (operands.size() != 2)
{
HPX_THROW_EXCEPTION(hpx::bad_parameter, "delete_operation::eval",
generate_error_message(
"the delete_operation primitive requires two arguments",
ctx));
}

if (!valid(operands[0]) || !valid(operands[1]))
{
HPX_THROW_EXCEPTION(hpx::bad_parameter, "delete_operation::eval",
generate_error_message(
"the delete_operation primitive requires that the "
"argument given by the operand are valid",
ctx));
}

auto this_ = this->shared_from_this();
return hpx::dataflow(
hpx::launch::sync,
[this_ = std::move(this_), ctx = std::move(ctx)](
hpx::future<primitive_argument_type>&& arg0,
hpx::future<primitive_argument_type>&& arg1) mutable
-> primitive_argument_type {
return this_->delete_elements(
arg0.get(), arg1.get(), std::move(ctx));
},
value_operand(operands[0], args, name_, codename_, ctx),
value_operand(operands[1], args, name_, codename_, ctx));
}
}}} // namespace phylanx::execution_tree::primitives
4 changes: 3 additions & 1 deletion src/plugins/listops/listops.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018 Hartmut Kaiser
// Copyright (c) 2018-2021Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -13,6 +13,8 @@ PHYLANX_REGISTER_PLUGIN_MODULE();

PHYLANX_REGISTER_PLUGIN_FACTORY(append_operation_plugin,
phylanx::execution_tree::primitives::append_operation::match_data);
PHYLANX_REGISTER_PLUGIN_FACTORY(delete_operation_plugin,
phylanx::execution_tree::primitives::delete_operation::match_data);
PHYLANX_REGISTER_PLUGIN_FACTORY(dict_operation_plugin,
phylanx::execution_tree::primitives::dict_operation::match_data);
PHYLANX_REGISTER_PLUGIN_FACTORY(len_operation_plugin,
Expand Down
19 changes: 19 additions & 0 deletions tests/regressions/python/1315_del_operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2021 Steven R. Brandt
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

# 1315: Missing del operator for dictionaries

from phylanx import Phylanx


@Phylanx
def test():
a = {"a": 1, "b": 2, "c": 3}
del a["a"]
return a


result = test()
assert result == {"b": 2, "c": 3}, result
1 change: 1 addition & 0 deletions tests/regressions/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ set(tests
1303_iterate_over_array
1306_indexing
1312_matrix_iteration
1315_del_operator
array_len_494
array_shape_486
array_subscript_403
Expand Down

0 comments on commit 4e33ece

Please sign in to comment.