Slide 50 de 53
Como um erro se parece
Três erros, e três mensagens
proc main(): void {
Str[3] parts = split("north,south", ",")
echo parts[0]
health := 3
echo hive.math.max(0, health)
}
O que o hive check diz sobre isso
$ hive check colony.hive
colony.hive:1: in `main`: the declaration of `parts` wants Str[3] and this is Str[dyn]
colony.hive:1: in `main`: the first argument of `hive.math.max` wants Float and this is Int
colony.hive:1: in `main`: the second argument of `hive.math.max` wants Float and this is Int
# Os três caem na linha 1 — a linha em que `main` é declarado. É o limite
# acima: depois do carregador, uma posição é a de uma declaração.
Uma mensagem que diz o que fazer
$ hive check guard.hive
guard.hive:1: in `main`: cannot prove this index is in range: it is a computed expression, and there is nothing to hang a guard on. Bind it to a name first, then guard that
$ hive check shouted.hive
shouted.hive:5: `Proc` is a keyword written the wrong way: every keyword in Hive is lower case, and only lower case. Write `proc` — or, if a name was meant, one the language has not already taken.
Integrando um editor
" No Vim ou Neovim. hive check roda todas as passagens do compilador e para
" antes da toolchain do Go, então responde tão rápido quanto o front end e
" não escreve nada ao lado do arquivo — que é o que o torna usável a cada save.
setlocal makeprg=hive\ check\ %:S
setlocal errorformat=%-G\ %.%#,%f:%l:\ %m,%-G%.%#
" :make preenche a lista de quickfix, e :cn percorre os erros. Os dois itens
" %-G descartam o que não é diagnóstico: o primeiro joga fora a continuação
" indentada de uma mensagem que se estende, o último joga fora o resto.
Todo diagnóstico começa dizendo onde aconteceu — arquivo:linha: mensagem — porque essa é a forma que editores esperam, então integrar um não precisa de mais que um comando de compilação e um padrão para ler a saída dele. Uma mensagem que se estende continua em linhas indentadas, então um erro continua sendo uma entrada só na lista de quickfix em vez de várias. E um erro de compilação é impresso sem absolutamente nada na frente: prefixá-lo com um nome de programa colocaria algo antes do nome do arquivo e quebraria justamente esse padrão. Só um erro de uso — hive build sem entrypoint — diz quem está reclamando, porque isso não é um diagnóstico sobre o código-fonte de ninguém.Toda passagem reporta tudo que consegue encontrar em vez de parar na primeira coisa, então um programa com três erros é um programa cujo autor é avisado sobre os três.O que uma mensagem deveria dizer não faz parte da gramática, mas é o padrão a que as próprias mensagens do compilador são submetidas. Nomeie a coisa: `v` é declarado Str[3], nunca "incompatibilidade de tipos". Diga o que fazer: um erro de limites que não consegue provar um índice diz como colocar uma guarda nele, e um sort que não consegue ordenar no lugar nomeia as duas correções. Diga por quê, quando o porquê é o ponto — hive.math.max(0, health) é recusado porque Hive nunca amplia um número pelas suas costas, e uma mensagem que só dissesse "esperava Float, encontrou Int" deixaria quem lê caçando uma conversão que supostamente deveria conhecer. E nunca adivinhe: uma palavra-chave mal grafada é reportada como palavra-chave escrita do jeito errado e como um nome já tomado, porque as duas leituras estão vivas e o compilador não tem como saber qual foi a intenção.Dois limites valem ser conhecidos, e os dois são o preço de uma decisão só — a de que toda passagem depois do carregador vê um programa achatado. Erros das passagens posteriores ao parsing chegam em uma declaração e não em uma linha dentro dela, então a declaração em que o erro está é o máximo de precisão que se consegue: a linha dela é o que a mensagem abre dizendo, e o nome dela é o que a mensagem cita. E em um programa com imports esses mesmos erros são reportados contra o entrypoint, mesmo quando a declaração culpada veio de um módulo importado. Os erros que o lexer, o parser e o resolvedor de imports levantam nomeiam o arquivo e a linha certos, porque esses três rodam por arquivo.Um diagnóstico não é um erro de forma alguma. A falha de um teste é uma resposta e não um defeito, então esse relatório vai para a stdout, e só uma falha do compilador ou da toolchain vai para a stderr.