Skip to content

Commit ab14558

Browse files
authored
Merge pull request #1085 from Shaikh-Ubaid/pass_print_list
PASS: print list
2 parents 2cd0648 + 268bda0 commit ab14558

12 files changed

+349
-1
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ RUN(NAME expr_10 LABELS cpython llvm)
166166
RUN(NAME expr_11 LABELS cpython llvm c wasm)
167167
RUN(NAME expr_12 LABELS llvm c)
168168
RUN(NAME loop_01 LABELS cpython llvm c)
169+
RUN(NAME print_02 LABELS cpython llvm)
169170
RUN(NAME test_types_01 LABELS cpython llvm)
170171
RUN(NAME test_str_01 LABELS cpython llvm)
171172
RUN(NAME test_str_02 LABELS cpython llvm)

integration_tests/print_02.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from ltypes import i32, f64
2+
3+
# Test: Printing ListConstant
4+
def f():
5+
a: list[str] = ["ab", "abc", "abcd"]
6+
b: list[i32] = [1, 2, 3, 4]
7+
c: list[f64] = [1.23 , 324.3 , 56.431, 90.5, 34.1]
8+
d: list[i32] = []
9+
10+
print(a)
11+
print(b)
12+
print(c)
13+
print(d)
14+
15+
# print list constant
16+
print([-3, 2, 1, 0])
17+
print(['a', 'b', 'c', 'd' , 'e', 'f'])
18+
19+
def test_nested_lists():
20+
w: list[list[list[list[list[f64]]]]] = [[[[[2.13, -98.17]]], [[[1.11]]]]]
21+
x: list[list[list[i32]]] = [[[3, -1], [-2, 5], [5]], [[-3, 1], [2, -5], [-5]]]
22+
y: list[list[f64]] = [[3.14, -1.0012], [-2.38, 5.51]]
23+
z: list[list[str]] = [["bat", "ball"], ["cat", "dog"], ["c", "c++", "java", "python"]]
24+
25+
print(w)
26+
print(x)
27+
print(y)
28+
print(z)
29+
30+
def test_nested_lists2():
31+
# It tests list printing on scale like lists of size (approx) 100.
32+
33+
# shape = (10, 10), values range from 0 to 99 (both inclusive)
34+
p: list[list[i32]] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], [70, 71, 72, 73, 74, 75, 76, 77, 78, 79], [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]]
35+
36+
# shape = (3, 3, 3, 3), values range between [-101.00, 101.00)
37+
q: list[list[list[list[f64]]]] = [[[[ 74.55, -77.64, 52.35],
38+
[ -78.25, -19.24, 81.38],
39+
[ 7.86, 12.11, 27.5 ]],
40+
41+
[[ -98.93, -79.62, -73.76],
42+
[ 42.05, -90.29, 69.95],
43+
[ 59.32, -70.78, -53.22]],
44+
45+
[[ 53.52, -93.88, 49.65],
46+
[ 2.18, 19.91, 69.24],
47+
[ 78.51, 89.69, -86.68]]],
48+
49+
50+
[[[ -92.48, -80.75, -27.76],
51+
[ -13.35, 12.28, 79.61],
52+
[ 48.48, -10.49, 41.1 ]],
53+
54+
[[ 20.33, 14.52, 82.56],
55+
[ -57.76, 76.03, 67.33],
56+
[ -21.5 , -11.92, -31.84]],
57+
58+
[[ 9.65, 11.15, -36.58],
59+
[ 56.55, -70.85, -50.67],
60+
[ 94.63, 25.68, 89.3 ]]],
61+
62+
63+
[[[ 28.53, 71.22, 71.87],
64+
[ -58.39, -6.96, 42.98],
65+
[ -8.95, -75.09, 37.96]],
66+
67+
[[ -31.75, 67.33, 58.17],
68+
[ -64.01, -9.22, 9.59],
69+
[ 15.71, 82.36, 51.18]],
70+
71+
[[-100.29, -32.72, -54.94],
72+
[ -0.32, 68.81, -55.09],
73+
[ 97.28, -28.2 , -62.61]]]]
74+
75+
# shape = (5, 5, 5), where each element is a string of random alphanumerals and length betweem 0 and 10
76+
r: list[list[list[str]]] = [[['Io', 'tl', 'bLvjV', 'wjFKQ', 'lY2'], ['Be2l6bqE', 'pQER3utIXA', 'llZBJj5Cdu', 'C8', 'gwTr77PdYR'], ['4M6L', 'ktPdowqERy', 'KSifqTkR', 'ZE2p1N78f1', 'Mi5e87Xw'], ['uwfzqDq9g', 'QaM1s', '', '', 'LB'], ['OJFRY6k', 'iz7Oie', '', 'LUYLF', 'JBND5FuV7l']], [['m', 'WIQBQfV', 'jxjDrqxu', 'kea', 'mu'], ['', 'GI8aOwLMe', 'Y5m8', 'a02Rz', 'xNKCJ'], ['LzkhyiJQHP', 'uzc3xyoXL', 'sKGnYfpRy', '7x', 'WTVKrnPO'], ['TZa6', 'GXRuyRX', 'R', 'JQxS', 'OH'], ['bSVJZ1OQ', 'M', 'I9omlF', 'x7FR', 'XtpL']], [['DKOpK', 'eg8Nz', 'ru', 'Sj', 'YUDxyI'], ['Q5uyhvp', 'Ydx', 'p', 'DLM5RX', 'pwOujxCO'], ['s5GOWnNJV', 'af', 'KAkD', '4IIZK', 'JQK040x'], ['9vF', '9pc7R8v', 'nDReIU7', 'K', 'btn'], ['', 'wVeivkdi', '', '', 'C']], [['vNTtcRXD', 'rsi', 'YsoF7mZD', 'VrPXU50rgA', 'mG7zqN0G'], ['la7cJ', 'M5rLJ8Go', 'gb', 'FjKwYZ7E', 'uSPD'], ['', 'oOa79jWcMx', 'yyAYZZ', 'wbvggXm', 'aE3BkCL4'], ['RdP', 'Hwc0x9RZ', 'sy', '9', 'W1d9xA2BXe'], ['A', '', 'QnK', 'N5tzN', 'ou7Lp']], [['DL68rDF', 'v', 'kQ3Mxm', 'g', '6KTeF4Eo'], ['Hx9', 'Y1IzQm85Z4', '3D8', 'ZLZ5', 'rWn'], ['LtT', 'Dh5B', 'M', 'F', 'QTARbY'], ['Sh', 'WL', 'yvAfWvZSx1', '90yx', 'v'], ['', '7IBW', 'nI', '', '6Cbp5c8RT']]]
77+
78+
print(p)
79+
print(q)
80+
print(r)
81+
82+
f()
83+
test_nested_lists()
84+
test_nested_lists2()

