Skip to content

Commit 9374feb

Browse files
authored
Added support for multi-level attribute for function call (#2794)
1 parent 42f385f commit 9374feb

File tree

10 files changed

+111
-19
lines changed

10 files changed

+111
-19
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ RUN(NAME c_mangling LABELS cpython llvm llvm_jit c)
838838
RUN(NAME class_01 LABELS cpython llvm llvm_jit)
839839
RUN(NAME class_02 LABELS cpython llvm llvm_jit)
840840
RUN(NAME class_03 LABELS cpython llvm llvm_jit)
841+
RUN(NAME class_04 LABELS cpython llvm llvm_jit)
841842

842843
# callback_04 is to test emulation. So just run with cpython
843844
RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython)

integration_tests/class_04.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from lpython import i32
2+
class Person:
3+
def __init__(self:"Person", first:str, last:str, birthyear:i32, sgender:str):
4+
self.first:str = first
5+
self.last:str = last
6+
self.birthyear:i32 = birthyear
7+
self.sgender:str = sgender
8+
9+
def describe(self:"Person"):
10+
print("first: " + self.first)
11+
print("last: " + self.last)
12+
print("birthyear: " + str(self.birthyear))
13+
print("sgender: " + self.sgender)
14+
15+
class Employee:
16+
def __init__(self:"Employee", person:Person, hire_date:i32, department:str):
17+
self.person:Person = person
18+
self.hire_date:i32 = hire_date
19+
self.department:str = department
20+
21+
def describe(self:"Employee"):
22+
self.person.describe()
23+
print("hire_date: " + str(self.hire_date))
24+
print("department: " + self.department)
25+
26+
def main():
27+
jack:Person = Person("Jack", "Smith", 1984, "M")
28+
jill_p:Person = Person("Jill", "Smith", 1984, "F")
29+
jill:Employee = Employee(jill_p, 2003, "sales")
30+
31+
jack.describe()
32+
assert jack.first == "Jack"
33+
assert jack.last == "Smith"
34+
assert jack.birthyear == 1984
35+
assert jack.sgender == "M"
36+
37+
jill.describe()
38+
assert jill.person.first == "Jill"
39+
assert jill.person.last == "Smith"
40+
assert jill.person.birthyear == 1984
41+
assert jill.person.sgender == "F"
42+
assert jill.department == "sales"
43+
assert jill.hire_date == 2003
44+
45+
if __name__ == '__main__':
46+
main()

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3169,7 +3169,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
31693169
visit_EnumType(*et);
31703170
} else if (is_a<ASR::Struct_t>(*item.second)) {
31713171
ASR::Struct_t *st = down_cast<ASR::Struct_t>(item.second);
3172+
mangle_prefix = mangle_prefix + "__class_" + st->m_name + "_";
31723173
instantiate_methods(*st);
3174+
mangle_prefix = "__module_" + std::string(x.m_name) + "_";
31733175
}
31743176
}
31753177
finish_module_init_function_prototype(x);

