# Prometeu — PR Plan (Arena-Driven) para um LSP Completo --- # **PR-00.X — Reorganização estrutural do workspace (pré–Arena / pré–LSP)** > **Objetivo macro:** separar *modelo/ABI*, *execução*, *kernel* e *tooling* antes de qualquer refator arena-driven. > > **Regra de ouro:** nenhuma mudança de comportamento. Apenas **movimentação de código + ajuste de dependências**. > > **Modelo final alvo:** > > * `prometeu-bytecode` ✅ (fica) > * `prometeu-abi` ✅ (novo — ex-`prometeu-core` sem execução) > * `prometeu-vm` ✅ (novo) > * `prometeu-kernel` ✅ (novo) > * `prometeu-runtime-desktop` ✅ (fica) > * `prometeu-compiler` ✅ (fica) > * `prometeu` (CLI) ✅ (fica agregando) --- > **Meta do Nilton / Junie workflow**: PRs extremamente prescritivos. A Junie só implementa; você revisa o design **antes** do código. > > **Regra de ouro:** cada PR abaixo vem com: > > 1. Arquivos/alvos exatos > 2. Estruturas e assinaturas obrigatórias > 3. Esquemas JSON (quando aplicável) > 4. Testes (golden + unit) > 5. Critérios de aceite “binário” (passou/não passou) --- ## Estado atual (confirmado pelo repo) Workspace (Archive.zip) tem crates: * `prometeu/` * `prometeu-bytecode/` * `prometeu-core/` * `prometeu-compiler/` (bin `src/main.rs`, deps: `serde`, `serde_json`, `anyhow`, `clap`, e família `oxc_*`). **Saída atual existente:** `symbols.json` (schema_version 0), exportando símbolos por projeto, com `decl_span` em `line/col` e paths absolutos. (Vamos evoluir isso no PR-07.) --- ## Visão de arquitetura alvo ### Camadas 1. **FileDB**: texto, URI/path, line-index, snapshots. 2. **Lexer/Parser**: produz **AstArena** (NodeId + spans por nó). 3. **Binder/Resolver**: produz **SymbolArena** + índices (def/ref). 4. **Typecheck**: produz **TypeArena** + facts (node→type, symbol→type). 5. **Analysis Export**: `analysis.json` (full) + `symbols.json` (leve e estável). 6. **LSP Server**: consome `AnalysisDb` e responde requests. ### IDs padronizados (newtypes) * `FileId(u32)` * `NodeId(u32)` * `NameId(u32)` (interner) * `SymbolId(u32)` * `TypeId(u32)` * `ProjectId(u32)` * `ModuleId(u32)` ### Invariantes * AST é **imutável** após construção (normativo na spec PBS). * Nenhuma fase expõe referências diretas entre nós; apenas **IDs**. * IDs externos são aceitos, mas sempre passam por **validate/resolve** (API checked). --- # Templates prescritivos para PR (usar em TODAS) ## Template de descrição (copiar/colar) * **Motivação:** * **Mudança de modelo de dados:** * **APIs novas / alteradas:** * **Arquivos tocados:** * **Testes adicionados/atualizados:** * **Riscos & rollback:** * **Checklist de aceite (binário):** ## Regras para Junie (para reduzir vai-e-volta) 1. Não “inventar design”. Se algo não estiver especificado, **criar TODO** e parar. 2. Não mudar formatação/estilo fora do escopo. 3. Todo novo tipo público precisa de doc-comment curta e exemplo. 4. Toda mudança de JSON precisa: * `schema_version` bump (se não for backward) * teste de snapshot 5. Cada PR deve deixar `cargo test` verde. --- # PRs (detalhados) ## PR-01 — FileDB + LineIndex (base do LSP e spans) **Branch:** `pr-01-filedb` ### Objetivo Criar uma base de arquivos com IDs estáveis na sessão e conversão offset<->(line,col). ### Arquivos / módulos * `prometeu-analysis/src/file_db.rs` * `prometeu-analysis/src/span.rs` * `prometeu-analysis/src/ids.rs` * `prometeu-analysis/src/lib.rs` (re-exports) ### Estruturas obrigatórias ```rust // prometeu-analysis/src/ids.rs #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct FileId(pub u32); // prometeu-analysis/src/span.rs #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Span { pub file: FileId, pub start: u32, // byte offset pub end: u32, // byte offset, exclusive } // prometeu-analysis/src/file_db.rs pub struct FileDB { // map uri->id, id->uri/text/line_index } pub struct LineIndex { // stores line start offsets } ``` ### Regras * Spans são **byte offsets UTF-8** (`start` inclusive, `end` exclusive) — alinhado ao Canonical Addenda. * `LineIndex` deve lidar com ` ` (LF). (CRLF pode ser normalizado na entrada.) ### APIs obrigatórias ```rust impl FileDB { pub fn upsert(&mut self, uri: &str, text: String) -> FileId; pub fn file_id(&self, uri: &str) -> Option; pub fn uri(&self, id: FileId) -> &str; pub fn text(&self, id: FileId) -> &str; pub fn line_index(&self, id: FileId) -> &LineIndex; } impl LineIndex { pub fn offset_to_line_col(&self, offset: u32) -> (u32, u32); pub fn line_col_to_offset(&self, line: u32, col: u32) -> Option; } ``` ### Testes obrigatórios * `tests/file_db_line_index.rs` (unit) * roundtrip offset->(l,c)->offset * bordas (start/end, EOF) ### Critérios de aceite * Testes passam. * Nenhuma mudança no output do `prometeu-compiler` ainda. --- ## PR-02 — NameInterner (NameId) e eliminação de String no hot path **Branch:** `pr-02-name-interner` ### Objetivo Trocar identificadores em AST/resolver de `String` para `NameId`. ### Arquivos * `prometeu-analysis/src/interner.rs` * Ajustar frontend PBS no `prometeu-compiler` (ver lista de toques abaixo). ### Estruturas obrigatórias ```rust #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct NameId(pub u32); pub struct NameInterner { // bidirectional: string->id, id->string } ``` ### APIs obrigatórias ```rust impl NameInterner { pub fn new() -> Self; pub fn intern(&mut self, s: &str) -> NameId; pub fn resolve(&self, id: NameId) -> &str; } ``` ### Regras * Interner é **session-local**. * `resolve` deve retornar `&str` estável (armazenar `String` internamente). ### Touch points no `prometeu-compiler` * Onde hoje existe `String` como nome de símbolo, token de identifier, etc: * AST nodes de `Ident` * Resolver scopes: `HashMap` ### Testes * Unit: intern/resolve, dedup * Golden: manter comportamento de resolver/diags ### Critérios de aceite * Redução de `String` em estruturas hot (resolver) * Build e testes ok. --- ## PR-03 — AST Arena (NodeId) para PBS **Branch:** `pr-03-ast-arena` ### Objetivo Refatorar o AST PBS (atualmente recursivo) para uma arena `Vec` com `NodeId`. ### Alvos no repo * `prometeu-compiler/src/frontends/pbs/*` (localizar AST/parser atuais) ### Estruturas obrigatórias ```rust #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct NodeId(pub u32); pub struct AstArena { pub nodes: Vec, pub spans: Vec, pub roots: Vec, } pub enum NodeKind { File { imports: Vec, decls: Vec }, Import { /* ... */ }, FnDecl { name: NameId, /* ... */, body: NodeId }, // ... (conforme canonical AST do PBS) } ``` ### Regras * `AstArena::push(kind, span) -> NodeId` sempre faz append. * `spans.len() == nodes.len()` sempre. ### APIs obrigatórias ```rust impl AstArena { pub fn push(&mut self, kind: NodeKind, span: Span) -> NodeId; pub fn kind(&self, id: NodeId) -> &NodeKind; pub fn span(&self, id: NodeId) -> Span; } ``` ### Testes obrigatórios * Parser golden tests: comparar JSON canonical (se você já tem) ou snapshots equivalentes. * Unit: invariantes (push mantém alinhamento). ### Critérios de aceite * Nenhum `Box` em AST PBS. * Resolver e typechecker passam a consumir NodeId. --- ## PR-04 — SymbolArena + índices (defs/refs) + node→symbol **Branch:** `pr-04-symbol-arena-index` ### Objetivo Criar `SymbolArena` e índices para features de LSP sem traversal pesado. ### Estruturas obrigatórias ```rust #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct SymbolId(pub u32); pub enum SymbolKind { Type, Value, Service, Function /* etc */ } pub struct Symbol { pub name: NameId, pub kind: SymbolKind, pub exported: bool, pub module: ModuleId, pub decl_span: Span, } pub struct SymbolArena { pub symbols: Vec } pub struct DefIndex { /* HashMap<(ModuleId, NameId, Namespace), SymbolId> */ } pub struct RefIndex { /* Vec> by SymbolId */ } pub struct NodeToSymbol { /* Vec> by NodeId */ } ``` ### APIs obrigatórias * `insert_symbol(...) -> SymbolId` (falha se duplicate, com diag E_RESOLVE_DUPLICATE_SYMBOL) * `record_ref(symbol_id, span)` * `bind_node(node_id, symbol_id)` ### Testes * Duplicate symbol * Undefined identifier * Visibility violations * Determinismo (mesma input → mesma ordem IDs, quando possível) --- ## PR-05 — TypeArena + TypeFacts (node→type, symbol→type) **Branch:** `pr-05-type-arena-facts` ### Objetivo Dar base para hover, completion e erros de tipo. ### Estruturas obrigatórias ```rust #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct TypeId(pub u32); pub enum TypeKind { Primitive { name: NameId }, Struct { sym: SymbolId }, Optional { inner: TypeId }, Result { ok: TypeId, err: TypeId }, Array { inner: TypeId, len: Option }, // ... conforme v0 } pub struct TypeArena { pub types: Vec } pub struct TypeFacts { pub node_type: Vec>, // index by NodeId pub symbol_type: Vec>, // index by SymbolId } ``` ### APIs obrigatórias * `intern_type(TypeKind) -> TypeId` (dedup opcional; documentar) * `set_node_type(NodeId, TypeId)` * `set_symbol_type(SymbolId, TypeId)` ### Testes * Hover type display snapshots. --- ## PR-06 — Diagnostics canonizados (E_* / W_*) **Branch:** `pr-06-diagnostics` ### Objetivo Diagnósticos estáveis e serializáveis, alinhados ao Canonical Addenda (codes). ### Estruturas obrigatórias ```rust pub enum Severity { Error, Warning } pub struct Diagnostic { pub severity: Severity, pub code: String, pub message: String, pub span: Span, pub related: Vec<(String, Span)>, } ``` ### Regras * Codes conforme Canonical Addenda (E_PARSE_*, E_RESOLVE_*, E_TYPE_*). ### Testes * Golden diag JSON determinístico. --- ## PR-07 — Export: `symbols.json` v1 + `analysis.json` v0 **Branch:** `pr-07-analysis-export` ### Objetivo Separar índice leve (`symbols.json`) e export completo (`analysis.json`). ### Símbolos (novo formato recomendado) * **IMPORTANTE:** parar de gravar paths absolutos (usar URI relativo ao projeto quando possível). `symbols.json` v1 (schema_version=1): * `projects[]`: * `project` (string) * `project_dir` (string) (pode ficar absoluto por enquanto) * `symbols[]`: * `symbol_id` (u32) **OU** string estável atual (mantém compat) * `name` (string) * `kind` (string) * `exported` (bool) * `module_path` (string) * `decl_span`: `{ file_uri, start:{line,col}, end:{line,col} }` `analysis.json` (schema_version=0): * `file_table`: [{file_id:u32, uri:string}] * `symbols`: [{symbol_id:u32, name_id:u32, kind, exported, module_id, decl_span}] * `refs`: [{symbol_id:u32, spans:[Span]}] * `types`: [{type_id:u32, kind:...}] * `facts`: { node_type: [...], symbol_type: [...] } * `diagnostics`: [Diagnostic] ### Testes * Snapshot de ambos JSONs. --- ## PR-08 — LSP MVP (diagnostics + symbols + goto definition) **Branch:** `pr-08-lsp-mvp` ### Objetivo LSP funcional mínimo usando `AnalysisDb` (em memória), recompilando quando arquivo muda. ### Features * `initialize` * `didOpen`/`didChange`/`didClose` * `publishDiagnostics` * `documentSymbol` / `workspaceSymbol` * `definition` ### Regras * `didChange`: por enquanto full-text (simplifica) * Rebuild: coarse (projeto inteiro) inicialmente ### Testes * Test harness: abrir doc e pedir definition. --- ## PR-09 — LSP: references + rename **Branch:** `pr-09-lsp-refs-rename` ### Objetivo Baseado em RefIndex e NodeToSymbol. ### Features * `references` * `prepareRename` * `rename` ### Regras de segurança * Não renomear se símbolo não-resolvido. * Não renomear se span em comentário/string. --- ## PR-10 — LSP: hover + signatureHelp **Branch:** `pr-10-lsp-hover-sighelp` ### Features * `hover`: type + docstring (docstring opcional por enquanto) * `signatureHelp`: para call nodes (se parser já marca) --- ## PR-11 — LSP: completion **Branch:** `pr-11-lsp-completion` ### Buckets * locals em scope (se você tiver scope facts) * symbols do módulo * exports importados * members via type facts --- ## PR-12 — LSP: semantic tokens + highlights **Branch:** `pr-12-lsp-semantic` --- ## PR-13 — LSP: formatting + code actions (opcional) **Branch:** `pr-13-lsp-actions` --- ## PR-14 — Incremental analysis + cancelation **Branch:** `pr-14-incremental` --- ## PR-15 — Debug map (pc→span) + integração com traps **Branch:** `pr-15-debug-map` --- --- # Sequência recomendada (travada) 1. PR-00.1 (`prometeu-abi` + compat) 2. PR-00.2 (`prometeu-vm`) 3. PR-00.3 (`prometeu-kernel`) 4. PR-00.4 (depurar `prometeu-core`) 5. PR-00.5 (opcional firmware) 6. PR-00.6 (remover core) > Após PR-00.X, iniciar a trilha Arena-Driven (PR-01..PR-07) no compiler/analysis.