run_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def single_test(test, specific_test, verbose, no_llvm, update_reference):
2525
pass_ = test.get("pass", None)
2626
optimization_passes = ["flip_sign", "div_to_mul", "fma", "sign_from_value",
2727
"inline_function_calls", "loop_unroll",
28-
"dead_code_removal", "loop_vectorise"]
28+
"dead_code_removal", "loop_vectorise", "print_list"]
2929

3030
if pass_ and (pass_ not in ["do_loops", "global_stmts"] and
3131
pass_ not in optimization_passes):

src/libasr/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(SRC
3535
pass/class_constructor.cpp
3636
pass/arr_slice.cpp
3737
pass/print_arr.cpp
38+
pass/print_list.cpp
3839
pass/pass_utils.cpp
3940
pass/unused_functions.cpp
4041
pass/flip_sign.cpp

src/libasr/pass/pass_manager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <libasr/pass/global_stmts.h>
2323
#include <libasr/pass/param_to_const.h>
2424
#include <libasr/pass/print_arr.h>
25+
#include <libasr/pass/print_list.h>
2526
#include <libasr/pass/arr_slice.h>
2627
#include <libasr/pass/flip_sign.h>
2728
#include <libasr/pass/div_to_mul.h>
@@ -59,6 +60,7 @@ namespace LCompilers {
5960
{"array_op", &LFortran::pass_replace_array_op},
6061
{"arr_slice", &LFortran::pass_replace_arr_slice},
6162
{"print_arr", &LFortran::pass_replace_print_arr},
63+
{"print_list", &LFortran::pass_replace_print_list},
6264
{"class_constructor", &LFortran::pass_replace_class_constructor},
6365
{"unused_functions", &LFortran::pass_unused_functions},
6466
{"flip_sign", &LFortran::pass_replace_flip_sign},
@@ -97,6 +99,7 @@ namespace LCompilers {
9799
"arr_slice",
98100
"array_op",
99101
"print_arr",
102+
"print_list",
100103
"array_dim_intrinsics_update",
101104
"do_loops",
102105
"forall",
@@ -113,6 +116,7 @@ namespace LCompilers {
113116
"arr_slice",
114117
"array_op",
115118
"print_arr",
119+
"print_list",
116120
"loop_vectorise",
117121
"loop_unroll",
118122
"array_dim_intrinsics_update",

src/libasr/pass/print_list.cpp

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#include <libasr/asr.h>
2+
#include <libasr/containers.h>
3+
#include <libasr/exception.h>
4+
#include <libasr/asr_utils.h>
5+
#include <libasr/asr_verify.h>
6+
#include <libasr/pass/pass_utils.h>
7+
#include <libasr/pass/print_list.h>
8+
9+
namespace LFortran {
10+
11+
/*
12+
This ASR pass replaces print list with print every value,
13+
comma_space, brackets and newline. The function
14+
`pass_replace_print_list` transforms the ASR tree in-place.
15+
16+
Converts:
17+
18+
print(l, sep="pqr", end="xyz") # l is a list
19+
20+
to:
21+
22+
print("[", end="")
23+
for i in range(len(l)):
24+
print(l[i], end="")
25+
if i < len(l) - 1:
26+
print(", ", end="")
27+
print("]", sep="pqr", end="xyz")
28+
29+
for nested lists it transforms to:
30+
31+
print("[", end="")
32+
for i in range(len(l)):
33+
# print(l[i], end="") is replaced by the following code
34+
35+
print("[", end="")
36+
for i1 in range(len(l[i])):
37+
print(l[i][i1], end="")
38+
if i1 < len(l[i]) - 1:
39+
print(", ", end="")
40+
print("]")
41+
42+
if i < len(l) - 1:
43+
print(", ", end="")
44+
print("]", sep="pqr", end="xyz")
45+
46+
Note: In code, the variable `i` is named as `__list_iterator`
47+
*/
48+
49+
class PrintListVisitor
50+
: public PassUtils::PassVisitor<PrintListVisitor> {
51+
private:
52+
std::string rl_path;
53+
54+
public:
55+
PrintListVisitor(Allocator &al, const std::string &rl_path_)
56+
: PassVisitor(al, nullptr), rl_path(rl_path_) {
57+
pass_result.reserve(al, 1);
58+
}
59+
60+
void visit_Print(const ASR::Print_t &x) {
61+
if (x.n_values == 1 &&
62+
ASR::is_a<ASR::List_t>(*ASRUtils::expr_type(x.m_values[0]))) {
63+
ASR::List_t *listC =
64+
ASR::down_cast<ASR::List_t>(ASRUtils::expr_type(x.m_values[0]));
65+
66+
ASR::ttype_t *int_type = ASRUtils::TYPE(
67+
ASR::make_Integer_t(al, x.base.base.loc, 4, nullptr, 0));
68+
ASR::ttype_t *bool_type = ASRUtils::TYPE(
69+
ASR::make_Logical_t(al, x.base.base.loc, 4, nullptr, 0));
70+
ASR::ttype_t *str_type_len_0 = ASRUtils::TYPE(ASR::make_Character_t(
71+
al, x.base.base.loc, 1, 0, nullptr, nullptr, 0));
72+
ASR::ttype_t *str_type_len_1 = ASRUtils::TYPE(ASR::make_Character_t(
73+
al, x.base.base.loc, 1, 1, nullptr, nullptr, 0));
74+
ASR::ttype_t *str_type_len_2 = ASRUtils::TYPE(ASR::make_Character_t(
75+
al, x.base.base.loc, 1, 2, nullptr, nullptr, 0));
76+
ASR::expr_t *comma_space =
77+
ASRUtils::EXPR(ASR::make_StringConstant_t(
78+
al, x.base.base.loc, s2c(al, ", "), str_type_len_2));
79+
ASR::expr_t *single_quote =
80+
ASRUtils::EXPR(ASR::make_StringConstant_t(
81+
al, x.base.base.loc, s2c(al, "'"), str_type_len_1));
82+
ASR::expr_t *empty_str = ASRUtils::EXPR(ASR::make_StringConstant_t(
83+
al, x.base.base.loc, s2c(al, ""), str_type_len_0));
84+
ASR::expr_t *open_bracket =
85+
ASRUtils::EXPR(ASR::make_StringConstant_t(
86+
al, x.base.base.loc, s2c(al, "["), str_type_len_1));
87+
ASR::expr_t *close_bracket =
88+
ASRUtils::EXPR(ASR::make_StringConstant_t(
89+
al, x.base.base.loc, s2c(al, "]"), str_type_len_1));
90+
91+
std::string list_iter_var_name;
92+
ASR::symbol_t *list_iter_variable;
93+
ASR::expr_t *list_iter_var;
94+
{
95+
list_iter_var_name =
96+
current_scope->get_unique_name("__list_iterator");
97+
list_iter_variable =
98+
ASR::down_cast<ASR::symbol_t>(ASR::make_Variable_t(
99+
al, x.base.base.loc, current_scope,
100+
s2c(al, list_iter_var_name), ASR::intentType::Local,
101+
nullptr, nullptr, ASR::storage_typeType::Default,
102+
int_type, ASR::abiType::Source, ASR::accessType::Public,
103+
ASR::presenceType::Required, false));
104+
105+
current_scope->add_symbol(list_iter_var_name,
106+
list_iter_variable);
107+
list_iter_var = ASRUtils::EXPR(
108+
ASR::make_Var_t(al, x.base.base.loc, list_iter_variable));
109+
}
110+
111+
ASR::expr_t *list_item = ASRUtils::EXPR(
112+
ASR::make_ListItem_t(al, x.base.base.loc, x.m_values[0],
113+
list_iter_var, listC->m_type, nullptr));
114+
ASR::expr_t *list_len = ASRUtils::EXPR(ASR::make_ListLen_t(
115+
al, x.base.base.loc, x.m_values[0], int_type, nullptr));
116+
ASR::expr_t *constant_one = ASRUtils::EXPR(
117+
ASR::make_IntegerConstant_t(al, x.base.base.loc, 1, int_type));
118+
ASR::expr_t *list_len_minus_one =
119+
ASRUtils::EXPR(ASR::make_IntegerBinOp_t(
120+
al, x.base.base.loc, list_len, ASR::binopType::Sub,
121+
constant_one, int_type, nullptr));
122+
ASR::expr_t *compare_cond =
123+
ASRUtils::EXPR(ASR::make_IntegerCompare_t(
124+
al, x.base.base.loc, list_iter_var, ASR::cmpopType::Lt,
125+
list_len_minus_one, bool_type, nullptr));
126+
127+
Vec<ASR::expr_t *> v1, v2, v3, v4;
128+
v1.reserve(al, 1);
129+
v3.reserve(al, 1);
130+
v4.reserve(al, 1);
131+
v1.push_back(al, open_bracket);
132+
v3.push_back(al, close_bracket);
133+
v4.push_back(al, comma_space);
134+
135+
if (ASR::is_a<ASR::Character_t>(*listC->m_type)) {
136+
v2.reserve(al, 3);
137+
v2.push_back(al, single_quote);
138+
v2.push_back(al, list_item);
139+
v2.push_back(al, single_quote);
140+
} else {
141+
v2.reserve(al, 1);
142+
v2.push_back(al, list_item);
143+
}
144+
145+
ASR::stmt_t *print_open_bracket = LFortran::ASRUtils::STMT(
146+
ASR::make_Print_t(al, x.base.base.loc, nullptr, v1.p, v1.size(),
147+
nullptr, empty_str));
148+
ASR::stmt_t *print_comma_space = ASRUtils::STMT(
149+
ASR::make_Print_t(al, x.base.base.loc, nullptr, v4.p, v4.size(),
150+
empty_str, empty_str));
151+
ASR::stmt_t *print_item = ASRUtils::STMT(
152+
ASR::make_Print_t(al, x.base.base.loc, nullptr, v2.p, v2.size(),
153+
empty_str, empty_str));
154+
ASR::stmt_t *print_close_bracket = LFortran::ASRUtils::STMT(
155+
ASR::make_Print_t(al, x.base.base.loc, nullptr, v3.p, v3.size(),
156+
x.m_separator, x.m_end));
157+
158+
Vec<ASR::stmt_t *> if_body;
159+
if_body.reserve(al, 1);
160+
if_body.push_back(al, print_comma_space);
161+
162+
ASR::stmt_t *if_cond = ASRUtils::STMT(
163+
ASR::make_If_t(al, x.base.base.loc, compare_cond, if_body.p,
164+
if_body.size(), nullptr, 0));
165+
166+
ASR::do_loop_head_t loop_head;
167+
Vec<ASR::stmt_t *> loop_body;
168+
{
169+
loop_head.loc = x.base.base.loc;
170+
loop_head.m_v = list_iter_var;
171+
loop_head.m_start = ASRUtils::EXPR(ASR::make_IntegerConstant_t(
172+
al, x.base.base.loc, 0, int_type));
173+
loop_head.m_end = list_len_minus_one;
174+
loop_head.m_increment =
175+
ASRUtils::EXPR(ASR::make_IntegerConstant_t(
176+
al, x.base.base.loc, 1, int_type));
177+
178+
if (!ASR::is_a<ASR::List_t>(*listC->m_type)) {
179+
loop_body.reserve(al, 2);
180+
loop_body.push_back(al, print_item);
181+
} else {
182+
visit_Print(*ASR::down_cast<ASR::Print_t>(print_item));
183+
loop_body.from_pointer_n_copy(al, pass_result.p, pass_result.size());
184+
pass_result.n = 0;
185+
}
186+
loop_body.push_back(al, if_cond);
187+
}
188+
189+
ASR::stmt_t *loop = ASRUtils::STMT(ASR::make_DoLoop_t(
190+
al, x.base.base.loc, loop_head, loop_body.p, loop_body.size()));
191+
192+
{
193+
pass_result.push_back(al, print_open_bracket);
194+
pass_result.push_back(al, loop);
195+
pass_result.push_back(al, print_close_bracket);
196+
}
197+
}
198+
}
199+
};
200+
201+
void pass_replace_print_list(
202+
Allocator &al, ASR::TranslationUnit_t &unit,
203+
const LCompilers::PassOptions &pass_options) {
204+
std::string rl_path = pass_options.runtime_library_dir;
205+
PrintListVisitor v(al, rl_path);
206+
v.visit_TranslationUnit(unit);
207+
LFORTRAN_ASSERT(asr_verify(unit));
208+
}
209+
210+
} // namespace LFortran

src/libasr/pass/print_list.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef LFORTRAN_PASS_PRINT_LIST_H
2+
#define LFORTRAN_PASS_PRINT_LIST_H
3+
4+
#include <libasr/asr.h>
5+
#include <libasr/utils.h>
6+
7+
namespace LFortran {
8+
9+
void pass_replace_print_list(
10+
Allocator &al, ASR::TranslationUnit_t &unit,
11+
const LCompilers::PassOptions &pass_options);
12+
13+
} // namespace LFortran
14+
15+
#endif // LFORTRAN_PASS_PRINT_LIST_H
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-print_02-afbe092",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/../integration_tests/print_02.py",
5+
"infile_hash": "80609aedaf75258395fafe6c444c79cc3217f000380bd39e1b0f6a84",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": "asr-print_02-afbe092.stdout",
9+
"stdout_hash": "4426c0f2cb900df00ddd7facbec9b7648c60d703a4fec573bdaf57e0",
10+
"stderr": null,
11+
"stderr_hash": null,
12+
"returncode": 0
13+
}

tests/reference/asr-print_02-afbe092.stdout

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "pass_print_list-print_02-d2853f6",
3+
"cmd": "lpython --pass=print_list --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/../integration_tests/print_02.py",
5+
"infile_hash": "80609aedaf75258395fafe6c444c79cc3217f000380bd39e1b0f6a84",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": "pass_print_list-print_02-d2853f6.stdout",
9+
"stdout_hash": "b5d47019cefd1d9b5a0c7e6a4ff68c91844af269bb9af00f0fc2afb8",
10+
"stderr": null,
11+
"stderr_hash": null,
12+
"returncode": 0
13+
}

tests/reference/pass_print_list-print_02-d2853f6.stdout

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)