Il progetto

· a new career in a new town

Come verificare che il compilatore compili se stesso, come si valutano le modifiche al linguaggio e quali sono i venti principi stampati da heroes this.

Come verificare che compili se stesso

Il compilatore di Heroes è scritto in Heroes. Compilarlo richiede dati annidati, tabelle di nomi, ricorsione, gestione degli errori e programmi distribuiti su più file. È una prova concreta di come il linguaggio gestisce un programma complesso.

Il repository, l’archivio del progetto, contiene il compilatore anche in un unico file C generato. Puoi compilarlo su un computer dove Heroes non è installato. Poi usi il compilatore ottenuto per tradurre i propri sorgenti in C e confronti i due file. Fallo su una release, la versione che il progetto ha pubblicato:

$ git checkout v0.5.0
$ clang -I runtime seed/heroes.c runtime/runtime.c -o heroes
$ ./heroes build selfhost/main.hero --emit-c -o out.c
$ cmp out.c seed/heroes.c
                    (cmp non stampa niente: non un byte di differenza)

  seed/heroes.c   il C che il repository contiene: la via d’ingresso
  out.c           quello che il compilatore scrive compilando se stesso

  oltre venti megabyte di C, e più di 250.000 righe

Se i file sono identici, cmp non stampa nulla. Il confronto verifica che il compilatore ricostruisca lo stesso C da cui è stato compilato. Il terzo comando richiede meno di due minuti su un MacBook Air. La prova può ripeterla chiunque: il repository è aperto e i quattro comandi sono tutto quello che serve.

Tra una release e l’altra il file C generato è il compilatore di un giorno precedente. Costruisce quello di oggi dai sorgenti in Heroes, e quello si riproduce identico un passo dopo, cosa che il progetto controlla a ogni modifica. heroes --version dice quale dei due hai: la sua seconda riga è un’impronta dei sorgenti da cui è stato costruito.

Heroes implementa tutte le parti del compilatore: l’analisi delle parole e della struttura del codice, l’associazione dei nomi alle dichiarazioni, il controllo dei tipi, la rappresentazione intermedia del programma e i suoi controlli, la gestione della memoria, la traduzione in C, le verifiche sulle librerie esterne, i messaggi d’errore, il formattatore e i comandi.

Gli errori trovati compilando i propri sorgenti

Il nuovo compilatore ha inizialmente rifiutato i propri sorgenti: segnalava, per errore, una struttura che conteneva se stessa. L’indagine ha individuato difetti sia nel compilatore nuovo sia in quello precedente. Uno riguardava la sottolineatura dei messaggi d’errore, che copriva l’annotazione usata dal test per verificarla.

Compilare i sorgenti del compilatore mette alla prova molte forme del linguaggio nello stesso programma. Diversi difetti avevano la stessa causa: un salto di ciclo dentro un ramo di match saltava l’istruzione che aggiornava un indice gestito a mano.

L’ultima differenza tra i due file riguardava l’ordine delle righe. Nel compilatore precedente alcune liste erano già ordinate; nel nuovo serviva un ordinamento esplicito, come indicavano le note lasciate nei sorgenti. Le mappe non garantiscono un ordine: aggiungendo gli ordinamenti mancanti, i file sono diventati identici.

Come si valutano le modifiche al linguaggio · five years

Le modifiche alla sintassi, alle regole del linguaggio, ai messaggi d’errore o alla struttura del compilatore vengono esaminate da un panel di cinque seggi. Ogni seggio riceve materiale diverso e quattro possono porre un veto. Le modifiche interne al compilatore o al runtime, il codice di supporto all’esecuzione, passano da due dei cinque se non cambiano sintassi, messaggi d’errore o specifica.

Il panel sceglie la soluzione che ritiene più solida e completa e la sottopone all’autore per l’approvazione. Il lavoro prosegue in attesa della conferma. Se esiste un’alternativa più prudente, viene registrata perché l’autore possa valutarla. Dopo i cinque verdetti un sesto lettore, il critico di completezza, chiede che cosa nessuno ha elencato, e più di una volta la soluzione adottata è stata una via che nessun seggio aveva proposto.

Ogni seduta è registrata in un file nel repository, con i materiali esaminati, i verdetti e gli eventuali veti. Le sedute sono più di centocinquanta. Ogni modifica al linguaggio richiede questa revisione. Quello che il panel ha rifiutato, e chi ha detto no, ha una pagina sua: i no di Heroes →

Venti righe

heroes this stampa questi principi, inclusi nel compilatore. Qui sono riportati in inglese per rispettare il testo originale, comprese le citazioni di una canzone.

