Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reversed(seq) #2644

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython)
RUN(NAME intrinsics_01 LABELS cpython llvm NOFAST) # any
RUN(NAME intrinsics_02 LABELS cpython llvm c) # floordiv
RUN(NAME test_builtin_type LABELS cpython llvm c) # type
RUN(NAME test_builtin_reversed LABELS llvm) # reversed

# lpython decorator
RUN(NAME lpython_decorator_01 LABELS cpython)
Expand Down
40 changes: 40 additions & 0 deletions integration_tests/test_builtin_reversed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from lpython import i32, f64


def test_builtin_reversed():
# list of strings
alphabets: list[str] = ["a", "b", "c", "d", "e"]

reversed_alphabets: list[str] = reversed(alphabets)
print(reversed_alphabets)
assert reversed_alphabets == ["e", "d", "c", "b", "a"]

# list of numbers
numbers: list[i32] = [1, 2, 3, 4, 5]

reversed_numbers: list[i32] = reversed(numbers)
print(reversed_numbers)
assert reversed_numbers == [5, 4, 3, 2, 1]

# list returned through function call
alphabet_dictionary: dict[str, i32] = {
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
reversed_keys: list[str] = reversed(alphabet_dictionary.keys())
print(reversed_keys)

assert reversed_keys == ["e", "d", "c", "b", "a"]

# list of another object
points: list[tuple[f64, f64]] = [(1.0, 0.0), (2.3, 5.9), (78.1, 23.2)]
reversed_points: list[tuple[f64, f64]] = reversed(points)
print(reversed_points)

assert reversed_points == [(78.1, 23.2), (2.3, 5.9), (1.0, 0.0)]


test_builtin_reversed()
10 changes: 8 additions & 2 deletions src/libasr/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
tmp = builder->CreateFSub(exp, one);
}

void generate_ListReverse(ASR::expr_t* m_arg) {
void generate_ListReverse(ASR::expr_t* m_arg, bool is_intrinsic_function) {
ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg));
int64_t ptr_loads_copy = ptr_loads;
ptr_loads = 0;
Expand All @@ -1802,6 +1802,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
ptr_loads = !LLVM::is_llvm_struct(asr_el_type);
ptr_loads = ptr_loads_copy;
list_api->reverse(plist, *module);

if (is_intrinsic_function) tmp = plist;
}

