Add while loops, GC mark-and-sweep, and malloc block reuse
- Lexer: add INDENT/DEDENT tokens, <, >, : operators, while keyword, closing DEDENT emission, include guards - Parser: add NODE_WHILE with while_loop union, parse while/cond/body blocks, include guards - Eval: add while loop evaluation, GC integration with roots from env, debug and gc flags, <, > comparison operators - GC: implement mark-and-sweep collector with 3 stages (mark roots, sweep unmarked, join free blocks) - Allocator: block reuse via first-fit search with splitting, exponential heap growth, NULL check on malloc, include guards, marked field in metadata - Object: add include guards, fix include to use allocator.h
This commit is contained in:
169
src/vm/eval.h
169
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user