Diferenças entre uma AST e uma ASR

Tomemos um simples código Fortran:

integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function

and look at what the AST and ASR look like.

AST

[1]:
%%showast
integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function
(TranslationUnit
    [(Function
        f
        [(a)
        (b)]
        [(AttrType
            TypeInteger
            []
            ()
            ()
            None
        )]
        r
        ()
        ()
        []
        []
        []
        [(Declaration
            (AttrType
                TypeInteger
                []
                ()
                ()
                None
            )
            [(AttrIntent
                In
            )]
            [(a
            []
            []
            ()
            ()
            None
            ())
            (b
            []
            []
            ()
            ()
            None
            ())]
            ()
        )
        (Declaration
            (AttrType
                TypeInteger
                []
                ()
                ()
                None
            )
            []
            [(c
            []
            []
            ()
            ()
            None
            ())
            (d
            []
            []
            ()
            ()
            None
            ())]
            ()
        )]
        [(Assignment
            0
            c
            (- (+ a b) d)
            ()
        )
        (Assignment
            0
            r
            (* c a)
            ()
        )]
        []
        []
    )]
)

A AST não possui nenhuma informação semântica, mas sim «nós» que representam declarações do tipo integer, intent(in) :: a. Variáveis como a são representadas pelo nó Name e ainda não estão conectadas às suas declarações.

The AST can also be exported in JSON, including source file name, line and column information: lfortran example.f90 --show-ast --json

ASR

[2]:
%%showasr
integer function f(a, b) result(r)
integer, intent(in) :: a, b
integer :: c, d
c = a + b - d
r = c * a
end function
(TranslationUnit
    (SymbolTable
        1
        {
            f:
                (Function
                    (SymbolTable
                        2
                        {
                            a:
                                (Variable
                                    2
                                    a
                                    []
                                    In
                                    ()
                                    ()
                                    Default
                                    (Integer 4)
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                    .false.
                                ),
                            b:
                                (Variable
                                    2
                                    b
                                    []
                                    In
                                    ()
                                    ()
                                    Default
                                    (Integer 4)
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                    .false.
                                ),
                            c:
                                (Variable
                                    2
                                    c
                                    []
                                    Local
                                    ()
                                    ()
                                    Default
                                    (Integer 4)
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                    .false.
                                ),
                            d:
                                (Variable
                                    2
                                    d
                                    []
                                    Local
                                    ()
                                    ()
                                    Default
                                    (Integer 4)
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                    .false.
                                ),
                            r:
                                (Variable
                                    2
                                    r
                                    []
                                    ReturnVar
                                    ()
                                    ()
                                    Default
                                    (Integer 4)
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                    .false.
                                )
                        })
                    f
                    (FunctionType
                        [(Integer 4)
                        (Integer 4)]
                        (Integer 4)
                        Source
                        Implementation
                        ()
                        .false.
                        .false.
                        .false.
                        .false.
                        .false.
                        []
                        .false.
                    )
                    []
                    [(Var 2 a)
                    (Var 2 b)]
                    [(Assignment
                        (Var 2 c)
                        (IntegerBinOp
                            (IntegerBinOp
                                (Var 2 a)
                                Add
                                (Var 2 b)
                                (Integer 4)
                                ()
                            )
                            Sub
                            (Var 2 d)
                            (Integer 4)
                            ()
                        )
                        ()
                    )
                    (Assignment
                        (Var 2 r)
                        (IntegerBinOp
                            (Var 2 c)
                            Mul
                            (Var 2 a)
                            (Integer 4)
                            ()
                        )
                        ()
                    )]
                    (Var 2 r)
                    Public
                    .false.
                    .false.
                    ()
                )
        })
    []
)

Uma ASR possui toda a informação semântica (tipos, etc.), nós do tipo Function possuem uma tabela de símbolos e não tem nenhuma nó de declaração. Variáveis são simplesmente ponteiros para a tabela de símbolos.

The ASR can also be exported in JSON, including source file name, line and column information: lfortran example.f90 --show-asr --json

Discussão

O exemplo acima foi simples. As coisas ficam mais evidentes para exemplos mais complicados, como:

integer function f2b(a) result(r)
use gfort_interop, only: c_desc1_int32
integer, intent(in) :: a(:)
interface
    integer function f2b_c_wrapper(a) bind(c, name="__mod1_MOD_f2b")
    use gfort_interop, only: c_desc1_t
    type(c_desc1_t), intent(in) :: a
    end function
end interface
r = f2b_c_wrapper(c_desc1_int32(a))
end function

As AST devem representar todos os comandos use e blocos de interface, bem como manter as coisas semanticamente consistentes.

As ASR, por outro lado, devem manter os registros de c_desc1_int32, c_desc1_t e f2b_c_wrapper na tabela de símbolos e sabe que eles foram definidos no módulo gfort_interop e portanto a ASR não possui nenhuma desses nós de declaração.

Ao converter uma ASR em uma AST, o LFortran criará todos os nós de declaração da AST apropriados de forma automática e correta.