void generate_ListPop_0(ASR::expr_t* m_arg) {
Expand Down Expand Up @@ -1954,8 +1956,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
generate_ListIndex(m_arg, m_ele, m_start, m_end);
break ;
}
case ASRUtils::IntrinsicElementalFunctions::Reversed: {
generate_ListReverse(x.m_args[0], true);
break;
}
case ASRUtils::IntrinsicElementalFunctions::ListReverse: {
generate_ListReverse(x.m_args[0]);
generate_ListReverse(x.m_args[0], false);
break;
}
case ASRUtils::IntrinsicElementalFunctions::ListPop: {
Expand Down
6 changes: 6 additions & 0 deletions src/libasr/pass/intrinsic_function_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace ASRUtils {
inline std::string get_intrinsic_name(int x) {
switch (x) {
INTRINSIC_NAME_CASE(ObjectType)
INTRINSIC_NAME_CASE(Reversed)
INTRINSIC_NAME_CASE(Kind)
INTRINSIC_NAME_CASE(Rank)
INTRINSIC_NAME_CASE(Sin)
Expand Down Expand Up @@ -172,6 +173,8 @@ namespace IntrinsicElementalFunctionRegistry {
verify_function>>& intrinsic_function_by_id_db = {
{static_cast<int64_t>(IntrinsicElementalFunctions::ObjectType),
{nullptr, &ObjectType::verify_args}},
{static_cast<int64_t>(IntrinsicElementalFunctions::Reversed),
{nullptr, &Reversed::verify_args}},
{static_cast<int64_t>(IntrinsicElementalFunctions::Gamma),
{&Gamma::instantiate_Gamma, &UnaryIntrinsicFunction::verify_args}},
{static_cast<int64_t>(IntrinsicElementalFunctions::Log10),
Expand Down Expand Up @@ -459,6 +462,8 @@ namespace IntrinsicElementalFunctionRegistry {
static const std::map<int64_t, std::string>& intrinsic_function_id_to_name = {
{static_cast<int64_t>(IntrinsicElementalFunctions::ObjectType),
"type"},
{static_cast<int64_t>(IntrinsicElementalFunctions::Reversed),
"reversed"},
{static_cast<int64_t>(IntrinsicElementalFunctions::Gamma),
"gamma"},
{static_cast<int64_t>(IntrinsicElementalFunctions::Log),
Expand Down Expand Up @@ -744,6 +749,7 @@ namespace IntrinsicElementalFunctionRegistry {
std::tuple<create_intrinsic_function,
eval_intrinsic_function>>& intrinsic_function_by_name_db = {
{"type", {&ObjectType::create_ObjectType, &ObjectType::eval_ObjectType}},
{"reversed", {&Reversed::create_Reversed, &Reversed::eval_Reversed}},
{"gamma", {&Gamma::create_Gamma, &Gamma::eval_Gamma}},
{"log", {&Log::create_Log, &Log::eval_Log}},
{"log10", {&Log10::create_Log10, &Log10::eval_Log10}},
Expand Down
42 changes: 42 additions & 0 deletions src/libasr/pass/intrinsic_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ the code size.

enum class IntrinsicElementalFunctions : int64_t {
ObjectType,
Reversed,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reversed returns an iterator, but does not actually reverse a list. I think we do not have support for iterators yet in LPython.

The approach in this PR reverses the entire list, which I think is not the correct approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Shaikh-Ubaid I return a reversed list using the approach used for dict.keys (#1881 (comment)) as we do not support iterators now.

Kind, // if kind is reordered, update `extract_kind` in `asr_utils.h`
Rank,
Sin,
Expand Down Expand Up @@ -568,6 +569,47 @@ namespace ObjectType {

} // namespace ObjectType

namespace Reversed {

static inline void verify_args(const ASR::IntrinsicElementalFunction_t& x, diag::Diagnostics& diagnostics) {
ASRUtils::require_impl(x.n_args == 1, "Call to reversed() must have atleast one argument",
x.base.base.loc, diagnostics);
ASR::ttype_t* arg_type = ASRUtils::expr_type(x.m_args[0]);
ASRUtils::require_impl(ASR::is_a<ASR::List_t>(*arg_type),
"Argument to reversed() must be of list type.",
x.base.base.loc, diagnostics);
}

static inline ASR::expr_t *eval_Reversed(Allocator &/*al*/,
const Location &/*loc*/, ASR::ttype_t */*t*/, Vec<ASR::expr_t*>& /*args*/, diag::Diagnostics& /*diag*/) {
// TODO: To be implemented for ListConstant expression
return nullptr;
}


static inline ASR::asr_t* create_Reversed(Allocator& al, const Location& loc,
Vec<ASR::expr_t*>& args,
diag::Diagnostics& diag) {
if (!ASR::is_a<ASR::List_t>(*ASRUtils::expr_type(args[0]))) {
append_error(diag,
"reversed() currently only accepts an object of type `list`", loc);
return nullptr;
}

Vec<ASR::expr_t*> arg_values;
arg_values.reserve(al, args.size());
for( size_t i = 0; i < args.size(); i++ ) {
arg_values.push_back(al, ASRUtils::expr_value(args[i]));
}
ASR::ttype_t *to_type = ASRUtils::expr_type(args[0]);
ASR::expr_t* compile_time_value = eval_Reversed(al, loc, to_type, arg_values, diag);
return ASR::make_IntrinsicElementalFunction_t(al, loc,
static_cast<int64_t>(IntrinsicElementalFunctions::Reversed),
args.p, args.n, 0, to_type, compile_time_value);
}

} // namespace Reversed

namespace Fix {
static inline ASR::expr_t *eval_Fix(Allocator &al, const Location &loc,
ASR::ttype_t *t, Vec<ASR::expr_t*>& args, diag::Diagnostics& /*diag*/) {
Expand Down
Loading