Repository navigation
Doc BOOTSTRAP
Copia di
BOOTSTRAP.md— torna a Documenti · Home
Stato: fase 0 (contratto di conformità + piano). Obiettivo: Triad che non dipende da Julia né da qualunque altro linguaggio di programmazione, in nessuna fase (runtime, bootstrap, build).
Il requisito "nessun altro linguaggio" esclude le scorciatoie ovvie:
| Scorciatoia | Perché è esclusa |
|---|---|
| Riscrivere il kernel in Rust/C/Go | introdurrebbe una dipendenza da un altro linguaggio |
| Tenere Julia come runtime dentro un binario impacchettato | è ancora Julia che esegue Triad |
| Committare un seed binario precompilato (prodotto una volta da Julia) | viola "nessun seed precompilato" |
L'unica catena coerente è:
- il primo eseguibile è un interprete per un sottoinsieme di Triad (Triad-Core) scritto a mano in codice macchina (byte x86-64 annotati, nessun compilatore/assembler);
- con quel seed si esegue l'implementazione completa di Triad scritta in Triad-Core;
- l'implementazione completa include un compilatore nativo scritto in Triad che compila se stesso: da lì in poi il seed è ritirato e la catena è Triad → Triad.
Questo è l'unico modo per non dipendere da un altro linguaggio: un linguaggio non può "compilarsi dal nulla", e il seed qui non è un binario ereditato ma la parte scritta a mano in codice macchina, che resta nel repository come sorgente (dump esadecimale annotato).
S0 seed: interprete Triad-Core in codice macchina (manuale, x86-64)
│ esegue
S1 implementazione completa di Triad scritta in Triad-Core
│ include
S2 compilatore nativo scritto in Triad (Triad-Core + capacita' gia' disponibili)
│ compila S1
S3 compilatore nativo self-hosted (nessun seed, nessun altro linguaggio)
│ compila
S4 Triad completo: REPL, CLI, esempi, conformance
Punti fissi:
- il seed non contiene Julia e non è generato da Julia;
- S1/S2 sono sorgenti Triad nel repository (
selfhost/), versionati come testo; - il repository finale non richiede Julia, Rust o C per costruire o usare Triad.
Il seed è un interprete per Triad-Core, non per tutto Triad. Deve saper leggere un sorgente Triad-Core da file, valutarlo e stampare su stdout. Triad-Core è scelto per essere:
- abbastanza piccolo da stare in un interprete scritto a mano in codice macchina;
- abbastanza espressivo (Turing-completo) da implementarci sopra tutto Triad.
Componenti del seed:
- lettura del file (apertura, read, chiusura) e parsing del lessico Triad-Core;
- valutatore con ambienti e chiusure;
- valori dinamici: Int, Bool, String, Symbol, List, Function, Nothing;
- primitive aritmetiche/confronti, liste, stringhe, I/O byte su stdout/stderr;
- allocatore (arena bump) e, in una fase successiva, GC mark-sweep;
- entrypoint CLI:
seed program.td [args...]+ argomenti inARGS.
Costo: questa è la parte critica del progetto. Un interprete del genere in codice macchina scritto a mano è nell'ordine delle migliaia di byte/istruzioni; è un lavoro plurisettimanale e va fatto a milestone verificabili (vedi §6). Non è comprimibile con scorciatoie senza reintrodurre un linguaggio ospite.
Definito in modo normativo in SPEC-CORE.md. Sintesi:
- tipi:
Int,Bool,String,Symbol,List,Function,Nothing(nienteFloat: S1 rappresenta iFloatdi Triad-Full con i tipi Core); - forme:
x = e,if/elseif/else,while,let,begin,function/lambda,return,break,continue, chiamata, ternario; nientequote, macro,for,struct,try; - primitive:
+ - * % ^, confronti, logica,length,push!, indicizzazione,*per stringhe,string,Symbol,Int,typeof,print/println; - primitivi di bootstrap (solo S1, non Triad-Full):
readfile,strlen,strbyte,strsub,exit; - niente Prolog nel seed:
fact/rule/solvesono implementati in S1 a livello Triad; - niente eccezioni nel seed: gli errori terminano con exit code 1.
Il seed implementa solo Triad-Core; S1 usa Triad-Core per implementare il resto
(Prolog, dispatch, macro, contratti, effetti, budget, tracce, REPL). I casi
conformance/core/ usano solo il sottoinsieme condiviso con Triad-Full.
- Valori: word taggata a 64 bit (tag nei bit bassi), heap a blocchi con header; liste come vettori dinamici; stringhe come (ptr,len) immutabili.
- Ambiente: catena di frame o hash table lineare (inizialmente liste di associazioni).
- GC: inizialmente nessun GC (arena che cresce; i programmi di bootstrap sono brevi), poi mark-sweep per far girare S1 e la suite.
- Codice: x86-64. Il seed è una funzione nativa con codice e dati in un unico file PE
per Windows e, in seguito, ELF per Linux. Chiamate OS isolate in 4–5 routine
(
os_open,os_read,os_write,os_exit,os_alloc), unico punto da riportare. - Niente libc: su Windows si importa solo
kernel32(ReadFile/WriteFile/GetCommandLineA/ ExitProcess); su Linux si usano syscall dirette (open/read/write/mmap/exit).
| Piattaforma | Stato | Motivo |
|---|---|---|
| Windows x86-64 (PE) | prima, testabile qui | unica piattaforma eseguibile in questo ambiente; nessun compilatore installato |
| Linux x86-64 (ELF) | in corso: E0 ✅ (ELF minimale testato su CachyOS); E1/E2/E3 dopo | ambiente Linux disponibile (CachyOS nativo) |
| macOS/ARM | dopo | dipende dalle prime due |
La logica del seed è per la gran parte indipendente dall'OS: si cambia solo il layer
os_* e il formato dell'eseguibile. Il primo traguardo è Windows; il port Linux è una
milestone dedicata, non un'aggiunta a posteriori.
| # | Milestone | Accettazione |
|---|---|---|
| M0 | piano + conformance suite golden |
conformance/ esiste, lo stage0 Julia la passa; nessuna dipendenza finale da Julia |
| M1 | seed "hello" in codice macchina | un PE x86-64 scritto come byte nel repository stampa una riga ed esce con 0 su Windows |
| M2 | seed con I/O file/argomenti | legge il file dal primo argomento e ne scrive i byte su stdout; exit 1/2 per errori (il vettore ARGS completo arriva con l'interprete in M3) |
| M3 | seed = interprete Triad-Core | esegue un programma Triad-Core con funzioni, liste, stringhe, chiusure |
| M4 | S1: Triad completo in Triad-Core | esempi examples/*.td e conformance girano sopra seed+S1 |
| M5 | S2: compilatore nativo in Triad | compila S1; S1 compilato passa la conformance senza seed |
| M6 | self-hosting | il compilatore nativo compila se stesso (fixed point), seed ritirato |
| M7 | parità + port Linux | conformance verde su Linux ELF; CLI/REPL; docs |
Il prodotto e la catena di bootstrap non usano altri linguaggi. Per sviluppare e verificare serve però qualcosa che esegua i test mentre il seed non esiste ancora:
- lo stage0 attuale (kernel Julia) è usato solo come generatore una tantum dei golden e come riferimento di comportamento durante M0–M4; non fa parte di S0–S4;
- i golden sono file di testo committati: da M3 in poi nessun test richiede Julia;
- il runner di conformità definitivo è
triad --conformance DIR, implementato in Triad (S1/M4). Fino ad allora si usaconformance/run.jlcome strumento temporaneo; - materializzare il seed dai byte committati usa solo strumenti di sistema (decodifica esadecimale,
certutil/xxd), non compilatori o interpreti; - il runner di conformance e'conformance/run.mjs(Node). - il generatore del seed (
seed/dev/gen_seed.js, Node) è uno strumento di sola manutenzione: produce il dump, non è richiesto per costruire/usare il seed e non fa parte di S0–S4. È versionato perché il codice macchina altrimenti non sarebbe più estendibile (è già stato perso una volta e ricostruito, verificato contro l'hash).
Regola: nessuno di questi strumenti deve essere necessario per usare Triad o per ricostruire la catena S0→S4 quando M6 è raggiunta.
La specifica eseguibile è conformance/: ogni caso è
conformance/cases/<nome>/
program.td # programma Triad
args.txt # opzionale: un argomento per riga
expected.out # stdout atteso (byte esatti, LF)
expected.code # exit code atteso
Un'implementazione passa la suite se, eseguendo program.td come script con ARGS da
args.txt, produce expected.out e expected.code. La suite è indipendente dal
linguaggio dell'implementazione: la eseguiranno il seed, S1 e il compilatore nativo.
I golden sono generati una tantum con lo stage0 (conformance/run.mjs --update) e poi committati: da quel momento sono il contratto e il runner Node basta per verificarli.
| Rischio | Mitigazione |
|---|---|
| Scrivere a mano un interprete in codice macchina è lentissimo e fragile | Triad-Core minimale; milestone M1/M2 verificabili subito; annotazioni byte per byte; niente GC all'inizio |
| Nessun ambiente Linux per testare ELF | risolto: CachyOS su secondo disco; E0 verificato, CI Linux in arrivo |
| Divergenza tra stage0 e implementazione indipendente | conformance golden come unico contratto; oracle stage0 solo per rigenerare i golden |
| Seed troppo legato a Windows | M2 usa ancora KERNEL32 direttamente: isolare le chiamate in routine os_* prima di M3/M7 |
| Aspettative sui tempi | il seed è un progetto plurisettimanale: M0-M2 sono le tappe intermedie da verificare |
- Requisito definito: nessun linguaggio ospite, nessun seed precompilato.
- Piano S0→S4 e milestone.
-
SPEC-CORE.md— sottoinsieme Triad-Core normativo (tipi, forme, primitive, primitivi di bootstrap, conformità). -
conformance/— 12 casi Full + 29 casi Core, verdi sullo stage0. - M1 — seed "Triad seed OK" in codice macchina: Windows x86-64 PE da 1024 byte,
seed/windows-x86_64/, costruito solo decodificando un dump esadecimale. - M2 — seed con I/O: legge il file dal primo argomento e ne scrive i byte su stdout
(blocchi da 4 KiB), exit
0/1/2, path tra virgolette; PE da 2560 byte, nessun runtime. - M3 (in corso) —
SPEC-CORE.md✅ econformance/core/✅ pronti; M3b1 ✅ interi; M3b2a ✅ variabili; M3b2b1 ✅ funzioni; M3b2b2 ✅ confronti/ternario/ricorsione; M3b2b3a-e ✅ Bool, operatori,if,while, lambda; M3b2b3f⚠️ cattura instabile. M3b2b3g ✅!,&&,||,+=; M3b2b3h ✅function … end; M3b2b3i ✅ corpo multi-istruzione; M3b2b3j ✅ frame lessicali elet; M3b2b3k ✅ chiusure; M3b2b3l ✅begin/ende CI; M3b2b3m ✅ stringhe heap base; M3b2b3n ✅nothing; M3b2b3o/p/q ✅ concat/simboli/coverage; M7/E0 ✅ ELF Linux minimale. Serve AST/bytecode per cattura multi-binding,elseif, liste; poi E1/E2 del seed Linux. Prossimo:elseif(casocontrollo), liste (casilisteevalori), cattura multi-binding; poi E1/E2 del seed Linux.
Parte prima
Parte seconda 4. Le parole del linguaggio 5. Valori e tipi 6. Espressioni, operatori e variabili 7. Decidere e ripetere 8. Funzioni e ricorsione 9. Lambda, chiusure e visibilità dei nomi 10. Liste e dati strutturati 11. Stringhe, simboli e byte 12. Quando le cose vanno storte 13. Progetto: un piccolo interprete
Parte terza 14. Tipi, struct e multiple dispatch 15. Programmazione logica 16. Codice come dato e macro 17. Garanzie, costrutti Full e interfaccia
Parte quarta 18. Anatomia del progetto e contratto di conformità 19. L'interprete di riferimento 20. Il seed in codice macchina 21. Verso il self-hosting 22. Gli strumenti di sviluppo
Appendici
- Riferimento dei builtin Core
- Catalogo conformance Core
- Catalogo conformance Full
- Sorgenti degli esempi
- Sorgenti self-hosted
- Documenti di riferimento
- Indice analitico
Manuale di consultazione