The Zen of Heroes

 1. This language begins with a tribute to David Bowie.
 2. It is made for language models; people can read it too.
 3. A model may have read everything; each page must still explain itself.
 4. What the eye can see is all there is: sound and vision.
 5. There is one way to say each thing; every program sings in the same voice.
 6. That way may not be obvious at first; the Starman already knows it.
 7. The semantics are familiar; the syntax is new.
 8. Turn and face the strange: every strange choice here is deliberate.
 9. Nothing changes behind your back; every change signs its name.
10. Every plausible mistake must become a compile error before the program runs.
11. Unless you mark the gap with ???: an honest hole beats a confident guess.
12. A compile-time error is an answer; a runtime error is an ambush.
13. An error should tell you how to fix the program. Anything less is a complaint.
14. Repeating a word is cheap; forgetting one can cost the whole program.
15. The specification stays small under pressure; every word must earn its place.
16. Crashes and leaks are bugs. Ashes to ashes: what Heroes takes, it returns.
17. When pretty code and safe code disagree, safe code wins.
18. There is no standard library; C is the man who sold the world.
19. Never crashing in the same car: what C might keep, Heroes assumes it keeps.
20. We can be heroes, just for one day.

La riga 10 esprime la tesi, la 18 il vincolo iniziale, la 19 quel che quel vincolo costa al confine con il C, e la 17 stabilisce la priorità quando due principi sono in conflitto. Perché il linguaggio è fatto così →

Cosa è costruito, e cosa viene dopo

La catena è una tabella nel repository, una riga per traguardo, chiusi prima e programmati dopo. Questa pagina la legge quando il sito viene generato: 71 traguardi chiusi di 92, e quello aperto è M-panic-location.

Quello che viene

