Skip to content

Commit 7ecac3e

Browse files
REPL str support (#2724)
* REPL `str` support * removing goto
1 parent dd6d546 commit 7ecac3e

File tree

8 files changed

+124
-3
lines changed

8 files changed

+124
-3
lines changed

src/bin/lpython.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,12 @@ int interactive_python_repl(
960960
std::cout << std::setprecision(17) << "(" << r.c64.re << ", " << r.c64.im << ")" << std::endl;
961961
break;
962962
}
963+
case (LCompilers::PythonCompiler::EvalResult::string) : {
964+
if (verbose) std::cout << "Return type: str" << std::endl;
965+
if (verbose) section("Result:");
966+
std::cout << (r.str == nullptr ? "" : r.str) << std::endl;
967+
break;
968+
}
963969
case (LCompilers::PythonCompiler::EvalResult::statement) : {
964970
if (verbose) {
965971
std::cout << "Return type: none" << std::endl;

src/libasr/codegen/evaluator.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ std::string LLVMModule::get_return_type(const std::string &fn_name)
110110
return "integer4";
111111
} else if (type->isIntegerTy(64)) {
112112
return "integer8";
113+
} else if (type->isPointerTy() && type->getPointerElementType()->isIntegerTy(8)) {
114+
return "integer1ptr";
113115
} else if (type->isStructTy()) {
114116
llvm::StructType *st = llvm::cast<llvm::StructType>(type);
115117
if (st->hasName()) {
@@ -273,6 +275,12 @@ intptr_t LLVMEvaluator::get_symbol_address(const std::string &name) {
273275
return (intptr_t)cantFail(std::move(addr0));
274276
}
275277

278+
char *LLVMEvaluator::strfn(const std::string &name) {
279+
intptr_t addr = get_symbol_address(name);
280+
char *(*f)() = (char *(*)())addr;
281+
return f();
282+
}
283+
276284
int8_t LLVMEvaluator::int8fn(const std::string &name) {
277285
intptr_t addr = get_symbol_address(name);
278286
int8_t (*f)() = (int8_t (*)())addr;

src/libasr/codegen/evaluator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class LLVMEvaluator
5252
void add_module(std::unique_ptr<llvm::Module> mod);
5353
void add_module(std::unique_ptr<LLVMModule> m);
5454
intptr_t get_symbol_address(const std::string &name);
55+
char *strfn(const std::string &name);
5556
int8_t int8fn(const std::string &name);
5657
int16_t int16fn(const std::string &name);
5758
int32_t int32fn(const std::string &name);

src/libasr/pass/global_stmts.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ void pass_wrap_global_stmts(Allocator &al,
9393
fn_scope->add_symbol(std::string(var_name), down_cast<ASR::symbol_t>(return_var));
9494
target = return_var_ref;
9595
idx++;
96-
} else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Complex) {
96+
} else if ((ASRUtils::expr_type(value)->type == ASR::ttypeType::Complex) ||
97+
(ASRUtils::expr_type(value)->type == ASR::ttypeType::Character)) {
9798
s.from_str(al, fn_name_s + std::to_string(idx));
9899
var_name = s.c_str(al);
99100
type = ASRUtils::expr_type(value);

src/libasr/runtime/lfortran_intrinsics.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,6 +1972,10 @@ LFORTRAN_API void _lfortran_strcpy(char** x, char *y, int8_t free_target)
19721972
// *x = (char*) malloc((strlen(y) + 1) * sizeof(char));
19731973
// _lfortran_string_init(strlen(y) + 1, *x);
19741974
}
1975+
if (y == NULL) {
1976+
*x = NULL;
1977+
return;
1978+
}
19751979
// if( *x == NULL ) {
19761980
*x = (char*) malloc((strlen(y) + 1) * sizeof(char));
19771981
_lfortran_string_init(strlen(y) + 1, *x);

src/lpython/python_evaluator.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,18 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
127127

128128
e->add_module(std::move(m));
129129
if (call_run_fn) {
130-
if (return_type == "integer1") {
130+
if (return_type == "integer1ptr") {
131+
ASR::symbol_t *fn = ASR::down_cast<ASR::Module_t>(symbol_table->resolve_symbol(module_name))
132+
->m_symtab->get_symbol(run_fn);
133+
LCOMPILERS_ASSERT(fn)
134+
if (ASRUtils::get_FunctionType(fn)->m_return_var_type->type == ASR::ttypeType::Character) {
135+
char *r = e->strfn(run_fn);
136+
result.type = EvalResult::string;
137+
result.str = r;
138+
} else {
139+
throw LCompilersException("PythonCompiler::evaluate(): Return type not supported");
140+
}
141+
} else if (return_type == "integer1") {
131142
ASR::symbol_t *fn = ASR::down_cast<ASR::Module_t>(symbol_table->resolve_symbol(module_name))
132143
->m_symtab->get_symbol(run_fn);
133144
LCOMPILERS_ASSERT(fn)
@@ -203,7 +214,7 @@ Result<PythonCompiler::EvalResult> PythonCompiler::evaluate(
203214
} else if (return_type == "none") {
204215
result.type = EvalResult::none;
205216
} else {
206-
throw LCompilersException("FortranEvaluator::evaluate(): Return type not supported");
217+
throw LCompilersException("PythonCompiler::evaluate(): Return type not supported");
207218
}
208219
}
209220

src/lpython/python_evaluator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class PythonCompiler
4949
real8,
5050
complex4,
5151
complex8,
52+
string,
5253
statement,
5354
none
5455
} type;
@@ -59,6 +60,7 @@ class PythonCompiler
5960
uint64_t u64;
6061
float f32;
6162
double f64;
63+
char *str;
6264
struct {float re, im;} c32;
6365
struct {double re, im;} c64;
6466
};

src/lpython/tests/test_llvm.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <tests/doctest.h>
22

33
#include <cmath>
4+
#include <cstring>
45

56
#include <lpython/python_evaluator.h>
67
#include <libasr/codegen/evaluator.h>
@@ -1270,3 +1271,90 @@ TEST_CASE("PythonCompiler u16 declaration") {
12701271
CHECK(r.result.type == PythonCompiler::EvalResult::unsignedInteger2);
12711272
CHECK(r.result.u32 == 45);
12721273
}
1274+
1275+
TEST_CASE("PythonCompiler string 1") {
1276+
CompilerOptions cu;
1277+
cu.po.disable_main = true;
1278+
cu.emit_debug_line_column = false;
1279+
cu.generate_object_code = false;
1280+
cu.interactive = true;
1281+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1282+
PythonCompiler e(cu);
1283+
LCompilers::Result<PythonCompiler::EvalResult>
1284+
1285+
r = e.evaluate2("\"My String\"");
1286+
CHECK(r.ok);
1287+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1288+
CHECK(std::strcmp(r.result.str, "My String") == 0);
1289+
1290+
r = e.evaluate2("\"s1\" + \" \" + \"s2\"");
1291+
CHECK(r.ok);
1292+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1293+
CHECK(std::strcmp(r.result.str, "s1 s2") == 0);
1294+
}
1295+
1296+
TEST_CASE("PythonCompiler string 2") {
1297+
CompilerOptions cu;
1298+
cu.po.disable_main = true;
1299+
cu.emit_debug_line_column = false;
1300+
cu.generate_object_code = false;
1301+
cu.interactive = true;
1302+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1303+
PythonCompiler e(cu);
1304+
LCompilers::Result<PythonCompiler::EvalResult>
1305+
1306+
r = e.evaluate2("s: str");
1307+
CHECK(r.ok);
1308+
CHECK(r.result.type == PythonCompiler::EvalResult::none);
1309+
1310+
r = e.evaluate2("s");
1311+
CHECK(r.ok);
1312+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1313+
CHECK(r.result.str == nullptr);
1314+
1315+
r = e.evaluate2(R"(
1316+
s = ""
1317+
i: i32 = 0
1318+
for i in range(10):
1319+
s += str(i)
1320+
)");
1321+
CHECK(r.ok);
1322+
CHECK(r.result.type == PythonCompiler::EvalResult::statement);
1323+
1324+
r = e.evaluate2("s");
1325+
CHECK(r.ok);
1326+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1327+
CHECK(std::strcmp(r.result.str, "0123456789") == 0);
1328+
}
1329+
1330+
TEST_CASE("PythonCompiler string 3") {
1331+
CompilerOptions cu;
1332+
cu.po.disable_main = true;
1333+
cu.emit_debug_line_column = false;
1334+
cu.generate_object_code = false;
1335+
cu.interactive = true;
1336+
cu.po.runtime_library_dir = LCompilers::LPython::get_runtime_library_dir();
1337+
PythonCompiler e(cu);
1338+
LCompilers::Result<PythonCompiler::EvalResult>
1339+
1340+
r = e.evaluate2(R"(
1341+
def my_concat(x: str, y: str) -> str:
1342+
return x + " " + y
1343+
)");
1344+
CHECK(r.ok);
1345+
CHECK(r.result.type == PythonCompiler::EvalResult::none);
1346+
1347+
r = e.evaluate2("s: str = \"0123456789\"");
1348+
CHECK(r.ok);
1349+
CHECK(r.result.type == PythonCompiler::EvalResult::none);
1350+
1351+
r = e.evaluate2("my_concat(s, \"NUM\")");
1352+
CHECK(r.ok);
1353+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1354+
CHECK(std::strcmp(r.result.str, "0123456789 NUM") == 0);
1355+
1356+
r = e.evaluate2("my_concat(\"Python\", \"REPL\")");
1357+
CHECK(r.ok);
1358+
CHECK(r.result.type == PythonCompiler::EvalResult::string);
1359+
CHECK(std::strcmp(r.result.str, "Python REPL") == 0);
1360+
}

0 commit comments

Comments
 (0)