Skip to content

Commit

Permalink
Added str.replace() (lcompilers#2587)
Browse files Browse the repository at this point in the history
* added str.replace() string API

* references updated

* Delete kishan.py

* updated references 2

* removed empty string tests

* fix c test

* fixed empty string case

* updated references 3

* TEST: Update reference tests

---------

Co-authored-by: Shaikh Ubaid <[email protected]>
  • Loading branch information
Kishan-Ved and Shaikh-Ubaid authored Mar 10, 2024
1 parent db6ed14 commit 3e6ddc6
Show file tree
Hide file tree
Showing 62 changed files with 1,348 additions and 1,229 deletions.
50 changes: 50 additions & 0 deletions integration_tests/test_str_01.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,55 @@ def test_str_split():
assert res5 == ["123"]
# assert res6 == [""]

def test_str_replace():
x: str = "abc"
a: str = "zzaaabracadabra"
print(a.replace("a",""))
print(a.replace("",""))
print(a.replace("a","b"))
print(a.replace("e","a"))
print(a.replace("ab","ba"))
print(a.replace("c","z"))
print(a.replace("zza","yo"))
print(a.replace("a","b",0))
print(a.replace("a","b",1))
print(a.replace("a","b",2))
print(a.replace("a","b",2))
print(a.replace("a","b",3))
print(a.replace("a","b",4))
print(a.replace("a","b",5))
print(a.replace("a","b",6))
print(a.replace("a","b",7))
print(a.replace("a","b",8))
print(a.replace("a","b",9))
print(a.replace("b","k",1))
print(a.replace("b","k",2))
print(a.replace("zza","yo",2))
print(x.replace("", ","))
assert a.replace("a","") == "zzbrcdbr"
assert a.replace("","") == "zzaaabracadabra"
assert a.replace("a","b") == "zzbbbbrbcbdbbrb"
assert a.replace("e","a") == "zzaaabracadabra"
assert a.replace("ab","ba") == "zzaabaracadbara"
assert a.replace("c","z") == "zzaaabrazadabra"
assert a.replace("zza","yo") == "yoaabracadabra"
assert a.replace("a","b",0) == "zzaaabracadabra"
assert a.replace("a","b",1) == "zzbaabracadabra"
assert a.replace("a","b",2) == "zzbbabracadabra"
assert a.replace("a","b",2) == "zzbbabracadabra"
assert a.replace("a","b",3) == "zzbbbbracadabra"
assert a.replace("a","b",4) == "zzbbbbrbcadabra"
assert a.replace("a","b",5) == "zzbbbbrbcbdabra"
assert a.replace("a","b",6) == "zzbbbbrbcbdbbra"
assert a.replace("a","b",7) == "zzbbbbrbcbdbbrb"
assert a.replace("a","b",8) == "zzbbbbrbcbdbbrb"
assert a.replace("a","b",9) == "zzbbbbrbcbdbbrb"
assert a.replace("b","k",1) == "zzaaakracadabra"
assert a.replace("b","k",2) == "zzaaakracadakra"
assert a.replace("zza","yo",2) == "yoaabracadabra"
assert x.replace("", ",") == ",a,b,c,"


def check():
f()
test_str_concat()
Expand All @@ -127,5 +176,6 @@ def check():
test_constant_str_subscript()
test_str_title()
test_str_split()
test_str_replace()

check()
35 changes: 35 additions & 0 deletions src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6789,6 +6789,41 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
} else {
fn_args.push_back(al, str);
}
} else if(attr_name == "replace") {
if(!(args.size() == 2 || args.size()==3)) {
throw SemanticError("str.replace() takes two or three arguments.", loc);
}
ASR::expr_t *arg_value = args[0].m_value;
ASR::ttype_t *arg_value_type = ASRUtils::expr_type(arg_value);
if (!ASRUtils::is_character(*arg_value_type)) {
throw SemanticError("str.replace() argument 1 must be str", loc);
}
arg_value = args[1].m_value;
arg_value_type = ASRUtils::expr_type(arg_value);
if (!ASRUtils::is_character(*arg_value_type)) {
throw SemanticError("str.replace() argument 2 must be str", loc);
}
fn_call_name = "_lpython_str_replace";
ASR::call_arg_t str;
str.loc = loc;
str.m_value = s_var;

ASR::call_arg_t value;
value.loc = loc;
value.m_value = args[0].m_value;
fn_args.push_back(al, str);
fn_args.push_back(al, value);
value.m_value = args[1].m_value;
fn_args.push_back(al, value);
if(args.size()==3){
ASR::expr_t *arg_value = args[2].m_value;
ASR::ttype_t *arg_value_type = ASRUtils::expr_type(arg_value);
if (!ASRUtils::is_integer(*arg_value_type)) {
throw SemanticError("str.replace() argument 3 must be int", loc);
}
value.m_value = args[2].m_value;
fn_args.push_back(al, value);
}
} else if(attr_name.size() > 2 && attr_name[0] == 'i' && attr_name[1] == 's') {
/*
String Validation Methods i.e all "is" based functions are handled here
Expand Down
1 change: 1 addition & 0 deletions src/lpython/semantics/python_comptime_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct PythonIntrinsicProcedures {
{"_lpython_str_lstrip", {m_builtin, &not_implemented}},
{"_lpython_str_strip", {m_builtin, &not_implemented}},
{"_lpython_str_split", {m_builtin, &not_implemented}},
{"_lpython_str_replace", {m_builtin, &not_implemented}},
{"_lpython_str_swapcase", {m_builtin, &not_implemented}},
{"_lpython_str_startswith", {m_builtin, &not_implemented}},
{"_lpython_str_endswith", {m_builtin, &not_implemented}},
Expand Down
33 changes: 33 additions & 0 deletions src/runtime/lpython_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,39 @@ def _lpython_str_split(x: str, sep:str) -> list[str]:
start += ind + len(sep)
return res

@overload
def _lpython_str_replace(x: str, old:str, new:str) -> str:
return _lpython_str_replace(x, old, new, len(x))


@overload
def _lpython_str_replace(x: str, old:str, new:str, count: i32) -> str:
if (old == ""):
res1: str = ""
s: str
for s in x:
res1 += new + s
return res1 + new
res: str = ""
i: i32 = 0
ind: i32 = -1
l: i32 = len(new)
lo: i32 = len(old)
lx: i32 = len(x)
c: i32 = 0
t: i32 = -1

while(c<count):
t = _lpython_str_find(x[i:lx], old)
if(t==-1):
break
ind = i + t
res = res + x[i:ind] + new
i = ind + lo
c = c + 1
res = res + x[i:lx]
return res

@overload
def _lpython_str_swapcase(s: str) -> str:
res :str = ""
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/asr-array_01_decl-39cf894.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "asr-array_01_decl-39cf894.stdout",
"stdout_hash": "7e3c68aa6acba27674e544f894bb141357db82f8840c756af448f5bb",
"stdout_hash": "f14010ffcf7d42b89e54c88ebecc7ca51d67b204825e07f4f708875e",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
Loading

0 comments on commit 3e6ddc6

Please sign in to comment.