From 7a62a3a8754c4c9dee23a24f34a1c8cc7e22cd31 Mon Sep 17 00:00:00 2001 From: Tanay Manerikar Date: Tue, 23 Jul 2024 20:27:52 +0530 Subject: [PATCH 1/3] Temp --- integration_tests/class_04.py | 24 +++++++++++++++++++++ src/libasr/codegen/llvm_utils.cpp | 3 ++- src/lpython/semantics/python_ast_to_asr.cpp | 21 ++++++++++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 integration_tests/class_04.py diff --git a/integration_tests/class_04.py b/integration_tests/class_04.py new file mode 100644 index 0000000000..b99ca36c73 --- /dev/null +++ b/integration_tests/class_04.py @@ -0,0 +1,24 @@ +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 + +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 main(): + jack:Person = Person("Jack", "Smith", 1984, "M") + jill_p:Person = Person("Jill", "Smith", 1984, "F") + jill:Employee = Employee(jill_p, 2003, "sales") + + print(jack.first, jack.last, jack.birthyear, jack.sgender) + print(jill.person.first, jill.person.last, jill.person.birthyear, jill.person.sgender, jill.department, jill.hire_date) + +if __name__ == '__main__': + main() \ No newline at end of file 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 4715cf8857..0a0a3a1c24 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 { From 7679f9fd59f8c51d26224f36d47eaf0f5da33db7 Mon Sep 17 00:00:00 2001 From: Tanay Manerikar Date: Fri, 26 Jul 2024 20:02:20 +0530 Subject: [PATCH 2/3] Partial implementation of multi-attrib --- integration_tests/CMakeLists.txt | 1 + integration_tests/class_04.py | 24 ++++++++++++++++--- src/libasr/codegen/asr_to_llvm.cpp | 2 ++ src/lpython/semantics/python_ast_to_asr.cpp | 11 +++++++++ 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 +- 9 files changed, 51 insertions(+), 19 deletions(-) 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 f397765d18..5d5ec4bc7f 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -836,6 +836,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 index b99ca36c73..564f24bbf5 100644 --- a/integration_tests/class_04.py +++ b/integration_tests/class_04.py @@ -6,19 +6,37 @@ def __init__(self:"Person", first:str, last:str, birthyear:i32, sgender:str): self.birthyear:i32 = birthyear self.sgender:str = sgender + def describe_person(self:"Person") -> str: + print("Name: " + self.first + " " + self.last + "\n" + + "Birth Year: " + str(self.birthyear) + "\n" + + "Gender: " + self.sgender) + return ("Name: " + self.first + " " + self.last + "\n" + + "Birth Year: " + str(self.birthyear) + "\n" + + "Gender: " + 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_employee(self:"Employee"): + self.person.describe_person() + # print (desc_person + "\n" + + # "Hire Date: " + str(self.hire_date) + "\n" + + # "Department: " + self.department) + # return (desc_person + "\n" + + # "Hire Date: " + str(self.hire_date) + "\n" + + # "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") - print(jack.first, jack.last, jack.birthyear, jack.sgender) - print(jill.person.first, jill.person.last, jill.person.birthyear, jill.person.sgender, jill.department, jill.hire_date) + op1:str = jack.describe_person() + jill.describe_employee() if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 2e923e9f8e..69afad3358 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -3154,7 +3154,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/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 0a0a3a1c24..6fcb328336 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -8251,6 +8251,17 @@ 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* inner_at = AST::down_cast(at->m_value); + if ( AST::is_a(*inner_at->m_value) ) { + AST::Name_t *n = AST::down_cast(at->m_value); + std::string mod_name = n->m_id; + std::string call_name = at->m_attr; + std::string call_name_store = "__" + mod_name + "_" + call_name; + ASR::symbol_t *st = nullptr; + } + tmp = make_call_helper(al, st, current_scope, args, call_name, loc); + return; } else { throw SemanticError("Only Name type and constant integers supported in Call", loc); } diff --git a/tests/errors/class_04.py b/tests/errors/class01.py similarity index 94% rename from tests/errors/class_04.py rename to tests/errors/class01.py index c8380a7910..2b3a09ad67 100644 --- a/tests/errors/class_04.py +++ b/tests/errors/class01.py @@ -9,4 +9,4 @@ def __init__(self:"coord", x:i32, y:i32): p2: coord = p1 p2.x = 2 print(p1.x) -print(p2.x) \ No newline at end of file +print(p2.x) diff --git a/tests/reference/asr-class01-4134616.json b/tests/reference/asr-class01-4134616.json new file mode 100644 index 0000000000..1397e91314 --- /dev/null +++ b/tests/reference/asr-class01-4134616.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-class01-4134616", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/class01.py", + "infile_hash": "abc039698c8285a3831089abdd0cd9711894af57eb142d2222b3583d", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-class01-4134616.stderr", + "stderr_hash": "4f104cca0ef2ac39634223611165efee9d107c94292a98071d863ed0", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-class_04-b89178d.stderr b/tests/reference/asr-class01-4134616.stderr similarity index 78% rename from tests/reference/asr-class_04-b89178d.stderr rename to tests/reference/asr-class01-4134616.stderr index cff5dfbaca..e441e5e300 100644 --- a/tests/reference/asr-class_04-b89178d.stderr +++ b/tests/reference/asr-class01-4134616.stderr @@ -1,5 +1,5 @@ semantic error: Only Class constructor is allowed in the object assignment for now - --> 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]] From 90266d8b6dc7d86024f94afddda8ff53cfe96c9f Mon Sep 17 00:00:00 2001 From: Tanay Manerikar Date: Sun, 28 Jul 2024 12:46:08 +0530 Subject: [PATCH 3/3] Added multi-lvl attrs for fn call --- integration_tests/class_04.py | 44 +++++++++++---------- src/lpython/semantics/python_ast_to_asr.cpp | 36 +++++++++++------ 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/integration_tests/class_04.py b/integration_tests/class_04.py index 564f24bbf5..7798526331 100644 --- a/integration_tests/class_04.py +++ b/integration_tests/class_04.py @@ -5,38 +5,42 @@ def __init__(self:"Person", first:str, last:str, birthyear:i32, sgender:str): self.last:str = last self.birthyear:i32 = birthyear self.sgender:str = sgender - - def describe_person(self:"Person") -> str: - print("Name: " + self.first + " " + self.last + "\n" + - "Birth Year: " + str(self.birthyear) + "\n" + - "Gender: " + self.sgender) - return ("Name: " + self.first + " " + self.last + "\n" + - "Birth Year: " + str(self.birthyear) + "\n" + - "Gender: " + self.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_employee(self:"Employee"): - self.person.describe_person() - # print (desc_person + "\n" + - # "Hire Date: " + str(self.hire_date) + "\n" + - # "Department: " + self.department) - # return (desc_person + "\n" + - # "Hire Date: " + str(self.hire_date) + "\n" + - # "Department: " + self.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") - - op1:str = jack.describe_person() - jill.describe_employee() + + 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/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 6fcb328336..d15c593c59 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -8251,17 +8251,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* inner_at = AST::down_cast(at->m_value); - if ( AST::is_a(*inner_at->m_value) ) { - AST::Name_t *n = AST::down_cast(at->m_value); - std::string mod_name = n->m_id; - std::string call_name = at->m_attr; - std::string call_name_store = "__" + mod_name + "_" + call_name; - ASR::symbol_t *st = nullptr; - } - tmp = make_call_helper(al, st, current_scope, args, call_name, loc); - 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