Skip to content

Commit 8f3393d

Browse files
Underscore: _ variable in REPL (#2755)
* support to print lists in REPL * `_` variable in REPL * fix * update according to code review suggestions * fix reference test (CI fail)
1 parent ba07d7b commit 8f3393d

File tree

6 files changed

+197
-6
lines changed

6 files changed

+197
-6
lines changed

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
205205
std::map<llvm::Value*, llvm::Value*> strings_to_be_allocated; // (array, size)
206206
Vec<llvm::Value*> strings_to_be_deallocated;
207207

208+
uint32_t global_underscore_hash; // used in interactive mode
209+
208210
ASRToLLVMVisitor(Allocator &al, llvm::LLVMContext &context, std::string infile,
209211
CompilerOptions &compiler_options_, diag::Diagnostics &diagnostics) :
210212
diag{diagnostics},
@@ -231,7 +233,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
231233
set_api_sc(std::make_unique<LLVMSetSeparateChaining>(context, llvm_utils.get(), builder.get())),
232234
arr_descr(LLVMArrUtils::Descriptor::get_descriptor(context,
233235
builder.get(), llvm_utils.get(),
234-
LLVMArrUtils::DESCR_TYPE::_SimpleCMODescriptor, compiler_options_, heap_arrays))
236+
LLVMArrUtils::DESCR_TYPE::_SimpleCMODescriptor, compiler_options_, heap_arrays)),
237+
global_underscore_hash(0)
235238
{
236239
llvm_utils->tuple_api = tuple_api.get();
237240
llvm_utils->list_api = list_api.get();
@@ -2709,11 +2712,20 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
27092712
}
27102713

