The book is currently only available in German.
Standard-Bibliothek — `mathe`
Verfügbar — implementiert in Phase B.6.1 (erstes stdlib-Modul). Vollständige Spec in
docs/mathe.md.
Die Standard-Bibliothek ist eine Sammlung von eingebauten Modulen, die du mit nutze aktivierst und über ihren Namen verwendest. Das erste fertige Modul ist mathe — alles, was die einfachen Operatoren + - * / % nicht können.
16.1 Wie ein eingebautes Modul aktiviert wird
nutze mathe // einbinden
sag mathe.PI // 3.141592653589793
sag mathe.wurzel(16) // 4.0
Eingebaute Module wie mathe sind immer da — du brauchst keine Datei mathe.ki im Projekt. Du musst sie aber explizit mit nutze einbinden, damit Kiste weiss, dass du sie willst.
16.2 Konstanten
| Name | Wert | Was es ist |
|---|---|---|
mathe.PI |
3.141592… | Kreiszahl π |
mathe.E |
2.718281… | Eulersche Zahl |
mathe.TAU |
6.283185… | 2π |
mathe.UNENDLICH |
+∞ | IEEE-754 +Unendlich |
mathe.NEG_UNENDLICH |
-∞ | IEEE-754 -Unendlich |
mathe.NAN |
NaN | „Keine Zahl" — IEEE-754 |
Konvention: Konstanten in GROSS-Schreibung, Funktionen in kleinschreibung. Das macht in Code sofort sichtbar, was sich nicht ändert.
16.3 Trigonometrie (alle Eingaben in Radian)
sag mathe.sinus(0) // 0.0
sag mathe.kosinus(mathe.PI) // -1.0
sag mathe.tangens(mathe.PI / 4) // ~ 1.0
// Inverse
sag mathe.arkussinus(1) // PI/2
sag mathe.arkuskosinus(0) // PI/2
sag mathe.arkustangens(1) // PI/4
sag mathe.arkustangens2(1, 1) // PI/4 (quadranten-bewusst)
// Grad ↔ Radian
sag mathe.als_radian(180) // PI
sag mathe.als_grad(mathe.PI) // 180.0
Wichtig: Trigonometrie-Funktionen geben immer komma zurück — Trigonometrie ist näherungsweise Mathematik, da gibt es kein „exakt".
16.4 Wurzel, Potenz, Logarithmus
sag mathe.wurzel(16) // 4.0
sag mathe.n_te_wurzel(27, 3) // ~3.0 (genau: 2.9999999999999996 — Float-Rundung)
sag mathe.hoch(2, 10) // 1024 ← bleibt ganz!
sag mathe.hoch(2, -1) // 0.5 ← negativer Exponent → komma
sag mathe.exp(1) // mathe.E
sag mathe.ln(mathe.E) // 1.0
sag mathe.log10(1000) // 3.0
sag mathe.log2(8) // 3.0
sag mathe.log(8, 2) // 3.0 ← Log mit beliebiger Basis
Spezialregel mathe.hoch: Bei zwei ganz-Argumenten und positivem Exponent bleibt das Ergebnis ganz (exakt, beliebig groß). Sonst wird es komma.
16.5 Min/Max, Absolutbetrag, Vorzeichen
sag mathe.maximum(3, 7, 2, 9) // 9 — variadisch
sag mathe.minimum(3, 7, 2, 9) // 2
// Liste? Mit ... entpacken!
nimm zahlen = [4, 11, 2, 8]
sag mathe.maximum(...zahlen) // 11
sag mathe.absolut(-5) // 5 (ganz bleibt ganz)
sag mathe.absolut(-1.5) // 1.5 (dezimal bleibt dezimal)
sag mathe.vorzeichen(-7) // -1
sag mathe.vorzeichen(0) // 0
sag mathe.vorzeichen(99.5) // 1
Wichtig: mathe.maximum und mathe.minimum brauchen mindestens 2 Argumente:
mathe.maximum(5) // Fehler: mindestens 2 Argumente
mathe.maximum([3, 7, 2]) // Fehler: kann liste nicht vergleichen
mathe.maximum(...[3, 7]) // ok — Spread macht aus Liste 2 Argumente
Das ist Absicht: mathe.maximum(5) ist fast immer ein Tippfehler. Lieber laut scheitern als stumm 5 zurückgeben.
16.6 Zufall — eigenes Modul zufall
Zufalls-Funktionen leben nicht in mathe, sondern im eigenständigen Modul zufall. Siehe Kapitel 17.
16.7 Helfer für komma-Spezialwerte
sag mathe.ist_nan(mathe.NAN) // wahr
sag mathe.ist_unendlich(mathe.UNENDLICH) // wahr
sag mathe.ist_endlich(mathe.PI) // wahr
Diese drei Helfer akzeptieren nur komma — bei ganz oder dezimal werfen sie einen Fehler. Begründung: ganz/dezimal sind per Definition endlich und nicht-NaN. Wer mathe.ist_nan(5) ruft, hat fast sicher einen Tippfehler — lieber scheitern als immer falsch zurückgeben.
16.8 Was nicht in mathe ist (und warum)
runden,aufrunden,abrunden,abschneiden,fast_gleich— sind globale Built-ins und bleiben das. Du nutzt sie ohnenutze mathe. Begründung: ein Symbol, ein Pfad. Es gibt keinmathe.rundenals Alias.mathe.maximumundmathe.minimumsind separate Funktionen — global gibt eslängeetc., aber Min/Max nur inmathe.kopiere,als_ganz,als_komma,als_dezimal,typ,doku— alle global.
16.9 Schatten-Warnung — wenn du eine Datei mathe.ki hast
Wenn du im Projekt-Ordner eine eigene Datei mathe.ki liegst und gleichzeitig nutze mathe schreibst, gewinnt das eingebaute mathe — deine lokale Datei wird ignoriert. kiste check warnt dich aber:
warning: lokale Datei .../mathe.ki wird vom eingebauten stdlib-Modul mathe
überschattet — die lokale Datei wird ignoriert
Lösung: deine eigene Datei umbenennen (meine_mathe.ki) oder das eingebaute Modul bewusst nicht nutzen.
16.10 Alle Stdlib-Module auf einen Blick
| Modul | Tree-Walker + VM | kiste build (LLVM-Pfad) |
Was es macht | Kapitel |
|---|---|---|---|---|
mathe |
verfügbar | Subset seit 9.3.A | Trigonometrie, Logarithmen, Min/Max, Konstanten | §16 |
zufall |
verfügbar | Subset seit 9.3.A | Zufallszahlen, Mischen, Sampling, Reproduzierbarkeit | §17 |
liste |
verfügbar | kommt mit 9.3.B+ | Higher-Order (gefiltert, abgebildet, gesammelt), Sortierung | §18 |
text |
verfügbar | Subset seit 9.3.B | Strings transformieren, suchen, aufteilen | §19 |
geld |
verfügbar | vertagt (braucht Dezimal-Pfad) | Exakte Geld-Arithmetik mit Währungen | §20 |
datei |
verfügbar | Subset seit 9.3.D | Dateien lesen/schreiben, Verzeichnisse, Pfade | §21 |
json |
verfügbar | Subset seit 9.3.I.1 | JSON parsen + serialisieren, Geld-Roundtrip | §22 |
pfad |
verfügbar | Subset seit 9.3.D | Pfad-Manipulation, OS-Trennzeichen | §23 |
umgebung |
verfügbar | Subset seit 9.3.F | OS-Info, Umgebungsvariablen, CLI-Args, exit | §24 |
hash |
verfügbar | Subset seit 9.3.C | SHA-256, HMAC, Base64/Hex-Encoding | §25 |
regex |
verfügbar | Subset seit 9.3.E | RE2-Pattern-Matching, Ersetzen, Zerlegen | §26 |
csv |
verfügbar | Subset seit 9.3.I.2 (Options-Karten in 9.3.I.3) | CSV lesen + schreiben mit Optionen | §27 |
zeit |
verfügbar | Subset seit 9.3.F | Datum/Zeit mit deutschen Format-Tokens, ISO-8601 | §28 |
prozess |
verfügbar | Subset seit 9.3.F | Externe Programme starten, args-immer-als-Liste | §29 |
bytes |
verfügbar | Subset seit 9.3.C | Binäre Daten, immutable, Datei-IO | §30 |
netz |
verfügbar | Subset seit 9.3.G | HTTP-Client (GET/POST/PUT/DELETE/PATCH), TLS-Stufen | §31 |
wert |
(LLVM-only-Modul) | NEU seit 9.3.I.0 | Heterogene-Werte: als_<typ>-Casts, ist_nichts, Skalar-Konstruktoren |
§16.10.7 |
16 Stdlib-Module sind komplett im Tree-Walker und VM, plus das LLVM-spezifische wert-Modul für heterogene Werte. Im nativen Pfad (kiste build) bringt Phase 9.3 die Module schrittweise — Stand 2026-05-14 (nach 9.3.I.2): mathe + zufall + text + bytes + hash + datei + pfad + regex + zeit + umgebung + prozess + netz + json + csv + wert (Subset) verfügbar (14 + 1 Foundation-Modul von 16), liste strukturell out-of-scope (Higher-Order/Closure-Strategie), geld vertagt (Dezimal-Pfad). Options-Karten für netz / prozess / csv kommen in 9.3.I.3.
16.10.0 Stdlib im kiste build-Pfad (seit 9.3.A)
Ab Phase 9.3.A kann der LLVM-Pfad mathe.* und zufall.* aufrufen — kein Boxing-Overhead, direkter cgo-Bridge-Call:
nutze mathe
nutze zufall
sag(mathe.wurzel(64f)) // 8.0
sag(mathe.absolut(-7.5f)) // 7.5
sag(mathe.vorzeichen(-3f)) // -1 (ganz)
zufall.setze_saat(42)
sag(zufall.zahl()) // reproduzierbar gleich zwischen `kiste run` und `kiste build`
sag(zufall.ganz(1, 6)) // wirft `Fehler` wenn min > max
Was im kiste build-Subset von 9.3.A funktioniert:
- mathe (20 Funktionen):
sinus/kosinus/tangens+ Arkus-Varianten +arkustangens2,als_radian/als_grad,wurzel/exp/ln/log10/log2/log,absolut(komma),vorzeichen(komma→ganz),ist_nan/ist_unendlich/ist_endlich. - zufall (3 Funktionen):
zahl,ganz(mit Throw bei min>max),setze_saat.
Seit 9.3.H zusätzlich:
- mathe-Konstanten:
mathe.PI,mathe.E,mathe.TAU,mathe.UNENDLICH,mathe.NEG_UNENDLICH,mathe.NANals Compile-Time-Literale. mathe.maximum(a, b, ...)undmathe.minimum(a, b, ...)variadic, ≥ 2 Komma-Args.
Aus dem kiste build-Subset noch ausgeschlossen (Tree-Walker akzeptiert weiterhin):
mathe.hoch(ganz, ganz)mit Ganz-Exponenten — Workaround:mathe.exp(mathe.ln(x) * y).mathe.absolut(ganz)— Workaround: noch keine.zufall.dezimal/zufall.element/zufall.gemischt/zufall.mische— Workaround: noch keine.
zufall.setze_saat gibt seit 9.3.H explizit Nichts zurück (keine Dummy-Ganz 0 mehr) — als bare Statement aufrufen, nimm x = zufall.setze_saat(42) ist Compile-Fehler in allen 3 Backends.
Implizite Ganz→Komma-Promotion funktioniert wie im Tree-Walker: mathe.wurzel(4) (ganz-Literal) klappt, weil der Compiler das Argument vor dem Bridge-Call auf komma hebt. Andere Konversionen (z.B. Text→Komma) sind harte Compile-Errors mit klarer deutscher Meldung.
16.10.1 text im kiste build-Pfad (seit 9.3.B)
Ab Phase 9.3.B kann der LLVM-Pfad 30 text.*-Funktionen rufen — Strings sind im nativen Build genauso komfortabel wie im Tree-Walker:
nutze text
nimm s = " Hallo schöne Welt "
sag(text.beschnitten(s)) // "Hallo schöne Welt"
sag(text.kleingeschrieben(text.beschnitten(s))) // "hallo schöne welt"
sag(text.umgekehrt("abcd")) // "dcba"
sag(text.ersetzt("a-b-c", "-", "+")) // "a+b+c"
sag(text.länge("é")) // 1 (UAX#29 grapheme)
nimm parts = text.zerlegt("rot,grün,blau", ",")
wiederhole p in parts { sag(p) } // rot / grün / blau
sag(text.verkettet(parts, " | ")) // "rot | grün | blau"
// finde_index returnt ?Ganz — Hit liefert Index, Miss liefert nichts
nimm idx = text.finde_index("Hallo Welt", "Welt")
sag(idx) // 6
nimm fehl = text.finde_index("Hallo Welt", "Mond")
sag(fehl) // nichts
sag(fehl ?? -1) // -1 (??-Coalesce)
Was im kiste build-Subset von 9.3.B funktioniert — alle 30 Funktionen aus internal/stdlib/text/text.go; die 2-Arg-Trim-Formen (text.beschnitten(s, "xyz") etc.) sind seit 9.3.H zusätzlich im Subset:
- Predicates/Reflection:
länge,bytes_länge,zeichen_länge,leer,enthält,beginnt_mit,endet_mit,zähle,finde_index(returnt?Ganz→ Nichts bei Miss). - Transformationen:
großgeschrieben,kleingeschrieben,kapitalisiert,beschnitten(Whitespace-Trim),links_beschnitten,rechts_beschnitten,umgekehrt,wiederholt,ersetzt,ersetzt_erstes. - Selection:
scheibe,zeichen_bei,erste_n,letzte_n,gefüllt_links,gefüllt_rechts. - Split → liste<text>:
zerlegt,zeilen,wörter,zeichen. - Join:
verkettet(nimmtliste<text>+ Trenner).
Throw-Verhalten wie im Tree-Walker: text.zähle(s, "") mit leerem Suchstring wirft Fehler, text.wiederholt(s, -1) analog, text.zeichen_bei(s, 99) bei Out-of-Range. Fangbar mit versuche/fange aus 9.2.E.
Aus dem kiste build-Subset noch ausgeschlossen (Tree-Walker akzeptiert weiterhin): keine spezifischen text-Items seit 9.3.H.
16.10.2 bytes + hash im kiste build-Pfad (seit 9.3.C)
Ab Phase 9.3.C kann der LLVM-Pfad mit binären Daten und kryptographischen Hashes arbeiten — Datei-Hashing, Base64/Hex-Encoding und HMAC-Auth-Tokens funktionieren in nativen Builds:
nutze bytes
nutze hash
// Bytes konstruieren, ansehen, in Hex/Base64 wandeln
nimm b = bytes.von_text("Hallo Kiste")
sag(b) // bytes(48616c6c6f204b69737465)
sag(länge(b)) // 11 (Byte-Anzahl, NICHT Grapheme)
sag(bytes.als_hex(b)) // 48616c6c6f204b69737465
sag(bytes.als_base64(b)) // SGFsbG8gS2lzdGU=
// Round-Trip via Hex
nimm back = bytes.als_text(bytes.aus_hex("48616c6c6f"))
sag(back) // Hallo
// SHA-256 als Hex
sag(hash.sha256("hello")) // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
sag(hash.sha256_bytes(b)) // Hash der Bytes (gleicher Algorithmus, Bytes-Input)
// HMAC für API-Authentifizierung
sag(hash.hmac_sha256("nachricht", "geheimer-schlüssel"))
// Base64 Roundtrip
sag(hash.base64_dekodiert(hash.base64_kodiert("Welt"))) // Welt
Was im kiste build-Subset von 9.3.C funktioniert:
- bytes (17 Funktionen): Konstruktion (
von_text,von_ganzen,aus_hex,aus_base64), Konversion (als_text,als_text_oder,als_ganze,als_hex,als_base64), Operationen (byte_beimit negativen Indizes,scheibe,enthält,ist_gleich). Plus globalesag(b)(Formatbytes(<hex>)mit Truncation für lange Sequenzen) undlänge(b)(Byte-Count). - hash (16 Funktionen):
md5/sha1/sha256/sha512jeweils für Text +_bytes-Varianten für Binär-Input.hmac_sha256/hmac_sha512plus_bytes-Varianten.base64_kodiert/base64_dekodiertundhex_kodiert/hex_dekodiertfür Text-Roundtrips.
Throw-Verhalten wie im Tree-Walker — fangbar mit versuche/fange: bytes.von_ganzen([72, 999]) wirft (außer 0-255), bytes.aus_hex("abc") wirft (ungerade Länge), bytes.als_text(...) wirft bei ungültigem UTF-8, hash.base64_dekodiert("@@@") wirft bei ungültigem Base64.
Aus dem kiste build-Subset noch ausgeschlossen:
bytes.verkettet(...args)variadic — Tree-Walker erlaubt beliebig viele Bytes-Args. Polish 9.3.H löst variadic-Stdlib-Konvention. Workaround: Bytes viabytes.von_text(text.verkettet([bytes.als_text(a), bytes.als_text(b)], ""))zusammenführen (für UTF-8-Daten) oder weiterhin Tree-Walker für binäre Joins.
16.10.3 datei + pfad im kiste build-Pfad (seit 9.3.D)
Ab Phase 9.3.D kann der LLVM-Pfad mit Dateien und Pfaden arbeiten — CLI-Tools, Log-Verarbeitung, Config-File-Parser und Datei-Hash-Pipelines funktionieren nativ:
nutze datei
nutze pfad
nutze hash
// Datei schreiben + lesen
datei.schreibe("notiz.txt", "Hallo Kiste\n")
sag(datei.inhalt("notiz.txt")) // Hallo Kiste
sag(datei.größe("notiz.txt")) // 12
// Pfad zerlegen
sag(pfad.dateiname("a/b/c.txt")) // c.txt
sag(pfad.erweiterung("c.txt")) // .txt
sag(pfad.basisname("c.txt")) // c
// Verzeichnisse + Iteration
datei.erstelle_ordner_rekursiv("logs/2026")
datei.schreibe(pfad.normalisiert("logs/2026/jan.log"), "...")
wiederhole e in datei.einträge("logs/2026") { sag(e) } // jan.log
// Datei-Hash via bytes-Pfad (9.3.C + 9.3.D Cross-Module)
nimm b = datei.bytes_inhalt("notiz.txt")
sag(hash.sha256_bytes(b))
// Aufräumen
datei.lösche("notiz.txt")
datei.lösche_ordner_rekursiv("logs")
Was im kiste build-Subset von 9.3.D funktioniert:
- datei (18 Funktionen):
- Lesen:
inhalt,zeilen(returntliste<text>),bytes_inhalt(returnt Bytes für binäre Dateien). - Schreiben:
schreibe,schreibe_bytes,hänge_an. - Prüfungen:
existiert,ist_datei,ist_ordner. - Metadaten:
größe(Byte-Count),geändert_unix(Unix-Timestamp als Ganz). - Manipulation:
lösche,kopiere,verschiebe(mit Cross-Device-Fallback). - Verzeichnisse:
erstelle_ordner,erstelle_ordner_rekursiv,lösche_ordner_rekursiv,einträge(sortiert).
- Lesen:
- pfad (10 Funktionen):
- Zerlegung:
dateiname,ordner,erweiterung,basisname,zerlegt(returntliste<text>). - Normalisierung:
normalisiert,absolut,relativ. - Prädikate:
ist_absolut,ist_relativ.
- Zerlegung:
Cross-Module-Verwendung mit bytes (9.3.C): datei.bytes_inhalt(p) returnt einen Bytes-Wert, der direkt an hash.sha256_bytes(b) oder bytes.als_hex(b) weitergereicht werden kann.
Throw-Verhalten wie im Tree-Walker — alle I/O-Operationen können werfen und sind fangbar mit versuche/fange: fehlende Dateien, Permission-Denied, nicht-UTF-8 bei datei.inhalt, ungültige Ziele bei kopiere/verschiebe.
Mutator-Funktionen (schreibe/lösche/kopiere/verschiebe/hänge_an/erstelle_ordner_*/lösche_ordner_rekursiv/schreibe_bytes) returnen seit 9.3.H in allen 3 Backends Nichts. Nutze sie als bare Statements — nimm x = datei.lösche(p) ist Compile-Fehler („Variable kann nicht auf einen Funktions-Aufruf gesetzt werden, der nichts zurückgibt").
Seit 9.3.H zusätzlich:
pfad.verbunden(a, b, ...)variadic mit ≥ 2 text-Args.pfad.trenner/pfad.listen_trennerKonstanten.
Aus dem kiste build-Subset noch ausgeschlossen:
datei.geändert(path) → Zeitist seit 9.3.F im Subset (Drift-Lift);datei.einträge_mit_detailsist noch out-of-subset (heterogene Map-Werte, kommt mit 9.3.I).
16.10.4 regex im kiste build-Pfad (seit 9.3.E)
Ab Phase 9.3.E kann der LLVM-Pfad RE2-Pattern-Matching nativ. Pattern-Compile-Cache (sync.Map) ist transparent — repeated Calls mit gleichem Pattern sind günstig:
nutze regex
sag(regex.passt("^hello", "hello world")) // wahr
sag(regex.gültig("a+b")) // wahr
sag(regex.gültig("a(")) // falsch (ungültiges Pattern)
// treffer returnt ?text — Nichts wenn kein Match
nimm m = regex.treffer("\\d+", "abc123def")
sag(m) // 123
sag(m ?? "kein-match") // 123 (Hit)
nimm fehl = regex.treffer("\\d+", "abcdef")
sag(fehl) // nichts
sag(fehl ?? "kein-match") // kein-match
// Alle Treffer iterieren
wiederhole zahl in regex.treffer_alle("\\d+", "a1b22c333") { sag(zahl) }
// 1 / 22 / 333
// Ersetzen
sag(regex.ersetzt("\\d", "a1b2c3", "X")) // aXbXcX
sag(regex.ersetzt_erstes("\\d", "a1b2c3", "X")) // aXb2c3
// Zerlegen + Maskieren
wiederhole p in regex.zerlegt(",", "rot,grün,blau") { sag(p) }
sag(regex.maskiert("a.b(c)")) // a\.b\(c\)
Was im kiste build-Subset von 9.3.E funktioniert (8 Funktionen):
passt(muster, text) → wahrheit— Match-Prüfung (CanThrow bei ungültigem Pattern).gültig(muster) → wahrheit— Pre-Flight Pattern-Validation (non-throw).treffer(muster, text) → ?text— erster Match oder Nichts (Nullable-Return).treffer_alle(muster, text) → liste<text>— alle Matches.ersetzt/ersetzt_erstes— Pattern-Replace.zerlegt(muster, text) → liste<text>— String-Split per Pattern (Throw bei leerem Pattern).maskiert(text) → text— escape meta-chars für literale Verwendung.
Aus dem kiste build-Subset noch ausgeschlossen:
regex.gruppen(muster, text) → ?liste<text>— brauchtTypNullableListTextder noch fehlt. Workaround: weiterhin Tree-Walker odertrefferfür nur-erstes-Match.regex.treffer_alle_gruppen(muster, text) → liste<liste<text>>— nested-list. Workaround: Tree-Walker oder iterativetreffer_alleohne Gruppen.
json und csv sind komplett aus dem 9.3.E-Subset draußen — siehe nutze json / nutze csv rejecten mit „Modul nicht registriert". Beide brauchen Type-System-Erweiterungen (heterogene Maps für JSON, nested Lists für CSV) die eine eigene Sub-Phase 9.3.I bekommen. Bis dahin: Tree-Walker / VM nutzen für JSON/CSV-lastige Programme.
16.10.5 zeit + umgebung + prozess im kiste build-Pfad (seit 9.3.F)
Ab Phase 9.3.F kann der LLVM-Pfad mit Zeitstempeln rechnen, Environment-Variablen lesen+schreiben und Sub-Prozesse starten — CLI-Tools, Build-Skripte, System-Automatisierung funktionieren nativ:
nutze zeit
nutze umgebung
nutze prozess
// Zeit-Operationen
nimm jetzt = zeit.jetzt()
sag(jetzt) // 2026-05-13T10:42:00Z (Beispiel)
sag(zeit.jahr(jetzt)) // 2026
sag(zeit.formatiert(jetzt, "JJJJ-MM-TT")) // 2026-05-13
nimm geburt = zeit.von_komponenten(2024, 1, 15, 12, 0, 0)
sag(zeit.ist_vor(geburt, jetzt)) // wahr
// Environment
sag(umgebung.betriebssystem()) // windows
nimm pfad = umgebung.wert("PATH")
sag(pfad ?? "kein-PATH")
umgebung.setze("KISTE_DEMO", "hallo")
sag(umgebung.wert("KISTE_DEMO")) // hallo
umgebung.entferne("KISTE_DEMO")
// Sub-Prozess (Windows-Beispiel)
nimm code = prozess.exit_code(["cmd", "/c", "exit", "0"])
sag(code) // 0
sag(prozess.erfolgreich(["cmd", "/c", "exit", "0"])) // wahr
Was im kiste build-Subset von 9.3.F funktioniert:
- zeit (22 Funktionen): Konstruktion (
jetzt/jetzt_lokal/heute/von_unix/von_unix_ms/von_komponenten), Parser (geparst_iso/geparst), 9 Komponenten-Getter (jahr/monat/tag/stunde/minute/sekunde/wochentag/unix/unix_ms), Formatieren (formatiert_iso/formatiertmit deutschen Tokens JJJJ/MM/TT/hh/mm/ss/…), Vergleich (ist_vor/ist_nach/ist_gleich), System (system_zone/schlafe_ms). - umgebung (14 Funktionen): env-vars (
wertmit?text-Return /wert_oder/alle→karte<text>/setze/entferne),argumente→liste<text>,arbeitsverzeichnis/wechsle_in/programm_ordner, OS-Info (betriebssystem/architektur/benutzer/benutzer_ordner),beende(code). - prozess (3 von 5 Funktionen):
ausgabe(argv)→text(Throw bei exit≠0),exit_code(argv)→Ganz,erfolgreich(argv)→wahrheit. argv ist immerliste<text>mit args[0] = Programm-Name (security-cornerstone, kein Shell-Expansion).
Drift-Lift seit 9.3.F: datei.geändert(path) → Zeit funktioniert jetzt — gibt den File-Mtime als Zeit-Wert zurück (statt nur Unix-Timestamp). zeit.unix(datei.geändert(p)) liefert exakt das gleiche wie datei.geändert_unix(p).
Aus dem kiste build-Subset noch ausgeschlossen:
zeit.von_komponenten3-Arg-Form ist seit 9.3.H im LLVM-Pfad verfügbar —zeit.von_komponenten(2026, 5, 13)setzt stunde/minute/sekunde auf 0 als Default (= Mitternacht UTC).prozess.ausgeführt+prozess.ausgeführt_bytes(heterogene Karte als Return) — vertagt auf 9.3.I. Workaround: weiterhin Tree-Walker.prozess-Options-Karte (2. Argument, heterogene Werte) — vertagt auf 9.3.I.umgebung.argumenteSource-Drift: TW nutztinterp.UserArgs(), LLVM-Pfad nutztos.Args[1:]der laufenden Process — Inhalt unterschiedlich zwischen den zwei Pfaden.- LogicalOp mit CallExpression-Operanden (
zeit.ist_vor(a, b) oder zeit.ist_gleich(a, b)) — Workaround: bind Bool-Results in Variablen.
länge(<Zeit>) ist bewusst rejected — Zeit ist kein Container. Wenn du Komponenten brauchst, nutze zeit.jahr/monat/tag/….
16.10.6 netz HTTP-Client im kiste build-Pfad (seit 9.3.G)
Ab Phase 9.3.G kann der LLVM-Pfad HTTP-Requests senden — REST-API-Clients, Download-Skripte, Status-Pings, einfache Web-Scraper laufen jetzt nativ als .exe:
nutze netz
// GET mit Antwort-Wert-Typ (status, inhalt, bytes, header, dauer_ms, url, erfolgreich)
nimm a = netz.hole("https://api.example.com/users")
sag(a.status) // 200
sag(a.erfolgreich) // wahr
sag(a.inhalt) // JSON-String
sag(a.dauer_ms) // 142
// Strict GET — wirft bei !erfolgreich oder !UTF-8
nimm text = netz.hole_text("https://api.example.com/info")
sag(text)
// POST mit text-Body
nimm post = netz.sende("POST", "https://api.example.com/echo", "hallo")
sag(post.inhalt) // hallo
// POST mit bytes-Body (für Binär-Uploads)
nutze bytes
nimm bin = bytes.von_text("binärer-payload")
nimm up = netz.sende_bytes("POST", "https://api.example.com/upload", bin)
sag(up.status)
// HEAD-Status-Check
sag(netz.pinge("https://api.example.com")) // 200
Was im kiste build-Subset von 9.3.G funktioniert:
- netz (5 Funktionen):
hole(url)→ Antwort (GET),hole_text(url)→ text (Strict GET, Throw bei !erfolgreich/!UTF-8),sende(method, url, text-body)→ Antwort (POST/PUT/DELETE/PATCH/...),sende_bytes(method, url, bytes-body)→ Antwort (Bytes-Body),pinge(url)→ Ganz (HEAD-Status). - Antwort-Felder (7):
a.status(Ganz),a.inhalt(text mit UTF-8-Validation),a.bytes(Bytes, identity-stable),a.header(karte<text>mit lowercased Keys, multi-values mit ", " joined),a.dauer_ms(Ganz),a.url(text),a.erfolgreich(wahrheit, 2xx).
Defaults sind hart-codiert (mirror Tree-Walker parseOptions):
- 30s Request-Timeout.
- Redirects folgen automatisch (max 10 Hops).
- TLS-Zertifikat-Prüfung aktiv.
- User-Agent:
kiste-netz/0.3.
Body-Drift zu Tree-Walker — wichtig zu wissen:
Tree-Walker's netz.sende(method, url, body) akzeptiert body als text | bytes | nichts. Der LLVM-Pfad teilt das in zwei separate Funktionen:
sende(method, url, text-body)— text-Bodysende_bytes(method, url, bytes-body)— bytes-Body
Warum? Die LLVM-Stdlib-Registry hat single-typed Parameter-Slots (ParamTypes []KisteType) und unterstützt aktuell keine Multi-Type-Union-Parameter. Eine Erweiterung wäre Architektur-Aufwand außerhalb des 9.3.G-Scopes. Die Lift zur Single-Function-API kommt in 9.3.I.
Aus dem kiste build-Subset noch ausgeschlossen (alle vertagt auf 9.3.I):
netz.sende_json(method, url, daten[, opts])— heterogene Daten als JSON-Body. Workaround:json.kodiere(daten)im Tree-Walker bauen, dannsende(method, url, json-text)aufrufen — oder vorerst kompletter TW/VM-Pfad.- Optionen-Karte (2. Arg von
hole/pinge, 4. Arg vonsende) mitheader/parameter/zeitlimit_ms/folge_redirects/ca_datei/tls_pruefen— heterogene Map-Werte brauchen TypBoxedMapAny. body = nichts(TW: kein Request-Body) — heute nicht im LLVM-Subset. Workaround:sende(method, url, "")schickt leeren Body mitContent-Length: 0.a.header[k] ?? "default"Map-Index-Coalesce auf einem Field-Read-Receiver — klemmt im aktuellen IndexExpression-Pfad. Workaround:nimm h = a.headerin eine Variable binden, dannh[k] ?? "default". Drift-Item für 9.3.H.
länge(<Antwort>) ist bewusst rejected — Antwort ist kein Container. Nutze länge(a.bytes) für die Body-Byte-Größe oder länge(a.header) für die Header-Count.
sag(<Antwort>) reproduziert das Tree-Walker-Format: antwort(<status>, <n> bytes, <ms>ms) — z.B. antwort(200, 1234 bytes, 142ms).
Seit 9.3.I.3.c zusätzlich (Options-Karten + sende_json):
nutze netz
nutze json
nutze wert
// Options-Karte als 2./4. Arg — header / parameter / zeitlimit_ms / folge_redirects
nimm a = netz.hole("https://api.example.com/user/42", {
"header": {"Accept": "application/json", "Authorization": "Bearer xyz"},
"parameter": {"include": "profile"},
"zeitlimit_ms": 5000,
"folge_redirects": wahr
})
// REST-API mit JSON-Body — neue sende_json-Funktion
nimm daten = {"name": "Sascha", "alter": 38, "aktiv": wahr}
nimm post = netz.sende_json("POST", "https://api.example.com/users", daten)
sag(post.status) // z.B. 201
// JSON-Roundtrip: API gibt JSON zurück → parsen → Felder lesen
nimm parsed = wert.als_karte(json.geparst(post.inhalt))
sag(wert.als_text(parsed["id"]))
Options-Karte (mirror TW):
header:karte<text>mit Request-Headers. Default User-Agentkiste-netz/0.3wenn nicht überschrieben.parameter:karte<text>mit URL-Query-Parametern.zeitlimit_ms:ganz(default 30000 = 30s). Bei Timeout wird ein Fehler geworfen.folge_redirects:wahrheit(defaultwahr, max 10 Hops).falsch→ 302/301 wird direkt zurückgegeben.
Drift im LLVM-Pfad (Drift-Backlog ohne hohe Priorität):
ca_dateiundtls_pruefensind imkiste build-Pfad heute no-op — die Option wird akzeptiert (kein Reject), hat aber keine Wirkung. TLS-Verifikation ist immer an. Tree-Walker spiegelt die TW-Variante mit stderr-Warning beitls_pruefen=falsch; das kommt mit einem späteren TLS-Config-Lift.
netz.sende_json(method, url, daten[, opts]) akzeptiert beliebige Kiste-Werte (ganz, text, bool, komma, dezimal, Karte, Liste) als daten — encodet intern via json.erzeugt und setzt Default-Content-Type "application/json; charset=utf-8" (außer User hat einen eigenen Header gesetzt).
16.10.7 wert — heterogene Werte im kiste build-Pfad (seit 9.3.I.0)
Mit Phase 9.3.I.0 unterstützt der LLVM-Pfad heterogene Werte (beliebig-Typ) — der Daten-Typ, den JSON-/CSV-Parser und ähnliche Quellen produzieren. Im Tree-Walker repräsentiert das ein Go-interface{}; im LLVM-Pfad ist es der Slot-Type TypBoxedValue mit Tagged-Union-Payload (InnerTag aus {nichts, ganz, komma, dezimal, bool, text, liste, karte}).
Das wert-Modul ist der User-Eintrittspunkt für die Arbeit mit heterogenen Werten:
nutze wert
// Skalar-Konstruktoren — packe einen typisierten Wert in eine `beliebig`-Box
nimm v1 = wert.ganz(42) // beliebig (innen ganz)
nimm v2 = wert.text("Sascha") // beliebig (innen text)
nimm v3 = wert.bool(wahr) // beliebig (innen bool)
nimm v4 = wert.nichts() // beliebig (innen nichts)
nimm v5 = wert.komma(3.14f) // beliebig (innen komma)
nimm v6 = wert.dezimal("0.1") // beliebig (innen dezimal)
// Cast zurück auf konkrete Typen — wirft bei Tag-Mismatch
nimm n = wert.als_ganz(v1) // ganz 42
nimm s = wert.als_text(v2) // text "Sascha"
nimm b = wert.als_bool(v3) // bool wahr
// Predicate für nichts-Test
wenn wert.ist_nichts(v4) {
sag("ist nichts")
}
// typ(v) liefert den inneren Typ als text
sag(typ(v1)) // "ganz"
sag(typ(v2)) // "text"
sag(typ(v4)) // "nichts"
// Display rekursiv — text in nested Containern in Quotes (mirror TW)
sag(v1) // 42
sag(v2) // Sascha
sag(v6) // 0.1
Was im kiste build-Subset von 9.3.I.0 funktioniert:
- Konstruktoren (6):
wert.nichts(),wert.ganz(n),wert.komma(f),wert.dezimal(t),wert.text(t),wert.bool(b). - Casts (7, alle CanThrow):
wert.als_ganz(v),wert.als_komma(v),wert.als_dezimal(v),wert.als_text(v),wert.als_bool(v),wert.als_liste(v)→liste<beliebig>,wert.als_karte(v)→karte<beliebig>. - Predicate (1):
wert.ist_nichts(v)→bool. - Builtins:
typ(v)returnt den InnerTag-Namen,sag(v)druckt rekursiv mit TW-Quoting,länge(als_liste(v))undlänge(als_karte(v))zählen die Container-Slots.
Throw-Format bei Cast-Mismatch: wert.als_<wanted>: erwartet <wanted>, gefunden <found> — z.B. wert.als_ganz: erwartet ganz, gefunden text.
Seit 9.3.I.0.1.a zusätzlich (E-134.a, 2026-05-15):
- Direct-Compare
v == nichts/v != nichts— der häufigste Predicate-Pfad funktioniert jetzt ohne expliziten Cast:nimm a = json.versucht_geparst(eingabe) wenn a == nichts { sag("Parse-Fehler") } sonst { sag("OK") } - Konstruktive Diagnose für Direct-Ops auf BoxedValue (
bv + 5,bv == 5,bv < 5,wenn bv, ...): User sieht jetzt eine konkrete Cast-Empfehlung statt der generischen „Operator nicht definiert"-Meldung. Beispiel:bv + 5zeigtCast zuerst: nimm n = wert.als_ganz(bv) dann n + .... Beiwenn bvsieht der User die Wahl zwischen Predicate (wenn nicht wert.ist_nichts(bv)) und Cast (wenn wert.als_bool(bv)).
Seit 9.3.I.0.1.b zusätzlich (E-134.b, 2026-05-16):
- Direct-Coalesce
v ?? d— Result-Type = Type-of-d (Q1.a). Compiler emittiert internwenn ist_nichts(v) { d } sonst { wert.als_<typ-of-d>(v) }. Bei Inner-Tag-Mismatch wirft der Cast (z.B.bv ?? 0mitbv=text("hi")wirftwert.als_ganz: erwartet ganz, gefunden text):nutze json nimm daten = json.geparst(eingabe) nimm karte = wert.als_karte(daten) nimm alter = karte["alter"] ?? 0 // Ganz-Default — als_ganz(bv) nimm name = karte["name"] ?? "unbekannt" // Text-Default — als_text(bv) - Direct-Index
v[k]undv[i]— Key-Typ entscheidet Cast-Pfad (Q2.a). Text-Key → Karten-Pfad. Ganz-Key → Listen-Pfad. Result ist immer wiederbeliebig, daher funktionieren mehrstufige Ketten ohne Cast-Vorstufe:nimm daten = json.geparst(eingabe) nimm erster_name = daten["users"][0]["name"] // Mehrstufig: Karte → Liste → Karte sag(wert.als_text(erster_name)) - Out-of-Subset (mit konstruktiver Diagnose): Container-Defaults für
bv ?? <liste>/bv ?? <karte>undbv ??= dbleiben Reject. Workarounds sind in der Diagnose genannt (wenn ist_nichts(bv) { d } sonst { ... }für Container-Defaults;bv = bv ?? dfür??=).
Seit 9.3.I.0.2 zusätzlich (E-134.c, 2026-05-16):
beliebigals Funktions-Parameter via Call-Site-Inferenz — Funktionen können heterogene Werte als Parameter empfangen. Der Multi-Pass-Solver leitet den Param-Type aus den Call-Sites her; primitive Args werden am Call-Boundary viawert.<X>automatisch geboxt (Q1.a):funktion log_wert(v) { sag(typ(v)) sag(v) } log_wert(42) // Auto-Box: wert.ganz(42) log_wert("hi") // Auto-Box: wert.text("hi") log_wert(json.geparst(eingabe)) // Pass-through (schon beliebig)beliebigals Funktions-Return —gib <konkret>undgib nichtsaus einer Funktion mit BoxedValue-Return werden implicit zuwert.<X>(...)bzw.wert.nichts()gewrappt (Q2.a):funktion feld_oder(d, k, default_wert) { gib d[k] ?? default_wert // Direct-Index + Direct-Coalesce auf BoxedValue-Param-Variable } funktion vielleicht_zahl(t) { wenn länge(t) > 0 { gib wert.ganz(42) } sonst { gib nichts } }- Mehrstufige Daten-Verarbeitung über mehrere Funktionen läuft natürlich nativ — alle 9.3.I.0.1.a/b-Pfade (Direct-Compare, Direct-Coalesce, Direct-Index) funktionieren im Body eines BoxedValue-Param genauso wie auf einer Variable.
Seit 2026-06-11 zusätzlich: implizites Unboxing an Call-Grenzen (docs/llvm-implizit-unbox.md):
- Die Gegenrichtung zum Auto-Box: ein
beliebig-Wert (z.B. aus einer gemischten Karte) darf direkt in einen Parameter mit konkretem Typ fließen — der Compiler setzt den Laufzeit-Typcheck, genau wie der Tree-Walker:nimm person = {"name": "Sascha", "alter": 38} // gemischte Karte → Werte sind beliebig funktion verdopple(n) { gib n * 2 } sag verdopple(3) // verankert n als ganz sag verdopple(person["alter"]) // beliebig → ganz: Laufzeit-Cast, läuft → 76 // verdopple(person["name"]) würde ZUR LAUFZEIT werfen: // "wert.als_ganz: erwartet ganz, gefunden text (Zeile N, Spalte M)" - Kein
wert.als_*mehr nötig für den 08/15-Fall — die Casts bleiben für explizite Kontrolle verfügbar. Gilt an allen Call-Grenzen (Funktionen, Closures, Methoden, Konstruktoren,super); Stdlib-Funktionen verlangen weiterhin den expliziten Cast (Overloads).
Aus dem 9.3.I-Subset noch rejected:
länge(<beliebig>)bleibt rejected — beliebig ist kein Container, nutzelänge(wert.als_liste(v))oder Analogon. Die Reject-Meldung enthält den Cast-Vorschlag.- Klassen-Instances als
beliebig-Wert (eigene Tracer-Erweiterung; eigene Sub-Phase falls je User-Bedarf). - Mix
f(beliebig)+f([1, 2])(Container-Wert mixed mit BoxedValue) → Konflikt mit „widersprüchliche Typen". Workaround: explizitwert.als_liste(...)am Call-Site.
Container in 9.3.I.0: Heterogene Listen und Karten kommen produktiv mit 9.3.I.1 (json.geparst als natürlicher Produzent). Das interne _test_box-Modul liefert temporär die Konstruktoren für die Differential-Test-Suite — wird mit 9.3.I.1 obsolet.
16.10.8 json JSON-Parser + Serializer im kiste build-Pfad (seit 9.3.I.1)
Mit Phase 9.3.I.1 unterstützt der LLVM-Pfad JSON-Parsing und -Serialisierung als ersten produktiven Konsumenten der 9.3.I.0-Foundation. REST-API-Clients mit JSON-Bodies funktionieren jetzt nativ:
nutze netz
nutze json
nutze wert
// REST-API-Use-Case: GET → JSON-Parsing → Feld-Zugriff
nimm a = netz.hole("https://api.example.com/user/42")
nimm daten = json.geparst(a.inhalt)
nimm karte = wert.als_karte(daten)
nimm name = wert.als_text(karte["name"])
nimm alter = wert.als_ganz(karte["alter"])
sag(name)
sag(alter)
// Fehlende Felder produzieren BoxedValue(IVNichts) — User prüft via ist_nichts
nimm vielleicht_email = karte["email"]
wenn wert.ist_nichts(vielleicht_email) {
sag("keine E-Mail im JSON")
} sonst {
sag(wert.als_text(vielleicht_email))
}
// Encode mit pretty-print
nimm formatiert = json.erzeugt_schön(daten)
sag(formatiert)
Was im kiste build-Subset von 9.3.I.1 funktioniert:
- json (4 Funktionen):
json.geparst(t)→beliebig— wirftFehlerbei Parse-Fehler oder Big-Int-Overflow.json.versucht_geparst(t)→beliebig— bei Parse-Fehler wirdBoxedValue(IVNichts)zurückgegeben (im LLVM-Pfad statt echtemnichts— siehe Drift-Hinweis unten). User prüft viawert.ist_nichts(v).json.erzeugt(v)→text— kompakt, kein Whitespace. Wirft bei NaN/Inf/zirkulärer Referenz.json.erzeugt_schön(v[, einrückung])→text— pretty-print mit Default 2 Leerzeichen oder eigenereinrückung(z.B."\t"für Tabs).
- Map-Index auf
karte<beliebig>:wert.als_karte(daten)["k"]returnt direktbeliebig(kein Nullable-Wrap). Missing-Key produziertBoxedValue(IVNichts).
Number-Heuristik beim Parsen (mirror docs/json.md §2.2):
- JSON-Zahl enthält
e/E(egal mit Punkt) →komma. - JSON-Zahl enthält
.ohnee/E→dezimal(kanonisiert:42.0→42,1.500→1.5). - Sonst →
ganz(wirft im LLVM-Pfad bei > int64-Range — TW hält exakt via BigInt).
Map-Reihenfolge: alphabetisch sortiert (mirror TW + encoding/json + RFC 8259's „unordered objects"-Semantik). Cross-Backend byte-identisch.
Drift zu Tree-Walker (wichtig zu wissen):
json.versucht_geparstbei Parse-Fehler: TW gibt echtesnichts-Value zurück, LLVM-Pfad gibtBoxedValue(IVNichts)zurück. Byte-identisch insag-Output (beide drucken"nichts") und funktional identisch viawert.ist_nichts(v). Nur direkter Vergleichversucht_geparst(t) == nichtsist im LLVM-Pfad bis 9.3.I.0.1 rejected. Workaround:wert.ist_nichts(versucht_geparst(t)).- Big-Int-JSON-Zahlen (> 2^63-1 oder < -(2^63)): TW hält exakt via
big.Int, LLVM-Pfad wirftFehlerbei Konversion. Workaround: solche Zahlen vorher als JSON-String parsen ("9223372036854775808"als String, dannwert.als_text).
Was im kiste build-Subset 9.3.I.1 NOCH NICHT funktioniert:
Direkter Vergleich→ seit 9.3.I.0.1.a (E-134.a, 2026-05-15).bv == nichts→ seit 9.3.I.0.1.b (E-134.b, 2026-05-16) — primitive Defaults.?? defaultaufbeliebig→ seit 9.3.I.0.1.b (E-134.b, 2026-05-16) — Text-Key + Ganz-Key.bv[k]direkt ohnewert.als_karte-Vorstufebv ?? <container>mit Liste/Karte-Default undbv ??= d(Assign-Coalesce) bleiben Reject mit konstruktiver Diagnose.→ seit 9.3.I.0.2 (E-134.c, 2026-05-16) — Call-Site-Inferenz mit Auto-Box am Boundary.beliebigals Funktions-Param oder Return
16.10.9 csv CSV-Parser + Serializer im kiste build-Pfad (seit 9.3.I.2)
Mit Phase 9.3.I.2 unterstützt der LLVM-Pfad CSV-Parsing und -Serialisierung als zweiten produktiven Konsumenten der 9.3.I.0-Foundation neben json. Buchhaltungs-Exporte, Excel-Roundtrips, Daten-Imports laufen nativ:
nutze csv
nutze wert
// Header-basierter Parse für tabellarische Daten
nimm text = "name,alter,stadt\nSascha,38,Berlin\nClaude,2,Wolke"
nimm rows = wert.als_liste(csv.karten(text))
// Zugriff auf jede Zeile als Karte
nimm row0 = wert.als_karte(rows[0])
sag(wert.als_text(row0["name"])) // "Sascha"
sag(wert.als_text(row0["alter"])) // "38" (Cell-Type ist immer text)
sag(wert.als_text(row0["stadt"])) // "Berlin"
// Fehlende Felder produzieren IVNichts — User prüft via ist_nichts
nimm vielleicht_email = row0["email"]
wenn wert.ist_nichts(vielleicht_email) {
sag("keine E-Mail im CSV")
}
// Rohformat parsen (jede Zeile als Liste von Cells)
nimm raw = csv.zeilen("a,b\n1,2\n3,4")
sag(raw)
// → [["a", "b"], ["1", "2"], ["3", "4"]]
// Roundtrip parse → encode
sag(csv.erzeugt_aus_karten(csv.karten(text)))
// → "name,alter,stadt\nSascha,38,Berlin\nClaude,2,Wolke\n"
Was im kiste build-Subset von 9.3.I.2 funktioniert:
- csv (4 Funktionen):
csv.zeilen(t)→beliebig(Form:liste<liste<text>>) — wirft bei Parse-Fehler oder ungleicher Cell-Count pro Zeile.csv.karten(t)→beliebig(Form:liste<karte<text,text>>) — wirft bei leerem Input oder duplizierten Header-Spaltennamen.csv.erzeugt(v)→text— Cells dürfen text/ganz/komma/dezimal/bool sein (Auto-Konversion in CSV-Text mirror TW).csv.erzeugt_aus_karten(v)→text— Header aus erster Karte (Insertion-Order). Wirft wenn weitere Karten andere Key-Sets haben.
Defaults (mirror TW):
- Trennzeichen:
,(Komma) - Kommentar-Zeichen: keines
- Behalte leere Zeilen: nein (
encoding/csvschluckt sie sowieso) - CRLF-Zeilenumbrüche: nein (LF-only)
Map-Reihenfolge bei csv.karten: Anders als json.geparst (alphabetisch sortiert) definiert hier die Header-Zeile die Spalten-Order. Alle Karten haben identische Insertion-Order = Header-Order. Cross-Backend byte-identisch.
Cell-Type: alle CSV-Zellen werden als IVText zurückgegeben (mirror TW — string-only). Auto-Detect von Ganz/Komma als Drift-Backlog. Beim Encode dagegen werden gemischte Cell-Types unterstützt: wert.ganz(42) → "42", wert.komma(3.5f) → "3.5", wert.bool(wahr) → "wahr".
Was seit 9.3.I.3.b zusätzlich funktioniert (Options-Karten als 2. Argument):
nutze csv
// Trennzeichen anpassen
nimm rows = csv.zeilen("a;b;c\n1;2;3", {"trenner": ";"})
// Kommentar-Zeilen ignorieren
nimm daten = csv.zeilen("# comment\nname,alter\nSascha,38", {"kommentar": "#"})
// CRLF-Zeilenumbrüche beim Encode
nimm csv_text = csv.erzeugt(rows, {"trenner": ";", "crlf_zeilenumbrüche": wahr})
// Tab-getrennte Werte
nimm tabs = csv.karten(t, {"trenner": "\t"})
Optionen (mirror TW):
- Lesen (
zeilen/karten):trenner(text, 1 Zeichen),kommentar(text/1-char odernichts),behalte_leere_zeilen(Bool — heute no-op, mirror TW). - Schreiben (
erzeugt/erzeugt_aus_karten):trenner(text, 1 Zeichen),crlf_zeilenumbrüche(Bool).
Heterogene Options-Karten funktionieren dank 9.3.I.3.a-Lift natürlich — gemischte Value-Typen (text + bool) in Karten-Literalen sind erlaubt. Auch eine reine {"trenner": ";"}-homogene Karte wird automatisch zu karte<beliebig> promotet am Call-Boundary (kein User-Workaround nötig).
Was im 9.3.I.3.b-Subset NOCH NICHT funktioniert:
- Direct-Compare / Direct-Coalesce / Direct-Index auf
beliebig— siehe §16.10.7 (gelift mit 9.3.I.0.1.a/b).
16.10.10 Regex-Gruppen + Datei-Details mit Karten-Werten (seit 9.3.I.4.a)
Mit Phase 9.3.I.4.a (E-132.a) lifted der LLVM-Pfad die letzten zwei regex-Funktionen + datei.einträge_mit_details — alle 10 TW-regex-Funktionen sind jetzt produktiv, und Verzeichnis-Listing mit Metadaten kommt nativ:
nutze regex
nutze wert
// regex.gruppen — `?liste<text>`-artige Semantik via TypBoxedValue
nimm g = regex.gruppen("(\\w+)=(\\d+)", "alter=38")
wenn nicht wert.ist_nichts(g) {
nimm parts = wert.als_liste(g)
sag(wert.als_text(parts[1])) // "alter"
sag(wert.als_text(parts[2])) // "38"
}
// No-Match liefert nichts
nimm leer = regex.gruppen("(\\d+)", "abc")
sag(wert.ist_nichts(leer)) // wahr
// regex.treffer_alle_gruppen — liste<liste<text>>, Direct-Index
nimm pairs = regex.treffer_alle_gruppen("(\\w+)=(\\d+)", "a=1 b=22")
sag(pairs[0][1]) // "a"
sag(pairs[1][2]) // "22"
sag(länge(pairs)) // 2
// Leere äußere Liste bei No-Match (NICHT nichts — mirror TW)
sag(regex.treffer_alle_gruppen("xyz", "abc")) // []
datei.einträge_mit_details listet ein Verzeichnis mit Metadaten pro Eintrag:
nutze datei
nutze wert
wiederhole eintrag in datei.einträge_mit_details("/tmp/projekt") {
sag(wert.als_text(eintrag["name"])) // text
sag(wert.als_bool(eintrag["ist_ordner"])) // wahr/falsch
sag(wert.als_ganz(eintrag["größe"])) // Bytes
sag(wert.als_ganz(eintrag["geändert_unix"])) // Sekunden seit 1970
}
Sortierung: alphabetisch nach name (deterministic, mirror TW).
Subset-Stand 9.3.I.4.a:
regex.gruppen(p, t)→beliebig(IVNichts bei No-Match, IVListe bei Match). Inner-Wrap via BoxedValue(IVText), nicht-matchende optionale Gruppen erscheinen als"".regex.treffer_alle_gruppen(p, t)→liste<liste<text>>(neuer Slot-TypeTypBoxedListListText). Direct-Indext[i][j]ohne Cast. Empty-Match: leere outer-Liste.datei.einträge_mit_details(pfad)→liste<karte<beliebig>>(neuer Slot-TypeTypBoxedListMapAny). Schlüssel:name(text),ist_ordner(Bool),größe(Ganz),geändert_unix(Ganz). Map-Indexliste[i]["k"]produktiv.
Was seit 9.3.I.0.1.a/b zusätzlich nativ ist:
- Direct-Compare
regex.gruppen(...) != nichtsohnewert.ist_nichts-Cast — seit 9.3.I.0.1.a. - Direct-Index
regex.gruppen(...)[0]ohnewert.als_liste-Vorstufe — seit 9.3.I.0.1.b.
16.10.11 Sub-Prozess-Output + IVBytes (seit 9.3.I.4.b)
Mit Phase 9.3.I.4.b (E-132.b) sind die letzten zwei prozess-Funktionen + ein neuer IVBytes-InnerTag für BoxedValue produktiv. Sub-Prozess-Aufrufe mit Zugriff auf stdout/stderr/exit_code laufen nativ:
nutze prozess
nutze wert
// Text-Variante: stdout/stderr sind text-Werte
nimm r = prozess.ausgeführt(["cmd", "/c", "echo", "hallo"])
sag(wert.als_text(r["stdout"])) // "hallo\n"
sag(wert.als_ganz(r["exit_code"])) // 0
// Non-zero exit-code wird in der Karte sichtbar — KEIN Throw (anders als ausgabe)
nimm r2 = prozess.ausgeführt(["cmd", "/c", "exit", "7"])
sag(wert.als_ganz(r2["exit_code"])) // 7
Für binäres Output (gzip, Bild-Konvertierung, custom-Protokolle) gibt es die _bytes-Variante:
nutze prozess
nutze wert
nutze bytes
nimm r = prozess.ausgeführt_bytes(["gzip", "-c", "/tmp/data.txt"])
nimm body = wert.als_bytes(r["stdout"]) // bytes-Handle, kein UTF-8-Decode
sag(länge(body)) // Byte-Count
sag(wert.als_ganz(r["exit_code"]))
Neuer IVBytes-InnerTag: wert.bytes(b) wraps einen bytes-Wert in einen BoxedValue. wert.als_bytes(v) peelt zurück. typ(v) returnt "bytes". sag(v) rendert byte-identisch zu sag(bytes-handle) (bytes(<hex>) mit 16-Byte-Cap + Truncation-Marker).
Subset-Stand 9.3.I.4.b:
prozess.ausgeführt(argv)→karte<beliebig>mit BoxedValue-Inner (IVText für stdout/stderr, IVGanz für exit_code).prozess.ausgeführt_bytes(argv)→ identische Karte, aberstdout/stderrsind BoxedValue(IVBytes).wert.bytes(b)+wert.als_bytes(v)neue Konstruktor + Cast.- IVBytes 9. InnerTag (8) im BoxedValue-System, voll integriert in Display/Tracer/Cast.
Was noch nicht funktioniert (Drift-Backlog 9.3.I.4.b):
- Options-Karte (
{arbeitsverzeichnis: ..., umgebung: ..., zeitlimit_ms: 5000}) als 2. Argument — Pattern aus 9.3.I.3.b/c wiederverwendbar, eigene künftige Mini-Sub-Phase.