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
2026-02-16 04:55:52 +01:00
|
|
|
#ifndef JLANG_OBJECT_H
|
|
|
|
|
#define JLANG_OBJECT_H
|
|
|
|
|
|
2026-02-15 22:12:19 +01:00
|
|
|
#include "../memory/allocator.h"
|
|
|
|
|
|
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
2026-02-16 04:55:52 +01:00
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
#define JLANG_RESOLVE(alloc, offset) \
|
|
|
|
|
((void *)(((JLANG_memory_allocator *)(alloc))->memory + (offset)))
|
|
|
|
|
|
|
|
|
|
typedef enum { OBJ_INT, OBJ_FLOAT, OBJ_STRING, OBJ_LIST, OBJ_NONE } ObjectType;
|
|
|
|
|
|
|
|
|
|
typedef struct Object {
|
|
|
|
|
ObjectType type;
|
|
|
|
|
union {
|
|
|
|
|
int int_val;
|
|
|
|
|
double float_val;
|
|
|
|
|
struct {
|
|
|
|
|
size_t chars;
|
|
|
|
|
int length;
|
|
|
|
|
} string_val;
|
|
|
|
|
struct {
|
2026-02-16 00:33:02 +01:00
|
|
|
size_t items;
|
2026-02-15 23:16:45 +01:00
|
|
|
int count;
|
|
|
|
|
int capacity;
|
|
|
|
|
} list_val;
|
|
|
|
|
} data;
|
2026-02-15 22:12:19 +01:00
|
|
|
} Object;
|
|
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
size_t obj_new_int(void *allocator, int value) {
|
|
|
|
|
// Object *objPtr = (Object *)JLANG_malloc(allocator, sizeof(Object));
|
|
|
|
|
size_t offset = JLANG_malloc(allocator, sizeof(Object));
|
|
|
|
|
Object *objPtr = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
objPtr->type = OBJ_INT;
|
|
|
|
|
objPtr->data.int_val = value;
|
|
|
|
|
return offset;
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
size_t obj_new_float(void *allocator, float value) {
|
|
|
|
|
size_t offset = JLANG_malloc(allocator, sizeof(Object));
|
|
|
|
|
Object *objPtr = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
objPtr->type = OBJ_FLOAT;
|
|
|
|
|
objPtr->data.float_val = value;
|
|
|
|
|
return offset;
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
size_t obj_new_string(void *allocator, const char *str) {
|
|
|
|
|
size_t offset = JLANG_malloc(allocator, sizeof(Object));
|
|
|
|
|
Object *objPtr = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
|
|
|
|
|
objPtr->type = OBJ_STRING;
|
2026-02-15 22:12:19 +01:00
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
int len = strlen(str);
|
2026-02-15 22:12:19 +01:00
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
// !! CUIDADO CON ESTE DOBLE MALLOC SI DISPARA EL GROW !!
|
|
|
|
|
size_t bufferOffset = JLANG_malloc(allocator, len + 1);
|
|
|
|
|
char *buffer = (char *)JLANG_RESOLVE(allocator, bufferOffset);
|
|
|
|
|
memcpy(buffer, str, len + 1);
|
2026-02-15 22:12:19 +01:00
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
objPtr->data.string_val.chars = bufferOffset;
|
|
|
|
|
objPtr->data.string_val.length = len;
|
|
|
|
|
|
|
|
|
|
return offset;
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-16 00:33:02 +01:00
|
|
|
size_t obj_new_list(void *allocator, int capacity) {
|
2026-02-15 23:16:45 +01:00
|
|
|
size_t offset = JLANG_malloc(allocator, sizeof(Object));
|
|
|
|
|
Object *objPtr = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
objPtr->type = OBJ_LIST;
|
2026-02-16 00:33:02 +01:00
|
|
|
|
|
|
|
|
size_t itemsOffset = JLANG_malloc(allocator, capacity * sizeof(size_t));
|
|
|
|
|
|
|
|
|
|
// Re-resolver por si malloc disparó grow
|
|
|
|
|
objPtr = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
|
|
|
|
|
objPtr->data.list_val.capacity = capacity;
|
|
|
|
|
objPtr->data.list_val.items = itemsOffset;
|
|
|
|
|
objPtr->data.list_val.count = 0;
|
|
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
return offset;
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-16 00:33:02 +01:00
|
|
|
void obj_list_append(void *allocator, size_t offset) {}
|
|
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
void obj_free(void *allocator, size_t offset) {
|
2026-02-16 00:33:02 +01:00
|
|
|
Object *obj = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
if (obj->type == OBJ_STRING) {
|
|
|
|
|
JLANG_free(allocator, obj->data.string_val.chars);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj->type == OBJ_LIST) {
|
|
|
|
|
JLANG_free(allocator, obj->data.list_val.items);
|
|
|
|
|
}
|
2026-02-15 22:12:19 +01:00
|
|
|
|
2026-02-15 23:16:45 +01:00
|
|
|
JLANG_free(allocator, offset);
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-16 00:33:02 +01:00
|
|
|
void obj_print(void *allocator, size_t offset, const char *preffix) {
|
2026-02-15 23:16:45 +01:00
|
|
|
Object *obj = (Object *)JLANG_RESOLVE(allocator, offset);
|
|
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
|
case OBJ_INT:
|
|
|
|
|
printf("%d", obj->data.int_val);
|
|
|
|
|
break;
|
|
|
|
|
case OBJ_FLOAT:
|
|
|
|
|
printf("%f", obj->data.float_val);
|
|
|
|
|
break;
|
2026-02-16 00:33:02 +01:00
|
|
|
case OBJ_LIST: {
|
|
|
|
|
|
|
|
|
|
// Iterate items
|
|
|
|
|
size_t *items =
|
|
|
|
|
(size_t *)JLANG_RESOLVE(allocator, obj->data.list_val.items);
|
|
|
|
|
|
|
|
|
|
printf("[");
|
|
|
|
|
for (int i = 0; i < obj->data.list_val.capacity; i++) {
|
|
|
|
|
|
|
|
|
|
// Check if the item is the list itself
|
|
|
|
|
if (items[i] == offset) {
|
|
|
|
|
printf("<self:0x%zu>", offset);
|
|
|
|
|
} else {
|
|
|
|
|
obj_print(allocator, items[i], "\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < obj->data.list_val.capacity - 1) {
|
|
|
|
|
printf(", ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("]\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-02-15 23:16:45 +01:00
|
|
|
case OBJ_STRING:
|
2026-02-16 00:33:02 +01:00
|
|
|
if (strcmp(preffix, "") != 0) {
|
|
|
|
|
printf("%s", preffix);
|
|
|
|
|
}
|
2026-02-15 23:16:45 +01:00
|
|
|
printf("%s", (char *)JLANG_RESOLVE(allocator, obj->data.string_val.chars));
|
2026-02-16 00:33:02 +01:00
|
|
|
|
|
|
|
|
if (strcmp(preffix, "") != 0) {
|
|
|
|
|
printf("%s", preffix);
|
|
|
|
|
}
|
2026-02-15 23:16:45 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2026-02-16 00:33:02 +01:00
|
|
|
};
|
2026-02-15 22:12:19 +01:00
|
|
|
}
|
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
2026-02-16 04:55:52 +01:00
|
|
|
|
|
|
|
|
#endif
|