lcompilers / lpython

Python compiler
https://lpython.org/
Other
1.37k stars 156 forks source link

Added static methods for classes #2721

Open tanay-man opened 3 weeks ago

Thirumalai-Shaktivel commented 3 weeks ago

The design would be the following: Convert

class test:
    def fn():
        pass

to

StructType test  {
    class procedure :: fn => f
    def f:
        pass
}
Thirumalai-Shaktivel commented 3 weeks ago

Here is the simple example from LFortran for member function:

module m

type t
    integer :: x
    integer :: y
contains
    procedure :: fn => f
end type t

contains

integer function f(this)
class(t), intent(in) :: this
end function

end module

program test
use m
implicit none

type(t) :: t1
print *, t1%fn()

end program test
Thirumalai-Shaktivel commented 3 weeks ago

Let's mark it as draft PR until it is ready to be merged.

Thirumalai-Shaktivel commented 2 weeks ago
diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantic
s/python_ast_to_asr.cpp
index 01031d704..8c9dd2dee 100644
--- a/src/lpython/semantics/python_ast_to_asr.cpp
+++ b/src/lpython/semantics/python_ast_to_asr.cpp
@@ -3194,12 +3194,14 @@ public:
                                 x.base.base.loc);
         }
         SymbolTable *parent_scope = current_scope;
-        ASR::symbol_t* clss_sym = current_scope->get_symbol(x_m_name);
+        ;
         ASR::StructType_t* clss = nullptr;
-        if(clss_sym != nullptr && !is_enum(x.m_bases, x.n_bases) && !is_union(
x.m_bases, x.n_bases)){
-            clss = ASR::down_cast<ASR::StructType_t>(clss_sym);
-            current_scope = clss->m_symtab;
-            is_generating_body = true;
+        if(ASR::symbol_t* clss_sym = current_scope->get_symbol(x_m_name) ) {
+            if ( is_a<ASR::StructType_t>(*clss_sym) ){
+                clss = ASR::down_cast<ASR::StructType_t>(clss_sym);
+                current_scope = clss->m_symtab;
+                is_generating_body = true;
+            }
Thirumalai-Shaktivel commented 2 weeks ago

Let's finish off this and move on to __init__ function in a new PR.

tanay-man commented 2 weeks ago

fixes #2722

certik commented 1 week ago

Static method typically means class method --- it doesn't access any members of the instance. I think in this case you mean a method that is not virtual?

How are class variables implemented in ASR --- can you show how the ASR looks like for the above class?

certik commented 1 week ago

Before we go too deep into this, I think we need to use Class for classes, not Struct.

Otherwise it will be hard to undo.

Thirumalai-Shaktivel commented 1 week ago

I forgot about the Class symbol and thought to represent ASR the same as LFortran. Sorry about that. Here is the ASR being generated:

ASR

```Clojure (TranslationUnit (SymbolTable 1 { __main__: (Module (SymbolTable 2 { Test: (StructType (SymbolTable 4 { fn_1: (Function (SymbolTable 5 { Test_fn_3: (ExternalSymbol 5 Test_fn_3 4 fn_3 Test [] fn_3 Public ) }) fn_1 (FunctionType [] () Source Implementation () .false. .false. .false. .false. .false. [] .false. ) [fn_2] [] [(Print [(StringConstant "Inside fn_1" (Character 1 11 ()) )] () () ) (Print [(StringConstant "fn_2 called" (Character 1 11 ()) )] () () ) (SubroutineCall 2 fn_2 () [] () ) (Print [(StringConstant "fn_3 called" (Character 1 11 ()) )] () () ) (SubroutineCall 5 Test_fn_3 () [] () ) (Return)] () Public .false. .false. () ), fn_3: (Function (SymbolTable 6 { }) fn_3 (FunctionType [] () Source Implementation () .false. .false. .false. .false. .false. [] .false. ) [] [] [(Print [(StringConstant "Inside fn_3" (Character 1 11 ()) )] () () )] () Public .false. .false. () ), mem: (Variable 4 mem [] Local () () Default (Integer 8) () Source Public Required .false. ), s: (Variable 4 s [] Local () () Default (Character 1 -2 ()) () Source Public Required .false. ) }) Test [] [mem s] Source Public .false. .false. [((Cast (IntegerConstant 5 (Integer 4)) IntegerToInteger (Integer 8) (IntegerConstant 5 (Integer 8)) )) ((StringConstant "abc" (Character 1 3 ()) ))] () () ), __main__global_stmts: (Function (SymbolTable 8 { }) __main__global_stmts (FunctionType [] () Source Implementation () .false. .false. .false. .false. .false. [] .false. ) [main] [] [(SubroutineCall 2 main () [] () )] () Public .false. .false. () ), fn_2: (Function (SymbolTable 3 { }) fn_2 (FunctionType [] () Source Implementation () .false. .false. .false. .false. .false. [] .false. ) [] [] [(Print [(StringConstant "Inside fn_2" (Character 1 11 ()) )] () () ) (Return)] () Public .false. .false. () ), main: (Function (SymbolTable 7 { Test_fn_1: (ExternalSymbol 7 Test_fn_1 4 fn_1 Test [] fn_1 Public ), t: (Variable 7 t [] Local () () Default (Struct 2 Test ) () Source Public Required .false. ) }) main (FunctionType [] () Source Implementation () .false. .false. .false. .false. .false. [] .false. ) [] [] [(Assignment (Var 7 t) (StructTypeConstructor 2 Test [((Cast (IntegerConstant 5 (Integer 4)) IntegerToInteger (Integer 8) (IntegerConstant 5 (Integer 8)) )) ((StringConstant "abc" (Character 1 3 ()) ))] (Struct 2 Test ) () ) () ) (Print [(StructInstanceMember (Var 7 t) 4 mem (Integer 8) () )] () () ) (Assert (IntegerCompare (StructInstanceMember (Var 7 t) 4 mem (Integer 8) () ) Eq (Cast (IntegerConstant 5 (Integer 4)) IntegerToInteger (Integer 8) (IntegerConstant 5 (Integer 8)) ) (Logical 4) () ) () ) (Print [(StructInstanceMember (Var 7 t) 4 s (Character 1 -2 ()) () )] () () ) (Assert (StringCompare (StructInstanceMember (Var 7 t) 4 s (Character 1 -2 ()) () ) Eq (StringConstant "abc" (Character 1 3 ()) ) (Logical 4) () ) () ) (SubroutineCall 7 Test_fn_1 () [] () )] () Public .false. .false. () ) }) __main__ [] .false. .false. ), main_program: (Program (SymbolTable 9 { __main__global_stmts: (ExternalSymbol 9 __main__global_stmts 2 __main__global_stmts __main__ [] __main__global_stmts Public ) }) main_program [__main__] [(SubroutineCall 9 __main__global_stmts 2 __main__global_stmts [] () )] ) }) [] ) ```

Thirumalai-Shaktivel commented 1 week ago

@tanay-man, as @certik suggested instead of StructType, we need to use ClassType (later we need to rename it to Class). I think you can work on a new branch.

Use is_dataclass function to check for the Struct.

tanay-man commented 1 week ago

Static method typically means class method --- it doesn't access any members of the instance. I think in this case you mean a method that is not virtual?

Currently due to 'self' not being implemented, we cannot access instance variables. I think static methods is correct.

Thirumalai-Shaktivel commented 1 week ago

Also, @tanay-man, as we have to create ClassType, we need it handle everywhere, like in asr_verify, declaration, Constructor, etc.