13 KiB
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-coresem 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:
- Arquivos/alvos exatos
- Estruturas e assinaturas obrigatórias
- Esquemas JSON (quando aplicável)
- Testes (golden + unit)
- 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/(binsrc/main.rs, deps:serde,serde_json,anyhow,clap, e famíliaoxc_*).
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
- FileDB: texto, URI/path, line-index, snapshots.
- Lexer/Parser: produz AstArena (NodeId + spans por nó).
- Binder/Resolver: produz SymbolArena + índices (def/ref).
- Typecheck: produz TypeArena + facts (node→type, symbol→type).
- Analysis Export:
analysis.json(full) +symbols.json(leve e estável). - LSP Server: consome
AnalysisDbe 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)
-
Não “inventar design”. Se algo não estiver especificado, criar TODO e parar.
-
Não mudar formatação/estilo fora do escopo.
-
Todo novo tipo público precisa de doc-comment curta e exemplo.
-
Toda mudança de JSON precisa:
schema_versionbump (se não for backward)- teste de snapshot
-
Cada PR deve deixar
cargo testverde.
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.rsprometeu-analysis/src/span.rsprometeu-analysis/src/ids.rsprometeu-analysis/src/lib.rs(re-exports)
Estruturas obrigatórias
// 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 (
startinclusive,endexclusive) — alinhado ao Canonical Addenda. LineIndexdeve lidar com(LF). (CRLF pode ser normalizado na entrada.)
APIs obrigatórias
impl FileDB {
pub fn upsert(&mut self, uri: &str, text: String) -> FileId;
pub fn file_id(&self, uri: &str) -> Option<FileId>;
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<u32>;
}
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-compilerainda.
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
#[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
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.
resolvedeve retornar&strestável (armazenarStringinternamente).
Touch points no prometeu-compiler
-
Onde hoje existe
Stringcomo nome de símbolo, token de identifier, etc:- AST nodes de
Ident - Resolver scopes:
HashMap<NameId, _>
- AST nodes de
Testes
- Unit: intern/resolve, dedup
- Golden: manter comportamento de resolver/diags
Critérios de aceite
- Redução de
Stringem 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
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct NodeId(pub u32);
pub struct AstArena {
pub nodes: Vec<NodeKind>,
pub spans: Vec<prometeu_analysis::Span>,
pub roots: Vec<NodeId>,
}
pub enum NodeKind {
File { imports: Vec<NodeId>, decls: Vec<NodeId> },
Import { /* ... */ },
FnDecl { name: NameId, /* ... */, body: NodeId },
// ... (conforme canonical AST do PBS)
}
Regras
AstArena::push(kind, span) -> NodeIdsempre faz append.spans.len() == nodes.len()sempre.
APIs obrigatórias
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<Node>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
#[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<Symbol> }
pub struct DefIndex { /* HashMap<(ModuleId, NameId, Namespace), SymbolId> */ }
pub struct RefIndex { /* Vec<Vec<Span>> by SymbolId */ }
pub struct NodeToSymbol { /* Vec<Option<SymbolId>> 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
#[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<u32> },
// ... conforme v0
}
pub struct TypeArena { pub types: Vec<TypeKind> }
pub struct TypeFacts {
pub node_type: Vec<Option<TypeId>>, // index by NodeId
pub symbol_type: Vec<Option<TypeId>>, // 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
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
initializedidOpen/didChange/didClosepublishDiagnosticsdocumentSymbol/workspaceSymboldefinition
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
referencesprepareRenamerename
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)
- PR-00.1 (
prometeu-abi+ compat) - PR-00.2 (
prometeu-vm) - PR-00.3 (
prometeu-kernel) - PR-00.4 (depurar
prometeu-core) - PR-00.5 (opcional firmware)
- PR-00.6 (remover core)
Após PR-00.X, iniciar a trilha Arena-Driven (PR-01..PR-07) no compiler/analysis.