# 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-00 — Infra: crates de análise + lsp (estrutura do workspace) **Branch:** `pr-00-analysis-lsp-foundations` ### Decisão travada (LSP) * **Biblioteca escolhida:** `tower-lsp` * **Motivo:** reduzir boilerplate, acelerar MVP e minimizar vai-e-volta. Cancelamento/incremental será feito **por cima** (tasks async + cancel tokens). ### Objetivo Adicionar crates novas sem mexer no pipeline existente. ### Entregas obrigatórias 1. **Novo crate:** `prometeu-analysis/` * `Cargo.toml` (library) * `src/lib.rs` 2. **Novo crate:** `prometeu-lsp/` * `Cargo.toml` (bin) * `src/main.rs` 3. Workspace root: ajustar `Cargo.toml` (se existir no root) para incluir members. ### Dependências (fixas) * `prometeu-analysis`: `serde`, `serde_json` * `prometeu-lsp`: * `tower-lsp = "0.20"` (ou versão estável atual) * `tokio` (full) * `prometeu-analysis` (path) ### Esqueleto obrigatório (`prometeu-lsp/src/main.rs`) ```rust use tower_lsp::{LspService, Server}; use tokio::sync::RwLock; use std::sync::Arc; #[derive(Default)] struct AnalysisDb { // FileDB, AstArena, SymbolArena, TypeArena, Diagnostics } struct Backend { db: Arc>, } #[tower_lsp::async_trait] impl tower_lsp::LanguageServer for Backend { async fn initialize(&self, _: tower_lsp::lsp_types::InitializeParams) -> tower_lsp::jsonrpc::Result { Ok(tower_lsp::lsp_types::InitializeResult { capabilities: tower_lsp::lsp_types::ServerCapabilities { text_document_sync: Some(tower_lsp::lsp_types::TextDocumentSyncCapability::Kind( tower_lsp::lsp_types::TextDocumentSyncKind::FULL, )), // Declaramos capacidades desde já para evitar churn posterior. definition_provider: Some(true.into()), document_symbol_provider: Some(true.into()), workspace_symbol_provider: Some(true.into()), hover_provider: Some(true.into()), references_provider: Some(true.into()), rename_provider: Some(tower_lsp::lsp_types::OneOf::Left(true)), completion_provider: Some(tower_lsp::lsp_types::CompletionOptions { resolve_provider: Some(false), trigger_characters: Some(vec![".".into(), ":".into()]), ..Default::default() }), semantic_tokens_provider: Some( tower_lsp::lsp_types::SemanticTokensServerCapabilities::SemanticTokensOptions( tower_lsp::lsp_types::SemanticTokensOptions { legend: tower_lsp::lsp_types::SemanticTokensLegend { // preenchido no PR-12 token_types: vec![], token_modifiers: vec![], }, full: Some(tower_lsp::lsp_types::SemanticTokensFullOptions::Bool(true)), range: None, ..Default::default() }, ), ), ..Default::default() }, ..Default::default() }) } async fn initialized(&self, _: tower_lsp::lsp_types::InitializedParams) {} } #[tokio::main] async fn main() { let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); let (service, socket) = LspService::new(|_| Backend { db: Arc::new(RwLock::new(AnalysisDb::default())) }); Server::new(stdin, stdout, socket).serve(service).await; } ``` ### Contrato exato do AnalysisDb (travado) > **Regra:** o LSP nunca recalcula segurando `RwLock` por muito tempo. Toda análise pesada roda fora do lock e depois faz swap. Criar arquivo: `prometeu-lsp/src/analysis_db.rs` ```rust use std::sync::Arc; use tokio::sync::RwLock; use tokio_util::sync::CancellationToken; use prometeu_analysis::FileDB; #[derive(Default)] pub struct AnalysisDb { pub file_db: FileDB, // Os campos abaixo serão conectados conforme PR-03/04/05 (podem começar como None) // pub ast: Option, // pub symbols: Option, // pub types: Option, // pub diagnostics: Vec, /// Incrementa a cada rebuild concluído com sucesso pub revision: u64, /// Cancel token do último rebuild em progresso (se houver) pub active_rebuild: Option, } pub type SharedDb = Arc>; ``` No `main.rs`, **substituir** o `AnalysisDb` local pelo import acima (ou manter local e delegar, mas sem duplicar). ### Modelo de cancelamento e coalescing (travado) > Objetivo: quando chegam múltiplos `didChange` em sequência, cancelar o rebuild anterior e rodar apenas o último. Adicionar dependência fixa em `prometeu-lsp/Cargo.toml`: * `tokio-util` Criar arquivo: `prometeu-lsp/src/rebuild.rs` ```rust use tokio_util::sync::CancellationToken; use crate::analysis_db::SharedDb; /// Solicita rebuild do projeto (coarse). Cancela rebuild anterior se em progresso. /// Implementação inicial: apenas cria task e retorna. pub async fn request_rebuild(db: SharedDb) { // 1) lock curto: cancelar token anterior e instalar token novo // 2) spawn task: roda análise fora do lock // 3) lock curto: se token não cancelado, swap estado + revision++ } ``` Regras obrigatórias: 1. `request_rebuild` deve: * cancelar `active_rebuild` anterior (se existir) * instalar um token novo * `tokio::spawn` uma task de rebuild 2. A task deve checar `token.is_cancelled()` em pontos seguros: * antes de começar * após parsing * após resolver * após typecheck 3. O lock (`RwLock`) deve ser segurado apenas: * para trocar `active_rebuild` * para aplicar o resultado final ### Critérios de aceite * `cargo build -p prometeu-lsp` ok * LSP inicializa em VS Code/Neovim sem crash * Nenhuma feature além do declarado --- ## Política fixa de cancelamento e rebuild (tower-lsp) ### Objetivo Garantir que edições rápidas não gerem backlog de análises e evitar race conditions. ### Decisão travada * Usar `tokio_util::sync::CancellationToken` * **Um token por rebuild** * Qualquer `didChange`: 1. Cancela o rebuild anterior 2. Cria novo token 3. Agenda nova task de análise ### Estruturas obrigatórias ```rust use tokio_util::sync::CancellationToken; struct AnalysisController { current: Option, } ``` ### Regras * Nunca segurar `RwLock` durante parsing/resolver/typecheck. * Fluxo correto: 1. Clonar snapshot dos textos (FileDB) 2. Soltar lock 3. Rodar análise pesada 4. Re-adquirir lock e substituir estado * Tasks devem checar `token.is_cancelled()` entre fases (parse / bind / type). ### Critérios de aceite * Digitar rapidamente não acumula tasks. * Apenas o último estado publica diagnostics. --- ## Contrato fechado do AnalysisDb (fonte de verdade do LSP) ### Objetivo Eliminar ambiguidade sobre o que vive no estado compartilhado. ### Estrutura obrigatória ```rust #[derive(Default)] pub struct AnalysisDb { pub files: FileDB, pub ast: Option, pub symbols: Option, pub types: Option, pub type_facts: Option, pub diagnostics: Vec, } ``` ### Regras * `AnalysisDb` **nunca** armazena estado parcialmente válido. * Se uma fase falhar: * `ast/symbols/types` podem ficar `None` * `diagnostics` deve estar preenchido * LSP handlers **não** rodam análise: apenas leem `AnalysisDb`. ### Leitura segura * Todos os handlers (`definition`, `hover`, `references`, etc.) devem: * adquirir `db.read()` * lidar com `Option::None` retornando `null` / resposta vazia ### Escrita segura * Apenas a task de rebuild escreve no `AnalysisDb`. * Escrita sempre substitui o estado inteiro (swap lógico). ### Critérios de aceite * Nenhum handler pode panic por `None`. * Rebuild substitui estado de forma atômica (do ponto de vista do LSP). --- # Série PR-00.X — Reestruturação de crates (Arena-Driven + LSP-ready) > **Objetivo da série PR-00.X:** reorganizar o workspace em crates com fronteiras claras, **sem alterar comportamento**, preparando o terreno para o Prometeu Arena-Driven (compiler/analysis) e um LSP completo depois. > > **Novo layout alvo (travado):** > > * `prometeu-bytecode` (fica) > * `prometeu-abi` (novo nome para o atual `prometeu-core` depurado) = **types + model + protocols** (sem execução) > * `prometeu-vm` (novo) = execução da VM > * `prometeu-kernel` (novo) = OS + FS + syscalls (implementa interface para a VM) > * `prometeu-runtime-desktop` (fica) = host desktop > * `prometeu-compiler` (fica) > * `prometeu` (CLI) (fica) > > **Regra de ouro:** 1 PR = 1 fronteira. Nada de mover tudo de uma vez. > > **Regras para Junie (serie 00.X):** > > 1. **Não mudar lógica**; apenas mover, ajustar imports, e deixar testes verdes. > 2. Se algo exigir mudança de API pública, criar `TODO(PR-00.Y)` e parar. > 3. Sempre manter o workspace compilável a cada PR. --- ## PR-00.1 — Introduzir `prometeu-abi` (renomear/diluir `prometeu-core`) **Branch:** `pr-00-1-prometeu-abi` ### Objetivo Criar crate `prometeu-abi` contendo **somente tipos e contratos** (types+model+protocols), e manter `prometeu-core` temporariamente como facade/reexport para não quebrar consumidores. ### Passos prescritivos 1. Criar novo crate `crates/prometeu-abi/` com `src/lib.rs`. 2. Copiar para `prometeu-abi` (sem execução): * `model/*` * `debugger_protocol.rs` * `telemetry.rs` * `log.rs` (somente tipos/config; se tiver runtime logger, deixar no core por enquanto) * **traits/contratos** usados por outros crates (ex.: IDs, enums de eventos) 3. Atualizar dependências dos crates consumidores para apontar para `prometeu-abi` onde aplicável. 4. Manter `prometeu-core` compilando com: * `pub use prometeu_abi as abi;` * reexports temporários de tipos que mudaram de path. ### Critérios de aceite * Workspace compila. * Nenhum comportamento muda. * `prometeu-core` ainda existe (temporário). --- ## PR-00.2 — Extrair `prometeu-vm` do `prometeu-core` **Branch:** `pr-00-2-prometeu-vm` ### Objetivo Mover `virtual_machine/*` para `crates/prometeu-vm/`. ### Passos prescritivos 1. Criar crate `crates/prometeu-vm/`. 2. Mover `crates/prometeu-core/src/virtual_machine/**` → `crates/prometeu-vm/src/**`. 3. Ajustar `use` paths em todos os crates. 4. Adicionar shim temporário no `prometeu-core` (se ainda existir): * `pub mod virtual_machine { pub use prometeu_vm::*; }` ### Critérios de aceite * `cargo test` verde. * runtime desktop ainda roda. --- ## PR-00.3 — Extrair `prometeu-kernel` (OS + FS + syscalls) **Branch:** `pr-00-3-prometeu-kernel` ### Objetivo Mover `prometeu_os/*` + `fs/*` (e qualquer dispatcher de syscalls) para `crates/prometeu-kernel/`. ### Passos prescritivos 1. Criar crate `crates/prometeu-kernel/`. 2. Mover: * `crates/prometeu-core/src/prometeu_os/**` → `crates/prometeu-kernel/src/**` * `crates/prometeu-core/src/fs/**` → `crates/prometeu-kernel/src/fs/**` 3. Garantir que o kernel **depende** de: * `prometeu-abi` * `prometeu-vm` 4. Garantir que a VM chama syscalls via interface implementada pelo kernel. 5. Manter shim temporário no `prometeu-core` (se existir): `pub mod prometeu_os { pub use prometeu_kernel::*; }` ### Critérios de aceite * `cargo test` verde. * Sem mudança comportamental (mesmo conjunto de syscalls e traps). --- ## PR-00.4 — Depurar `prometeu-core`: remover execução e virar apenas compat layer **Branch:** `pr-00-4-deprecate-prometeu-core` ### Objetivo Eliminar o conteúdo executável restante do `prometeu-core`, deixando-o como reexport/compat por um curto período. ### Passos * `hardware` e `firmware/hub` ficam onde estiverem por enquanto (podem virar PR-00.5/00.6 se necessário) * `prometeu-core` passa a reexportar: * `prometeu-abi` * `prometeu-vm` * `prometeu-kernel` ### Critérios * Zero imports internos `crate::virtual_machine` etc. fora da facade. --- ## PR-00.5 — (Opcional) Extrair `prometeu-firmware` (hub/boot) **Branch:** `pr-00-5-prometeu-firmware` ### Objetivo Mover `firmware/*` + `prometeu_hub/*` para `crates/prometeu-firmware/`. ### Critérios * runtime desktop depende de `prometeu-firmware`. --- ## PR-00.6 — Remover `prometeu-core` e migrar consumidores **Branch:** `pr-00-6-remove-prometeu-core` ### Objetivo Apagar `prometeu-core` após migração total. ### Critérios * Nenhum crate depende de `prometeu-core`. --- ## 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.