Como um formatador reorganiza código sem perder seu significado?
Dois arquivos podem parecer completamente diferentes e ainda representar o mesmo programa. Como escolher uma forma canônica sem apagar comentários, quebrar strings ou alterar operadores?
se(condição){
mostre(valor)//nota
}se (condição) {
··mostre(valor) // nota
}VOCABULÁRIO VISUAL
As decisões que tornam o resultado confiável.
entrada: mostre("a b") // dois espaços importam
regex: mostre("a b") // conteúdo foi alterado
entrada: a - -b
regex: a--b // outro token, outro significado| Ferramenta | Responsabilidade |
|---|---|
| Estilo manual | decisões humanas locais |
| Crivo | diagnósticos e correções específicas |
| Traço | apresentação canônica da estrutura inteira |
| Refatoração | mudança intencional de estrutura semântica |
fonte → lexer → tokens significativos → parser → AST → execução
└─ espaços, quebras, comentários descartados
Traço: fonte → tokens + trivia + posições → estrutura preservadaReaproveitamos lexer e parser da Pulso, porém o lexer agora emite trivia num canal preservado.
| Representação | Conserva | Custo |
|---|---|---|
| AST | significado essencial | perde pontuação e trivia |
| CST | todos os tokens e trivia | árvore mais volumosa |
| AST enriquecida | nós + tokens anexados | associação complexa |
O Traço usa uma CST compacta: folhas apontam para intervalos do texto original e nós representam construções. A AST semântica continua sendo produzida para a prova posterior.
// explica soma → leading da declaração seguinte
função soma() {} // rápido → trailing de soma
a + /* unidade */ b → dangling no operador
// entre blocos → preserva linha vazia e vizinhançaComentários não são reescritos. Strings também são folhas literais: o Traço organiza o entorno, nunca seu conteúdo.
CST + comentários
→ FormatRules produz FormatElement
→ Renderer simples aplica espaços, quebras e indentação
→ texto + SourceMap de intervalosRegras cobrem declarações, chamadas, operadores, funções, condicionais, laços e blocos. Neste capítulo, chamadas longas quebram sempre; o motor que escolhe alternativas virá depois.
função soma(a,b){retorne a+b}
↓
função soma(a, b) {
retorne a + b
}Linhas vazias consecutivas viram uma. Comentários de fim de linha permanecem ali; comentários isolados mantêm sua própria linha.
$ traco format exemplo.pulso
--- exemplo.pulso
+++ exemplo.pulso (Traço 0.1)
-função soma(a,b){retorne a+b}
+função soma(a, b) {
+ retorne a + b
+}
$ traco check exemplo.pulso
arquivo precisa de formatação · exit 1Em check, nenhum byte muda. Em escrita, o Traço confere a versão lida, grava temporário no mesmo filesystem e substitui somente após sucesso.
Os testes verificam que tokens significativos e strings são idênticos, que todos os comentários reaparecem uma vez e que entrada e saída produzem ASTs semanticamente equivalentes para as construções suportadas.
O Traço reorganiza o arquivo porque sabe quais partes carregam significado, quais carregam apresentação e onde cada comentário pertence. Regex não possui esse mapa.
PROJETO COMPLETO · ESTADO EXATO DESTE CAPÍTULO
Baixe o Traço 0.1.
Pacote exclusivo com código Rust, corpus Pulso, testes e limites documentados. O modo check nunca modifica arquivos.