Skip to content

Commit 39344db

Browse files
committed
Add pop with argument
1 parent 0072610 commit 39344db

11 files changed

+190
-61
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ RUN(NAME test_list_section LABELS cpython llvm c)
378378
RUN(NAME test_list_count LABELS cpython llvm)
379379
RUN(NAME test_list_index LABELS cpython llvm)
380380
RUN(NAME test_list_reverse LABELS cpython llvm)
381+
RUN(NAME test_list_pop LABELS cpython llvm)
381382
RUN(NAME test_tuple_01 LABELS cpython llvm c)
382383
RUN(NAME test_tuple_02 LABELS cpython llvm c)
383384
RUN(NAME test_tuple_03 LABELS cpython llvm c)

integration_tests/test_list_pop.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from lpython import i32, f64
2+
3+
def test_list_pop():
4+
l1: list[i32]
5+
l2: list[tuple[i32, f64]]
6+
l3: list[list[str]]
7+
i: i32
8+
j: i32
9+
total: i32
10+
x: tuple[i32, f64]
11+
12+
l1 = [1, 2, 3]
13+
assert l1.pop() == 3
14+
assert l1 == [1, 2]
15+
16+
l1 = []
17+
total = 10
18+
for i in range(total):
19+
l1.append(i)
20+
if i % 2 == 1:
21+
assert l1.pop() == i
22+
for i in range(total // 2):
23+
assert l1[i] == 2 * i
24+
25+
l2 = [(1, 2.0)]
26+
x = l2.pop()
27+
assert x == (1, 2.0)
28+
assert len(l2) == 0
29+
l2.append((2, 3.0))
30+
31+
l3 = []
32+
for i in range(total):
33+
l3.insert(0, ["a"])
34+
for j in range(len(l3)):
35+
l3[j] += ["a"]
36+
while len(l3) > 0:
37+
total = len(l3)
38+
assert len(l3.pop()) == total + 1
39+
assert len(l3) == 0
40+
41+
l1 = [0, 1, 2, 3, 4]
42+
assert l1.pop(3) == 3
43+
assert l1.pop(0) == 0
44+
assert l1.pop(len(l1) - 1) == 4
45+
assert l1 == [1, 2]
46+
47+
total = 10
48+
l1 = []
49+
for i in range(total):
50+
l1.append(i)
51+
j = 0
52+
for i in range(total):
53+
assert l1.pop(j - i) == i
54+
j += 1
55+
assert len(l1) == 0
56+
57+
l2 = [(1, 1.0), (2, 4.0)]
58+
x = l2.pop(0)
59+
# print(x) # incorrect
60+
# print(l2) # correct
61+
62+
test_list_pop()

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,7 +2015,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
20152015
list_api->reverse(plist, asr_el_type, *module);
20162016
}
20172017

2018-
void generate_ListPop(ASR::expr_t* m_arg) {
2018+
void generate_ListPop_0(ASR::expr_t* m_arg) {
20192019
ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg));
20202020
int64_t ptr_loads_copy = ptr_loads;
20212021
ptr_loads = 0;
@@ -2024,7 +2024,21 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
20242024

20252025
ptr_loads = !LLVM::is_llvm_struct(asr_el_type);
20262026
ptr_loads = ptr_loads_copy;
2027-
tmp = list_api->pop(plist, asr_el_type, *module);
2027+
tmp = list_api->pop_last(plist, asr_el_type, *module);
2028+
}
2029+
2030+
void generate_ListPop_1(ASR::expr_t* m_arg, ASR::expr_t* m_ele) {
2031+
ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg));
2032+
int64_t ptr_loads_copy = ptr_loads;
2033+
ptr_loads = 0;
2034+
this->visit_expr(*m_arg);
2035+
llvm::Value* plist = tmp;
2036+
2037+
ptr_loads = !LLVM::is_llvm_struct(asr_el_type);
2038+
this->visit_expr_wrapper(m_ele, true);
2039+
ptr_loads = ptr_loads_copy;
2040+
llvm::Value *pos = tmp;
2041+
tmp = list_api->pop_position(plist, pos, asr_el_type, *module);
20282042
}
20292043