#traguardocosa consegna
72M-panic-locationan abort a program raises names its file, line, column and function, an assert on any value shows both sides, and no program's text forges a report
73M-generated-programsprograms nobody wrote: a generator that composes valid Heroes and knows the answer before the compiler is asked
74M-compatibility-promisethe paragraph 1.0.0 rests on, and the suite that makes a broken promise red
75M-latency-ceilinga latency the compiler may not lose without a decision: heroes check and clang on the seed timed at every close, the incremental frontend its return condition
76M-core-packagessmall packages that compose, organised as Go's tree, in Heroes or over C
77M-package-managerheroes add/heroes fetch; bindings instead of a standard library
78M-web-frameworkcomposes the core packages, Go/Echo style: explicit routes, records, no magic
79M-doc-generatorheroes doc, the one direction Part 6's literate-source row promises
80M-compared-languagesthe same tasks written by a model in Heroes, Go, Rust, C and Zig, scored on hidden tests, turns and silent failures, the prediction registered before the first run
81M-deployable-binarywhat the machine that RUNS a Heroes program needs, on the three platforms, and which -O a shipped artifact carries
82M-standalone-compilerheroes needing nothing else installed: a C compiler and a linker inside it, and what each platform's C library needs beside it
83M-install-channelsa Homebrew tap, winget, a Nix flake, a Docker image, all built from the seed and pinned to a v* release tag; the version scheme itself was decided ahead, 2026-09-07
84M-online-compilerthe compiler reached without installing anything: the site's visitor writes Heroes and gets its answer
85M-lsp-serverheroes lsp
86M-vscode-extensionthe extension, complete
87M-publication-gatethe last gate before anything goes outward
88M-launch-poststhe first posts, each with the numbers its command produced, after the first hour a stranger spends was tried
89M-microcontroller-verdictthe ruling on a Heroes program running on a microcontroller under an RTOS, RISC-V first; the two facts a 32-bit build refuses today are its brief
90M-qbe-backendPart 7 item 15 — the proof that the IR is not C in disguise
91M-journey-bookthe journey — how this language came to be
92M-guide-bookthe guide, as a book you would find in a shop
I 71 traguardi chiusi, il più recente per primo
#traguardochiusocosa ha consegnato
71M-rechecked-issues2026-10-25every open issue re-checked against the tree: closed with the commit that settled it, closed with the reason it no longer applies, repaired, or re-homed on a row still to come
70M-thesis-harness2026-10-24Part 11's metrics 2 and 4 run for the first time, as a Heroes program: forty held-out tasks sealed and a prediction pushed before the run, the primary inconclusive at +0.0 points with no discordant pair, the strict arm paying at turn 1 and level by turn 3
69M-witnessed-seed2026-10-18the seed witnessed by a second implementation: the archived Rust bootstrap rebuilt and agreeing with the seed at its tag, a gcc leg beside clang, every seed since the archive rebuilt from the one before it, 39 of 39, and every refresh since naming its route for the CI; then the bootstrap out of the tree, kept at its tag
68M-readonly-lend2026-10-18a function reads the caller's place without claiming to change it: lent on a parameter, C's const T * bound read-only, and beside it an @ of the same place and a read-only lend past a variadic prototype refused
67M-bounded-seed2026-10-17the seed bounded in shape and in rhythm: its re-anchoring #lines joined to their anchors, refreshed only when the two-stage build needs it and at each release, every program carrying the key of what it was compiled from, and kept in the history at every tag, the history rewritten once and announced
66M-buildable-structs2026-10-17a C struct with long arrays is built by naming the fields that matter and ending with rest: zero.
65M-typed-inspection2026-10-13a stopped program shows Heroes values: the frame lists the author's bindings alone, the emitter declaring what it invented nodebug, and one fixed formatter, editors/lldb/heroes_lldb.py, which the editor loads, shows a record, a str, a [T], a {K: V}, a T?'s live arm and a variant's case in Heroes' syntax; the names keep their C prefix, refused in the emitted C by panel 213's two vetoes and kept by the author's answer of 2026-10-14 on its issue 2037
64M-issue-files2026-10-12every item this project tracks is one GitHub issue: one file each of issues/ first, a card on each, then 2,029 issues imported in the order they were born with their own days, then GitHub alone and the folder out of the tree.
63M-inferred-cell2026-10-10a mutable cell declared by its own symbol, @=, and typed by its value as a binding is; a cell nothing re-binds refused with a certain fix; the tree rewritten through the compiler's own fix.
62M-agreed-retention2026-09-28one C function, one story about who frees what it is handed: two modules may declare it with contradictory retention marks and the compiler takes both; one declaration cannot carry a contract chosen per call, which is sqlite3_bind_text's three modes; and nothing says a pointer C made is C's to free once.
61M-declared-extents2026-09-21how far C may read through a lent address, and what becomes of the pointer afterwards: counted_by declares the extent and the emitter checks it against the field's own sizeof in C; then the author flipped the default, so a C parameter is taken to KEEP what it is handed and a lend reaches only one declared lent; and where no word can reach — C frees the bytes from a callback, or from a later call with no pointer at all — the runtime names the leases that were live.
60M-readable-bytes2026-09-18a C byte buffer becomes text a program can print: the inbound direction str has never had
59M-arm-platform2026-09-18the fourth real machine: arm64 Linux, where a container runs and where char is unsigned
58M-check-completeness2026-09-17ten defects the hunt turned up, closed — and three were not what their own entry said
57M-marked-acquisition2026-09-14the mark goes where the obligation is CREATED — on the acquiring call — so a C handle nobody releases stops being silent
56M-cleanup-verdict2026-09-14the ruling on a scope-bound release for a C handle: a releaser keyed on the TYPE refused to Part 6, because ownership is a property of the CALL
55M-handle-verdict2026-09-14the ruling on telling one C handle from another, and three defects that were one question
54M-deferral-ledger2026-09-13every Part 7 item with no milestone gets a dated verdict or a return condition, and Part 8's homeless warts with it
53M-declared-thresholds2026-09-12every ceiling and floor says which way it may move, and something notices when it should have moved and did not
52M-reflection-verdict2026-09-12reflection refused at run time and as a general tag; a field's name becomes a name the checker resolves
51M-stated-grammar2026-09-12every syntactic form stated once, in Wirth's notation, inside the specification beside the prose that governs it, and heroes grammar for the half the compiler can print from its own tables
50M-rotated-records2026-09-12the records become directories, one entry per file and one milestone per file, and the file that held each stays behind as a map so every citation still resolves
49M-named-callbacks2026-09-11the role inversion through a generic callback, closed at 7 of 7 against a cheaper reading's 2 of 7: fold's type names its accumulator and its element, and a function handed to it names them the same way — a naming mandate the author chose over the sitting's own recommendation, with both numbers in front of them
48M-labelled-types2026-09-11defect 026 repaired: a function type names the parameters that can be confused, the names are part of its identity, and the classic inversion through a function value goes from 17% to 100% — at 432 lines against a condition of about 150, which is the sitting's own headline
47M-positional-values2026-09-11defect 026 narrowed: a label at a call through a function value is refused, the note stops prescribing the hole in silence, and spec § 3 says the call is positional — a sentence vetoed as false at the ballot that the refusal made true
46M-labelled-builtins2026-09-11defect 025 repaired: the same-typed-argument rule reaches the two built-ins it did not, both halves of it, 1022 call sites relabelled, and the classic argument inversion drops from 367 survivors to 75 with the swapped fail( at zero
45M-anchored-spec2026-09-11the specification takes the shape of a Report: thirteen numbered sections in reference order, one home per rule, the numbers as the citation anchors, two checks that keep the form, 81 citations converted, and the site's page copying the text in one click
44M-interpolated-strings2026-09-09f"line {n}: {word}": one token kind, one AST node, three helper modules, four decided ceilings moved by their measured lines, the spec at +138 real with R6's two sentences, and heroes mutate reaching the holes
43M-interpolation-verdict2026-09-09the ruling on design.md Part 7 item 7: string interpolation ENTERS as f"line {n}: {word}", three counts and one sitting, the spelling the author's; closed with the verdict and not the form, as it was named to
42M-held-bytes2026-09-09§4.19's FOURTH case: x: cstr @ s.lease() is a COPY C may read until end_lease(@x).
41M-cstr-lifetime2026-09-09a cstr may not outlive the str it was lent from: three positional clauses, 0 of 638 files moved.
40M-closures-verdict2026-09-08the ruling on Part 7 items 1 and 12: both refused, closures to Part 6 and inline blocks left unplaced
39M-discard-refusal2026-09-08_ = on a fallible value becomes a compile error, in two positions and not three
38M-open-repository2026-09-08the repository opens, and every page that says it is shut stops saying so
37M-declared-freer2026-09-07owned <C function>: the string C hands you is freed by the name its own declaration gives
36M-thread-stacks2026-09-06the guard speaks on every thread, and a worker's floor is the thread that ran main
35M-isolated-threads2026-09-06Part 7.13 concurrency: three of four measured corruption classes closed, and the door was in the checker
34M-c-callbacks2026-09-05a Heroes function reaches a C callback parameter, and a foreign thread is refused by name rather than left to corrupt
33M-corpus-depth2026-09-04the rung between a program and the compiler: nine programs, and half of every frame
32M-robustness-guards2026-09-03the guards that shut the holes §1.12 named: @ on an immutable, the stack, the C pointer verdict, the harness scratch
31M-documentation-site2026-09-02the site, anchored to programs that run
30M-corpus-coverage2026-09-02every language form has a program that runs it
29M-selfhost-nesting2026-09-02the compiler's own modules move into ten directories
28M-package-layout2026-09-02use paths, the qualifier, as, and where a program's files live
27M-argv-execution2026-08-31the compiler runs programs by argument list, and the shell stops being the boundary
26M-separate-compilation2026-08-26one .c per module, prototypes across TUs, the cache
25M-bootstrap-archive2026-08-19the third language dies
24M-harness-port2026-08-18the net in Heroes
23M-selfhost-fixpoint2026-08-18the fixpoint and the seed
22M-selfhost-port2026-08-17the compiler twice over, and one hash
21M-selfhost-probe2026-08-15the lexer ported, to measure what was missing
20M-complete-structs2026-08-15every field form a C header can write
19M-struct-passing2026-08-15a struct crosses by value
18M-binding-fidelity2026-08-14what an extern accepts
17M-program-corpus2026-08-13nine programs, six compiler defects, a CI
16M-sized-integers2026-08-12eight widths; int stops being a word
15M-literal-bases2026-08-120x 0o 0b, the _ separator
14M-header-constants2026-08-12the number leaves the file
13M-ffi-ladder2026-08-12Heroes calls C; SQLite with no shim
12M-module-namespace2026-08-12a program is many files
11M-generics-library2026-08-11sugar, heroes test, generics, the library
10M-optional-map2026-08-10T? and {K: V} — the last two types
9M-value-aggregates2026-08-10records and variants by value, copy-on-write
8M-strings-ownership2026-08-05str in C, and the ownership pass
7M-scalars-run2026-08-04the first native binary
6M-ir-lowering2026-08-04desugaring, the three-address IR with basic blocks
5M-typed-frontend2026-08-04the frontend complete: names, types, errors as a product
4M-name-resolution2026-08-04scopes, no shadowing, order-free top level
3M-syntax-tree2026-08-04parser, AST, the canonical formatter
2M-token-stream2026-08-04the lexer, and --dump-tokens
1M-day-zero2026-08-03git, workspace, four hand-written C targets

Poi: quattro comandi e lo compili, oppure prenditi tutto il linguaggio in un file solo.