Skip to content

Commit 318a6fe

Browse files
authored
Merge pull request #954 from Abdelrahman-Kh-Fouad/str_cap
strings: capialize, lower
2 parents 4900bd9 + a942556 commit 318a6fe

File tree

55 files changed

+221
-47
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+221
-47
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,4 @@ RUN(NAME generics_01 LABELS cpython llvm)
226226
RUN(NAME generics_02 LABELS cpython llvm)
227227
RUN(NAME generics_array_01 LABELS llvm)
228228
RUN(NAME test_statistics LABELS cpython llvm)
229+
RUN(NAME test_str_attributes LABELS cpython llvm)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
def capitalize():
2+
s: str
3+
s = "tom and jerry"
4+
assert s.capitalize() == "Tom and jerry"
5+
s = "12wddd"
6+
assert s.capitalize() == s
7+
s = " tom and jerry"
8+
assert s.capitalize() == s
9+
assert "empty string" .capitalize() == "Empty string"
10+
assert "".capitalize() == ""
11+
12+
def lower():
13+
s: str
14+
s = "AaaaAABBbbbbBB!@12223BN"
15+
assert s.lower() == "aaaaaabbbbbbbb!@12223bn"
16+
assert "DDd12Vv" .lower() == "ddd12vv"
17+
18+
capitalize()
19+
lower()

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4239,6 +4239,37 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
42394239
}
42404240
ASR::expr_t *se = ASR::down_cast<ASR::expr_t>(
42414241
ASR::make_Var_t(al, x.base.base.loc, st));
4242+
if (ASR::is_a<ASR::Character_t>(*(ASRUtils::expr_type(se)))) {
4243+
if (std::string(at->m_attr) == std::string("capitalize")) {
4244+
if(args.size() != 0) {
4245+
throw SemanticError("str.capitalize() takes no arguments",
4246+
x.base.base.loc);
4247+
}
4248+
ASR::symbol_t *fn_div = resolve_intrinsic_function(x.base.base.loc, "_lpython_str_capitalize");
4249+
Vec<ASR::call_arg_t> args;
4250+
args.reserve(al, 1);
4251+
ASR::call_arg_t arg;
4252+
arg.loc = x.base.base.loc;
4253+
arg.m_value = se;
4254+
args.push_back(al, arg);
4255+
tmp = make_call_helper(al, fn_div, current_scope, args, "_lpython_str_capitalize", x.base.base.loc);
4256+
return;
4257+
} else if (std::string(at->m_attr) == std::string("lower")) {
4258+
if(args.size() != 0) {
4259+
throw SemanticError("str.lower() takes no arguments",
4260+
x.base.base.loc);
4261+
}
4262+
ASR::symbol_t *fn_div = resolve_intrinsic_function(x.base.base.loc, "_lpython_str_lower");
4263+
Vec<ASR::call_arg_t> args;
4264+
args.reserve(al, 1);
4265+
ASR::call_arg_t arg;
4266+
arg.loc = x.base.base.loc;
4267+
arg.m_value = se;
4268+
args.push_back(al, arg);
4269+
tmp = make_call_helper(al, fn_div, current_scope, args, "_lpython_str_lower", x.base.base.loc);
4270+
return;
4271+
}
4272+
}
42424273
handle_attribute(se, at->m_attr, x.base.base.loc, eles);
42434274
return;
42444275
}
@@ -4272,6 +4303,39 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
42724303
throw SemanticError("'int' object has no attribute '" + std::string(at->m_attr) + "'",
42734304
x.base.base.loc);
42744305
}
4306+
} else if (AST::is_a<AST::ConstantStr_t>(*at->m_value)) {
4307+
if (std::string(at->m_attr) == std::string("capitalize")) {
4308+
if(args.size() != 0) {
4309+
throw SemanticError("str.capitalize() takes no arguments",
4310+
x.base.base.loc);
4311+
}
4312+
AST::ConstantStr_t *n = AST::down_cast<AST::ConstantStr_t>(at->m_value);
4313+
std::string res = n->m_value;
4314+
res[0] = toupper(res[0]);
4315+
ASR::ttype_t *str_type = ASRUtils::TYPE(ASR::make_Character_t(al, x.base.base.loc,
4316+
1, 1, nullptr, nullptr , 0));
4317+
tmp = ASR::make_StringConstant_t(al, x.base.base.loc, s2c(al, res), str_type);
4318+
return;
4319+
} else if (std::string(at->m_attr) == std::string("lower")) {
4320+
if(args.size() != 0) {
4321+
throw SemanticError("str.lower() takes no arguments",
4322+
x.base.base.loc);
4323+
}
4324+
AST::ConstantStr_t *n = AST::down_cast<AST::ConstantStr_t>(at->m_value);
4325+
std::string res = n->m_value;
4326+
for (auto &i : res) {
4327+
if (i >= 'A' && i<= 'Z') {
4328+
i = tolower(i);
4329+
}
4330+
}
4331+
ASR::ttype_t *str_type = ASRUtils::TYPE(ASR::make_Character_t(al, x.base.base.loc,
4332+
1, 1, nullptr, nullptr , 0));
4333+
tmp = ASR::make_StringConstant_t(al, x.base.base.loc, s2c(al, res), str_type);
4334+
return;
4335+
} else {
4336+
throw SemanticError("'str' object has no attribute '" + std::string(at->m_attr) + "'",
4337+
x.base.base.loc);
4338+
}
42754339
} else {
42764340
throw SemanticError("Only Name type and constant integers supported in Call",
42774341
x.base.base.loc);

src/lpython/semantics/python_comptime_eval.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ struct PythonIntrinsicProcedures {
6161
{"_lpython_floordiv", {m_builtin, &eval__lpython_floordiv}},
6262
{"_mod", {m_builtin, &eval__mod}},
6363
{"max" , {m_builtin , &eval_max}},
64-
{"min" , {m_builtin , &eval_min}}
64+
{"min" , {m_builtin , &eval_min}},
65+
{"_lpython_str_capitalize", {m_builtin, &eval__lpython_str_capitalize}},
66+
{"_lpython_str_lower", {m_builtin, &eval__lpython_str_lower}}
67+
6568
};
6669
}
6770