20302044
void visit_IntrinsicFunction(const ASR::IntrinsicFunction_t& x) {
@@ -2049,7 +2063,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
20492063
break;
20502064
}
20512065
case ASRUtils::IntrinsicFunctions::ListPop: {
2052-
generate_ListPop(x.m_args[0]);
2066+
switch(x.m_overload_id) {
2067+
case 0:
2068+
generate_ListPop_0(x.m_args[0]);
2069+
break;
2070+
case 1:
2071+
generate_ListPop_1(x.m_args[0], x.m_args[1]);
2072+
break;
2073+
}
20532074
break;
20542075
}
20552076
case ASRUtils::IntrinsicFunctions::Exp: {

src/libasr/codegen/llvm_utils.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2902,7 +2902,7 @@ namespace LCompilers {
29022902
builder->CreateStore(end_point, end_point_ptr);
29032903
}
29042904

2905-
llvm::Value* LLVMList::pop(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module) {
2905+
llvm::Value* LLVMList::pop_last(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module) {
29062906
// If list is empty, output error
29072907

29082908
llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list);
@@ -2934,6 +2934,64 @@ namespace LCompilers {
29342934
return tmp;
29352935
}
29362936

2937+
llvm::Value* LLVMList::pop_position(llvm::Value* list, llvm::Value* pos,
2938+
ASR::ttype_t* list_type, llvm::Module& module) {
2939+
2940+
/* Equivalent in C++:
2941+
* while(end_point > pos) {
2942+
* tmp = pos + 1;
2943+
* list[pos] = list[tmp];
2944+
* pos = tmp;
2945+
* }
2946+
*/
2947+
2948+
llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list);
2949+
llvm::Value* end_point = LLVM::CreateLoad(*builder, end_point_ptr);
2950+
2951+
llvm::AllocaInst *pos_ptr = builder->CreateAlloca(
2952+
llvm::Type::getInt32Ty(context), nullptr);
2953+
LLVM::CreateStore(*builder, pos, pos_ptr);
2954+
llvm::Value* tmp = nullptr;
2955+
2956+
// Get element to return
2957+
llvm::Value* item = read_item(list, LLVM::CreateLoad(*builder, pos_ptr),
2958+
true, module, LLVM::is_llvm_struct(list_type));
2959+
2960+
llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head");
2961+
llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body");
2962+
llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end");
2963+
2964+
// head
2965+
llvm_utils->start_new_block(loophead);
2966+
{
2967+
llvm::Value *cond = builder->CreateICmpSGT(end_point,
2968+
LLVM::CreateLoad(*builder, pos_ptr));
2969+
builder->CreateCondBr(cond, loopbody, loopend);
2970+
}
2971+
2972+
// body
2973+
llvm_utils->start_new_block(loopbody);
2974+
{
2975+
tmp = builder->CreateAdd(
2976+
LLVM::CreateLoad(*builder, pos_ptr),
2977+
llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
2978+
write_item(list, LLVM::CreateLoad(*builder, pos_ptr),
2979+
read_item(list, tmp, false, module, false), false, module);
2980+
LLVM::CreateStore(*builder, tmp, pos_ptr);
2981+
}
2982+
builder->CreateBr(loophead);
2983+
2984+
// end
2985+
llvm_utils->start_new_block(loopend);
2986+
2987+
// Decrement end point by one
2988+
end_point = builder->CreateSub(end_point, llvm::ConstantInt::get(
2989+
context, llvm::APInt(32, 1)));
2990+
builder->CreateStore(end_point, end_point_ptr);
2991+
2992+
return item;
2993+
}
2994+
29372995
void LLVMList::list_clear(llvm::Value* list) {
29382996
llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list);
29392997
llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),

src/libasr/codegen/llvm_utils.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@ namespace LCompilers {
259259
void remove(llvm::Value* list, llvm::Value* item,
260260
ASR::ttype_t* item_type, llvm::Module& module);
261261

262-
llvm::Value* pop(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module);
262+
llvm::Value* pop_position(llvm::Value* list, llvm::Value* pos,
263+
ASR::ttype_t* list_type, llvm::Module& module);
264+
llvm::Value* pop_last(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module);
263265

264266
void list_clear(llvm::Value* list);
265267

src/libasr/pass/intrinsic_function_registry.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,11 +1050,20 @@ static inline ASR::asr_t* create_ListReverse(Allocator& al, const Location& loc,
10501050
namespace ListPop {
10511051

10521052
static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) {
1053-
ASRUtils::require_impl(x.n_args == 1, "Call to list.pop must have exactly one argument",
1053+
ASRUtils::require_impl(x.n_args <= 2, "Call to list.pop must have at most one argument",
10541054
x.base.base.loc, diagnostics);
10551055
ASRUtils::require_impl(ASR::is_a<ASR::List_t>(*ASRUtils::expr_type(x.m_args[0])),
10561056
"Argument to list.pop must be of list type",
10571057
x.base.base.loc, diagnostics);
1058+
switch(x.m_overload_id) {
1059+
case 0:
1060+
break;
1061+
case 1:
1062+
ASRUtils::require_impl(ASR::is_a<ASR::Integer_t>(*ASRUtils::expr_type(x.m_args[1])),
1063+
"Argument to list.pop must be an integer",
1064+
x.base.base.loc, diagnostics);
1065+
break;
1066+
}
10581067
ASRUtils::require_impl(ASRUtils::check_equal_type(x.m_type,
10591068
ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_args[0]))),
10601069
"Return type of list.pop must be of same type as list's element type",
@@ -1070,8 +1079,8 @@ static inline ASR::expr_t *eval_list_pop(Allocator &/*al*/,
10701079
static inline ASR::asr_t* create_ListPop(Allocator& al, const Location& loc,
10711080
Vec<ASR::expr_t*>& args,
10721081
const std::function<void (const std::string &, const Location &)> err) {
1073-
if (args.size() != 1) {
1074-
err("For now pop() takes no arguments", loc);
1082+
if (args.size() > 2) {
1083+
err("Call to list.pop must have at most one argument", loc);
10751084
}
10761085

10771086
ASR::expr_t* list_expr = args[0];
@@ -1085,9 +1094,10 @@ static inline ASR::asr_t* create_ListPop(Allocator& al, const Location& loc,
10851094
}
10861095
ASR::expr_t* compile_time_value = eval_list_pop(al, loc, arg_values);
10871096
ASR::ttype_t *to_type = list_type;
1097+
int64_t overload_id = (args.size() == 2);
10881098
return ASR::make_IntrinsicFunction_t(al, loc,
10891099
static_cast<int64_t>(ASRUtils::IntrinsicFunctions::ListPop),
1090-
args.p, args.size(), 0, to_type, compile_time_value);
1100+
args.p, args.size(), overload_id, to_type, compile_time_value);
10911101
}
10921102

10931103
} // namespace ListPop

src/lpython/semantics/python_attribute_eval.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -250,40 +250,6 @@ struct AttributeHandler {
250250
return make_ListInsert_t(al, loc, s, args[0], args[1]);
251251
}
252252

253-
// static ASR::asr_t* eval_list_pop(ASR::expr_t *s, Allocator &al, const Location &loc,
254-
// Vec<ASR::expr_t*> &args, diag::Diagnostics &diag) {
255-
// if (args.size() > 1) {
256-
// throw SemanticError("pop() takes atmost one argument",
257-
// loc);
258-
// }
259-
// ASR::expr_t *idx = nullptr;
260-
// ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc,
261-
// 4, nullptr, 0));
262-
// ASR::ttype_t *type = ASRUtils::expr_type(s);
263-
// ASR::ttype_t *list_type = ASR::down_cast<ASR::List_t>(type)->m_type;
264-
// if (args.size() == 1) {
265-
// ASR::ttype_t *pos_type = ASRUtils::expr_type(args[0]);
266-
// if (!ASRUtils::check_equal_type(pos_type, int_type)) {
267-
// std::string fnd = ASRUtils::type_to_str_python(pos_type);
268-
// std::string org = ASRUtils::type_to_str_python(int_type);
269-
// diag.add(diag::Diagnostic(
270-
// "Type mismatch in 'pop', List index should be of integer type",
271-
// diag::Level::Error, diag::Stage::Semantic, {
272-
// diag::Label("type mismatch (found: '" + fnd + "', expected: '" + org + "')",
273-
// {args[0]->base.loc})
274-
// })
275-
// );
276-
// throw SemanticAbort();
277-
// }
278-
// idx = args[0];
279-
// } else {
280-
// // default is last index
281-
// idx = (ASR::expr_t*)ASR::make_IntegerConstant_t(al, loc, -1, int_type);
282-
// }
283-
284-
// return make_ListPop_t(al, loc, s, idx, list_type, nullptr);
285-
// }
286-
287253
static ASR::asr_t* eval_list_clear(ASR::expr_t *s, Allocator &al,
288254
const Location &loc, Vec<ASR::expr_t*> &args, diag::Diagnostics & diag) {
289255
if (args.size() != 0) {

tests/reference/asr-list1-770ba33.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"infile_hash": "9d6b3f1a83a585d5a7a5e50ff5e1ddd15705fce268208d0cc2749514",
66
"outfile": null,
77
"outfile_hash": null,
8-
"stdout": null,
9-
"stdout_hash": null,
10-
"stderr": "asr-list1-770ba33.stderr",
11-
"stderr_hash": "d59edc7304ac9368ed52a7a950ae6ce6717980982b68bc42b6905e34",
12-
"returncode": 2
8+
"stdout": "asr-list1-770ba33.stdout",
9+
"stdout_hash": "2d641bce0649af3b66ee2caa317e5ae3660fb13a82ca1ecdbae59f86",
10+
"stderr": null,
11+
"stderr_hash": null,
12+
"returncode": 0
1313
}

tests/reference/asr-list1-770ba33.stdout

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,19 +323,22 @@
323323
)
324324
(=
325325
(Var 2 d)
326-
(ListPop
327-
(Var 2 a)
328-
(IntegerConstant -1 (Integer 4 []))
326+
(IntrinsicFunction
327+
ListPop
328+
[(Var 2 a)]
329+
0
329330
(Integer 4 [])
330331
()
331332
)
332333
()
333334
)
334335
(=
335336
(Var 2 d)
336-
(ListPop
337-
(Var 2 a)
338-
(IntegerConstant 2 (Integer 4 []))
337+
(IntrinsicFunction
338+
ListPop
339+
[(Var 2 a)
340+
(IntegerConstant 2 (Integer 4 []))]
341+
1
339342
(Integer 4 [])
340343
()
341344
)

tests/reference/asr-test_list3-5f4d2a8.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
"stdout": null,
99
"stdout_hash": null,
1010
"stderr": "asr-test_list3-5f4d2a8.stderr",
11-
"stderr_hash": "a169feded8f4cb003ec23fcd035fc095e50dde3937f4595ae0261d38",
12-
"returncode": 2
11+
"stderr_hash": "58b16800ceb54fe5e98678cf6804644236004e2e1028ef0816a59d71",
12+
"returncode": 1
1313
}
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
semantic error: For now pop() takes no arguments
2-
--> tests/errors/test_list3.py:5:9
3-
|
4-
5 | x = a.pop(2.2)
5-
| ^^^^^^^^^^
1+
ASR verify pass error: ASR verify: Argument to list.pop must be an integer
2+
Internal Compiler Error: Unhandled exception
3+
BFD: DWARF error: section .debug_info is larger than its filesize! (0x93ef57 vs 0x530ea0)
4+
Traceback (most recent call last):
5+
 Binary file "$DIR/src/bin/lpython", in _start()
6+
 Binary file "/lib/x86_64-linux-gnu/libc.so.6", in __libc_start_main()
7+
 File "$DIR/src/bin/lpython.cpp", line 1732, in ??
8+
return emit_asr(arg_file, lpython_pass_manager, runtime_library_dir,
9+
 File "$DIR/src/bin/lpython.cpp", line 230, in ??
10+
compiler_options, true, infile);
11+
LCompilersException: Verify failed

0 commit comments

Comments
 (0)