diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 7f1c976aaa..a02636a0a9 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -766,6 +766,7 @@ RUN(NAME func_static_02 LABELS cpython llvm c wasm) RUN(NAME func_dep_03 LABELS cpython llvm c) RUN(NAME func_dep_04 LABELS cpython llvm c) RUN(NAME func_internal_def_01 LABELS cpython llvm NOFAST) +RUN(NAME func_01 LABELS cpython llvm) RUN(NAME float_01 LABELS cpython llvm c wasm wasm_x64) RUN(NAME recursive_01 LABELS cpython llvm c wasm wasm_x64 wasm_x86) diff --git a/integration_tests/func_01.py b/integration_tests/func_01.py new file mode 100644 index 0000000000..0230bfcac2 --- /dev/null +++ b/integration_tests/func_01.py @@ -0,0 +1,14 @@ +from lpython import i32, InOut + +def reserve(a: InOut[list[i32]], b: i32): + a.append(b) + print("user defined reserve() called") + +def main0(): + x: list[i32] = [] + reserve(x, 5) + + assert len(x) == 1 + assert x[0] == 5 + +main0() diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index d20a338dec..471b86b42e 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -1168,7 +1168,7 @@ class CommonVisitor : public AST::BaseVisitor { // generic symbol then it changes the name accordingly. ASR::asr_t* make_call_helper(Allocator &al, ASR::symbol_t* s, SymbolTable *current_scope, Vec args, std::string call_name, const Location &loc, - bool ignore_return_value=false, AST::expr_t** pos_args=nullptr, size_t n_pos_args=0, + AST::expr_t** pos_args=nullptr, size_t n_pos_args=0, AST::keyword_t* kwargs=nullptr, size_t n_kwargs=0) { if (intrinsic_node_handler.is_present(call_name)) { return intrinsic_node_handler.get_intrinsic_node(call_name, al, loc, @@ -1293,7 +1293,7 @@ class CommonVisitor : public AST::BaseVisitor { new_call_arg.loc = args.p[i].loc; new_args.push_back(al, new_call_arg); } - return make_call_helper(al, t, current_scope, new_args, new_call_name, loc, ignore_return_value); + return make_call_helper(al, t, current_scope, new_args, new_call_name, loc); } if (args.size() != func->n_args) { std::string fnd = std::to_string(args.size()); @@ -1326,14 +1326,9 @@ class CommonVisitor : public AST::BaseVisitor { visit_expr_list_with_cast(func->m_args, func->n_args, args_new, args, !ASRUtils::is_intrinsic_function2(func)); dependencies.push_back(al, ASRUtils::symbol_name(stemp)); - ASR::asr_t* func_call_asr = ASRUtils::make_FunctionCall_t_util(al, loc, stemp, + return ASRUtils::make_FunctionCall_t_util(al, loc, stemp, s_generic, args_new.p, args_new.size(), a_type, value, nullptr); - if( ignore_return_value ) { - return make_dummy_assignment(ASRUtils::EXPR(func_call_asr)); - } else { - return func_call_asr; - } } else { Vec args_new; args_new.reserve(al, func->n_args); @@ -6657,112 +6652,7 @@ class BodyVisitor : public CommonVisitor { void visit_Expr(const AST::Expr_t &x) { if (AST::is_a(*x.m_value)) { AST::Call_t *c = AST::down_cast(x.m_value); - std::string call_name; - if (AST::is_a(*c->m_func)) { - AST::Name_t *n = AST::down_cast(c->m_func); - call_name = n->m_id; - ASR::symbol_t* s = current_scope->resolve_symbol(call_name); - if( call_name == "p_c_pointer" && !s ) { - tmp = create_PointerToCPtr(*c); - return; - } - } else if (AST::is_a(*c->m_func)) { - Vec args; - parse_args(*c, args); - AST::Attribute_t *at = AST::down_cast(c->m_func); - handle_attribute(at, args, x.base.base.loc); - return; - } else { - throw SemanticError("Only Name/Attribute supported in Call", - x.base.base.loc); - } - - Vec args; - // Keyword arguments to be handled in make_call_helper - args.reserve(al, c->n_args); - visit_expr_list(c->m_args, c->n_args, args); - // TODO: Avoid overriding of user defined functions with same name as - // intrinsics like print, quit and reserve. Right now, user defined - // functions will never be considered. - if (call_name == "print") { - ASR::expr_t *fmt = nullptr; - Vec args_expr = ASRUtils::call_arg2expr(al, args); - ASR::expr_t *separator = nullptr; - ASR::expr_t *end = nullptr; - if (c->n_keywords > 0) { - std::string arg_name; - for (size_t i = 0; i < c->n_keywords; i++) { - arg_name = c->m_keywords[i].m_arg; - if (arg_name == "sep") { - visit_expr(*c->m_keywords[i].m_value); - separator = ASRUtils::EXPR(tmp); - ASR::ttype_t *type = ASRUtils::expr_type(separator); - if (!ASRUtils::is_character(*type)) { - std::string found = ASRUtils::type_to_str(type); - diag.add(diag::Diagnostic( - "Separator is expected to be of string type", - diag::Level::Error, diag::Stage::Semantic, { - diag::Label("Expected string, found: " + found, - {separator->base.loc}) - }) - ); - throw SemanticAbort(); - } - } - if (arg_name == "end") { - visit_expr(*c->m_keywords[i].m_value); - end = ASRUtils::EXPR(tmp); - ASR::ttype_t *type = ASRUtils::expr_type(end); - if (!ASRUtils::is_character(*type)) { - std::string found = ASRUtils::type_to_str(type); - diag.add(diag::Diagnostic( - "End is expected to be of string type", - diag::Level::Error, diag::Stage::Semantic, { - diag::Label("Expected string, found: " + found, - {end->base.loc}) - }) - ); - throw SemanticAbort(); - } - } - } - } - tmp = ASR::make_Print_t(al, x.base.base.loc, fmt, - args_expr.p, args_expr.size(), separator, end); - return; - - } else if (call_name == "quit") { - ASR::expr_t *code; - if (args.size() == 0) { - code = nullptr; - } else if (args.size() == 1) { - code = args[0].m_value; - } else { - throw SemanticError("The function quit() requires 0 or 1 arguments", - x.base.base.loc); - } - tmp = ASR::make_Stop_t(al, x.base.base.loc, code); - return; - } else if( call_name == "reserve" ) { - ASRUtils::create_intrinsic_function create_func = - ASRUtils::IntrinsicScalarFunctionRegistry::get_create_function("reserve"); - Vec args_exprs; args_exprs.reserve(al, args.size()); - for( size_t i = 0; i < args.size(); i++ ) { - args_exprs.push_back(al, args[i].m_value); - } - tmp = create_func(al, x.base.base.loc, args_exprs, - [&](const std::string &msg, const Location &loc) { - throw SemanticError(msg, loc); }); - return ; - } - ASR::symbol_t *s = current_scope->resolve_symbol(call_name); - if (!s) { - throw SemanticError("Function '" + call_name + "' is not declared", - x.base.base.loc); - } - tmp = make_call_helper(al, s, current_scope, args, call_name, - x.base.base.loc, true, c->m_args, c->n_args, c->m_keywords, - c->n_keywords); + visit_Call(*c); return; } this->visit_expr(*x.m_value); @@ -7524,12 +7414,78 @@ class BodyVisitor : public CommonVisitor { /* throw SemanticError("The function '" + call_name + "' is not declared and not intrinsic", x.base.base.loc); - } - if (false) { */ - // This will all be removed once we port it to intrinsic functions - // Intrinsic functions - if (call_name == "size") { + if (call_name == "print") { + args.reserve(al, x.n_args); + visit_expr_list(x.m_args, x.n_args, args); + ASR::expr_t *fmt = nullptr; + Vec args_expr = ASRUtils::call_arg2expr(al, args); + ASR::expr_t *separator = nullptr; + ASR::expr_t *end = nullptr; + if (x.n_keywords > 0) { + std::string arg_name; + for (size_t i = 0; i < x.n_keywords; i++) { + arg_name = x.m_keywords[i].m_arg; + if (arg_name == "sep") { + visit_expr(*x.m_keywords[i].m_value); + separator = ASRUtils::EXPR(tmp); + ASR::ttype_t *type = ASRUtils::expr_type(separator); + if (!ASRUtils::is_character(*type)) { + std::string found = ASRUtils::type_to_str(type); + diag.add(diag::Diagnostic( + "Separator is expected to be of string type", + diag::Level::Error, diag::Stage::Semantic, { + diag::Label("Expected string, found: " + found, + {separator->base.loc}) + }) + ); + throw SemanticAbort(); + } + } + if (arg_name == "end") { + visit_expr(*x.m_keywords[i].m_value); + end = ASRUtils::EXPR(tmp); + ASR::ttype_t *type = ASRUtils::expr_type(end); + if (!ASRUtils::is_character(*type)) { + std::string found = ASRUtils::type_to_str(type); + diag.add(diag::Diagnostic( + "End is expected to be of string type", + diag::Level::Error, diag::Stage::Semantic, { + diag::Label("Expected string, found: " + found, + {end->base.loc}) + }) + ); + throw SemanticAbort(); + } + } + } + } + tmp = ASR::make_Print_t(al, x.base.base.loc, fmt, + args_expr.p, args_expr.size(), separator, end); + return; + } else if (call_name == "quit") { + parse_args(x, args); + ASR::expr_t *code; + if (args.size() == 0) { + code = nullptr; + } else if (args.size() == 1) { + code = args[0].m_value; + } else { + throw SemanticError("The function quit() requires 0 or 1 arguments", + x.base.base.loc); + } + tmp = ASR::make_Stop_t(al, x.base.base.loc, code); + return; + } else if( call_name == "reserve" ) { + parse_args(x, args); + ASRUtils::create_intrinsic_function create_func = + ASRUtils::IntrinsicScalarFunctionRegistry::get_create_function("reserve"); + Vec args_exprs = ASRUtils::call_arg2expr(al, args); + tmp = create_func(al, x.base.base.loc, args_exprs, + [&](const std::string &msg, const Location &loc) { + throw SemanticError(msg, loc); }); + return ; + } else if (call_name == "size") { parse_args(x, args); if( args.size() < 1 || args.size() > 2 ) { throw SemanticError("array accepts only 1 (arr) or 2 (arr, axis) arguments, got " + @@ -7555,6 +7511,9 @@ class BodyVisitor : public CommonVisitor { } else if (call_name == "c_p_pointer") { tmp = create_CPtrToPointer(x); return; + } else if( call_name == "p_c_pointer" && !s ) { + tmp = create_PointerToCPtr(x); + return; } else if (call_name == "empty_c_void_p") { // TODO: check that `empty_c_void_p uses` has arguments that are compatible // with the type @@ -7860,7 +7819,7 @@ class BodyVisitor : public CommonVisitor { parse_args(x, args); tmp = make_call_helper(al, s, current_scope, args, call_name, x.base.base.loc, - false, x.m_args, x.n_args, x.m_keywords, x.n_keywords); + x.m_args, x.n_args, x.m_keywords, x.n_keywords); } void visit_Global(const AST::Global_t &/*x*/) {