Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Kapitel 02: Dina två bästa vänner: `ridgunc` och `stable` (Noll YAML-filer, jag lovar) |
| 2 | |
| 3 | Det finns språk vars kompilator är underbar, men vars projektsystem verkar vara konstruerat av din värsta fiende: än är det en `Makefile` på 400 rader med osynliga tabulatorer, än en oändlig `pom.xml`, än en `webpack.config.js` som slutar fungera om du tittar för länge på den... |
| 4 | |
| 5 | I Ridgun gav vi oss själva ett mycket enkelt löfte redan från första dagen: |
| 6 | |
| 7 | > *"Det ska bara finnas två körbara program i hela ekosystemet (`ridgunc` och `stable`), båda ska vara skrivna i Ridgun självt, och projektets konfigurationsfil (`build.rg`) ska vara helt vanlig Ridgun-kod. Ingen JSON, ingen YAML, ingen TOML och inga konstiga påhitt."* |
| 8 | |
| 9 | Låt oss se hur de används. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## 2.1. `ridgunc`: Prickskytten för enskilda filer |
| 14 | |
| 15 | När du har en enskild `.rg`-fil framför dig och vill testa en snabb idé, analysera dess typer eller kompilera en körbar fil pratar du direkt med **`ridgunc`**. |
| 16 | |
| 17 | Den har bara 4 kommandon som du verkligen behöver komma ihåg: |
| 18 | |
| 19 | ```bash |
| 20 | # 1. "Kompilerar det här eller har jag gjort bort mig med någon typ?" |
| 21 | ridgunc check experiment.rg |
| 22 | |
| 23 | # 2. "Kör det nu!" (Kompilerar och kör i ett svep) |
| 24 | ridgunc run experiment.rg |
| 25 | |
| 26 | # 3. "Gör en inbyggd ELF-binär färdig att ta med" |
| 27 | ridgunc build experiment.rg -o mitt_program |
| 28 | |
| 29 | # 4. "Ta fram mellanartefakten med bytekod (.rgc)" |
| 30 | ridgunc compile experiment.rg -o experiment.rgc |
| 31 | ``` |
| 32 | |
| 33 | ### Den dolda superkraften i `ridgunc check` |
| 34 | När du kör `ridgunc check` säger den inte bara *"0 fel"*. Den avslöjar också vilken strategi den statiska analysatorn har valt för var och en av dina funktioner: |
| 35 | - **`InlineSequential`**: *"Den här funktionen är liten och rak; jag kör den direkt i linje utan att lägga på någon schemaläggningskostnad"*. |
| 36 | - **`LazyStealableTask`**: *"Här finns rekursion eller en parallell graf `||`; jag förbereder den så att andra processorkärnor kan stjäla arbete om det behövs"*. |
| 37 | |
| 38 | ### Skalpellprecisionen i `ridgunc build` (Varför dina binärer inte väger 20 MB) |
| 39 | När du kör `ridgunc build` nöjer sig kompilatorn inte med att spotta ur sig all kod från de bibliotek du har importerat: |
| 40 | 1. Den börjar i din `main`-funktion och vandrar genom anropsgrafen för att se **vilka funktioner du faktiskt använder**. Om du har importerat ett enormt bibliotek med 80 funktioner men bara anropar 2, kastas de andra 78 bort innan de ens når assemblern (*Tree-Shaking*). |
| 41 | 2. Den letar upp alla svansrekursiva funktioner och omvandlar dem till inbyggda `loop`-snurror som förbrukar **0 byte stackminne**. |
| 42 | 3. Den kör slutlänkningen med global optimering (*fat LTO*) och rensar bort DWARF-felsökningsskräp för att ge dig en kompakt och knivskarp binär (~350 KB). |
| 43 | |
| 44 | --- |
| 45 | |
| 46 | ## 2.2. `stable`: När ditt projekt växer och du vill ha ordning |
| 47 | |
| 48 | En enskild fil är toppen för ett skript, men så fort du har flera moduler, delade bibliotek och tester behöver du en dirigent. Det är **`stable`**. |
| 49 | |
| 50 | Mappstrukturen i ett Ridgun-projekt rymmer inga mysterier: |
| 51 | |
| 52 | ```text |
| 53 | mitt-superverktyg/ |
| 54 | ├── build.rg # Projektmanifestet (det är Ridgun-kod!) |
| 55 | ├── src/ |
| 56 | │ ├── main/ |
| 57 | │ │ └── ridgun/ |
| 58 | │ │ ├── lib/ # Dina återanvändbara moduler (`import verktyg`) |
| 59 | │ │ └── app/ |
| 60 | │ │ └── main.rg # Startpunkt (`main => ()`) |
| 61 | │ └── test/ |
| 62 | │ └── ridgun/ # Dina testsviter (`test *.rg`) |
| 63 | │ └── test allt.rg |
| 64 | └── target/ # Där de kompilerade binärerna dyker upp |
| 65 | ``` |
| 66 | |
| 67 | --- |
| 68 | |
| 69 | ## 2.3. `build.rg`: En konfigurationsfil som aldrig ljuger för dig |
| 70 | |
| 71 | Varför vägrar vi att använda YAML eller TOML för att konfigurera ett Ridgun-projekt? |
| 72 | Därför att i YAML råkar du skriva två mellanslag fel i indraget och märker det inte förrän driftsättningen kraschar. Eftersom **`build.rg` är en Ridgun-fil** har den däremot statiska typer, kontrolleras med `stable check` och justeras automatiskt med `stable format`: |
| 73 | |
| 74 | ```ridgun |
| 75 | type ProjectInfo = |
| 76 | name: String |
| 77 | version: String |
| 78 | edition: String |
| 79 | |
| 80 | project => ProjectInfo |
| 81 | project = ProjectInfo "mitt-superverktyg" "0.1.0" "2026" |
| 82 | |
| 83 | source dir => String |
| 84 | source dir = "src/main/ridgun" |
| 85 | |
| 86 | test dir => String |
| 87 | test dir = "src/test/ridgun" |
| 88 | |
| 89 | target dir => String |
| 90 | target dir = "target" |
| 91 | |
| 92 | -- Valfritt: aktivera strikt läge för signaturer och namn (inaktiverat som standard) |
| 93 | strict mode => Bool |
| 94 | strict mode = True |
| 95 | ``` |
| 96 | |
| 97 | Om du stavar fel på ett fält varnar kompilatorn själv. Inga överraskningar. |
| 98 | |
| 99 | ### Strikt läge (`--strict` / `strict mode = True`) |
| 100 | Som standard är strikt läge **inaktiverat** i både `ridgunc` och nya projekt som skapas med `stable new` eller `stable init`, så att du kan bygga prototyper i full frihet. När du vill låsa den kanoniska stilen i ett projekt (som vi gör i Ridguns egen kompilator) kan du skicka `--strict` till `ridgunc` eller lägga till `strict mode = True` i din `build.rg`. Strikt läge kräver två elegansregler: |
| 101 | 1. **Namn på `fn ::` och `op ::` med naturliga mellanslag, utan `_`**: deklarationer måste använda mellanslag (`fn :: berakna skatt`, aldrig `fn :: berakna_skatt`). |
| 102 | 2. **Flertalsreturer åtskilda med mellanslag efter `=>`**: när en funktion eller operator returnerar flera värden skrivs dess utdatasignatur som `=> Int Int` eller `=> Tillstand Int` (aldrig `=> (Int, Int)` med parenteser eller kommatecken). |
| 103 | |
| 104 | --- |
| 105 | |
| 106 | ## 2.4. Din dagliga rutin med `stable` (De 4 fantastiska) |
| 107 | |
| 108 | När du arbetar inne i ditt projekt kokar din vardag ner till fyra kommandon: |
| 109 | |
| 110 | ### 1. `stable format` — Slutet på alla kodstilsdiskussioner i teamet |
| 111 | ```bash |
| 112 | stable format |
| 113 | ``` |
| 114 | Sätter din kollega tre mellanslag före `=>` medan du sätter ett? Det spelar ingen roll. Du kör `stable format` och på mindre än en sekund är **alla** `.rg`-filer i förrådet uppradade som en schweizisk tabell. |
| 115 | |
| 116 | ### 2. `stable check` — Den omedelbara radarn |
| 117 | ```bash |
| 118 | stable check |
| 119 | ``` |
| 120 | Går igenom alla moduler i `src/main/ridgun/`, verifierar typer, konstruktorer, aritet och tensordimensioner, och ger dig utslaget modul för modul. |
| 121 | |
| 122 | ### 3. `stable test` — Sov gott om natten |
| 123 | ```bash |
| 124 | stable test |
| 125 | ``` |
| 126 | Letar upp alla testsviter `src/test/ridgun/test *.rg`, kör dem och kontrollerar varje `assert equals` och `assert true`. |
| 127 | |
| 128 | ```ridgun |
| 129 | -- Exempel på src/test/ridgun/test matte.rg |
| 130 | import test |
| 131 | |
| 132 | dubbel Int => Int |
| 133 | dubbel x = x * 2 |
| 134 | |
| 135 | main => () |
| 136 | main = |
| 137 | assert equals (dubbel 21) 42 |
| 138 | assert true ((dubbel 5) > 0) |
| 139 | ``` |
| 140 | |
| 141 | ### 4. `stable built` (och `stable clean`) — Ut i produktion |
| 142 | ```bash |
| 143 | stable built |
| 144 | ``` |
| 145 | Kompilerar alla inbyggda mål i `target/`. Och om du någon dag vill radera `target/` och börja om från rent bord: `stable clean`. |
| 146 | |
| 147 | --- |
| 148 | |
| 149 | ## 2.5. Hur importerar jag en fil från en annan? (`import`) |
| 150 | |
| 151 | Inga helvetiska relativa sökvägar av typen `../../../lib/grejer.rg`. Om du har en fil `src/main/ridgun/lib/strangar.rg` skriver du helt enkelt längst upp i vilken annan fil som helst: |
| 152 | |
| 153 | ```ridgun |
| 154 | import strangar |
| 155 | ``` |
| 156 | |
| 157 | Och klart: alla funktioner och typer i `strangar.rg` är tillgängliga precis som om de låg i din egen fil. Men vad händer om modul `A` gör `import strangar`, modul `B` också gör `import strangar` och din `main.rg` importerar både `A` och `B`? Ta det lugnt: Ridguns laddare kommer ihåg vilka kanoniska filer den redan har läst och **inkluderar den bara en gång**. |
| 158 | |
| 159 | Nu när du har full koll på verktygslådan går vi vidare till **Kapitel 03** för att bemästra funktioner, typer, block och knep med textsträngar. |