src/libasr/codegen/llvm_utils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1960,7 +1960,8 @@ namespace LCompilers {
19601960
while( struct_type_t != nullptr ) {
19611961
for( auto item: struct_type_t->m_symtab->get_scope() ) {
19621962
if( ASR::is_a<ASR::ClassProcedure_t>(*item.second) ||
1963-
ASR::is_a<ASR::CustomOperator_t>(*item.second) ) {
1963+
ASR::is_a<ASR::CustomOperator_t>(*item.second) ||
1964+
ASR::is_a<ASR::Function_t>(*item.second) ) {
19641965
continue ;
19651966
}
19661967
std::string mem_name = item.first;

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,8 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
29562956
}
29572957

29582958
void get_members_init (const AST::FunctionDef_t &x,
2959-
Vec<char*>& member_names, Vec<ASR::call_arg_t> &member_init){
2959+
Vec<char*>& member_names, Vec<ASR::call_arg_t> &member_init,
2960+
SetChar& struct_dependencies){
29602961
if(x.n_decorator_list > 0) {
29612962
throw SemanticError("Decorators for __init__ not implemented",
29622963
x.base.base.loc);
@@ -2997,6 +2998,22 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
29972998
c_arg.loc = var_sym->base.loc;
29982999
c_arg.m_value = nullptr;
29993000
member_init.push_back(al, c_arg);
3001+
ASR::ttype_t* var_type = ASRUtils::type_get_past_pointer(ASRUtils::symbol_type(var_sym));
3002+
char* aggregate_type_name = nullptr;
3003+
if( ASR::is_a<ASR::StructType_t>(*var_type) ) {
3004+
aggregate_type_name = ASRUtils::symbol_name(
3005+
ASR::down_cast<ASR::StructType_t>(var_type)->m_derived_type);
3006+
} else if( ASR::is_a<ASR::Enum_t>(*var_type) ) {
3007+
aggregate_type_name = ASRUtils::symbol_name(
3008+
ASR::down_cast<ASR::Enum_t>(var_type)->m_enum_type);
3009+
} else if( ASR::is_a<ASR::Union_t>(*var_type) ) {
3010+
aggregate_type_name = ASRUtils::symbol_name(
3011+
ASR::down_cast<ASR::Union_t>(var_type)->m_union_type);
3012+
}
3013+
if( aggregate_type_name &&
3014+
!current_scope->get_symbol(std::string(aggregate_type_name)) ) {
3015+
struct_dependencies.push_back(al, aggregate_type_name);
3016+
}
30003017
}
30013018
}
30023019

@@ -3027,7 +3044,7 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
30273044
*f = AST::down_cast<AST::FunctionDef_t>(x.m_body[i]);
30283045
std::string f_name = f->m_name;
30293046
if (f_name == "__init__") {
3030-
this->get_members_init(*f, member_names, member_init);
3047+
this->get_members_init(*f, member_names, member_init, struct_dependencies);
30313048
this->visit_stmt(*x.m_body[i]);
30323049
member_fn_names.push_back(al, f->m_name);
30333050
} else {
@@ -8244,6 +8261,31 @@ we will have to use something else.
82448261
}
82458262
handle_builtin_attribute(subscript_expr, at->m_attr, loc, eles);
82468263
return;
8264+
} else if ( AST::is_a<AST::Attribute_t>(*at->m_value) ) {
8265+
AST::Attribute_t* at_m_value = AST::down_cast<AST::Attribute_t>(at->m_value);
8266+
visit_Attribute(*at_m_value);
8267+
ASR::expr_t* e = ASRUtils::EXPR(tmp);
8268+
if ( !ASR::is_a<ASR::StructInstanceMember_t>(*e) ) {
8269+
throw SemanticError("Expected a class variable here", loc);
8270+
}
8271+
if ( !ASR::is_a<ASR::StructType_t>(*ASRUtils::expr_type(e)) ) {
8272+
throw SemanticError("Only Classes supported in nested attribute call", loc);
8273+
}
8274+
ASR::StructType_t* der = ASR::down_cast<ASR::StructType_t>(ASRUtils::expr_type(e));
8275+
ASR::symbol_t* der_sym = ASRUtils::symbol_get_past_external(der->m_derived_type);
8276+
std::string call_name = at->m_attr;
8277+
8278+
Vec<ASR::call_arg_t> new_args; new_args.reserve(al, args.n + 1);
8279+
ASR::call_arg_t self_arg;
8280+
self_arg.loc = args[0].loc;
8281+
self_arg.m_value = e;
8282+
new_args.push_back(al, self_arg);
8283+
for (size_t i=0; i<args.n; i++) {
8284+
new_args.push_back(al, args[i]);
8285+
}
8286+
ASR::symbol_t* st = get_struct_member(der_sym, call_name, loc);
8287+
tmp = make_call_helper(al, st, current_scope, new_args, call_name, loc);
8288+
return;
82478289
} else {
82488290
throw SemanticError("Only Name type and constant integers supported in Call", loc);
82498291
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ def __init__(self:"coord", x:i32, y:i32):
99
p2: coord = p1
1010
p2.x = 2
1111
print(p1.x)
12-
print(p2.x)
12+
print(p2.x)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "asr-class01-4134616",
3+
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
4+
"infile": "tests/errors/class01.py",
5+
"infile_hash": "abc039698c8285a3831089abdd0cd9711894af57eb142d2222b3583d",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": null,
9+
"stdout_hash": null,
10+
"stderr": "asr-class01-4134616.stderr",
11+
"stderr_hash": "4f104cca0ef2ac39634223611165efee9d107c94292a98071d863ed0",
12+
"returncode": 2
13+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
semantic error: Only Class constructor is allowed in the object assignment for now
2-
--> tests/errors/class_04.py:9:1
2+
--> tests/errors/class01.py:9:1
33
|
44
9 | p2: coord = p1
55
| ^^^^^^^^^^^^^^

tests/reference/asr-class_04-b89178d.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/tests.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ pass = "class_constructor"
362362
cumulative = true
363363

364364
[[test]]
365-
filename = "errors/class_04.py"
365+
filename = "errors/class01.py"
366366
asr = true
367367

368368
[[test]]

0 commit comments

Comments
 (0)