Skip to content

Commit

Permalink
Mejora documentación interna
Browse files Browse the repository at this point in the history
  • Loading branch information
CrysoK committed Sep 3, 2024
1 parent c232e10 commit 1563f3d
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 11 deletions.
42 changes: 40 additions & 2 deletions src/eval/expr.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @file
* @brief Implementación de la evaluación de expresiones.
*/
#include "expr.h"

#include <stddef.h>
Expand All @@ -20,6 +24,15 @@ static ResNode *eval_expr_a(AstNode *ast);
static ResNode *eval_expr_b(AstNode *ast);
static ResNode *eval_expr_x(AstNode *ast);
static bool valid_operand(ResNode *node);
/**
* @brief Asigna los argumentos de la llamada a su correspondiente parámetro.
* @param args Argumentos de la llamada.
* @param fndef_ast AST de la definición de la función.
* @param a_cnt Cantidad de argumentos.
* @param fname Nombre de la función.
* @return `NULL` o `ResErrorN`.
*/
ResNode *eval_fncall_params(ResNode *args, AstNode *fndef_ast, int a_cnt, char *fname);

// No devuelve `NULL`
ResNode *eval_expr(AstNode *node) {
Expand Down Expand Up @@ -325,7 +338,14 @@ ResNode *eval_div(AstNode *div_ast) {
free_a: res_free(a);
return MAYBE_ERROR(r);
}
ResNode *eval_fncall_params(ResNode *args, AstNode *fndef_ast, int a_cnt, char *fname);
/**
* Se crea un símbolo para cada parámetro y asigna como valor al argumento
* correspondiente. También reporta detalladamente el error si la cantidad de
* argumentos no coincide con los requeridos.
*
* El parámetro especial `...` permite recibir un número variable de argumentos.
* Estos se guardan en el símbolo especial `_args` como una lista.
*/
ResNode *eval_fncall_params(
ResNode *args, AstNode *fndef_ast, int a_cnt, char *fname
) {
Expand Down Expand Up @@ -369,7 +389,25 @@ ResNode *eval_fncall_params(
}
return r;
}

/**
* Primero se evalúa el símbolo de la función para obtener el AST de su
* definición, luego de asegurarse de que efectivamente lo sea.
*
* Después se evalúa la lista de expresiones que conforman los argumentos. Si no
* hay errores, se procede a guardar el ámbito en el que se realiza la llamada y
* se establece el ámbito global como actual.q
*
* Se crea un ámbito local para la función y se asignan los argumentos a su
* respectivo parámetro (ver @ref eval_fncall_params).
*
* Lo siguiente es evaluar la lista de sentencias del cuerpo de la función . Al
* terminar, se elimina el alcance local y se regresa al ámbito donde se hizo la
* llamada.
*
* Finalmente se analiza el resultado: si es un `return`, se devuelve el dato
* que contiene; si es un `exit` o un error, se propaga; y en cualquier otro
* caso, se devuelve nulo, representado por un nodo de tipo `VOID_R`.
*/
ResNode *eval_fncall(AstNode *fncall_ast) {
DBG_FN_START;
NULL_RETURN(fncall_ast, "Interno", S("fncall_ast == NULL"));
Expand Down
5 changes: 5 additions & 0 deletions src/eval/expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ ResNode *eval_add(AstNode *node);
ResNode *eval_sub(AstNode *node);
ResNode *eval_mul(AstNode *node);
ResNode *eval_div(AstNode *node);
/**
* @brief Evalúa una llamada a una función.
* @param node AST de una llamada a una función.
* @return Dato (entero, lista, etc), `VOID_R`, `EXIT_R` o `ResErrorN`.
*/
ResNode *eval_fncall(AstNode *node);

// Operaciones /////////////////////////////////////////////////////////////////
Expand Down
71 changes: 63 additions & 8 deletions src/eval/stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ ResNode *eval_decl(AstNode *ast_node) {
"Sintaxis", S("Cantidad de identificadores y de expresiones distinta")
);
}

/**
* La asignación tiene la forma:
*
Expand Down Expand Up @@ -261,7 +260,6 @@ ResNode *eval_assign_to_id(AstNode *sym, ResNode *value, AstNodeT a_type) {
garbage_collect(prev);
return NULL; // Éxito
}

/**
* @brief Asignación a un elemento de una lista.
*
Expand Down Expand Up @@ -308,7 +306,6 @@ ResNode *eval_assign_to_elem(AstNode *ast_node, ResNode *value, AstNodeT a_type)
res_free(list);
return MAYBE_ERROR(r);
}

/**
* @brief Asignación "aumentada" o compuesta.
*
Expand Down Expand Up @@ -405,7 +402,14 @@ ResNode *eval_insert(AstNode *ast_node) {
res_free(list);
return MAYBE_ERROR(r);
}

/**
* Primero se evalúa la condición fuera del alcance del bloque. Su resultado se
* convierte a un valor lógico (var @ref bool_cast). Se crea el alcance para el
* bloque, se evalúa la lista de sentencias correspondiente al valor lógico y se
* abandona el alcance creado. Finalmente se devuelve el resultado, que podría
* ser `NULL`, un error o alguna interrupción (`return`, `break`, `continue`,
* `exit`).
*/
ResNode *eval_if(AstNode *if_ast) {
DBG_FN_START;
NULL_RETURN(if_ast, "Interno", S("if_ast == NULL"));
Expand All @@ -423,7 +427,25 @@ ResNode *eval_if(AstNode *if_ast) {
scope_pop();
return MAYBE_ERROR(r);
}

/**
* El primer paso es evaluar la condición y obtener su valor lógico (ver @ref
* bool_cast). Si es falso, el ciclo se detiene y se devuelve `NULL` indicando
* que no hubo interrupciones ni errores. SI es verdadero, se crea el alcance
* del bloque y se evalúa la lista de sentencias. Al terminar, se elimina el
* alcance creado y se analiza el resultado.
*
* - Si la lista de sentencias devuelve `NULL`, no hubo errores ni interrupciones,
* por lo que el ciclo continúa.
* - Si devuelve un error, el ciclo se detiene y el error se propaga al
* exterior.
* - Si devuelve un `break` entonces se libera, para evitar que afecte a ciclos
* exteriores, y el ciclo se detiene.
* - Si devuelve un `return` o `exit`, el ciclo se detiene y el resultado se
* propaga al exterior. `return` debe detener la ejecución de la función que
* "envuelve" al ciclo y `exit` debe detener la ejecución de todo el programa.
* - En cualquier otro caso, incluyendo `continue`, se libera el resultado y se
* pasa a la siguiente iteración.
*/
ResNode *eval_while(AstNode *while_ast) {
DBG_FN_START;
NULL_RETURN(while_ast, "Interno", S("while_ast == NULL"));
Expand Down Expand Up @@ -468,8 +490,33 @@ ResNode *eval_while(AstNode *while_ast) {
}
return MAYBE_ERROR(r);
}

// a = id, b = iter, c = stmts
/**
* La sentencia tiene la forma:
*
* for id in iter block
* a b c
*
* Para comenzar, se evalúa la expresión que resultará en una lista o un
* conjunto de elementos para recorrer y se verifica que efectivamente sea un
* iterable.
*
* Puede ocurrir que no sea referenciado en ningún lugar fuera del encabezado
* del `for`, por lo que se incrementa su `refcnt` para evitar que sus elementos
* sean liberados al final de cada iteración.
*
* Antes de evaluar la lista de sentencias se crea un nuevo alcance.
*
* Si el iterable es una lista, se declara un símbolo especial `_i` con el
* índice del elemento actual.
*
* Se crea el símbolo con el elemento actual y se evalúa el cuerpo del `for`. Al
* terminar, se elimina el alcance del bloque.
*
* El análisis del resultado es exactamente igual al de @ref eval_while.
*
* Antes de finalizar el `for` se decrementa el `refcnt` del iterable y se
* libera si no posee más referencias.
*/
ResNode *eval_for(AstNode *for_ast) {
DBG_FN_START;
NULL_RETURN(for_ast, "Interno", S("for_ast == NULL"));
Expand Down Expand Up @@ -522,11 +569,19 @@ ResNode *eval_for(AstNode *for_ast) {
res_free(iter);
return MAYBE_ERROR(r);
}

/**
* La sentencia tiene la forma:
*
* fn id(params) block
*
* La evaluación es simplemente declarar un símbolo con el identificador de la
* función y asignarle como valor un dato de tipo `fn`, que no es más que un
* "envoltorio" para el AST de la definición.
*
* Si el agregado del símbolo falla, se libera el dato de tipo `fn` y se propaga
* el error.
*
* Para llamadas ver eval_fncall().
*/
ResNode *eval_fndef(AstNode *fn_def_ast) {
DBG_FN_START;
Expand Down
17 changes: 16 additions & 1 deletion src/eval/stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,28 @@ ResNode *eval_decl(AstNode *decl_ast);
ResNode *eval_del(AstNode *del_ast);
/**
* @brief Evalúa una asignación.
* @param assign_ast Puntero al AST de la asignación.
* @param assign_ast AST de la asignación.
* @return `NULL` o `ResErrorN`.
*/
ResNode *eval_assign(AstNode *assign_ast);
ResNode *eval_insert(AstNode *insert_ast);
/**
* @brief Evalúa la sentencia `if`.
* @param if_ast AST de la sentencia `if`.
* @return `NULL`, `ResErrorN` o alguna interrupción.
*/
ResNode *eval_if(AstNode *if_ast);
/**
* @brief Evalúa la sentencia `while`.
* @param while_ast AST de la sentencia `while`.
* @return `NULL`, `ResErrorN` o alguna interrupción.
*/
ResNode *eval_while(AstNode *while_ast);
/**
* @brief Evalúa la sentencia `for`.
* @param for_ast AST de la sentencia `for`.
* @return `NULL`, `ResErrorN` o alguna interrupción.
*/
ResNode *eval_for(AstNode *for_ast);
/**
* @brief Evalúa la definición de una función.
Expand Down

0 comments on commit 1563f3d

Please sign in to comment.