@@ -650,6 +653,41 @@ struct PythonIntrinsicProcedures {
650653

651654
}
652655

656+
static ASR::expr_t *eval__lpython_str_capitalize(Allocator &al, const Location &loc, Vec<ASR::expr_t *> &args) {
657+
LFORTRAN_ASSERT(ASRUtils::all_args_evaluated(args));
658+
if (args.size() != 0) {
659+
throw SemanticError("str.capitalize() takes no arguments", loc);
660+
}
661+
ASR::expr_t *arg = args[0];
662+
ASR::ttype_t *arg_type = ASRUtils::expr_type(arg);
663+
std::string val = ASR::down_cast<ASR::StringConstant_t>(arg)->m_s;
664+
if (val.size()) {
665+
val[0] = std::toupper(val[0]);
666+
}
667+
ASR::ttype_t *type = ASRUtils::TYPE(ASR::make_Character_t(al, loc,
668+
1, 1, nullptr, nullptr, 0));
669+
ASR::ttype_t *res_type = ASRUtils::TYPE(ASR::make_StringConstant_t(al, loc, s2c(al, ""), type));
670+
return ASR::down_cast<ASR::expr_t>(ASR::make_StringConstant_t(al, loc, s2c(al, val), res_type));
671+
}
672+
673+
static ASR::expr_t *eval__lpython_str_lower(Allocator &al, const Location &loc, Vec<ASR::expr_t *> &args) {
674+
LFORTRAN_ASSERT(ASRUtils::all_args_evaluated(args));
675+
if (args.size() != 0) {
676+
throw SemanticError("str.lower() takes no arguments", loc);
677+
}
678+
ASR::expr_t *arg = args[0];
679+
ASR::ttype_t *arg_type = ASRUtils::expr_type(arg);
680+
std::string val = ASR::down_cast<ASR::StringConstant_t>(arg)->m_s;
681+
for (auto &i: val) {
682+
if (i >= 'A' && i <= 'Z') {
683+
i = std::tolower(i);
684+
}
685+
}
686+
ASR::ttype_t *type = ASRUtils::TYPE(ASR::make_Character_t(al, loc,
687+
1, 1, nullptr, nullptr, 0));
688+
ASR::ttype_t *res_type = ASRUtils::TYPE(ASR::make_StringConstant_t(al, loc, s2c(al, ""), type));
689+
return ASR::down_cast<ASR::expr_t>(ASR::make_StringConstant_t(al, loc, s2c(al, val), res_type));
690+
}
653691

654692

655693
}; // ComptimeEval

src/runtime/lpython_builtin.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,26 @@ def pow(x: i64, y: i64, z: i64) -> i64:
613613
result: i64
614614
result = _mod(x**y, z)
615615
return result
616+
617+
@overload
618+
def _lpython_str_capitalize(x: str) -> str:
619+
if len(x) == 0:
620+
return x
621+
val: i32
622+
val = ord(x[0])
623+
if val >= ord('a') and val <= ord('x'):
624+
val -= 32
625+
x = chr(val) + x[1:]
626+
return x
627+
628+
@overload
629+
def _lpython_str_lower(x: str) ->str:
630+
res: str
631+
res = ""
632+
i:str
633+
for i in x:
634+
if ord('A') <= ord(i) and ord('Z') >= ord(i):
635+
res += chr(ord(i) +32)
636+
else:
637+
res += i
638+
return res

tests/errors/test_str_capitalize.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
def ff():
2+
s: str
3+
s = "empty"
4+
s = s.capitalize(23)
5+
print(s)
6+
7+
8+
ff()

tests/reference/asr-complex1-f26c460.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"outfile": null,
77
"outfile_hash": null,
88
"stdout": "asr-complex1-f26c460.stdout",
9-
"stdout_hash": "b9a56d837eec6123cbb7457d37b8d259d2429cb64a3506842ad2910e",
9+
"stdout_hash": "0fb9cae39aefa01c8744f5657e256f05bb9efa74fefed59000535758",
1010
"stderr": null,
1111
"stderr_hash": null,
1212
"returncode": 0

0 commit comments

Comments
 (0)