Pular para o conteúdo

O compilador: o mapa

Item por item da parte 7 da referência Deep Tech — pipeline, lexer, parser, AST, HIR, MIR, LIR e análise estática — cruzado com o que o DataForge tem.

A sétima parte de uma referência Deep Tech abre o compilador: as oito seções vão do pipeline às análises. É a parte em que o DataForge tem mais do que parece — ele tem lexer, parser, AST, analisador e backend próprios — e ao mesmo tempo a primeira em que um item é honestamente não se aplica.

30 · Pipeline de compilação#

ItemNo DataForgeOnde
fluxo de fasesseis fases, e dataforge ir mostra cada umaPipeline
type checkingtypechecker.py — 1752 linhas, entre o HIR e o MIRAnálise estática
borrow checkingArcane.Posse mais as checagens de fluxo do checkPosse
LLVM IR, machine code, linkernão se aplica: o DataForge é interpretado. O backend é o compilador de fechamentos, e a última fase é chamar fechamento PythonPipeline

31 · Lexer#

ItemNo DataForgeOnde
tokenização, identificadores, keywordslexer.py; 81 palavras reservadas, e as contextuais que não sãoPalavras
literais, operadoresinteiro, real, texto, yes/no/void, tupla; ~/ para divisão inteiraOperadores
comentários// é comentário por padrão, e vira divisão só quando o que segue confirmaOperadores
strings, interpolação$"…{expr}…", com {x:.2f}; a string aninhada é copiada verbatimInterpolação
source spanslinha, coluna e span em todo nó e em todo erro — é o que desenha a setaErros
erros léxicosSyncError para tab na indentação, e a mensagem diz o que fazerErros
INDENT/DEDENTalém da lista: o lexer emite os dois, e é deles que sai a profundidade do formatadorArquitetura

32 · Parser#

ItemNo DataForgeOnde
recursive descentparser.py, 1941 linhas, descendente recursivoArquitetura
precedência, associatividadepor nível de função (parse_orparse_and → …)Gramática
parsing de expressões e declaraçõeso conjunto todo, com a EBNF gerada do códigoGramática
AST constructionast_nodes.py — 140 dataclassesAST
Pratt parsernão é a técnica usada: a precedência é a cascata de funções. Pratt paga quando a tabela de operadores é dinâmica, e aqui ela é fixa
recuperação de errosparcial: o check continua depois de um arquivo que não compila (a superfície devolve aberta = yes), mas dentro de um arquivo o primeiro erro de sintaxe encerra a leitura

33 · AST#

ItemNo DataForgeOnde
nós de expressão e de declaração140 classes; dataforge ast e K.arvore(fonte)Pipeline
tipos, funções, structs, traits, genericsTypeDeclaration, ActionDeclaration, RecordDeclaration, TraitDeclaration, type_paramsTipos
pattern matchingoito classes de padrão, de WildcardPattern a OrPatternPattern matching
metadados, source locationsline, column em toda ASTNode; a ação sabe em que arquivo nasceuErros
a árvore como dadoalém da lista: Arcane.Macro a entrega como vault, e a volta é conferidaMacros

34 · HIR#

ItemNo DataForgeOnde
desugaringhir.normalizar — cinco açúcares, e oito formas que só parecemHIR
resolução de nomeshir.resolucao — parâmetro, local, livre, embutido, por corpoHIR
normalizaçãoé o mesmo passo: o HIR é a AST restrita ao núcleoHIR
expansão de macrosroda na carga, no comptime e no decorador de macro — antes desta fasecomptime
representação semânticao HIR usa as mesmas classes da AST, de propósito: é o que permite provar a equivalência rodando os doisHIR

35 · MIR#

ItemNo DataForgeOnde
basic blocks, controle de fluxomir.construir — um corpo por ação, arestas rotuladasMIR
dataflow analysisvivacidade, definição em todo caminho, propagação de constanteAnálises
borrow checkingposse-movida, emprestimo-escapa, recurso-vazado — no typechecker, sobre a árvorePosse
ownership analysisa mesma família, e escapam responde quem mais alcança o valorAnálises
lifetime analysisnão há tempo de vida nomeado ('a): o coletor do Python responde pela memória, e um 'a sem nada para provar seria cerimônia
otimizações intermediáriasnão há: o MIR é para analisar, não para reescrever. O ganho de velocidade vem do compilador de fechamentos, medido em 1,5× a 1,8×

36 · LIR#

ItemNo DataForgeOnde
loweringa árvore vira fechamentos Python, uma vezLIR
operações primitivascada fechamento delega aos mesmos auxiliares do interpretador (_operar, _comparar) — não há segunda semânticaArquitetura
preparação para backendé o backend: dataforge ir --fase=lir diz o que compilou e o que recuouLIR
calling conventions, ABI loweringexistem, mas só na fronteira com o C: Arcane.C declara a assinatura e o ctypes aplica a ABI da plataformaFFI
representação de memóriao mesmo: C.estrutura dá tamanho, alinhamento e deslocamento de verdadeFFI
registradores, spillingnão se aplica

37 · Análise estática#

ItemNo DataForgeOnde
type checkingdataforge check, e ele atravessa arquivos: aridade, tipo de parâmetro e de retorno pela fronteira do adoptAnálise estática
dataflow analysisas cinco análises do MIRAnálises
reachabilityalcancaveis, mais o unreachable depois de yield/halt/skip e o point-inalcancavelAnálises
dead code analysisunused-variable, unused-import, unused-parameter no lintLint
constant propagationconstantes, e o check já provava indice-fora-do-alcance e chave-ausente a partir de literalAnálises
escape analysisescapam, com quatro motivosAnálises
borrow / lifetime analysisa família da posse; tempo de vida nomeado não existePosse
static assertionsassert dentro de comptime — o check o executa e acusa comptime-falhoucomptime
formal verification hooksexpects, promises, invariant são contratos cobrados em execução, e --plugin= deixa acoplar uma regra própria. Prova formal (SMT, refinamento provado) não existeContratos

O resumo honesto#

Das oito seções, seis estão cobertas de ponta a ponta — e duas delas (HIR e MIR) passaram a existir como representação inspecionável, não só como código escondido dentro do analisador. O que fica de fora é o que depende de gerar código de máquina: LLVM, registradores, linker. Não é uma lacuna a preencher: é o que a escolha de ser interpretado significa, e o teto dessa técnica já está medido em ~6,5×.