New execution mode: ./run vm <file.j> compiles AST to bytecodes and runs them in a while/switch loop. Ints/floats live on the stack (no heap allocation), ~7.7x faster than the tree-walking interpreter. Implements: opcodes, compiler with backpatching (if/while), stack VM with arithmetic, comparisons, variables, strings, and print/println. Reorganizes backend into src/backend/eval/ and src/backend/bytecode/.
j-lang
Un proto-lenguaje con sintaxis inspirada en Python, implementado desde cero en C. El objetivo es aprender sobre gestion de memoria, tokenizacion, parsing y evaluacion de un lenguaje de programacion.
Estado actual
Las 5 fases del interprete estan implementadas y funcionando:
Codigo fuente (.j)
|
[LEXER] src/frontend/lexer.h
|
Tokens
|
[PARSER] src/frontend/parser.h
|
AST
|
[EVAL] src/vm/eval.h
|
Ejecucion + GC
Que funciona
- Variables y asignacion:
x = 10 - Aritmetica:
+,-,*,/con enteros - Comparaciones:
<,> - Strings: literales, concatenacion con
+,len() - Control de flujo:
ifywhilecon bloques indentados (estilo Python) - Funciones built-in:
print(),println(),len() - Llamadas a funciones con multiples argumentos separados por
, - Expresiones con parentesis:
2 * (4 - 2) - Numeros negativos:
-300 - Comentarios:
// esto es un comentario
Ejemplo
x = 0
while x < 10:
x = x + 1
if x > 9:
println("fin")
Estructura del proyecto
src/
frontend/
lexer.h Tokenizador: texto -> tokens
parser.h Parser: tokens -> AST
memory/
allocator.h Memory allocator custom (heap simulado)
gc.h Garbage collector (mark-and-sweep)
objects/
object.h Modelo de objetos (int, float, string, list)
vm/
eval.h Evaluador: recorre el AST y ejecuta
main.c Punto de entrada
projects/ Scripts de ejemplo en .j
docs/
roadmap.md Roadmap detallado de implementacion
Memory allocator
Heap simulado sobre un array de bytes con metadatos por bloque (size, in_use, marked). Soporta asignacion, liberacion, reutilizacion de bloques libres (first-fit) y crecimiento automatico cuando se queda sin espacio.
Garbage collector
Mark-and-sweep: marca los objetos alcanzables desde las variables del environment, barre los no marcados y fusiona bloques libres contiguos.
Modelo de objetos
Los valores del lenguaje se representan como Object con tagged union. Tipos soportados: OBJ_INT, OBJ_FLOAT, OBJ_STRING, OBJ_LIST, OBJ_NONE. Los objetos viven en el heap custom y se referencian por offset (no punteros absolutos).
Compilar y ejecutar
gcc src/main.c -o run
./run projects/sum.j
Roadmap: que falta para hacer un juego 2D con JLang
Para poder escribir un juego 2D tipo "mover un personaje por pantalla, disparar, colisiones" con JLang, harian falta estos bloques:
1. Funciones de usuario
Lo mas urgente. Sin funciones no se puede organizar nada.
fn update(dt):
player_x = player_x + speed * dt
fn draw():
draw_rect(player_x, player_y, 32, 32)
Implica: nuevo token fn, nodo NODE_FUNC_DEF en el AST, almacenar el cuerpo de la funcion en el environment, y un mecanismo de scopes (variables locales vs globales).
2. Return
Las funciones necesitan devolver valores.
fn distance(x1, y1, x2, y2):
dx = x1 - x2
dy = y1 - y2
return sqrt(dx * dx + dy * dy)
3. Structs o clases
Para representar entidades del juego (jugador, enemigos, balas...).
class Entity:
x = 0
y = 0
w = 32
h = 32
player = Entity()
player.x = 100
player.y = 200
Implica: acceso a campos con ., constructor, almacenar la definicion de la clase como un objeto mas en el heap.
4. Listas funcionales
Las listas ya existen como tipo (OBJ_LIST) pero no hay sintaxis para usarlas. Se necesitan para manejar colecciones de entidades.
enemies = [Enemy(), Enemy(), Enemy()]
append(enemies, Enemy())
i = 0
while i < len(enemies):
update(enemies[i])
i = i + 1
Implica: sintaxis [...], acceso por indice lista[i], append(), len() para listas.
5. Else / elif
Imprescindible para logica de juego.
if key == "left":
player_x = player_x - speed
elif key == "right":
player_x = player_x + speed
else:
speed = 0
6. For loops
Iterar de forma mas limpia que con while.
for enemy in enemies:
draw_rect(enemy.x, enemy.y, enemy.w, enemy.h)
7. Operadores que faltan
%(modulo) - util para animaciones ciclicas, wrapping==,!=(ya tokenizados pero no evaluados completamente)<=,>=and,or,not- operadores logicos+=,-=- azucar sintactico
8. Floats funcionales
El tipo OBJ_FLOAT existe pero no se puede usar desde el lenguaje. Para un juego se necesita aritmetica de punto flotante para posiciones, velocidades, delta time, etc.
player_x = 100.0
speed = 2.5
player_x = player_x + speed * dt
9. Libreria grafica (FFI a C)
El punto critico. JLang necesita poder llamar a una libreria grafica en C como SDL2 o raylib. Hay dos caminos:
Opcion A: Built-in functions (mas facil)
Registrar funciones C directamente en el evaluador, como ya se hace con print:
// En el eval, junto a print/println:
if (strcmp(name, "draw_rect") == 0) { SDL_RenderFillRect(...); }
if (strcmp(name, "key_pressed") == 0) { ... }
Opcion B: FFI generico (mas ambicioso) Un sistema para enlazar funciones C arbitrarias desde JLang.
Las funciones minimas para un juego serian:
| Funcion | Descripcion |
|---|---|
create_window(w, h, title) |
Crear ventana |
clear() |
Limpiar pantalla |
draw_rect(x, y, w, h, r, g, b) |
Dibujar rectangulo |
draw_image(path, x, y) |
Dibujar imagen/sprite |
present() |
Mostrar frame |
key_pressed(key) |
Consultar tecla |
get_dt() |
Delta time entre frames |
random(min, max) |
Numero aleatorio |
10. Funciones matematicas
sqrt(), sin(), cos(), abs(), random(). Todas se pueden registrar como built-ins que llamen a math.h.
Orden sugerido de implementacion
1. Funciones de usuario + return (sin esto no se puede hacer nada)
2. Else / elif
3. Floats funcionales
4. Operadores que faltan (%, <=, >=, and, or)
5. Listas con sintaxis ([], indexado, append)
6. For loops
7. Structs o clases
8. Built-ins graficos (SDL2/raylib)
9. Funciones matematicas
10. Juego 2D funcional
Los pasos 1-7 son trabajo puro de lenguaje (lexer/parser/eval). El paso 8 es donde JLang toca el mundo real: linkear con SDL2 o raylib a la hora de compilar y exponer las funciones como built-ins en el evaluador.