Skip to content

Attempt to Impelent list.count() method without generics #1644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6008,6 +6008,39 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
tmp = ASR::make_StringConstant_t(al, loc, s2c(al, s_var), str_type);
}

void handle_list_attributes(ASR::expr_t *s_var,
Vec<ASR::call_arg_t> &args, std::string attr_name, const Location &loc) {
std::string fn_call_name = "";
Vec<ASR::call_arg_t> fn_args;
fn_args.reserve(al, 1);
if (attr_name == "count" ) {
if(args.size() != 1) {
throw SemanticError("list.count() takes one argument",
loc);
}
ASR::expr_t *arg_sub = args[0].m_value;
ASR::ttype_t *arg_sub_type = ASRUtils::expr_type(arg_sub);
if (!ASRUtils::is_integer(*arg_sub_type)) {
throw SemanticError("list.count() takes one argument of type: integer",
loc);
}
fn_call_name = "_lpython_list_count";
ASR::call_arg_t str;
str.loc = loc;
str.m_value = s_var;
ASR::call_arg_t sub;
sub.loc = loc;
sub.m_value = args[0].m_value;
fn_args.push_back(al, str);
fn_args.push_back(al, sub);

} else {
throw SemanticError("List method not implemented: " + attr_name, loc);
}
ASR::symbol_t *fn_call = resolve_intrinsic_function(loc, fn_call_name);
tmp = make_call_helper(al, fn_call, current_scope, fn_args, fn_call_name, loc);
}

void visit_Call(const AST::Call_t &x) {
std::string call_name = "";
Vec<ASR::call_arg_t> args;
Expand Down Expand Up @@ -6055,6 +6088,10 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
handle_string_attributes(se, args, at->m_attr, x.base.base.loc);
return;
}
if (ASR::is_a<ASR::List_t>(*(ASRUtils::expr_type(se)))) {
handle_list_attributes(se, args, at->m_attr, x.base.base.loc);
return;
}
handle_attribute(se, at->m_attr, x.base.base.loc, eles);
return;
}
Expand Down Expand Up @@ -6135,7 +6172,6 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
throw SemanticError("Only Name or Attribute type supported in Call",
x.base.base.loc);
}

ASR::symbol_t *s = current_scope->resolve_symbol(call_name);
if( s && ASR::is_a<ASR::Module_t>(*s) ) {
std::string mangled_name = ASRUtils::get_mangled_name(ASR::down_cast<ASR::Module_t>(s), call_name);
Expand Down
2 changes: 2 additions & 0 deletions src/lpython/semantics/python_comptime_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ struct PythonIntrinsicProcedures {
{"max" , {m_builtin , &eval_max}},
{"min" , {m_builtin , &eval_min}},
{"sum" , {m_builtin , &not_implemented}},
// List methods
{"_lpython_list_count", {m_builtin, &not_implemented}},
// The following functions for string methods are not used
// for evaluation.
{"_lpython_str_capitalize", {m_builtin, &not_implemented}},
Expand Down
11 changes: 11 additions & 0 deletions src/runtime/lpython_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,17 @@ def _lpython_str_find(s: str, sub: str) -> i32:

return res

@overload
def _lpython_list_count(l: list[i32], x: i32) -> i32:
count : i32
count = 0
i : i32
i = 0
for i in l:
if(i == x):
count = count + 1
return count
Comment on lines +746 to +755
Copy link
Collaborator

@czgdp1807 czgdp1807 Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well three approaches,

  1. Use generics - Very messy and not worth it at the moment.
  2. Use IntrinsicFunction infrastructure to programmatically generate the code for these functions and call it in intrinsic_functions.cpp pass.
  3. Insert a new node, ListCount(expr list, expr x) in ASR.asdl and implement it directly in LLVM backend.

Approach 3 is most doable right now and will generate the most efficient LLVM code. However to scale well across all backends, approach 2 is the best one but should be done later. There is no disadvantage in going for approach 3. Once approach 2 is implemented we can remove ListCount node easily. @certik What do you say?

P.S. @gptsarthak I would say don't worry much about my comment right now. Let's see what @certik has to say on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, 3 is fine, later we'll move to 2.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gptsarthak Go ahead with approach 3 for now.


def _lpython_str_rstrip(x: str) -> str:
ind: i32
ind = len(x) - 1
Expand Down