# design_vm.md — Design da Máquina Virtual Holodeck (v0.1)

> **O Holodeck é a máquina virtual minimalista da NeuroLang.**
>
> Ele executa o IR definido em `../SPEC_IR.md` com semântica determinística,
> stack-based, sem syscalls, sem heap e sem side-effects externos.
>
> Este documento descreve o design interno da VM — como ela representa estado,
> como executa instruções, e como lida com recursão, frames e labels.

---

# 1. Objetivos do design

O Holodeck v0.1 precisa ser:

### ✔ Simples  
Implementável em poucas centenas de linhas quando chegarmos lá.

### ✔ Determinístico  
Sem aleatoriedade, sem concorrência, sem IO.

### ✔ Pedagógico  
Cada instrução tem efeito claro sobre o estado interno.

### ✔ Compatível com backend futuro  
O IR interpretado deve ser mapeável para assembly real.

---

# 2. Modelo de Execução

O Holodeck é uma **máquina de stack** com **call frames**.

Ele mantém dois estados principais:

```

VMState:
stack: [valores inteiros]
call_stack: [Frame]
functions: {nome → Function}

```

E cada frame:

```

Frame:
locals: {nome → valor inteiro}
ip: índice da instrução atual
code: vetor de instruções linearizadas
nargs: número de argumentos exigidos

```

---

# 3. Estrutura Interna das Funções

Funções são carregadas assim:

```

Function:
name: "fib"
nargs: 1
code: [lista de Instruções (com labels já resolvidos)]

```

Labels são resolvidos antes da execução, convertendo:

```

JUMP L_else

```

para:

```

JUMP 12

```

onde `12` é o índice da instrução.

---

# 4. Semântica da Stack

A **stack global** é uma lista de inteiros; toda operação a manipula.

Exemplos:

### `PUSH_CONST 5`
```

stack.push(5)

```

### `ADD`
```

b = stack.pop()
a = stack.pop()
stack.push(a + b)

```

### `CALL f 1`
```

arg = stack.pop()
novo frame com locals = {"arg0": arg}

```

A stack nunca contém objetos complexos no v0.1:
apenas inteiros.

---

# 5. A Call Stack

A call stack é uma pilha de frames.  
Quando uma função chama outra:

### No `CALL name nargs`

1. Retira `nargs` valores da stack.
2. Cria novo Frame:

```

Frame {
locals = {param_name → arg_value},
ip = 0,
code = Function.code,
nargs = Function.nargs
}

```

3. Empilha o frame.
4. Execução continua no novo frame.

### No `RET`

1. Valor de retorno = topo da stack.
2. Desempilha frame atual.
3. Coloca o valor de retorno no topo da stack do frame anterior.
4. Continuação no frame anterior.

Se o frame é `__main__`, a execução termina.

---

# 6. Ciclo de Execução

O loop principal da VM é:

```

frame = call_stack.top()

while true:
instr = frame.code[frame.ip]
executar(instr)
atualizar_ip(instr)

```

### Atualização do IP

* para instruções normais: `frame.ip += 1`
* para `JUMP`: `frame.ip = destino`
* para `JUMP_IF_FALSE`:
  * avalia topo da stack;
  * se false → salta
  * senão → avança uma instrução

### Término

Quando a instrução `RET` retorna para um frame vazio
(significando que estávamos no `__main__`), o programa termina.

---

# 7. Representação das Instruções (IR)

Cada instrução é armazenada internamente como:

```

Instr:
opcode: string
args: lista de argumentos inteiros ou nomes

```

Exemplo:

```

Instr("LOAD_VAR", ["x"])
Instr("PUSH_CONST", [3])
Instr("CALL", ["fib", 1])
Instr("JUMP", [12])

```

Isto simplifica parsing, debugging e execução.

---

# 8. Semântica Formal das Instruções

### `PUSH_CONST n`
```

stack.push(n)

```

### `LOAD_VAR name`
```

stack.push(frame.locals[name])

```

### `STORE_VAR name`
*(não usado em fib, mas previsto)*

```

value = stack.pop()
frame.locals[name] = value

```

### `ADD`
```

b = pop()
a = pop()
push(a + b)

```

### `SUB`
```

b = pop()
a = pop()
push(a - b)

```

### `LT`
```

b = pop()
a = pop()
push(a < b ? 1 : 0)

```

### `JUMP offset`
```

frame.ip = offset

```

### `JUMP_IF_FALSE offset`
```

cond = pop()
if cond == 0:
frame.ip = offset
else:
frame.ip += 1

```

### `CALL name nargs`
```

args = []
for i in range(nargs):
args.append(stack.pop())
args.reverse()

novo_frame = Frame(function=name, locals=params→args)
push novo_frame

```

### `RET`
```

ret = pop()
pop frame atual
push ret na stack do frame anterior

```

---

# 9. Erros e Validações (v0.1)

Erros de runtime levantam falha imediata:

- variável não definida,
- função inexistente,
- número errado de argumentos,
- stack vazia numa operação binária,
- divisão por zero (quando suportarmos DIV mais tarde),
- saltos para offsets inválidos.

O Holodeck v0.1 **não tenta recuperar erros**.
Ele falha rápido e de forma explícita.

---

# 10. Exemplo de Execução: `fib(4)`

### Entrada:

```

CALL fib 1

```

### Execução inicial:

frame0: fib(x=4)

stack:
```

LOAD_VAR x        → [4]
PUSH_CONST 3      → [4,3]
LT                → [0]
JUMP_IF_FALSE     → vai para L_else

```

### No else:

```

x-1 → fib(3)
x-2 → fib(2)
somar resultados

```

Cada chamada cria novo frame,
com IP independente,
stack independente,
retorno empilhado no frame anterior.

---

# 11. Limitações Intencionais

v0.1 NÃO tem:

- heap,
- objetos,
- strings,
- arrays,
- syscalls,
- exceções,
- otimizações,
- tail-call optimization (TCO).

Estas capacidades surgirão no Holodeck v0.2–v0.5.

---

# 12. Teoria Subjacente

O Holodeck v0.1 mistura conceitos de:

- **Python bytecode** (stack VM),
- **Lua VM clássica**,
- **Wasm sem memória externa**,
- **JVM minimal**,
- **Máquinas abstratas usadas no ensino de compiladores**.

É uma máquina virtual ideal:

- simples o suficiente para o Neurotron aprender,
- expressiva o suficiente para recursão não-trivial,
- mapeável para assembly real mais tarde.

---

# 13. Fronteira com o Backend

Quando o backend estiver pronto, cada instrução do Holodeck IR mapeia-se para:

| IR            | x86-64 (exemplo)     |
|---------------|-----------------------|
| `PUSH_CONST`  | `mov rax,imm; push`  |
| `LOAD_VAR x`  | `mov rax,[rbp-offset]` |
| `ADD`         | `pop rbx; pop rax; add rax,rbx; push rax` |
| `CALL`        | prólogo/epílogo padrão |
| `RET`         | `leave; ret`          |

O Holodeck define a semântica;  
o backend define a correspondência binária.

---

# 14. Resumo

O Holodeck v0.1 oferece:

- execução determinística de IR,
- stack machine simples,
- frames recursivos,
- suporte completo para `fib`,
- semântica clara para CALL/RET,
- labels resolvidos,
- loop central simples e robusto.

É o ambiente perfeito para nascer:

```

source.nl → AST → IR → HOLODECK → (validado) → ELF → NFDOS → Neurotron

```

---

Fim de `design_vm.md`