From 9374feb17362d8046db1e4060d633f7ff9887100 Mon Sep 17 00:00:00 2001 From: tanay-man <93091118+tanay-man@users.noreply.github.com> Date: Wed, 31 Jul 2024 20:34:01 +0530 Subject: [PATCH] Added support for multi-level attribute for function call (#2794) --- integration_tests/CMakeLists.txt | 1 + integration_tests/class_04.py | 46 +++++++++++++++++++ src/libasr/codegen/asr_to_llvm.cpp | 2 + src/libasr/codegen/llvm_utils.cpp | 3 +- src/lpython/semantics/python_ast_to_asr.cpp | 46 ++++++++++++++++++- tests/errors/{class_04.py => class01.py} | 2 +- tests/reference/asr-class01-4134616.json | 13 ++++++ ...178d.stderr => asr-class01-4134616.stderr} | 2 +- tests/reference/asr-class_04-b89178d.json | 13 ------ tests/tests.toml | 2 +- 10 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 integration_tests/class_04.py rename tests/errors/{class_04.py => class01.py} (94%) create mode 100644 tests/reference/asr-class01-4134616.json rename tests/reference/{asr-class_04-b89178d.stderr => asr-class01-4134616.stderr} (78%) delete mode 100644 tests/reference/asr-class_04-b89178d.json diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 7b0b20a13f..52ccd6d074 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -838,6 +838,7 @@ RUN(NAME c_mangling LABELS cpython llvm llvm_jit c) RUN(NAME class_01 LABELS cpython llvm llvm_jit) RUN(NAME class_02 LABELS cpython llvm llvm_jit) RUN(NAME class_03 LABELS cpython llvm llvm_jit) +RUN(NAME class_04 LABELS cpython llvm llvm_jit) # callback_04 is to test emulation. So just run with cpython RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython) diff --git a/integration_tests/class_04.py b/integration_tests/class_04.py new file mode 100644 index 0000000000..7798526331 --- /dev/null +++ b/integration_tests/class_04.py @@ -0,0 +1,46 @@ +from lpython import i32 +class Person: + def __init__(self:"Person", first:str, last:str, birthyear:i32, sgender:str): + self.first:str = first + self.last:str = last + self.birthyear:i32 = birthyear + self.sgender:str = sgender + + def describe(self:"Person"): + print("first: " + self.first) + print("last: " + self.last) + print("birthyear: " + str(self.birthyear)) + print("sgender: " + self.sgender) + +class Employee: + def __init__(self:"Employee", person:Person, hire_date:i32, department:str): + self.person:Person = person + self.hire_date:i32 = hire_date + self.department:str = department + + def describe(self:"Employee"): + self.person.describe() + print("hire_date: " + str(self.hire_date)) + print("department: " + self.department) + +def main(): + jack:Person = Person("Jack", "Smith", 1984, "M") + jill_p:Person = Person("Jill", "Smith", 1984, "F") + jill:Employee = Employee(jill_p, 2003, "sales") + + jack.describe() + assert jack.first == "Jack" + assert jack.last == "Smith" + assert jack.birthyear == 1984 + assert jack.sgender == "M" + + jill.describe() + assert jill.person.first == "Jill" + assert jill.person.last == "Smith" + assert jill.person.birthyear == 1984 + assert jill.person.sgender == "F" + assert jill.department == "sales" + assert jill.hire_date == 2003 + +if __name__ == '__main__': + main() diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 5f94cfd379..407be4083b 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -3169,7 +3169,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor visit_EnumType(*et); } else if (is_a(*item.second)) { ASR::Struct_t *st = down_cast(item.second); + mangle_prefix = mangle_prefix + "__class_" + st->m_name + "_"; instantiate_methods(*st); + mangle_prefix = "__module_" + std::string(x.m_name) + "_"; } } finish_module_init_function_prototype(x); diff --git a/src/libasr/codegen/llvm_utils.cpp b/src/libasr/codegen/llvm_utils.cpp index 9ba3acfe10..c49640329f 100644 --- a/src/libasr/codegen/llvm_utils.cpp +++ b/src/libasr/codegen/llvm_utils.cpp @@ -1960,7 +1960,8 @@ namespace LCompilers { while( struct_type_t != nullptr ) { for( auto item: struct_type_t->m_symtab->get_scope() ) { if( ASR::is_a(*item.second) || - ASR::is_a(*item.second) ) { + ASR::is_a(*item.second) || + ASR::is_a(*item.second) ) { continue ; } std::string mem_name = item.first; diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 4e32544167..24daf36684 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -2956,7 +2956,8 @@ class CommonVisitor : public AST::BaseVisitor { } void get_members_init (const AST::FunctionDef_t &x, - Vec& member_names, Vec &member_init){ + Vec& member_names, Vec &member_init, + SetChar& struct_dependencies){ if(x.n_decorator_list > 0) { throw SemanticError("Decorators for __init__ not implemented", x.base.base.loc); @@ -2997,6 +2998,22 @@ class CommonVisitor : public AST::BaseVisitor { c_arg.loc = var_sym->base.loc; c_arg.m_value = nullptr; member_init.push_back(al, c_arg); + ASR::ttype_t* var_type = ASRUtils::type_get_past_pointer(ASRUtils::symbol_type(var_sym)); + char* aggregate_type_name = nullptr; + if( ASR::is_a(*var_type) ) { + aggregate_type_name = ASRUtils::symbol_name( + ASR::down_cast(var_type)->m_derived_type); + } else if( ASR::is_a(*var_type) ) { + aggregate_type_name = ASRUtils::symbol_name( + ASR::down_cast(var_type)->m_enum_type); + } else if( ASR::is_a(*var_type) ) { + aggregate_type_name = ASRUtils::symbol_name( + ASR::down_cast(var_type)->m_union_type); + } + if( aggregate_type_name && + !current_scope->get_symbol(std::string(aggregate_type_name)) ) { + struct_dependencies.push_back(al, aggregate_type_name); + } } } @@ -3027,7 +3044,7 @@ class CommonVisitor : public AST::BaseVisitor { *f = AST::down_cast(x.m_body[i]); std::string f_name = f->m_name; if (f_name == "__init__") { - this->get_members_init(*f, member_names, member_init); + this->get_members_init(*f, member_names, member_init, struct_dependencies); this->visit_stmt(*x.m_body[i]); member_fn_names.push_back(al, f->m_name); } else { @@ -8244,6 +8261,31 @@ we will have to use something else. } handle_builtin_attribute(subscript_expr, at->m_attr, loc, eles); return; + } else if ( AST::is_a(*at->m_value) ) { + AST::Attribute_t* at_m_value = AST::down_cast(at->m_value); + visit_Attribute(*at_m_value); + ASR::expr_t* e = ASRUtils::EXPR(tmp); + if ( !ASR::is_a(*e) ) { + throw SemanticError("Expected a class variable here", loc); + } + if ( !ASR::is_a(*ASRUtils::expr_type(e)) ) { + throw SemanticError("Only Classes supported in nested attribute call", loc); + } + ASR::StructType_t* der = ASR::down_cast(ASRUtils::expr_type(e)); + ASR::symbol_t* der_sym = ASRUtils::symbol_get_past_external(der->m_derived_type); + std::string call_name = at->m_attr; + + Vec new_args; new_args.reserve(al, args.n + 1); + ASR::call_arg_t self_arg; + self_arg.loc = args[0].loc; + self_arg.m_value = e; + new_args.push_back(al, self_arg); + for (size_t i=0; i tests/errors/class_04.py:9:1 + --> tests/errors/class01.py:9:1 | 9 | p2: coord = p1 | ^^^^^^^^^^^^^^ diff --git a/tests/reference/asr-class_04-b89178d.json b/tests/reference/asr-class_04-b89178d.json deleted file mode 100644 index b0422ead8a..0000000000 --- a/tests/reference/asr-class_04-b89178d.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "basename": "asr-class_04-b89178d", - "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", - "infile": "tests/errors/class_04.py", - "infile_hash": "e1e1c48050cce1b2855e4f8409aa3d72df716f61b8aa045aa97ae914", - "outfile": null, - "outfile_hash": null, - "stdout": null, - "stdout_hash": null, - "stderr": "asr-class_04-b89178d.stderr", - "stderr_hash": "7f8e807f5582952b4ad93b1fb3d4d264842a0700aeda5be00611d098", - "returncode": 2 -} \ No newline at end of file diff --git a/tests/tests.toml b/tests/tests.toml index 452a018a43..8969f43c8b 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -362,7 +362,7 @@ pass = "class_constructor" cumulative = true [[test]] -filename = "errors/class_04.py" +filename = "errors/class01.py" asr = true [[test]]