Add bytecode VM backend (compile AST to bytecodes + stack-based VM)
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/.
This commit is contained in:
266
readme.md
266
readme.md
@@ -1,52 +1,240 @@
|
||||
# j-lang
|
||||
|
||||
La idea de j-lang es crear un "proto-lenguaje" parecido a python pero implementado desde 0 para validar y aprender más sobre la gestión de memoria.
|
||||
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.
|
||||
|
||||
Actualmente en `mem-heap\src\allocator.h` ya hay una implementeción de un Memory Allocator casi funcional.
|
||||
## Estado actual
|
||||
|
||||
## 🗺️ Hoja de Ruta: Proyecto Proto-Lenguaje
|
||||
Esta ruta va desde lo más bajo (la memoria) hasta lo más alto (ejecutar código).
|
||||
Las 5 fases del interprete estan implementadas y funcionando:
|
||||
|
||||
### Fase 1: El Cimiento (Gestión de Memoria) 🏗️
|
||||
Objetivo: Tener un malloc y free propios que gestionen metadatos compactos.
|
||||
```
|
||||
Codigo fuente (.j)
|
||||
|
|
||||
[LEXER] src/frontend/lexer.h
|
||||
|
|
||||
Tokens
|
||||
|
|
||||
[PARSER] src/frontend/parser.h
|
||||
|
|
||||
AST
|
||||
|
|
||||
[EVAL] src/vm/eval.h
|
||||
|
|
||||
Ejecucion + GC
|
||||
```
|
||||
|
||||
Estado: ¡Ya estás aquí!
|
||||
### Que funciona
|
||||
|
||||
Tareas clave:
|
||||
- [ ] Terminar CMA_malloc con la cabecera compactada (Size + Marked + InUse).
|
||||
- [ ] Implementar una función CMA_free que pueda liberar un bloque específico.
|
||||
- **Variables y asignacion:** `x = 10`
|
||||
- **Aritmetica:** `+`, `-`, `*`, `/` con enteros
|
||||
- **Comparaciones:** `<`, `>`
|
||||
- **Strings:** literales, concatenacion con `+`, `len()`
|
||||
- **Control de flujo:** `if` y `while` con 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`
|
||||
|
||||
### Fase 2: El Modelo de Objetos (Object Model) 📦
|
||||
Objetivo: Definir cómo se ve un número, una cadena o una lista dentro de tu memoria C.
|
||||
Conexión: Cada objeto de tu lenguaje será un struct en C que comienza con tu CMA_metadata.
|
||||
### Ejemplo
|
||||
|
||||
Tareas clave:
|
||||
- [ ] Crear un enum para los tipos (ENTERO, STRING, LISTA).
|
||||
- [ ] Definir el struct Object genérico que envuelve tus datos.
|
||||
```
|
||||
x = 0
|
||||
while x < 10:
|
||||
x = x + 1
|
||||
|
||||
### Fase 3: El Front-End (Lexer y Parser) 📖
|
||||
Objetivo: Convertir el texto del código fuente en algo que C entienda.
|
||||
|
||||
Tareas clave:
|
||||
- [ ] Lexer (Tokenizador): Romper el texto x = 10 en fichas: [ID:x], [OP:=], [NUM:10].
|
||||
- [ ] Parser: Organizar esas fichas en un Árbol de Sintaxis Abstracta (AST). Por ejemplo, un nodo "Asignación" que tiene un hijo "x" y otro "10".
|
||||
|
||||
### Fase 4: El Motor (Evaluador o VM) ⚙️
|
||||
Objetivo: Recorrer el árbol y "hacer" lo que dice.
|
||||
|
||||
Tareas clave:
|
||||
- [ ] Crear una función recursiva eval(nodo) que ejecute la lógica.
|
||||
|
||||
Si es un nodo SUMA, suma los hijos. Si es un nodo IMPRIMIR, muestra en pantalla.
|
||||
|
||||
### Fase 5: El Recolector de Basura (Garbage Collector) 🧹
|
||||
Objetivo: Automatizar la limpieza.
|
||||
|
||||
Tareas clave:
|
||||
- [ ] Implementar Mark (Marcar): Recorrer todos los objetos accesibles desde tus variables y poner el bit Marked a 1.
|
||||
- [ ] Implementar Sweep (Barrer): Recorrer todo el heap linealmente (usando tu función next_block). Si un bloque tiene Marked == 0 y InUse == 1, llamar a CMA_free.
|
||||
if x > 9:
|
||||
println("fin")
|
||||
```
|
||||
|
||||
## Estructura del proyecto
|
||||
|
||||
- vm: maquina virtual de j-lang
|
||||
- projects: carpeta con scripts en j-lang
|
||||
```
|
||||
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
|
||||
|
||||
```bash
|
||||
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`:
|
||||
|
||||
```c
|
||||
// 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.
|
||||
|
||||
Reference in New Issue
Block a user