Slide 70 de 74

Como um erro aparece

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

# As três caem na linha 1, a linha em que `main` é declarado: 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. A keyword is reserved however it is spelled, so `Proc` is no more a name than `proc` is.
Onde cai um erro num módulo
$ hive check main.hive
main.hive:2: cannot read `lib/missing.hive`: open lib/missing.hive: no such file or directory

# Com o import corrigido, o erro dentro do módulo é informado lá,
# pelo nome que o módulo dá a ele.
$ hive check main.hive
lib/text.hive:1: in `shout`: `+` wants two of one type, and these are Str and Int

$ hive build
hive: `hive build` needs an entrypoint: `hive build <entrypoint.hive>`.
Integrando um editor
" No Vim ou no Neovim. hive check roda todos os passos do compilador e para
" antes do Go, então responde tão rápido quanto o front end e não escreve
" nada ao lado do arquivo — o que o torna usável a cada vez que se salva.
setlocal makeprg=hive\ check\ %:S
setlocal errorformat=%f:%l:\ %m,%-G%.%#

" :make preenche a lista quickfix, e :cn percorre os erros. O item %-G
" descarta toda linha que não é um diagnóstico.

Todo diagnóstico começa por onde aconteceu — file:line: message — que é o formato que os editores esperam, então integrar um leva um comando de compilação e um padrão. Um erro de compilação não tem nada na frente. Um erro de uso, como hive build sem ponto de entrada, começa com hive:, porque é sobre o que foi digitado e não sobre o código de alguém. Os dois vão para a saída de erro e terminam com 1, então hive emit main.hive > main.go nunca escreve um erro dentro do Go. Um teste que falha é uma resposta e não um defeito, então o relatório dele vai para a saída padrão.

O que uma mensagem diz segue um padrão só:

  • a coisa, pelo nome: parts quer Str[3] e isto é Str[dyn], nunca "tipos incompatíveis";
  • o que fazer: um erro de limites diz como proteger o índice, e um sort que não consegue ordenar no lugar cita as duas correções;
  • por quê, quando o porquê é o ponto: hive.math.max(0, health) é recusado porque o Hive nunca alarga um número pelas suas costas;
  • nenhum palpite: uma palavra-chave com maiúscula errada é informada como uma palavra-chave escrita do jeito errado, e como um nome que a linguagem já tomou.

Cada passo informa tudo o que encontra, mas os passos rodam um depois do outro e o primeiro a encontrar algo para os demais. Um programa com um erro de tipo e um índice sem proteção fica sabendo do erro de tipo, e do índice quando chega até lá. O lexer, o parser e o carregador apontam a linha exata, e um import que não nomeia arquivo nenhum é informado na linha do import. Os passos depois deles veem um programa plano só, então o que eles encontram cai numa declaração — a linha dela, e in `main`: — no arquivo de onde a declaração veio, com os nomes como aquele arquivo os escreve.