Add evaluator with environment and file-based execution
Implements recursive AST evaluator with variable environment, reads .j files from command line args, and executes programs end-to-end (lexer -> parser -> eval).
This commit is contained in:
4
projects/sum.j
Normal file
4
projects/sum.j
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
x = 10
|
||||||
|
y = 5
|
||||||
|
z = x + y
|
||||||
|
print z
|
||||||
48
src/main.c
48
src/main.c
@@ -1,38 +1,40 @@
|
|||||||
#include "frontend/parser.h"
|
#include "vm/eval.h"
|
||||||
#include "objects/object.h"
|
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("usage: %s <path to .j file>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
// Creamos un allocator
|
// Creamos un allocator
|
||||||
JLANG_memory_allocator *allocPtr = JLANG_CreateAllocator();
|
JLANG_memory_allocator *allocPtr = JLANG_CreateAllocator();
|
||||||
|
|
||||||
size_t stringVar1 = obj_new_string(allocPtr, "Hello world!");
|
// Read file from argv
|
||||||
size_t floatVar1 = obj_new_float(allocPtr, 3.14);
|
FILE *fptr = fopen(argv[1], "r");
|
||||||
size_t listVar1 = obj_new_list(allocPtr, 3);
|
if (fptr == NULL) {
|
||||||
Object *list = (Object *)JLANG_RESOLVE(allocPtr, listVar1);
|
printf("error leyendo: %s\n", argv[1]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
size_t *items = (size_t *)JLANG_RESOLVE(allocPtr, list->data.list_val.items);
|
fseek(fptr, 0, SEEK_END); // ir al final
|
||||||
items[0] = floatVar1;
|
long length = ftell(fptr); // cuántos bytes tiene
|
||||||
items[1] = stringVar1;
|
fseek(fptr, 0, SEEK_SET); // volver al inicio
|
||||||
items[2] = listVar1;
|
char *buff = malloc(length + 1);
|
||||||
|
size_t bytesRead = fread(buff, 1, length, fptr);
|
||||||
|
buff[bytesRead] = '\0';
|
||||||
|
|
||||||
obj_print(allocPtr, listVar1, "");
|
fclose(fptr);
|
||||||
|
|
||||||
obj_free(allocPtr, stringVar1);
|
printf("%s\n", buff);
|
||||||
|
|
||||||
stringVar1 = obj_new_string(allocPtr, "Hola Mundo!");
|
|
||||||
items[1] = stringVar1;
|
|
||||||
items[2] = stringVar1;
|
|
||||||
|
|
||||||
obj_print(allocPtr, listVar1, "");
|
|
||||||
|
|
||||||
JLANG_visualize(allocPtr);
|
|
||||||
|
|
||||||
// Lexer test
|
// Lexer test
|
||||||
int totalTokens = 0;
|
int totalTokens = 0;
|
||||||
Token *tokens = tokenize("x = 10\ny = 5\nz = x + y\nprint z", &totalTokens);
|
Token *tokens = tokenize(buff, &totalTokens);
|
||||||
printf("totalTokens=%d\n", totalTokens);
|
printf("totalTokens=%d\n", totalTokens);
|
||||||
ASTNode* block = parse(tokens, totalTokens);
|
ASTNode *block = parse(tokens, totalTokens);
|
||||||
ast_debug(block);
|
ast_debug(block);
|
||||||
|
|
||||||
|
Environment env = {0};
|
||||||
|
eval(block, &env, allocPtr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
86
src/vm/eval.h
Normal file
86
src/vm/eval.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "../objects/object.h"
|
||||||
|
#include "../frontend/parser.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
size_t value; // offset al Object en el allocator
|
||||||
|
} Variable;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No existe, añadir
|
||||||
|
env->vars[env->count].name = (char *)name;
|
||||||
|
env->vars[env->count].value = value;
|
||||||
|
env->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t eval(ASTNode *node, Environment *env, void *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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user