Contribuindo

Aceitamos contribuições de qualquer pessoa, mesmo se você é novo(a) ao mundo do código fonte aberto. Pode parecer assustador contribuir com um compilador logo no início, mas por favor o faça, não é complicado. Vamos te ajudar com qualquer problema técnico e ajudar com sua contribuição até que esta seja implementada.

Configuração Básica

Para contribuir, certifique-se de sua configuração:

  • Seu nome de usuário + e-mail

  • Seu ~/.gitconfig

  • Seu prompt de shell para exibir o nome atual do branch

Fork o LFortran

Passo 1. Crie um fork do repositório do projeto

Passo 2. Configure sua chave SSH no GitHub

Passo 3. Clone o repositório do projeto a partir do GitHub e configure seu repositório remoto

git clone https://github.com/lfortran/lfortran.git
cd lfortran
git remote add REMOTE_NAME git@github.com:YOUR_GITHUB_ID/lfortran.git

:fontawesome-solid-edit: REMOTE_NAME é o nome do seu repositório remoto e pode ser qualquer nome que você queira, por exemplo seu primeiro nome.

:fontawesome-solid-edit: YOUR_GITHUB_ID é a sua identificação de usuário no GitHub e deve ser parte do caminho da sua conta.

Você pode usar git remote -vpara checar se o novo repositório está configurado corretamente.

Envie uma nova requisição de Merge

Passo 1. Crie um novo ramo

git checkout -b fix1

Passo 3. Faça mudanças no(s) arquivo(s) relevante(s)

Passo 3. Realize o commit de suas mudanças:

git add FILE1 (FILE2 ...)
git commit -m "YOUR_COMMIT_MESSAGE"

Veja aqui algumas dicas excelentes sobre como escrever boas mensagens de commit.

Passo 4. Se assegure de que suas mudanças estão boas

git log --pretty=oneline --graph --decorate --all

Passo 5. Envie o pedido de merge

git push REMOTE_NAME fix1

O comando irá enviar o novo ramo fix1 para o seu repositório remoto REMOTE_NAME que você criou anteriormente. Além disso, será mostrado um link que você pode clicar para abrir o novo pedido de merge. Após clicar no link, escreva um título com uma descrição breve e clique em no botão «Create». Uhull! Agora está tudo pronto.

Adicionar Novos Recursos

O exemplo abaixo mostra os passos que seriam necessários para criar o operador binário ^ que calcula o valor médio dos dois operandos.

Crie Novos Tokens

Estendemos o tokenizer.re bem como o parser.yy de modo a adicionar o novo token ^. Também dizemos ao LFortran como ele deve mostrar na tela o novo token no arquivo parser.cpp.

:fontawesome-solid-code: src/lfortran/parser/tokenizer.re

// "^" { RET(TK_CARET) }

:fontawesome-solid-code: src/lfortran/parser/parser.yy

%token TK_CARET "^"

:fontawesome-solid-code: src/lfortran/parser/parser.cpp

std:string token2text(const int token)
{
    switch (token) {
        T(TK_CARET, "^")
    }
}

O código adicionado é testado com o comando lfortran --show-tokens examples2/expr2.f90

Realize o Parsing do Novo Token

Agora temos que fazer o parsing do novo operador. Nós adicionamos ele à AST ao extender o BinOp com o operador «chapéu» ao modificar o arquivo AST.asdl. Então, colocamos ele no parse.yy para realizar o parsing apropriadamente e gerar a nova AST em semantics.h. Por fim, estendemos o arquivo pickle.cpp para que o novo operador possa ser mostrado.

:fontawesome-solid-code:grammar/AST.asdl

operator = Add | Sub | Mul | Div | Pow | Caret

:fontawesome-solid-code:src/lfortran/parser/parser.yy

%left "^"

expr
    : id { $$=$1; }
    | expr "^" expr { $$ = CARET($1, $3, @$); }

:fontawesome-solid-code:src/lfortran/parser/semantics.h

#define CARET(x,y,l) make_BinOp_t(p.m_a, l, EXPR(x), operatorType::Caret, EXPR(y))

:fontawesome-solid-code:src/lfortran/pickle.cpp

std::string op2str(const operatorType type)
{
    switch (type) {
        case (operatorType::Caret) : return "^";
    } // now the caret operator can print itself

}

