From 747ac81da23658cb779430129f29d06bbc5a6ef8 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 3 Feb 2026 15:35:36 +0000 Subject: [PATCH] prepare prs --- docs/specs/pbs/files/PRs para Junie Global.md | 43 +- docs/specs/pbs/files/PRs para Junie.md | 789 ++++++++++++++++++ 2 files changed, 825 insertions(+), 7 deletions(-) diff --git a/docs/specs/pbs/files/PRs para Junie Global.md b/docs/specs/pbs/files/PRs para Junie Global.md index 7fa467a7..0c037b57 100644 --- a/docs/specs/pbs/files/PRs para Junie Global.md +++ b/docs/specs/pbs/files/PRs para Junie Global.md @@ -1,10 +1,39 @@ -# PRs for Junie — Compiler Dependency Resolution & Linking Pipeline +## Visão de arquitetura alvo -> Goal: Move dependency resolution + linking orchestration into **prometeu_compiler** so that the compiler produces a **single fully-linked bytecode blob**, and the VM/runtime only **loads + executes**. +### Camadas -## Non-goals (for this PR set) +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. -* No lockfile format (yet) -* No registry (yet) -* No advanced SAT solver: first iteration is deterministic and pragmatic -* No incremental compilation (yet) \ No newline at end of file +### 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). + +--- + +## 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. \ No newline at end of file diff --git a/docs/specs/pbs/files/PRs para Junie.md b/docs/specs/pbs/files/PRs para Junie.md index e69de29b..df068187 100644 --- a/docs/specs/pbs/files/PRs para Junie.md +++ b/docs/specs/pbs/files/PRs para Junie.md @@ -0,0 +1,789 @@ +# Prometeu — PR Plan (Arena-Driven) para um LSP Completo + +> **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.) + +--- + +# 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):** + +--- + +# 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). + +--- + +## 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` + +--- + +# Ordem recomendada (para minimizar refator churn) + +1. PR-00, PR-01 +2. PR-02 +3. PR-03 +4. PR-04 +5. PR-06 +6. PR-05 +7. PR-07 +8. PR-08 → PR-12 +9. PR-14 +10. PR-15