|
| 1 | +# Robustez do Pretty Printer |
| 2 | + |
| 3 | +> Objetivo: garantir que o pretty printer seja previsível, observável e extensível antes de ampliarmos o front-end e a geração de código. |
| 4 | +
|
| 5 | +Este documento complementa o `REFACTORING_LOG.md` descrevendo como e quando usar os recursos opcionais e novos combinadores do sistema de pretty printing. |
| 6 | + |
| 7 | +## Visão Geral |
| 8 | +O pretty printer segue abordagem algébrica (Wadler) com variantes: `Nil, Text, Line, HardLine, Nest, Concat, Group`. Otimizações e extensões introduzidas na Fase 6 visam: |
| 9 | +- Observabilidade (tempo, contadores) |
| 10 | +- Robustez estrutural (balanceamento, cache opcional) |
| 11 | +- Ergonomia (fill, comentários, prelude) |
| 12 | + |
| 13 | +## Combinadores Principais |
| 14 | +- `group(doc)`: tenta layout em uma linha; se não couber, quebra nos `Line`. |
| 15 | +- `nest(indent, doc)`: aplica indentação às quebras internas. |
| 16 | +- `line() / hardline()`: quebra suave vs obrigatória. |
| 17 | +- `space()`: atalho `" "`. |
| 18 | +- `concat(a, b)`: concatenação direta. |
| 19 | +- `punctuate(sep, docs)`: intercala `sep` entre elementos; adaptativo (balanceado) para listas > 8. |
| 20 | +- `fill(docs)`: tenta manter itens sucessivos na mesma linha antes de quebrar. |
| 21 | +- `hardline_if_nonempty(docs)`: adiciona `hardline` após cada doc quando há pelo menos um. |
| 22 | +- Comentários: `line_comment`, `line_comment_ln`, `block_comment`. |
| 23 | + |
| 24 | +## Comentários |
| 25 | +- `line_comment("foo")` produz `// foo` (prefixo `//` opcional na entrada é normalizado). |
| 26 | +- `line_comment_ln` adiciona quebra obrigatória após o comentário. |
| 27 | +- `block_comment`: |
| 28 | + - Entrada single-line => `/* body */`. |
| 29 | + - Multi-linha => formato padronizado com prefixo ` * ` e fechamento em linha separada. |
| 30 | + - Linhas externas vazias são removidas; espaços à esquerda por linha normalizados. |
| 31 | + |
| 32 | +## Prelude |
| 33 | +Uso opcional de ergonomia. Para a lista curada de símbolos e política de estabilidade consulte `docs/PRELUDE.md`. |
| 34 | +Exemplo rápido: |
| 35 | +``` |
| 36 | +use r_python::prelude::*; |
| 37 | +let doc = group(concat(text("a"), concat(line(), text("b")))); |
| 38 | +assert_eq!(pretty(4, &doc), "a b"); |
| 39 | +``` |
| 40 | + |
| 41 | +## Features de Instrumentação |
| 42 | +| Feature | Propósito | Overhead | Quando usar | |
| 43 | +|---------|-----------|----------|-------------| |
| 44 | +| `pp-profile` | Contadores (`flatten`, `fits`, grupos) | Muito baixo | Diagnóstico de regressões / tuning rápido | |
| 45 | +| `pp-timing` | Tempo total + métricas (struct `PrettyMetrics`) | Baixo (chamada a `Instant`) | Medir impacto de novos combinadores | |
| 46 | +| `pp-flatten-cache` | Memoização de `flatten(doc)` por identidade | Médio (HashMap) | Árvores grandes reutilizando subdocs | |
| 47 | + |
| 48 | +Ative combinando: |
| 49 | +``` |
| 50 | +cargo test --features "pp-profile pp-timing" |
| 51 | +``` |
| 52 | + |
| 53 | +## Estratégias Recomendadas |
| 54 | +1. Investigação de desempenho: ligue `pp-profile` para contagem de chamadas. |
| 55 | +2. Medição comparativa: adicione `pp-timing` e compare `duration_ns` antes/depois. |
| 56 | +3. Casos sintéticos repetitivos: experimente `pp-flatten-cache` e verifique se `flatten_calls` cai proporcionalmente. |
| 57 | +4. Uso cotidiano / produção: nenhuma feature para via mais enxuta. |
| 58 | + |
| 59 | +## Padrões de Uso |
| 60 | +- Listas grandes: use `punctuate` diretamente; o balanceamento interno evita profundidade excessiva. |
| 61 | +- Sequências densas heterogêneas (ex.: parâmetros de função com tamanhos variáveis): considere `fill` para melhor compactação horizontal. |
| 62 | +- Comentários antes de blocos: `line_comment_ln` seguido de `group(...)` do bloco garante isolamento visual. |
| 63 | +- Documentar módulo público: `block_comment` multi-linha antes de declarações top-level. |
| 64 | + |
| 65 | +## Limitações Atuais |
| 66 | +- `fill` ainda não implementa heurística de redistribuição após primeira quebra (versão incremental). |
| 67 | +- `block_comment` normaliza indentação em vez de preservar formato ASCII-art. |
| 68 | +- Sem suporte a comentários de documentação diferenciados (planejável via futura função `doc_comment`). |
| 69 | + |
| 70 | +## Possíveis Evoluções Futuras |
| 71 | +- Interning lazy da forma flatten dentro de `Group` (elimina HashMap externo). |
| 72 | +- `fill` avançado (variante com alternância espaço/quebra minimizando altura total). |
| 73 | +- Comentários doc vs regulares com marcação distinta. |
| 74 | +- Ferramenta de benchmark sintético automatizado (collect + relatório diff). |
| 75 | + |
| 76 | +## Exemplo End-to-End |
| 77 | +``` |
| 78 | +use r_python::prelude::*; |
| 79 | +
|
| 80 | +let params: Vec<_> = [ |
| 81 | + text("user_id"), |
| 82 | + text("very_long_parameter_name"), |
| 83 | + text("flag"), |
| 84 | +].into_iter().collect(); |
| 85 | +
|
| 86 | +let signature = group(concat(text("fn foo("), concat(fill(¶ms), text(")")))); |
| 87 | +let commented = concat(line_comment_ln("Função de exemplo"), signature); |
| 88 | +let out = pretty(40, &commented); |
| 89 | +println!("{out}"); |
| 90 | +``` |
| 91 | + |
| 92 | +## Checklist Rápido |
| 93 | +- Resultado inesperado flatten? Ative `pp-profile` e observe contadores. |
| 94 | +- Layout muito vertical? Tente `fill` em vez de `punctuate` simples. |
| 95 | +- Performance degradou? Compare `duration_ns` com e sem alteração. |
| 96 | + |
| 97 | +## Exemplos Práticos |
| 98 | + |
| 99 | +### 1. Instrumentação (tempo + contadores) |
| 100 | +Arquivo: `examples/pp_timing.rs` |
| 101 | + |
| 102 | +Somente tempo: |
| 103 | +``` |
| 104 | +cargo run --release --features pp-timing --example pp_timing |
| 105 | +``` |
| 106 | +Tempo + contadores: |
| 107 | +``` |
| 108 | +cargo run --release --features "pp-timing pp-profile" --example pp_timing |
| 109 | +``` |
| 110 | +Mostra variação de layout (larguras 120 / 40 / 15) e, quando `pp-profile` ativado, imprime `flatten=`, `fits=`, `groups=`. |
| 111 | + |
| 112 | +### 2. Comentário seguido de bloco |
| 113 | +``` |
| 114 | +let seq = concat(line_comment_ln("comentário"), group(concat(text("x = 1"), concat(line(), text("y = 2"))))); |
| 115 | +``` |
| 116 | + |
| 117 | +### 3. Lista grande balanceada (> 8 elementos) |
| 118 | +``` |
| 119 | +let xs: Vec<_> = (0..15).map(|i| text(format!("x{i}"))).collect(); |
| 120 | +let doc = group(punctuate(concat(text(","), line()), &xs)); |
| 121 | +``` |
| 122 | + |
| 123 | +### 4. Fill com itens heterogêneos |
| 124 | +``` |
| 125 | +let docs = vec![text("a"), text("bbbbbbbbbbbb"), text("c"), text("dd")]; |
| 126 | +let laid = fill(&docs); |
| 127 | +``` |
| 128 | +Mantém densidade à esquerda até a quebra forçada pelo item longo. |
| 129 | + |
| 130 | + |
| 131 | +--- |
| 132 | +Manter este arquivo conciso e focado em operação; detalhes cronológicos continuam em `REFACTORING_LOG.md`. |
0 commit comments