27112714
void visit_Variable(const ASR::Variable_t &x) {
2715+
if (compiler_options.interactive &&
2716+
std::strcmp(x.m_name, "_") == 0 &&
2717+
x.m_abi == ASR::abiType::Interactive) {
2718+
return;
2719+
}
27122720
if (x.m_value && x.m_storage == ASR::storage_typeType::Parameter) {
27132721
this->visit_expr_wrapper(x.m_value, true);
27142722
return;
27152723
}
27162724
uint32_t h = get_hash((ASR::asr_t*)&x);
2725+
if (compiler_options.interactive &&
2726+
std::strcmp(x.m_name, compiler_options.po.global_underscore.c_str()) == 0) {
2727+
global_underscore_hash = h;
2728+
}
27172729
// This happens at global scope, so the intent can only be either local
27182730
// (global variable declared/initialized in this translation unit), or
27192731
// external (global variable not declared/initialized in this
@@ -6966,6 +6978,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
69666978

69676979
inline void fetch_val(ASR::Variable_t* x) {
69686980
uint32_t x_h = get_hash((ASR::asr_t*)x);
6981+
if (compiler_options.interactive &&
6982+
std::strcmp(x->m_name, "_") == 0 &&
6983+
x->m_abi == ASR::abiType::Interactive &&
6984+
llvm_symtab.find(x_h) == llvm_symtab.end()) {
6985+
x_h = global_underscore_hash;
6986+
}
69696987
llvm::Value* x_v;
69706988
LCOMPILERS_ASSERT(llvm_symtab.find(x_h) != llvm_symtab.end());
69716989
x_v = llvm_symtab[x_h];
@@ -8472,6 +8490,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
84728490
if (ASR::is_a<ASR::Variable_t>(*var_sym)) {
84738491
ASR::Variable_t *arg = EXPR2VAR(x.m_args[i].m_value);
84748492
uint32_t h = get_hash((ASR::asr_t*)arg);
8493+
if (compiler_options.interactive &&
8494+
std::strcmp(arg->m_name, "_") == 0 &&
8495+
arg->m_abi == ASR::abiType::Interactive) {
8496+
h = global_underscore_hash;
8497+
}
84758498
if (llvm_symtab.find(h) != llvm_symtab.end()) {
84768499
tmp = llvm_symtab[h];
84778500
if( !ASRUtils::is_array(arg->m_type) ) {
@@ -10085,7 +10108,7 @@ Result<std::unique_ptr<LLVMModule>> asr_to_llvm(ASR::TranslationUnit_t &asr,
1008510108
diag::Diagnostics &diagnostics,
1008610109
llvm::LLVMContext &context, Allocator &al,
1008710110
LCompilers::PassManager& pass_manager,
10088-
CompilerOptions &co, const std::string &run_fn,
10111+
CompilerOptions &co, const std::string &run_fn, const std::string &global_underscore,
1008910112
const std::string &infile)
1009010113
{
1009110114
#if LLVM_VERSION_MAJOR >= 15
@@ -10102,6 +10125,7 @@ Result<std::unique_ptr<LLVMModule>> asr_to_llvm(ASR::TranslationUnit_t &asr,
1010210125
ASRUtils::IntrinsicElementalFunctions::SignFromValue));
1010310126

1010410127
co.po.run_fun = run_fn;
10128+
co.po.global_underscore = global_underscore;
1010510129
co.po.always_run = false;
1010610130
co.po.skip_optimization_func_instantiation = skip_optimization_func_instantiation;
1010710131
pass_manager.rtlib = co.rtlib;

src/libasr/codegen/asr_to_llvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace LCompilers {
1313
LCompilers::PassManager& pass_manager,
1414
CompilerOptions &compiler_options,
1515
const std::string &run_fn,
16+
const std::string &global_underscore,
1617
const std::string &infile);
1718

1819
} // namespace LCompilers

src/libasr/utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct PassOptions {
3131
int default_integer_kind = 4;
3232

3333
std::string run_fun; // for global_stmts pass
34+
std::string global_underscore; // for global_stmts pass
3435
// TODO: Convert to std::filesystem::path (also change find_and_load_module())
3536
std::string runtime_library_dir;
3637
bool always_run = false; // for unused_functions pass

src/lpython/python_evaluator.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ PythonCompiler::PythonCompiler(CompilerOptions compiler_options)
3939
e{std::make_unique<LLVMEvaluator>()},
4040
#endif
4141
eval_count{1},
42-
symbol_table{nullptr}
42+
symbol_table{nullptr},
43+
global_underscore_name{""}
4344
{
4445
}
4546

@@ -122,13 +123,18 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
122123
result.llvm_ir = m->str();
123124
}
124125

126+
ASR::symbol_t *global_underscore_symbol = symbol_table->get_symbol("_" + run_fn);
127+
if (global_underscore_symbol) {
128+
global_underscore_name = "_" + run_fn;
129+
}
130+
125131
bool call_run_fn = false;
126132
std::string return_type = m->get_return_type(run_fn);
127133
if (return_type != "none") {
128134
call_run_fn = true;
129135
}
130136

131-
ASR::symbol_t *global_underscore_sym = symbol_table->get_symbol("_" + run_fn);
137+
ASR::symbol_t *global_underscore_sym = symbol_table->get_symbol(global_underscore_name);
132138
if ((return_type == "struct") && (global_underscore_sym)) {
133139
// we compute the offsets of the struct's attribute here
134140
// we will be using it later in aggregate_type_to_string to print the struct
@@ -233,7 +239,7 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
233239
} else if (return_type == "struct") {
234240
e->execfn<void>(run_fn);
235241
if (global_underscore_sym) {
236-
void *r = (void*)e->get_symbol_address("_" + run_fn);
242+
void *r = (void*)e->get_symbol_address(global_underscore_name);
237243
LCOMPILERS_ASSERT(r)
238244
result.structure.structure = r;
239245
result.type = EvalResult::struct_type;
@@ -252,6 +258,18 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
252258
ASR::down_cast<ASR::Module_t>(symbol_table->resolve_symbol(module_name))->m_symtab
253259
->erase_symbol(run_fn);
254260
}
261+
if (global_underscore_symbol) {
262+
if (symbol_table->resolve_symbol("_")) {
263+
symbol_table->erase_symbol("_");
264+
}
265+
ASR::Variable_t *a = ASR::down_cast<ASR::Variable_t>(global_underscore_symbol);
266+
ASR::Variable_t *b = al.make_new<ASR::Variable_t>();
267+
*b = *a;
268+
Str s;
269+
s.from_str(al, "_");
270+
b->m_name = s.c_str(al);
271+
symbol_table->add_symbol("_", ASR::down_cast<ASR::symbol_t>((ASR::asr_t*)b));
272+
}
255273

256274
eval_count++;
257275
return result;
@@ -429,7 +447,7 @@ Result<std::unique_ptr<LLVMModule>> PythonCompiler::get_llvm3(
429447
Result<std::unique_ptr<LCompilers::LLVMModule>> res
430448
= asr_to_llvm(asr, diagnostics,
431449
e->get_context(), al, lpm, compiler_options,
432-
run_fn, infile);
450+
run_fn, global_underscore_name, infile);
433451
if (res.ok) {
434452
m = std::move(res.result);
435453
} else {

src/lpython/python_evaluator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class PythonCompiler
137137
int eval_count;
138138
SymbolTable *symbol_table;
139139
std::string run_fn;
140+
std::string global_underscore_name;
140141
};
141142

142143
} // namespace LCompilers

src/lpython/tests/test_llvm.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,152 @@ TEST_CASE("PythonCompiler lists") {
15061506
CHECK(e.aggregate_type_to_string(r.result) == "[\"lfortran\", \"lpython\", \"lc\"]");
15071507
}
15081508

1509+
TEST_CASE("PythonCompiler underscore 1") {
1510+
CompilerOptions cu;
1511+
cu.po.disable_main = true;
1512+
cu.emit_debug_line_column = false;
1513+
cu.generate_object_code = false;
1514+
cu.interactive = true;
1515+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1516+
PythonCompiler e(cu);
1517+
LCompilers::Result<PythonCompiler::EvalResult>
1518+
1519+
r = e.evaluate2("2");
1520+
CHECK(r.ok);
1521+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1522+
CHECK(r.result.i32 == 2);
1523+
1524+
r = e.evaluate2("_");
1525+
CHECK(r.ok);
1526+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1527+
CHECK(r.result.i32 == 2);
1528+
1529+
r = e.evaluate2("_ + 4");
1530+
CHECK(r.ok);
1531+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1532+
CHECK(r.result.i32 == 6);
1533+
1534+
r = e.evaluate2("_ * 2");
1535+
CHECK(r.ok);
1536+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1537+
CHECK(r.result.i32 == 12);
1538+
}
1539+
1540+
TEST_CASE("PythonCompiler underscore 2") {
1541+
CompilerOptions cu;
1542+
cu.po.disable_main = true;
1543+
cu.emit_debug_line_column = false;
1544+
cu.generate_object_code = false;
1545+
cu.interactive = true;
1546+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1547+
PythonCompiler e(cu);
1548+
LCompilers::Result<PythonCompiler::EvalResult>
1549+
1550+
r = e.evaluate2("2");
1551+
CHECK(r.ok);
1552+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1553+
CHECK(r.result.i32 == 2);
1554+
r = e.evaluate2("_");
1555+
CHECK(r.ok);
1556+
CHECK(r.result.type == PythonCompiler::EvalResult::integer4);
1557+
CHECK(r.result.i32 == 2);
1558+
1559+
r = e.evaluate2("2.5");
1560+
CHECK(r.ok);
1561+
CHECK(r.result.type == PythonCompiler::EvalResult::real8);
1562+
CHECK(r.result.f64 == 2.5);
1563+
r = e.evaluate2("_");
1564+
CHECK(r.ok);
1565+
CHECK(r.result.type == PythonCompiler::EvalResult::real8);
1566+
CHECK(r.result.f64 == 2.5);
1567+
1568+
r = e.evaluate2("\"lpython\"");
1569+
CHECK(r.ok);
1570+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1571+
CHECK(std::strcmp(r.result.str, "lpython") == 0);
1572+
r = e.evaluate2("_");
1573+
CHECK(r.ok);
1574+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1575+
CHECK(std::strcmp(r.result.str, "lpython") == 0);
1576+
1577+
r = e.evaluate2("[1, 2, 3]");
1578+
CHECK(r.ok);
1579+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1580+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1581+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1582+
r = e.evaluate2("_");
1583+
CHECK(r.ok);
1584+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1585+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1586+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1587+
}
1588+
1589+
TEST_CASE("PythonCompiler underscore 3") {
1590+
CompilerOptions cu;
1591+
cu.po.disable_main = true;
1592+
cu.emit_debug_line_column = false;
1593+
cu.generate_object_code = false;
1594+
cu.interactive = true;
1595+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1596+
PythonCompiler e(cu);
1597+
LCompilers::Result<PythonCompiler::EvalResult>
1598+
1599+
r = e.evaluate2("[1, 2, 3]");
1600+
CHECK(r.ok);
1601+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1602+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1603+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1604+
1605+
r = e.evaluate2("_ + [1, 2, 3]");
1606+
CHECK(r.ok);
1607+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1608+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1609+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3, 1, 2, 3]");
1610+
1611+
r = e.evaluate2(R"(
1612+
_.append(5)
1613+
x: list[i32] = _
1614+
x
1615+
)");
1616+
CHECK(r.ok);
1617+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1618+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1619+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3, 1, 2, 3, 5]");
1620+
}
1621+
1622+
TEST_CASE("PythonCompiler underscore 4") {
1623+
CompilerOptions cu;
1624+
cu.po.disable_main = true;
1625+
cu.emit_debug_line_column = false;
1626+
cu.generate_object_code = false;
1627+
cu.interactive = true;
1628+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1629+
PythonCompiler e(cu);
1630+
LCompilers::Result<PythonCompiler::EvalResult>
1631+
1632+
r = e.evaluate2("[1, 2, 3]");
1633+
CHECK(r.ok);
1634+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1635+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1636+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1637+
1638+
r = e.evaluate2("_");
1639+
CHECK(r.ok);
1640+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1641+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1642+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1643+
1644+
r = e.evaluate2("f: bool = False");
1645+
CHECK(r.ok);
1646+
CHECK(r.result.type == PythonCompiler::EvalResult::none);
1647+
1648+
r = e.evaluate2("_");
1649+
CHECK(r.ok);
1650+
CHECK(r.result.type == PythonCompiler::EvalResult::struct_type);
1651+
CHECK(LCompilers::ASRUtils::get_type_code(r.result.structure.ttype) == "list[i32]");
1652+
CHECK(e.aggregate_type_to_string(r.result) == "[1, 2, 3]");
1653+
}
1654+
15091655
TEST_CASE("PythonCompiler asr verify 1") {
15101656
CompilerOptions cu;
15111657
cu.po.disable_main = true;

0 commit comments

Comments
 (0)