Skip to content

Commit fa9df0a

Browse files
authored
Implement string contains for lpython (#2787)
1 parent c5be7c7 commit fa9df0a

File tree

6 files changed

+59
-0
lines changed

6 files changed

+59
-0
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ RUN(NAME test_str_02 LABELS cpython llvm llvm_jit c)
532532
RUN(NAME test_str_03 LABELS cpython llvm llvm_jit c)
533533
RUN(NAME test_str_04 LABELS cpython llvm llvm_jit c wasm)
534534
RUN(NAME test_str_05 LABELS cpython llvm llvm_jit c)
535+
RUN(NAME test_str_06 LABELS cpython llvm llvm_jit c)
535536
RUN(NAME test_list_01 LABELS cpython llvm llvm_jit c)
536537
RUN(NAME test_list_02 LABELS cpython llvm llvm_jit c)
537538
RUN(NAME test_list_03 LABELS cpython llvm llvm_jit c NOFAST)

integration_tests/test_str_06.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
def main0():
2+
x: str
3+
x = "Hello, World"
4+
5+
assert "Hello" in x
6+
assert "," in x
7+
assert "rld" in x
8+
9+
assert "Hello" not in "World"
10+
11+
main0()

src/libasr/codegen/asr_to_c_cpp.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,15 @@ PyMODINIT_FUNC PyInit_lpython_module_)" + fn_name + R"((void) {
12441244
src = "_lfortran_strrepeat_c(" + s + ", " + n + ")";
12451245
}
12461246

1247+
void visit_StringContains(const ASR::StringContains_t &x) {
1248+
CHECK_FAST_C_CPP(compiler_options, x)
1249+
self().visit_expr(*x.m_left);
1250+
std::string substr = src;
1251+
self().visit_expr(*x.m_right);
1252+
std::string str = src;
1253+
src = "_lfortran_str_contains(" + str + ", " + substr + ")";
1254+
}
1255+
12471256
void visit_Assignment(const ASR::Assignment_t &x) {
12481257
std::string target;
12491258
ASR::ttype_t* m_target_type = ASRUtils::expr_type(x.m_target);

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,21 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
723723
return builder->CreateCall(fn, {str, idx1});
724724
}
725725

726+
llvm::Value* lfortran_str_contains(llvm::Value* str, llvm::Value* substr)
727+
{
728+
std::string runtime_func_name = "_lfortran_str_contains";
729+
llvm::Function *fn = module->getFunction(runtime_func_name);
730+
if (!fn) {
731+
llvm::FunctionType *function_type = llvm::FunctionType::get(
732+
llvm::Type::getInt1Ty(context), {
733+
character_type, character_type
734+
}, false);
735+
fn = llvm::Function::Create(function_type,
736+
llvm::Function::ExternalLinkage, runtime_func_name, *module);
737+
}
738+
return builder->CreateCall(fn, {str, substr});
739+
}
740+
726741
llvm::Value* lfortran_str_copy(llvm::Value* str, llvm::Value* idx1, llvm::Value* idx2)
727742
{
728743
std::string runtime_func_name = "_lfortran_str_copy";
@@ -6416,6 +6431,22 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
64166431
}
64176432
}
64186433

6434+
void visit_StringContains(const ASR::StringContains_t& x) {
6435+
if (x.m_value) {
6436+
this->visit_expr_wrapper(x.m_value, true);
6437+
return;
6438+
}
6439+
6440+
this->visit_expr_wrapper(x.m_left, true);
6441+
llvm::Value *substr = tmp;
6442+
6443+
this->visit_expr_wrapper(x.m_right, true);
6444+
llvm::Value *right = tmp;
6445+
6446+
tmp = lfortran_str_contains(right, substr);
6447+
strings_to_be_deallocated.push_back(al, tmp);
6448+
}
6449+
64196450
void visit_StringSection(const ASR::StringSection_t& x) {
64206451
if (x.m_value) {
64216452
this->visit_expr_wrapper(x.m_value, true);

src/libasr/runtime/lfortran_intrinsics.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,12 @@ LFORTRAN_API char* _lfortran_str_item(char* s, int32_t idx) {
21972197
return res;
21982198
}
21992199

2200+
/// Find a substring in a string
2201+
LFORTRAN_API bool _lfortran_str_contains(char* str, char* substr) {
2202+
char* res = strstr(str, substr);
2203+
return res != NULL;
2204+
}
2205+
22002206
// idx1 and idx2 both start from 1
22012207
LFORTRAN_API char* _lfortran_str_copy(char* s, int32_t idx1, int32_t idx2) {
22022208

src/libasr/runtime/lfortran_intrinsics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ LFORTRAN_API void _lfortran_free(char* ptr);
209209
LFORTRAN_API void _lfortran_alloc(char** ptr, int32_t len);
210210
LFORTRAN_API void _lfortran_string_init(int size_plus_one, char *s);
211211
LFORTRAN_API char* _lfortran_str_item(char* s, int32_t idx);
212+
LFORTRAN_API bool _lfortran_str_contains(char* str, char* substr);
212213
LFORTRAN_API char* _lfortran_str_copy(char* s, int32_t idx1, int32_t idx2); // idx1 and idx2 both start from 1
213214
LFORTRAN_API char* _lfortran_str_slice(char* s, int32_t idx1, int32_t idx2, int32_t step,
214215
bool idx1_present, bool idx2_present);

0 commit comments

Comments
 (0)