Contribuyendo

Damos la bienvenida a todas las contribuciones, aún si usted es nuevo en código abierto. Al principio, puede parecer abrumador contribuir a un compilador, pero hágalo, no es complicado. Ayudaremos con cualquier problema técnico, así como a mejorar su contribución para que esta pueda integrarse.

Configuración básica

Para contribuir, asegúrese de configurar:

  • Su nombre de usuario + correo electrónico

  • Su ~/.gitconfig

  • Su indicador de interfaz para mostrar el nombre de la rama actual

Bifurcar LFortran

Paso 1. Crear una bifurcación del repositorio del proyecto

Paso 2. Configure su clave SSH con GitHub

Paso 3. Clone el repositório del proyecto desde Github y configure su 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 es el nombre de su repositório remoto y puede ser cualquier nombre de su elección, por ejemplo su primer nombre.

:fontawesome-solid-edit: YOUR_GITHUB_ID es su identificador de usuario en Github y debe ser parte de la ruta de su cuenta.

Usted puede usar git remote -v para verificar si el nuevo enlace remoto está correctamente configurado.

Enviar una nueva solicitud de fusión

Paso 1. Crear una nueva rama

git checkout -b fix1

Paso 2. Realizar cambios en archivos relevantes

Paso 3. Confirmar los cambios:

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

Aquí algunos consejos sobre como escribir buenos mensajes de confirmación.

Paso 4. Verifique que sus cambios se vean bien

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

Paso 5. Enviar la solicitud de fusión

git push REMOTE_NAME fix1

El comando insertará la nueva rama fix1 en su repositorio remoto REMOTE_NAME que creó anteriormente. Además, también mostrará un enlace en el que puede hacer clic para abrir la nueva solicitud de fusión. Después de hacer clic en el enlace, escriba un título y una descripción concisa y luego haga clic en el botón «Create». Sí, ya está todo listo.

Adicionar nuevas características

El siguiente ejemplo muestra los pasos necesarios para crear un operador binario de intercalación ^ que calcula el valor promedio de los dos operandos.

Crear un nuevo identificador

Extendemos el tokenizer.re así como el parser.yy para adcionar el nuevo indentificador ^. También le decimos a LFortran como imprimir el nuevo identificador en 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, "^")
    }
}

El código adicionado es evaluado con lfortran --show-tokens examples2/expr2.f90

Analizar el nuevo identificador

Ahora tenemos que analizar el nuevo operador. Lo agregamos al AST extendiendo BinOp con un operador de intercalación y modificando el archivo AST.asdl. Luego lo agregamos en parse.yy para analizar correctamente y generar el nuevo AST en semantics.h. Finalmente, extendemos pickle.cpp para que el nuevo operador pueda imprimirse solo.

: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

}

La sección es evaluada con lfortran --show-ast examples/expr2.f90

Implementar todas las semánticas del nuevo identificador

Primero extendemos el ASR en ASR.asdl y adicionamos ^ como una opción del operador 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;
        }
  }
}
}
}
}

Después lo transformamos desde AST para ASR extendiendo src/lfortran/semantics/ast_common_visitor.h.

También lo agregamos a la evaluación en tiempo de compilación desencadenada por expresiones como e = (2+3)^5, que se evalúa en tiempo de compilación. Una expresión como e = x^5 se evalúa solo en tiempo de ejecución.

La sección es evaluada con lfortran --show-asr examples/expr2.f90

Implementando el nuevo identificador en LLVM

Para implementar en LLVM, extendemos la traducción de BinOp manejando el nuevo operador. Primero sumamos los dos números y luego dividimos por dos. :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;
                };
}
}
}

La sección es evaluada con lfortran --show-llvm examples/expr2.f90

Ahora, cuando LLVM funciona, podemos probar el ejecutable final:

lfortran examples/expr2.f90
./a.out

Y debería imprimir 6.

También funciona de forma interactiva:

$ 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

Alcanzar

Si tiene alguna pregunta o necesita ayuda, pregunte en nuestra lista de correo o un chat.

Tenga en cuenta que se espera que todos los participantes de este proyecto sigan nuestro Código de conducta. Al participar en este proyecto, usted acepta cumplir con sus términos. Ver CODE_OF_CONDUCT.md.

Al enviar un PR, acepta licenciar su contribución bajo la licencia BSD de LFortran, a menos que se indique explícitamente lo contrario.