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.
- 680+moduli di Heroes
- 179krighe, e crescono
- 0TODO, FIXME o HACK nel compilatore
- 220+sedute di design nei record
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 lettoreRiceve la specifica e programmi d’esempio, senza il documento di design né i sorgenti del compilatore. Verifica con prove concrete se il linguaggio si capisce. veto
- L’ingegnere del compilatoreEsamina i sorgenti e valuta quanto codice bisogna scrivere e mantenere per introdurre la modifica. veto
- Il pragmatico del CCompila il codice C necessario per usare una libreria da Heroes, oppure documenta perché la compilazione fallisce. veto
- Il guardiano della specificaConfronta il numero di token prima e dopo la modifica e verifica che la specifica rispetti il limite previsto. I token sono i frammenti di testo letti da un modello. veto
- Lo storicoDeve cercare sul web e citare date e fonti: un precedente senza fonte è inammissibile. Ha letto anche la storia dei linguaggi scritta dall’autore, e la usa per sapere dove guardare, non come fonte: un libro dell’autore di questo progetto non può fargli da prova. Dà consigli e non ha potere di veto.
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
| # | traguardo | cosa consegna |
|---|---|---|
| 72 | M-panic-location | an 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 |
| 73 | M-generated-programs | programs nobody wrote: a generator that composes valid Heroes and knows the answer before the compiler is asked |
| 74 | M-compatibility-promise | the paragraph 1.0.0 rests on, and the suite that makes a broken promise red |
| 75 | M-latency-ceiling | a 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 |
| 76 | M-core-packages | small packages that compose, organised as Go's tree, in Heroes or over C |
| 77 | M-package-manager | heroes add/heroes fetch; bindings instead of a standard library |
| 78 | M-web-framework | composes the core packages, Go/Echo style: explicit routes, records, no magic |
| 79 | M-doc-generator | heroes doc, the one direction Part 6's literate-source row promises |
| 80 | M-compared-languages | the 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 |
| 81 | M-deployable-binary | what the machine that RUNS a Heroes program needs, on the three platforms, and which -O a shipped artifact carries |
| 82 | M-standalone-compiler | heroes needing nothing else installed: a C compiler and a linker inside it, and what each platform's C library needs beside it |
| 83 | M-install-channels | a 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 |
| 84 | M-online-compiler | the compiler reached without installing anything: the site's visitor writes Heroes and gets its answer |
| 85 | M-lsp-server | heroes lsp |
| 86 | M-vscode-extension | the extension, complete |
| 87 | M-publication-gate | the last gate before anything goes outward |
| 88 | M-launch-posts | the first posts, each with the numbers its command produced, after the first hour a stranger spends was tried |
| 89 | M-microcontroller-verdict | the 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 |
| 90 | M-qbe-backend | Part 7 item 15 — the proof that the IR is not C in disguise |
| 91 | M-journey-book | the journey — how this language came to be |
| 92 | M-guide-book | the guide, as a book you would find in a shop |
I 71 traguardi chiusi, il più recente per primo
| # | traguardo | chiuso | cosa ha consegnato |
|---|---|---|---|
| 71 | M-rechecked-issues | 2026-10-25 | every 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 |
| 70 | M-thesis-harness | 2026-10-24 | Part 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 |
| 69 | M-witnessed-seed | 2026-10-18 | the 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 |
| 68 | M-readonly-lend | 2026-10-18 | a 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 |
| 67 | M-bounded-seed | 2026-10-17 | the 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 |
| 66 | M-buildable-structs | 2026-10-17 | a C struct with long arrays is built by naming the fields that matter and ending with rest: zero. |
| 65 | M-typed-inspection | 2026-10-13 | a 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 |
| 64 | M-issue-files | 2026-10-12 | every 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. |
| 63 | M-inferred-cell | 2026-10-10 | a 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. |
| 62 | M-agreed-retention | 2026-09-28 | one 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. |
| 61 | M-declared-extents | 2026-09-21 | how 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. |
| 60 | M-readable-bytes | 2026-09-18 | a C byte buffer becomes text a program can print: the inbound direction str has never had |
| 59 | M-arm-platform | 2026-09-18 | the fourth real machine: arm64 Linux, where a container runs and where char is unsigned |
| 58 | M-check-completeness | 2026-09-17 | ten defects the hunt turned up, closed — and three were not what their own entry said |
| 57 | M-marked-acquisition | 2026-09-14 | the mark goes where the obligation is CREATED — on the acquiring call — so a C handle nobody releases stops being silent |
| 56 | M-cleanup-verdict | 2026-09-14 | the 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 |
| 55 | M-handle-verdict | 2026-09-14 | the ruling on telling one C handle from another, and three defects that were one question |
| 54 | M-deferral-ledger | 2026-09-13 | every Part 7 item with no milestone gets a dated verdict or a return condition, and Part 8's homeless warts with it |
| 53 | M-declared-thresholds | 2026-09-12 | every ceiling and floor says which way it may move, and something notices when it should have moved and did not |
| 52 | M-reflection-verdict | 2026-09-12 | reflection refused at run time and as a general tag; a field's name becomes a name the checker resolves |
| 51 | M-stated-grammar | 2026-09-12 | every 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 |
| 50 | M-rotated-records | 2026-09-12 | the 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 |
| 49 | M-named-callbacks | 2026-09-11 | the 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 |
| 48 | M-labelled-types | 2026-09-11 | defect 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 |
| 47 | M-positional-values | 2026-09-11 | defect 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 |
| 46 | M-labelled-builtins | 2026-09-11 | defect 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 |
| 45 | M-anchored-spec | 2026-09-11 | the 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 |
| 44 | M-interpolated-strings | 2026-09-09 | f"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 |
| 43 | M-interpolation-verdict | 2026-09-09 | the 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 |
| 42 | M-held-bytes | 2026-09-09 | §4.19's FOURTH case: x: cstr @ s.lease() is a COPY C may read until end_lease(@x). |
| 41 | M-cstr-lifetime | 2026-09-09 | a cstr may not outlive the str it was lent from: three positional clauses, 0 of 638 files moved. |
| 40 | M-closures-verdict | 2026-09-08 | the ruling on Part 7 items 1 and 12: both refused, closures to Part 6 and inline blocks left unplaced |
| 39 | M-discard-refusal | 2026-09-08 | _ = on a fallible value becomes a compile error, in two positions and not three |
| 38 | M-open-repository | 2026-09-08 | the repository opens, and every page that says it is shut stops saying so |
| 37 | M-declared-freer | 2026-09-07 | owned <C function>: the string C hands you is freed by the name its own declaration gives |
| 36 | M-thread-stacks | 2026-09-06 | the guard speaks on every thread, and a worker's floor is the thread that ran main |
| 35 | M-isolated-threads | 2026-09-06 | Part 7.13 concurrency: three of four measured corruption classes closed, and the door was in the checker |
| 34 | M-c-callbacks | 2026-09-05 | a Heroes function reaches a C callback parameter, and a foreign thread is refused by name rather than left to corrupt |
| 33 | M-corpus-depth | 2026-09-04 | the rung between a program and the compiler: nine programs, and half of every frame |
| 32 | M-robustness-guards | 2026-09-03 | the guards that shut the holes §1.12 named: @ on an immutable, the stack, the C pointer verdict, the harness scratch |
| 31 | M-documentation-site | 2026-09-02 | the site, anchored to programs that run |
| 30 | M-corpus-coverage | 2026-09-02 | every language form has a program that runs it |
| 29 | M-selfhost-nesting | 2026-09-02 | the compiler's own modules move into ten directories |
| 28 | M-package-layout | 2026-09-02 | use paths, the qualifier, as, and where a program's files live |
| 27 | M-argv-execution | 2026-08-31 | the compiler runs programs by argument list, and the shell stops being the boundary |
| 26 | M-separate-compilation | 2026-08-26 | one .c per module, prototypes across TUs, the cache |
| 25 | M-bootstrap-archive | 2026-08-19 | the third language dies |
| 24 | M-harness-port | 2026-08-18 | the net in Heroes |
| 23 | M-selfhost-fixpoint | 2026-08-18 | the fixpoint and the seed |
| 22 | M-selfhost-port | 2026-08-17 | the compiler twice over, and one hash |
| 21 | M-selfhost-probe | 2026-08-15 | the lexer ported, to measure what was missing |
| 20 | M-complete-structs | 2026-08-15 | every field form a C header can write |
| 19 | M-struct-passing | 2026-08-15 | a struct crosses by value |
| 18 | M-binding-fidelity | 2026-08-14 | what an extern accepts |
| 17 | M-program-corpus | 2026-08-13 | nine programs, six compiler defects, a CI |
| 16 | M-sized-integers | 2026-08-12 | eight widths; int stops being a word |
| 15 | M-literal-bases | 2026-08-12 | 0x 0o 0b, the _ separator |
| 14 | M-header-constants | 2026-08-12 | the number leaves the file |
| 13 | M-ffi-ladder | 2026-08-12 | Heroes calls C; SQLite with no shim |
| 12 | M-module-namespace | 2026-08-12 | a program is many files |
| 11 | M-generics-library | 2026-08-11 | sugar, heroes test, generics, the library |
| 10 | M-optional-map | 2026-08-10 | T? and {K: V} — the last two types |
| 9 | M-value-aggregates | 2026-08-10 | records and variants by value, copy-on-write |
| 8 | M-strings-ownership | 2026-08-05 | str in C, and the ownership pass |
| 7 | M-scalars-run | 2026-08-04 | the first native binary |
| 6 | M-ir-lowering | 2026-08-04 | desugaring, the three-address IR with basic blocks |
| 5 | M-typed-frontend | 2026-08-04 | the frontend complete: names, types, errors as a product |
| 4 | M-name-resolution | 2026-08-04 | scopes, no shadowing, order-free top level |
| 3 | M-syntax-tree | 2026-08-04 | parser, AST, the canonical formatter |
| 2 | M-token-stream | 2026-08-04 | the lexer, and --dump-tokens |
| 1 | M-day-zero | 2026-08-03 | git, workspace, four hand-written C targets |
Poi: quattro comandi e lo compili, oppure prenditi tutto il linguaggio in un file solo.