Esta seção é testada usando o comando lfortran --show-ast examples/expr2.f90

Implementar a Semântica do Novo Token

Primeiro estendemos a ASR em ASR.asdl e adicionamos o «^» como um operador do tipo BinOp.

:fontawesome-solid-code:src/libasr/ASR.asdl

binop = Add | Sub | Mul | Div | Pow | Caret

:fontawesome-solid-code:src/lfortran/semantics/ast_common_visitor.h

namespace LFortran {
class CommonVisitorMethods {
public:
  inline static void visit_BinOp(Allocator &al, const AST::BinOp_t &x,
                                 ASR::expr_t *&left, ASR::expr_t *&right,
                                 ASR::asr_t *&asr) {
    ASR::binopType op;
    switch (x.m_op) {

    case (AST::Caret):
      op = ASR::Caret;
      break;
    }
    if (LFortran::ASRUtils::expr_value(left) != nullptr &&
        LFortran::ASRUtils::expr_value(right) != nullptr) {
      if (ASR::is_a<LFortran::ASR::Integer_t>(*dest_type)) {
        int64_t left_value = ASR::down_cast<ASR::IntegerConstant_t>(
                                 LFortran::ASRUtils::expr_value(left))
                                 ->m_n;
        int64_t right_value = ASR::down_cast<ASR::IntegerConstant_t>(
                                  LFortran::ASRUtils::expr_value(right))
                                  ->m_n;
        int64_t result;
        switch (op) {
        case (ASR::Caret):
          result = (left_value + right_value)/2;
          break;
        }
  }
}
}
}
}

Então, transformamos da AST para a ASR editando o arquivo src/lfortran/semantics/ast_common_visitor.h.

Também o adicionamos para avaliação de expressões em tempo de compilação como e = (2+3)^5 que é calculado em tempo de compilação. Uma expressão como e = x^5 é calculada apenas em tempo de execução.

A seção é testada com lfortran --show-asr examples/expr2.f90

Implemente o Novo Token no LLVM

Para implementá-lo no LLVM estendemos a tradução da BinOp (operação binária) para o novo operador. Primeiro adicionamos os dois números e depois dividimos por dois. :fontawesome-solid-code:src/lfortran/codegen/asr_to_llvm.cpp

    void visit_BinOp(const ASR::BinOp_t &x) {
        if (x.m_value) {
            this->visit_expr_wrapper(x.m_value, true);
            return;
        }
        this->visit_expr_wrapper(x.m_left, true);
        llvm::Value *left_val = tmp;
        this->visit_expr_wrapper(x.m_right, true);
        llvm::Value *right_val = tmp;
        if (x.m_type->type == ASR::ttypeType::Integer ||
            x.m_type->type == ASR::ttypeType::IntegerPointer) {
            switch (x.m_op) {

                case ASR::binopType::Caret: {
                    tmp = builder->CreateAdd(left_val, right_val);
                    llvm::Value *two = llvm::ConstantInt::get(context,
                        llvm::APInt(32, 2, true));
                    tmp = builder->CreateUDiv(tmp, two);
                    break;
                };
}
}
}

Esta seção é testada usando lfortran --show-llvm examples/expr2.f90

Agora que o LLVM funciona, podemos finalmente testar o executável usando:

lfortran examples/expr2.f90
./a.out

O que deve mostrar na tela 6.

Também funciona interativamente:

$ lfortran
Interactive Fortran. Experimental prototype, not ready for end users.
  * Use Ctrl-D to exit
  * Use Enter to submit
  * Use Alt-Enter or Ctrl-N to make a new line
    - Editing (Keys: Left, Right, Home, End, Backspace, Delete)
    - History (Keys: Up, Down)
>>> 4^8                                                                  1,4   ]
6
>>> integer :: x                                                         1,13  ]
>>> x = 4                                                                1,6   ]
>>> x^8                                                                  1,4   ]
6

Entre em contato

Se você tiver alguma dúvida ou precisa de ajuda, por favor pergunte na nossa lista de e-mail ou no chat.

Por favor, note que todos os participantes deste projeto devem seguir nosso Código de Conduta. Ao participar deste projeto, você concorda em cumprir seus termos. Consulte CODE_OF_CONDUCT.md.

Ao enviar um PR, você concorda em licenciar sua contribuição sob a licença BSD da LFortran, menos nos casos em que é explicitamente dito o contrário.