diff --git a/projects/while.j b/projects/while.j new file mode 100644 index 0000000..174f331 --- /dev/null +++ b/projects/while.j @@ -0,0 +1,4 @@ +x = 0 +while x < 100000000: + x = x + 1 +print x diff --git a/src/frontend/lexer.h b/src/frontend/lexer.h index 9c06998..f9f1c59 100644 --- a/src/frontend/lexer.h +++ b/src/frontend/lexer.h @@ -1,3 +1,5 @@ +#ifndef JLANG_LEXER_H +#define JLANG_LEXER_H /* Convierte texto en una lista de tokens */ @@ -67,6 +69,8 @@ Token *tokenize(const char *source, int *token_count) { int count = 0; int pos = 0; + int indent_level = 0; + while (source[pos] != '\0' && pos < strlen(source)) { char c = source[pos]; @@ -75,6 +79,20 @@ Token *tokenize(const char *source, int *token_count) { } else if (c == '\n') { tokens[count++] = make_token(TOK_NEWLINE, "\n"); pos++; + + // Contar espacios al inicio de la linea + int spaces = 0; + while (source[pos] == ' ') { + spaces++; + pos++; + } + int new_level = spaces / 4; // 4 espacios = 1 nivel + if (new_level > indent_level) { + tokens[count++] = make_token(TOK_INDENT, "INDENT"); + } else if (new_level < indent_level) { + tokens[count++] = make_token(TOK_DEDENT, "DEDENT"); + } + indent_level = new_level; } else if (c == '+') { tokens[count++] = make_token(TOK_PLUS, "+"); pos++; @@ -90,6 +108,15 @@ Token *tokenize(const char *source, int *token_count) { } else if (c == '=') { tokens[count++] = make_token(TOK_ASSIGN, "="); pos++; + } else if (c == '<') { + tokens[count++] = make_token(TOK_LT, "<"); + pos++; + } else if (c == '>') { + tokens[count++] = make_token(TOK_GT, ">"); + pos++; + } else if (c == ':') { + tokens[count++] = make_token(TOK_COLON, ":"); + pos++; } else if (c >= '0' && c <= '9') { // Leer todos los digitos consecutivos int start = pos; @@ -106,6 +133,8 @@ Token *tokenize(const char *source, int *token_count) { // Comprobar si es una keyword reservada if (strcmp(word, "print") == 0) { tokens[count++] = make_token(TOK_PRINT, word); + } else if (strcmp(word, "while") == 0) { + tokens[count++] = make_token(TOK_WHILE, word); } else { tokens[count++] = make_token(TOK_ID, word); } @@ -115,6 +144,15 @@ Token *tokenize(const char *source, int *token_count) { } } + // Cerrar indents pendientes + + while (indent_level > 0) { + tokens[count++] = make_token(TOK_DEDENT, "DEDENT"); + indent_level--; + } + *token_count = count; return tokens; } + +#endif diff --git a/src/frontend/parser.h b/src/frontend/parser.h index ba25103..b104c10 100644 --- a/src/frontend/parser.h +++ b/src/frontend/parser.h @@ -1,208 +1,226 @@ +#ifndef JLANG_PARSER_H +#define JLANG_PARSER_H /* Convierte tokens en un arbol */ #include "lexer.h" -typedef enum -{ - NODE_INT_LIT, // literal entero - NODE_STRING_LIT, // literal string - NODE_VAR, // referencia a variable - NODE_ASSIGN, // asignacion: x = expr - NODE_BINOP, // operacion binaria: a + b - NODE_PRINT, // print(expr) - NODE_IF, // if cond: bloque - NODE_WHILE, // while cond: bloque - NODE_BLOCK, // secuencia de statements +typedef enum { + NODE_INT_LIT, // literal entero + NODE_STRING_LIT, // literal string + NODE_VAR, // referencia a variable + NODE_ASSIGN, // asignacion: x = expr + NODE_BINOP, // operacion binaria: a + b + NODE_PRINT, // print(expr) + NODE_IF, // if cond: bloque + NODE_WHILE, // while cond: bloque + NODE_BLOCK, // secuencia de statements } NodeType; -typedef struct ASTNode -{ - NodeType type; - union - { - int int_val; // NODE_INT_LIT - char *string_val; // NODE_STRING_LIT - struct - { - char *name; - struct ASTNode *value; - } assign; // NODE_ASSIGN - struct - { - char op; - struct ASTNode *left; - struct ASTNode *right; - } binop; // NODE_BINOP - struct - { - struct ASTNode *expr; - } print; // NODE_PRINT - struct - { - struct ASTNode **stmts; - int count; - } block; // NODE_BLOCK - } data; +typedef struct ASTNode { + NodeType type; + union { + int int_val; // NODE_INT_LIT + char *string_val; // NODE_STRING_LIT + struct { + char *name; + struct ASTNode *value; + } assign; // NODE_ASSIGN + struct { + char op; + struct ASTNode *left; + struct ASTNode *right; + } binop; // NODE_BINOP + struct { + struct ASTNode *expr; + } print; // NODE_PRINT + struct { + struct ASTNode **stmts; + int count; + } block; // NODE_BLOCK + struct { + struct ASTNode *cond; + struct ASTNode *body; + } while_loop; // NODE_WHILE + } data; } ASTNode; -ASTNode *make_node(NodeType type) -{ - ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); - node->type = type; - return node; +ASTNode *make_node(NodeType type) { + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = type; + return node; } int pos = 0; -ASTNode *parse_term(Token *tokens) -{ - if (tokens[pos].type == TOK_INT) - { - ASTNode *node = make_node(NODE_INT_LIT); - node->data.int_val = atoi(tokens[pos].value); +ASTNode *parse_term(Token *tokens) { + if (tokens[pos].type == TOK_INT) { + ASTNode *node = make_node(NODE_INT_LIT); + node->data.int_val = atoi(tokens[pos].value); + pos++; + return node; + } else if (tokens[pos].type == TOK_ID) { + ASTNode *node = make_node(NODE_VAR); + node->data.string_val = tokens[pos].value; + pos++; + return node; + } + printf("ERROR: esperaba INT o ID, encontré tipo %d\n", tokens[pos].type); + exit(1); +} + +ASTNode *parse_expr(Token *tokens) { + ASTNode *left = parse_term(tokens); + + while (tokens[pos].type == TOK_PLUS || tokens[pos].type == TOK_MINUS || + tokens[pos].type == TOK_STAR || tokens[pos].type == TOK_SLASH || + tokens[pos].type == TOK_LT || tokens[pos].type == TOK_GT) { + char op = tokens[pos].value[0]; // +,-,*,/ + pos++; + ASTNode *right = parse_term(tokens); + + ASTNode *binop = make_node(NODE_BINOP); + binop->data.binop.op = op; + binop->data.binop.left = left; + binop->data.binop.right = right; + left = binop; // encadenar: (a + b) + c + } + return left; +} + +ASTNode *parse_statement(Token *tokens) { + if (tokens[pos].type == TOK_ID) { + char *name = tokens[pos].value; + pos++; // consumir ID + pos++; // consumir "=" + ASTNode *value = parse_expr(tokens); + + ASTNode *node = make_node(NODE_ASSIGN); + node->data.assign.name = name; + node->data.assign.value = value; + return node; + } + if (tokens[pos].type == TOK_PRINT) { + pos++; // consumir "print" + ASTNode *expr = parse_expr(tokens); + + ASTNode *node = make_node(NODE_PRINT); + node->data.print.expr = expr; + return node; + } + + if (tokens[pos].type == TOK_WHILE) { + pos++; // consumir while + ASTNode *cond = parse_expr(tokens); + pos++; // consumir ":" + pos++; // consumir NEWLINE + pos++; // consumir INDENT + + // Parsear bloque de statements hasta DEDENT + ASTNode *body = make_node(NODE_BLOCK); + body->data.block.stmts = (ASTNode **)malloc(sizeof(ASTNode *) * 256); + body->data.block.count = 0; + while (tokens[pos].type != TOK_DEDENT) { + body->data.block.stmts[body->data.block.count++] = + parse_statement(tokens); + if (tokens[pos].type == TOK_NEWLINE) { pos++; - return node; + } } - else if (tokens[pos].type == TOK_ID) - { - ASTNode *node = make_node(NODE_VAR); - node->data.string_val = tokens[pos].value; - pos++; - return node; - } - printf("ERROR: esperaba INT o ID, encontré tipo %d\n", tokens[pos].type); - exit(1); + pos++; // Consumir DEDENT + + ASTNode *node = make_node(NODE_WHILE); + node->data.while_loop.cond = cond; + node->data.while_loop.body = body; + return node; + } + printf("ERROR: statement inesperado\n"); + exit(1); } -ASTNode *parse_expr(Token *tokens) -{ - ASTNode *left = parse_term(tokens); +ASTNode *parse(Token *tokens, int token_count) { + ASTNode *block = make_node(NODE_BLOCK); + block->data.block.stmts = (ASTNode **)malloc(sizeof(ASTNode *) * 256); + block->data.block.count = 0; - while (tokens[pos].type == TOK_PLUS || tokens[pos].type == TOK_MINUS || tokens[pos].type == TOK_STAR || tokens[pos].type == TOK_SLASH) - { - char op = tokens[pos].value[0]; // +,-,*,/ - pos++; - ASTNode *right = parse_term(tokens); - - ASTNode *binop = make_node(NODE_BINOP); - binop->data.binop.op = op; - binop->data.binop.left = left; - binop->data.binop.right = right; - left = binop; // encadenar: (a + b) + c + while (pos < token_count) { + if (tokens[pos].type == TOK_NEWLINE) { + pos++; // Saltar newlines sueltos + continue; } - return left; + block->data.block.stmts[block->data.block.count++] = + parse_statement(tokens); + + // Consumir newline despues del statement + if (pos < token_count && tokens[pos].type == TOK_NEWLINE) { + pos++; + } + } + return block; } -ASTNode *parse_statement(Token *tokens) -{ - if (tokens[pos].type == TOK_ID) - { - char *name = tokens[pos].value; - pos++; // consumir ID - pos++; // consumir "=" - ASTNode *value = parse_expr(tokens); +void ast_print(ASTNode *node, const char *prefix, int is_last) { + if (!node) + return; - ASTNode *node = make_node(NODE_ASSIGN); - node->data.assign.name = name; - node->data.assign.value = value; - return node; + printf("%s", prefix); + printf(is_last ? "`-- " : "|-- "); + + // Construir nuevo prefijo para hijos + char new_prefix[256]; + snprintf(new_prefix, sizeof(new_prefix), "%s%s", prefix, + is_last ? " " : "| "); + + switch (node->type) { + case NODE_WHILE: + printf("NODE_WHILE\n"); + ast_print(node->data.while_loop.cond, new_prefix, 0); + ast_print(node->data.while_loop.body, new_prefix, 1); + break; + + case NODE_INT_LIT: + printf("NODE_INT_LIT(%d)\n", node->data.int_val); + break; + + case NODE_STRING_LIT: + printf("NODE_STRING_LIT(\"%s\")\n", node->data.string_val); + break; + + case NODE_VAR: + printf("NODE_VAR(\"%s\")\n", node->data.string_val); + break; + + case NODE_ASSIGN: + printf("NODE_ASSIGN { name:\"%s\" }\n", node->data.assign.name); + ast_print(node->data.assign.value, new_prefix, 1); + break; + + case NODE_BINOP: + printf("NODE_BINOP('%c')\n", node->data.binop.op); + ast_print(node->data.binop.left, new_prefix, 0); + ast_print(node->data.binop.right, new_prefix, 1); + break; + + case NODE_PRINT: + printf("NODE_PRINT\n"); + ast_print(node->data.print.expr, new_prefix, 1); + break; + + case NODE_BLOCK: + printf("NODE_BLOCK\n"); + for (int i = 0; i < node->data.block.count; i++) { + ast_print(node->data.block.stmts[i], new_prefix, + i == node->data.block.count - 1); } - if (tokens[pos].type == TOK_PRINT) { - pos++; // consumir "print" - ASTNode *expr = parse_expr(tokens); + break; - ASTNode*node = make_node(NODE_PRINT); - node->data.print.expr = expr; - return node; - } - - printf("ERROR: statement inesperado\n"); - exit(1); + default: + printf("UNKNOWN\n"); + break; + } } -ASTNode *parse(Token *tokens, int token_count) -{ - ASTNode *block = make_node(NODE_BLOCK); - block->data.block.stmts = (ASTNode **)malloc(sizeof(ASTNode *) * 256); - block->data.block.count = 0; +void ast_debug(ASTNode *node) { ast_print(node, "", 1); } - while (pos < token_count) - { - if (tokens[pos].type == TOK_NEWLINE) - { - pos++; // Saltar newlines sueltos - continue; - } - block->data.block.stmts[block->data.block.count++] = parse_statement(tokens); - - // Consumir newline despues del statement - if (pos < token_count && tokens[pos].type == TOK_NEWLINE) - { - pos++; - } - } - return block; -} - -void ast_print(ASTNode *node, const char *prefix, int is_last) -{ - if (!node) - return; - - printf("%s", prefix); - printf(is_last ? "`-- " : "|-- "); - - // Construir nuevo prefijo para hijos - char new_prefix[256]; - snprintf(new_prefix, sizeof(new_prefix), "%s%s", prefix, is_last ? " " : "| "); - - switch (node->type) - { - case NODE_INT_LIT: - printf("NODE_INT_LIT(%d)\n", node->data.int_val); - break; - - case NODE_STRING_LIT: - printf("NODE_STRING_LIT(\"%s\")\n", node->data.string_val); - break; - - case NODE_VAR: - printf("NODE_VAR(\"%s\")\n", node->data.string_val); - break; - - case NODE_ASSIGN: - printf("NODE_ASSIGN { name:\"%s\" }\n", node->data.assign.name); - ast_print(node->data.assign.value, new_prefix, 1); - break; - - case NODE_BINOP: - printf("NODE_BINOP('%c')\n", node->data.binop.op); - ast_print(node->data.binop.left, new_prefix, 0); - ast_print(node->data.binop.right, new_prefix, 1); - break; - - case NODE_PRINT: - printf("NODE_PRINT\n"); - ast_print(node->data.print.expr, new_prefix, 1); - break; - - case NODE_BLOCK: - printf("NODE_BLOCK\n"); - for (int i = 0; i < node->data.block.count; i++) - { - ast_print(node->data.block.stmts[i], new_prefix, i == node->data.block.count - 1); - } - break; - - default: - printf("UNKNOWN\n"); - break; - } -} - -void ast_debug(ASTNode *node) -{ - ast_print(node, "", 1); -} +#endif diff --git a/src/main.c b/src/main.c index b51a3d5..dfcc845 100644 --- a/src/main.c +++ b/src/main.c @@ -34,7 +34,10 @@ int main(int argc, char **argv) { ast_debug(block); Environment env = {0}; - eval(block, &env, allocPtr); + eval(block, &env, allocPtr, 0, 1); + + printf("heapSize=%zu\n", allocPtr->size); + // JLANG_visualize(allocPtr); return 0; } \ No newline at end of file diff --git a/src/memory/allocator.h b/src/memory/allocator.h index 575f722..37ad0ac 100644 --- a/src/memory/allocator.h +++ b/src/memory/allocator.h @@ -1,3 +1,6 @@ +#ifndef JLANG_ALLOCATOR_H +#define JLANG_ALLOCATOR_H + #include #include #include @@ -24,7 +27,7 @@ typedef struct { size_t size; // 8 bytes int in_use; // 4 bytes - // --- aquí el compilador mete 4 bytes invisibles --- + int marked; // 4 bytes } JLANG_metadata; /* @@ -94,44 +97,110 @@ void *JLANG_last_free(void *ptr) { size_t JLANG_malloc(void *ptr, size_t size) { JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr; - // 1. Hay bloques disponibles?? - size_t used = JLANG_used(ptr); - size_t available = allocPtr->size - used; + // Recorrer memoria hasta encontrar un hueco libre + JLANG_metadata *currentHead = (JLANG_metadata *)allocPtr->memory; + size_t used = 0; + while (1) { + used += currentHead->size; + + if (currentHead->in_use == 0 && currentHead->size >= size) { + break; + } + + if (currentHead->size == 0) { + size_t offset = (char *)currentHead - allocPtr->memory; + if (offset + sizeof(JLANG_metadata) + size > allocPtr->size) { + // No cabe, grow + size_t newSize = allocPtr->size * 2; + // asegurar que quepa la peticion + while (newSize < offset + sizeof(JLANG_metadata) + size) { + newSize *= 2; + } + + char *newBuffer = (char *)malloc(newSize); // pedir newSize bytes + if (newBuffer == NULL) { + printf("ERROR: out of memory\n"); + exit(1); + } + memset(newBuffer, 0, newSize); + memcpy(newBuffer, allocPtr->memory, + allocPtr->size); // Copiamos al nuevo buffer + + allocPtr->size = newSize; + + free(allocPtr->memory); // Liberamos el buffer antiguo + allocPtr->memory = newBuffer; // Seteamos el nuevo buffer + + JLANG_metadata *freeHeader = + (JLANG_metadata *)(allocPtr->memory + offset); + freeHeader->size = size; + freeHeader->in_use = 1; + + void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata); + return (char *)payloadPtr - allocPtr->memory; + } + // Fin del heap, asignar aqui + currentHead->size = size; + currentHead->in_use = 1; + return (char *)currentHead - allocPtr->memory + sizeof(JLANG_metadata); + } + + // Go next + currentHead = + (JLANG_metadata *)((char *)currentHead + sizeof(JLANG_metadata) + + currentHead->size); + } + + // currentHead tiene sitio para nosotros, particionamos y usamos + currentHead->in_use = 1; + size_t oldSize = currentHead->size; + currentHead->size = size; + + if (oldSize > size + sizeof(JLANG_metadata)) { + // creamos un bloque vacio con los bytes que sobran + JLANG_metadata *emptyBlock = + (JLANG_metadata *)((char *)currentHead + sizeof(JLANG_metadata) + size); + emptyBlock->size = oldSize - size - sizeof(JLANG_metadata); + } + + return (char *)currentHead - allocPtr->memory + sizeof(JLANG_metadata); + + /* + // 1. Hay bloques disponibles?? + size_t used = JLANG_used(ptr); + size_t available = allocPtr->size - used; + + // chequear si hay suficiente espacio libre + if (available > size + sizeof(JLANG_metadata)) { + JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr); + freeHeader->size = size; + freeHeader->in_use = 1; + + void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata); + + return (char *)payloadPtr - allocPtr->memory; + } + + // Se necesita más espacio.. + + int newSize = allocPtr->size + 1024; + char *newBuffer = (char *)malloc(newSize); // Otro 1KB + memset(newBuffer, 0, newSize); + memcpy(newBuffer, allocPtr->memory, + allocPtr->size); // Copiamos al nuevo buffer + + allocPtr->size = newSize; + + free(allocPtr->memory); // Liberamos el buffer antiguo + allocPtr->memory = newBuffer; // Seteamos el nuevo buffer - // chequear si hay suficiente espacio libre - if (available > size + sizeof(JLANG_metadata)) { JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr); freeHeader->size = size; freeHeader->in_use = 1; void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata); - return (char *)payloadPtr - allocPtr->memory; - } - - /* - Se necesita más espacio.. - De momento vamos a pedir otro array más grande y liberar el antiguo - Mantenemos toda la memoria contigua */ - - int newSize = allocPtr->size + 1024; - char *newBuffer = (char *)malloc(newSize); // Otro 1KB - memset(newBuffer, 0, newSize); - memcpy(newBuffer, allocPtr->memory, - allocPtr->size); // Copiamos al nuevo buffer - - allocPtr->size = newSize; - - free(allocPtr->memory); // Liberamos el buffer antiguo - allocPtr->memory = newBuffer; // Seteamos el nuevo buffer - - JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr); - freeHeader->size = size; - freeHeader->in_use = 1; - - void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata); - return (char *)payloadPtr - allocPtr->memory; } void JLANG_free(void *ptr, size_t blockOffset) { @@ -254,3 +323,5 @@ void JLANG_visualize(void *ptr) { printf("]\n"); } } + +#endif diff --git a/src/memory/gc.h b/src/memory/gc.h new file mode 100644 index 0000000..f8743bf --- /dev/null +++ b/src/memory/gc.h @@ -0,0 +1,95 @@ +#ifndef JLANG_GC_H +#define JLANG_GC_H + +#include "../objects/object.h" +#include "allocator.h" + +void gc_collect(JLANG_memory_allocator *allocPtr, size_t *roots, + int root_count) { + // Stage 1. Mark blocks + for (int i = 0; i < root_count; i++) { + // get blockHeader from object offset + JLANG_metadata *blockHeader = + (JLANG_metadata *)((char *)allocPtr->memory + roots[i] - + sizeof(JLANG_metadata)); + + // Mark block + blockHeader->marked = 1; + + Object *objPtr = (Object *)((char *)allocPtr->memory + roots[i]); + if (objPtr->type == OBJ_LIST) { + JLANG_metadata *itemsHeader = + (JLANG_metadata *)((char *)allocPtr->memory + + objPtr->data.list_val.items - + sizeof(JLANG_metadata)); + itemsHeader->marked = 1; + } else if (objPtr->type == OBJ_STRING) { + JLANG_metadata *itemsHeader = + (JLANG_metadata *)((char *)allocPtr->memory + + objPtr->data.string_val.chars - + sizeof(JLANG_metadata)); + itemsHeader->marked = 1; + } + } + + // Stage 2. Sweep memory + JLANG_metadata *currentHead = (JLANG_metadata *)allocPtr->memory; + while (currentHead->size != 0) { + size_t blockOffset = (char *)currentHead - (char *)allocPtr->memory; + + if (currentHead->marked == 0 && currentHead->in_use) { + // Free block + JLANG_free(allocPtr, blockOffset + sizeof(JLANG_metadata)); + } + + // Reset mark + currentHead->marked = 0; + + currentHead = (JLANG_metadata *)((char *)currentHead + currentHead->size + + sizeof(JLANG_metadata)); + } + + // Stage 3. Join free blocks + currentHead = (JLANG_metadata *)allocPtr->memory; + while (currentHead->size != 0) { + + if (currentHead->in_use == 0) { + // iterate until last next free block + JLANG_metadata *nextHeader = + (JLANG_metadata *)((char *)currentHead + sizeof(JLANG_metadata) + + currentHead->size); + JLANG_metadata *lastHeader = currentHead; + while (1) { + if (nextHeader->in_use == 1 || nextHeader->size == 0) { + // Volvemos atrás + break; + } + + lastHeader = nextHeader; + nextHeader = + (JLANG_metadata *)((char *)nextHeader + sizeof(JLANG_metadata) + + nextHeader->size); + } + + // Make from currentHead to nextHeader + nextHeader(size) one block + size_t startIndex = (char *)currentHead - (char *)allocPtr->memory; + size_t endIndex = + ((char *)lastHeader + sizeof(JLANG_metadata) + lastHeader->size) - + (char *)allocPtr->memory; + + // Set to 0 + for (int i = 0; i < (endIndex - startIndex); i++) { + allocPtr->memory[i + startIndex] = 0; + } + + // Create valid header + currentHead = (JLANG_metadata *) ((char *)allocPtr->memory + startIndex); + currentHead->size = (endIndex - startIndex) - sizeof(JLANG_metadata); + } + + currentHead = (JLANG_metadata *)((char *)currentHead + currentHead->size + + sizeof(JLANG_metadata)); + } +} + +#endif diff --git a/src/objects/object.h b/src/objects/object.h index b457f4f..866f735 100644 --- a/src/objects/object.h +++ b/src/objects/object.h @@ -1,5 +1,9 @@ +#ifndef JLANG_OBJECT_H +#define JLANG_OBJECT_H + #include "../memory/allocator.h" + #define JLANG_RESOLVE(alloc, offset) \ ((void *)(((JLANG_memory_allocator *)(alloc))->memory + (offset))) @@ -137,3 +141,5 @@ void obj_print(void *allocator, size_t offset, const char *preffix) { break; }; } + +#endif diff --git a/src/vm/eval.h b/src/vm/eval.h index dfca63b..688ed41 100644 --- a/src/vm/eval.h +++ b/src/vm/eval.h @@ -1,99 +1,120 @@ -#include "../objects/object.h" -#include "../frontend/parser.h" +#ifndef JLANG_EVAL_H +#define JLANG_EVAL_H -typedef struct -{ - char *name; - size_t value; // offset al Object en el allocator +#include "../frontend/parser.h" +#include "../memory/gc.h" + +typedef struct { + char *name; + size_t value; // offset al Object en el allocator } Variable; -typedef struct -{ - Variable vars[256]; - int count; +typedef struct { + Variable vars[256]; + int count; } Environment; -size_t env_get(Environment *env, const char *name) -{ - for (int i = 0; i < env->count; i++) - { - if (strcmp(env->vars[i].name, name) == 0) - { - return env->vars[i].value; - } +size_t env_get(Environment *env, const char *name) { + for (int i = 0; i < env->count; i++) { + if (strcmp(env->vars[i].name, name) == 0) { + return env->vars[i].value; } + } - printf("ERROR: variable '%s' no definida\n", name); - exit(1); + printf("ERROR: variable '%s' no definida\n", name); + exit(1); } -void env_set(Environment *env, const char *name, size_t value) -{ - for (int i = 0; i < env->count; i++) - { - if (strcmp(env->vars[i].name, name) == 0) - { - env->vars[i].value = value; - return; - } +void env_set(Environment *env, const char *name, size_t value) { + for (int i = 0; i < env->count; i++) { + if (strcmp(env->vars[i].name, name) == 0) { + env->vars[i].value = value; + return; } + } - // No existe, añadir - env->vars[env->count].name = (char *)name; - env->vars[env->count].value = value; - env->count++; + // No existe, añadir + env->vars[env->count].name = (char *)name; + env->vars[env->count].value = value; + env->count++; } int step = 0; -size_t eval(ASTNode *node, Environment *env, void *allocator) { +size_t eval(ASTNode *node, Environment *env, void *allocator, int debug, int gc) { + + // Run GC + if (gc) { + size_t roots[256]; + for (int i = 0; i < env->count; i++) { + roots[i] = env->vars[i].value; + } + gc_collect(allocator, roots, env->count); + } + + if (debug > 0) { step++; printf("===== VM Step: %d =====\n", step); printf("executing node:\n"); ast_debug(node); printf("\n"); JLANG_visualize(allocator); + } - switch (node->type) { - case NODE_INT_LIT: - return obj_new_int(allocator, node->data.int_val); - case NODE_VAR: - return env_get(env, node->data.string_val); - case NODE_ASSIGN: { - size_t val = eval(node->data.assign.value, env, allocator); - env_set(env, node->data.assign.name, val); - return val; - } - case NODE_BINOP: { - size_t left = eval(node->data.binop.left, env, allocator); - size_t right = eval(node->data.binop.right, env, allocator); + switch (node->type) { + case NODE_INT_LIT: + return obj_new_int(allocator, node->data.int_val); + case NODE_VAR: + return env_get(env, node->data.string_val); + case NODE_ASSIGN: { + size_t val = eval(node->data.assign.value, env, allocator, debug, gc); + env_set(env, node->data.assign.name, val); + return val; + } + case NODE_BINOP: { + size_t left = eval(node->data.binop.left, env, allocator, debug, gc); + size_t right = eval(node->data.binop.right, env, allocator, debug, gc); - // Resolver objects - Object* l = (Object *) JLANG_RESOLVE(allocator, left); - Object* r = (Object *) JLANG_RESOLVE(allocator, right); + // Resolver objects + Object *l = (Object *)JLANG_RESOLVE(allocator, left); + Object *r = (Object *)JLANG_RESOLVE(allocator, right); - // Operar (ints por ahora) - if (node->data.binop.op == '+'){ - return obj_new_int(allocator, l->data.int_val + r->data.int_val); - } else if (node->data.binop.op == '-') { - return obj_new_int(allocator, l->data.int_val - r->data.int_val); - } else if (node->data.binop.op == '*') { - return obj_new_int(allocator, l->data.int_val * r->data.int_val); - } else if (node->data.binop.op == '/') { - return obj_new_int(allocator, l->data.int_val / r->data.int_val); - } - } - case NODE_PRINT: { - size_t val = eval(node->data.print.expr, env, allocator); - obj_print(allocator, val, ""); - printf("\n"); - return val; - } - case NODE_BLOCK: - for (int i=0; i< node->data.block.count; i++) - eval(node->data.block.stmts[i], env, allocator); - return 0; - default: - break; + // Operar (ints por ahora) + if (node->data.binop.op == '+') { + return obj_new_int(allocator, l->data.int_val + r->data.int_val); + } else if (node->data.binop.op == '-') { + return obj_new_int(allocator, l->data.int_val - r->data.int_val); + } else if (node->data.binop.op == '*') { + return obj_new_int(allocator, l->data.int_val * r->data.int_val); + } else if (node->data.binop.op == '/') { + return obj_new_int(allocator, l->data.int_val / r->data.int_val); + } else if (node->data.binop.op == '<') { + return obj_new_int(allocator, l->data.int_val < r->data.int_val); + } else if (node->data.binop.op == '>') { + return obj_new_int(allocator, l->data.int_val > r->data.int_val); } -} \ No newline at end of file + } + case NODE_PRINT: { + size_t val = eval(node->data.print.expr, env, allocator, debug, gc); + obj_print(allocator, val, ""); + printf("\n"); + return val; + } + case NODE_BLOCK: + for (int i = 0; i < node->data.block.count; i++) + eval(node->data.block.stmts[i], env, allocator, debug, gc); + return 0; + case NODE_WHILE: + while (1) { + size_t cond = eval(node->data.while_loop.cond, env, allocator, debug, gc); + Object *obj = (Object *)JLANG_RESOLVE(allocator, cond); + if (obj->data.int_val == 0) + break; + eval(node->data.while_loop.body, env, allocator, debug, gc); + } + default: + break; + } +} + +#endif