Funktionen (vertieft)

Funktionen sind der zentrale Baustein jedes Lyx-Programms. Diese Seite geht über die Grunddeklaration hinaus und behandelt Tupel-Rückgaben, anonyme Funktionen, Funktionstypen, Higher-Order Functions und den Pipe-Operator.

 
PrintF64 ist seit lyxc 1.0.17C ein Builtin (#1254, #1284) — kein Import nötig, auch nicht std.io. Es gibt sechs Nachkommastellen mit abschließendem Zeilenumbruch aus: PrintF64(1.25)1.250000. Die Ausgabe rundet sichtbar (3.141593.141589); für exakte Stellenzahl FloatToStr nehmen.

Ebenfalls in std.io: PrintFloatLn(x: f64) (mit Umbruch) und FloatToStr(val: f64, prec: int64) (Zeichenkette, etwa Print(FloatToStr(3.75, 2)) für Ausgabe ohne Umbruch).

→ Einführung: Erste Schritte · Syntax: Sprachsyntax · Methoden: OOP & Klassen · Generics: Generics & Interfaces


1. Grunddeklaration

fn Add(a: int64, b: int64): int64 {
    return a + b;
}

  • Rückgabetyp steht nach dem Doppelpunkt hinter der Parameterliste.
  • Kein Rückgabewert: Rückgabetyp weglassen (implizit void); return ohne Wert oder ganz weglassen.
  • pub macht eine Funktion aus anderen Units importierbar.

// Kein Rückgabewert
fn Log(msg: pchar) {
    PrintLn(msg);
}

// Öffentlich sichtbar (exportiert)
pub fn GetVersion(): pchar {
    return "1.0.0";
}

Alle Funktionen ohne pub sind privat — sie sind nur innerhalb derselben Unit sichtbar. Das ist die strenge Voreinstellung; explizites Exportieren verhindert unkontrollierte Kopplung zwischen Modulen.

Default-Werte für Parameter

Ein Parameter kann einen Vorgabewert erhalten. Wird das Argument beim Aufruf weggelassen, setzt der Compiler den Vorgabewert ein. Der Wert muss zur Compile-Zeit feststehen.

fn Verbinde(host: pchar, port: int64 = 8080, timeout: int64 = 30): int64 {
    // ...
    return 0;
}

Verbinde("localhost");            // port = 8080, timeout = 30
Verbinde("localhost", 9000);      // timeout = 30
Verbinde("localhost", 9000, 5);   // alle Werte explizit

Benannte Argumente erlauben eine freie Reihenfolge:

fn F(a: int64, b: int64 = 5): int64 { return a - b; }

F(b: 3, a: 10);   // 7 — Reihenfolge frei, weil benannt
F(10, b: 3);      // 7 — positional und benannt gemischt

 
Benannte Argumente und Vorgabewerte lassen sich seit lyxc 1.0.17C kombinieren (#1252). Ein hinterer Parameter kann einzeln gesetzt werden, der mittlere bleibt auf seiner Vorgabe:

fn G(a: int64, b: int64 = 2, c: int64 = 3): int64 { return a*100 + b*10 + c; }

G(1);             // 123 — rein positional, Vorgaben greifen
G(1, 5, 9);       // 159
G(1, c: 9);       // 129 — b bleibt auf 2
G(a: 1, c: 9);    // 129


Bis 1.0.16x verlangte jeder Aufruf mit benanntem Argument alle Parameter (Parameter ohne Argument im Aufruf von 'G').
 
Die Signaturprüfung greift auch über Unit-Grenzen (#1264, nachgemessen mit lyxc 1.2.2B): Clamp64(5) aus std.math bricht mit sema error: falsche Argument-Anzahl im Aufruf von 'Clamp64' ab. Frühere Fassungen prüften nur freie Funktionen aus derselben Datei.

Ungeprüft bleiben die Builtins: StrConcat("a") mit einem statt zwei Argumenten übersetzt weiterhin ohne Meldung — StrLen, StrSub, StrCharAt und die übrigen eingebauten Namen sind nicht Teil dieser Prüfung.

Struct-Parameter: Wert oder Referenz

Ein Struct-Parameter ist ein Wert. Die Funktion bekommt beim Eintritt eine Kopie; Änderungen daran bleiben in der Funktion. Das entspricht der Zuweisung, die seit 1.0.20A ebenfalls kopiert.

Wer das Original des Aufrufers ändern will, sagt das mit ref:

type Punkt = struct { x: int64; y: int64; }

fn AlsWert(p: Punkt): void    { p.x := 99; }   // wirkt nur auf die Kopie
fn AlsRef(ref p: Punkt): void { p.x := 99; }   // wirkt auf das Original

fn main(): int64 {
    var p: Punkt;
    p.x := 1;
    AlsWert(p);  PrintLn("nach AlsWert: ", IntToStr(p.x));
    AlsRef(p);   PrintLn("nach AlsRef:  ", IntToStr(p.x));
    return 0;
}

nach AlsWert: 1
nach AlsRef:  99

Fall Verhalten
fn f(p: T) mit Struct T Kopie — das Original bleibt unberührt
fn f(ref p: T) mit Struct T arbeitet auf dem Original
ref an einem Skalartyp Fehler: ref ist nur bei Struct-Parametern wirksam
Klassen immer Referenz; ref ist dort weder nötig noch vorgesehen

ref ist ein weiches Schlüsselwort: es gilt nur unmittelbar vor einem Parameternamen mit folgendem Doppelpunkt. Ein Parameter, der schlicht ref heißt (fn F(ref: int64)), und eine Variable var ref := 5 bleiben zulässig.

 
Bis 1.0.20E verhielt sich ein Struct-Parameter umgekehrt — die Funktion arbeitete auf dem Original, und wer seine Daten behalten wollte, musste vorher selbst kopieren. Code aus dieser Zeit braucht an den betreffenden Stellen jetzt ref, sonst verpufft die Änderung stillschweigend (#1351, #1528).

2. Tupel-Rückgabe — mehrere Werte

Funktionen können mehr als einen Wert zurückgeben, indem der Rückgabetyp als Tupel angegeben wird. Das ersetzt Out-Parameter und verhindert, dass Fehlerinformationen über Ausnahmen transportiert werden müssen.

Syntax

fn Divide(a: int64, b: int64): (int64, bool) {
    if (b == 0) { return (0, false); }
    return (a / b, true);
}

Rückgabetyp: (int64, bool) — ein Tupel aus zwei Typen.
Rückgabewert: (Ausdruck1, Ausdruck2) — beide Werte in runden Klammern, kommagetrennt.

Destrukturierung beim Aufruf

unit main;
import std.io;
import std.string;

fn Divide(a: int64, b: int64): (int64, bool) {
    if (b == 0) { return (0, false); }
    return (a / b, true);
}

fn main(): int64 {
    var result, ok := Divide(10, 3);
    if (ok) {
        PrintLn(IntToStr(result));  // 3
        PrintLn("");
    }

    // Kurzform ohne explizite Typangabe — Typen werden inferiert
    var q, ok2 := Divide(7, 0);
    if (ok2 == false) {
        PrintLn("Division durch null");
    }

    return 0;
}

Genau zwei Elemente

Ein Tupel trägt höchstens zwei Werte — die Aufrufkonvention gibt zwei Register her (rax, rdx). Drei Elemente werden abgewiesen:

fn Drei(): (int64, int64, int64) { return (1, 2, 3); }
// sema error: Tupel mit mehr als zwei Elementen

Für mehr Werte ein Struct zurückgeben — das ist ohnehin die lesbarere Form, weil die Felder benannt sind:

type Koordinate = struct {
    lat:   f64;
    lon:   f64;
    valid: bool;
};

fn ParseCoord(input: pchar): Koordinate {
    var k: Koordinate;
    k.lat := 48.137;
    k.lon := 11.576;
    k.valid := true;
    return k;
}

Beim Entpacken steht die Form ohne Klammern: var a, b := F();. Die geklammerte Schreibweise var (a, b) := F(); gibt es nicht.

Tupel-Rückgabe vs. struct

Situation Empfehlung
Zwei eng zusammengehörige Werte (Ergebnis + Fehlerflag) Tupel-Rückgabe
Drei oder mehr Werte Struct — Tupel tragen nur zwei
Rückgabe soll benannt und dokumentiert sein Struct — Feldnamen machen den Code lesbarer
Temporäres Ergebnis in einer Funktion Tupel — weniger Overhead als ein Typ zu definieren

3. Anonyme Funktionen

Lyx erlaubt Funktionsliterale — also Funktionen ohne Namen, die direkt als Ausdruck geschrieben werden. Sie folgen der gleichen Syntax wie benannte Funktionen, tragen aber keinen Bezeichner.

Syntax

fn(param1: Typ1, param2: Typ2): RückgabeTyp {
    return ...;
}

Inline als Argument

import std.io;

fn Apply(value: int64, transform: fn(int64): int64): int64 {
    return transform(value);
}

fn main(): int64 {
    var result: int64 := Apply(21, fn(x: int64): int64 {
        return x * 2;
    });
    PrintLn(IntToStr(result));  // 42
    PrintLn("");
    return 0;
}

Als Variable speichern

Eine anonyme Funktion kann mit let oder var gebunden werden:

unit main;
import std.io;
import std.string;

fn main(): int64 {
    let double: fn(int64): int64 := fn(x: int64): int64 {
        return x * 2;
    };

    let greet: fn(pchar): void := fn(name: pchar): void {
        PrintLn(StrConcat("Hallo, ", name));
    };

    PrintLn(IntToStr(double(21)));  // 42
    greet("Lyx");                   // Hallo, Lyx
    return 0;
}

 
Lambda an einem ausgeschriebenen fn-Typ arbeitet seit lyxc 1.0.17C (#1249). Apply(21, fn(x: int64): int64 { return x * 2; }) liefert 42 — vorher stürzte genau diese Verbindung ohne Meldung ab (SIGSEGV).

Anonyme Funktionen dürfen auch auf Modulebene stehen (#1589 behoben). let double: fn(int64): int64 := fn(x: int64): int64 { return x * 2; }; übersetzt außerhalb jeder Funktion und liefert mit 1.1.2E double(21) = 42; vorher meldete das codegen error: globale Variable 'double': Startwert ist zur Uebersetzungszeit nicht bekannt.

Ein Verweis auf eine benannte Funktion geht global ebenfalls — mit let, var und seit #1589 auch mit con. Globale Variablen vom Funktionstyp sind seit #1574 in beiden Formen benutzbar (mit und ohne Startwert).
Zum Erfassen der Umgebung: Anonyme Funktionen greifen auf Variablen des umgebenden Scope zu — anders als frühere Fassungen dieser Seite behaupteten. Der Wert wird dabei zum Definitionszeitpunkt übernommen; eine spätere Änderung wirkt nicht mehr:

var n: int64 := 100;
var f := fn(x: int64): int64 { return x + n; };
n := 1;
f(5);        // 105, nicht 6


Für Safety-kritischen Code (DO-178C, MISRA) bleibt die Empfehlung, Zustand ausdrücklich als Parameter zu übergeben — die versteckte Abhängigkeit besteht hier real, sie wird nur nicht verhindert.

4. Funktionstypen

Ein Funktionstyp beschreibt die Signatur einer Funktion — welche Parameter sie nimmt und welchen Typ sie zurückgibt. Mit type lässt sich ein benannter Alias für einen Funktionstyp anlegen.

Syntax

type TypName = fn(Param1Typ, Param2Typ): RückgabeTyp;

Beispiele

// Vergleichsfunktion für zwei int64-Werte — gibt Ordnung zurück
type Comparator = fn(a: int64, b: int64): int32;

// Transformationsfunktion: int64 → int64
type Transformer = fn(value: int64): int64;

// Ereignis-Handler ohne Rückgabewert
type EventHandler = fn(event_id: int32, data: int64): void;

 
Bruch seit 1.0.x — die Aufrufkonvention für fn-Zeiger (#1274). Betroffen ist nur, wer einen fn-Zeiger aus einer rohen Maschinencode-Adresse baut; wer Funktionen und Lambdas ganz normal übergibt, merkt nichts. Der Compiler meldet hier nichts, und alter Code übersetzt weiterhin.

Bis 0.9.x war ein fn-Zeiger ein Closure-Deskriptor: der Wert zeigte auf einen Zwei-Wort-Block ([fp+0] = Codeadresse, [fp+8] = Umgebung), der Aufruf übergab die Umgebung in rdi und schob die deklarierten Argumente nach rsi, rdx, …

Seither ist der Wert die Codeadresse, und die deklarierten Argumente folgen SysV unmittelbar:

var f: fn(int64,int64): int64 := adresse as fn(int64,int64): int64;
f(a, b);        // a landet in rdi, b in rsi


Handgeschriebener Maschinencode, der die Argumente noch aus rsi/rdx liest — Kontextwechsel, Scheduler-Primitive, Fences in LyxOS —, läuft nach dem Wechsel weiter und liest die falschen Register. Eine Compiler-Warnung an der as-Umwandlung gäbe es dafür nicht: sie träfe genau die legitime Schreibweise und sagte nichts darüber, welche Konvention der Zielcode erwartet.

Benannte Typen verbessern die Lesbarkeit von Parameterlisten erheblich:

// Ohne Alias — schwer zu lesen
fn Sort(arr: int64, n: int64, cmp: fn(int64, int64): int32): void { ... }

// Mit Alias — sofort klar
type Comparator = fn(a: int64, b: int64): int32;
fn Sort(arr: int64, n: int64, cmp: Comparator): void { ... }

Benannte Funktionen können überall dort übergeben werden, wo ein passender Funktionstyp erwartet wird — einfach durch Angabe des Namens ohne ():

unit main;
import std.io;
import std.string;

type Comparator = fn(a: int64, b: int64): int32;

fn CompareAsc(a: int64, b: int64): int32 {
    if (a < b) { return -1; }
    if (a > b) { return  1; }
    return 0;
}

fn CompareDesc(a: int64, b: int64): int32 {
    return CompareAsc(b, a);   // Reihenfolge getauscht
}

fn main(): int64 {
    var cmp: Comparator := CompareAsc;   // Funktion als Wert
    PrintLn(IntToStr(cmp(3, 7) as int64));  // -1

    cmp := CompareDesc;
    PrintLn(IntToStr(cmp(3, 7) as int64));  // 1

    return 0;
}


5. Higher-Order Functions

Eine Higher-Order Function (HOF) ist eine Funktion, die eine andere Funktion als Parameter entgegennimmt oder eine Funktion als Ergebnis zurückgibt.

Funktion als Parameter

Der Parameter wird mit dem Präfix fn und dem Funktionstyp deklariert:

fn paramName: fn(ArgTyp): RückgabeTyp

import std.io;

// Apply: wendet transform auf value an und gibt das Ergebnis zurück
fn Apply(value: int64, transform: fn(int64): int64): int64 {
    return transform(value);
}

// Für jeden Index in [0, n) callback aufrufen
fn ForEach(n: int64, callback: fn(int64): void): void {
    var i: int64 := 0;
    while (i < n) limit(1000000) {
        callback(i);
        i := i + 1;
    }
}

// Akkumuliert f(i) für alle i in [0, n)
fn Accumulate(n: int64, initial: int64, fold: fn(int64, int64): int64): int64 {
    var acc: int64 := initial;
    var i: int64 := 0;
    while (i < n) limit(1000000) {
        acc := fold(acc, i);
        i := i + 1;
    }
    return acc;
}

fn Square(x: int64): int64  { return x * x; }
fn PrintIdx(i: int64): void { Print(IntToStr(i)); Print(" "); }
fn Sum(acc: int64, val: int64): int64 { return acc + val; }

fn main(): int64 {
    PrintLn(IntToStr(Apply(7, Square)));  // 49
    PrintLn("");

    ForEach(5, PrintIdx);            // 0 1 2 3 4
    PrintLn("");

    PrintLn(IntToStr(Accumulate(5, 0, Sum)));  // 0+1+2+3+4 = 10
    PrintLn("");

    return 0;
}

HOF mit Generics

Funktionsparameter lassen sich mit Generics kombinieren:

fn MapApply<In, Out>(value: In, transform: fn(In): Out): Out {
    return transform(value);
}

fn main(): int64 {
    var doubled: int64 := MapApply<int64, int64>(21, fn(x: int64): int64 {
        return x * 2;
    });
    PrintLn(IntToStr(doubled));  // 42
    PrintLn("");
    return 0;
}

→ Ausführliche Generics-Syntax: Generics & Interfaces

Dispatch-Tabelle

Funktionstypen lassen sich in Arrays speichern — das ist das Lyx-Äquivalent einer vtable ohne Klassen:

type Handler = fn(data: int64): void;

fn OnConnect(data: int64): void    { Print("connect\n"); }
fn OnDisconnect(data: int64): void { Print("disconnect\n"); }
fn OnMessage(data: int64): void    { Print("message\n"); }

con CONNECT:    int64 := 0;
con DISCONNECT: int64 := 1;
con MESSAGE:    int64 := 2;

fn main(): int64 {
    var dispatch: [3]Handler := [OnConnect, OnDisconnect, OnMessage];

    var event: int64 := MESSAGE;
    if (event >= 0 & event < 3) {
        var h: Handler := dispatch[event];   // erst in eine Variable
        h(0);                                 // dann aufrufen  -> message
    }

    return 0;
}

 
Der Aufruf muss über eine Zwischenvariable gehen. dispatch[event](0) direkt ist ein Parse-Fehler: Aufruf ueber einen indizierten Ausdruck wird nicht unterstuetzt (#1505). Dasselbe gilt für Feldzugriffe. Der Wert wird also erst einer Variablen des Funktionstyps zugewiesen und diese dann aufgerufen — inhaltlich derselbe Sprung, nur eine Zeile mehr.

Funktionen an Threads übergeben

std.thread erwartet den Funktionszeiger als int64. Das ist die einzige Ausnahme von der typisierten Übergabe — es liegt an der C-POSIX-Schnittstelle unter der Haube:

import std.thread;
import std.io;

fn Worker(arg: int64): int64 {
    PrintLn("Thread läuft");
    return 0;
}

fn main(): int64 {
    var t: Thread := ThreadCreate(Worker as int64, 0);
    ThreadJoin(t);
    return 0;
}

→ Vollständige Thread-Dokumentation: Threads & Nebenläufigkeit


6. Pipe-Operator

Der Pipe-Operator |> leitet den Wert auf der linken Seite als erstes Argument an die Funktion auf der rechten Seite weiter. Er macht Transformationsketten ohne verschachtelte Klammern lesbar.

Syntax

wert |> Funktion()            // entspricht: Funktion(wert)
wert |> Funktion(?, arg)      // entspricht: Funktion(wert, arg)
wert |> Funktion(arg, ?)      // entspricht: Funktion(arg, wert)

Der Platzhalter ? benennt die Stelle, an die der gepipte Wert eingesetzt wird. Bei einer Funktion ohne weitere Argumente kann die Klammer leer bleiben.

 
Seit lyxc 1.0.17C setzt |> den Wert auch ohne Platzhalter ein (#1253): 50 |> Clamp(0, 30) liefert 30, der linke Wert wird erstes Argument. Der ausdrückliche Platzhalter 50 |> Clamp(?, 0, 30) bleibt gültig und ist die deutlichere Schreibweise, sobald der Wert nicht an die erste Stelle soll. Bis 1.0.16x scheiterte die Form ohne ? an der Argumentzahl.

Beispiel: Wert-Transformation

import std.math;
import std.io;

fn Clamp(val: f64, lo: f64, hi: f64): f64 {
    if (val < lo) { return lo; }
    if (val > hi) { return hi; }
    return val;
}

fn main(): int64 {
    // Ohne Pipe — schwer zu lesen bei tiefer Schachtelung
    var r1: f64 := RoundF64(Clamp(AbsF64(-3.7), 0.0, 3.0));

    // Mit Pipe — Datenfluss von links nach rechts
    var r2: f64 := -3.7 |> AbsF64() |> Clamp(?, 0.0, 3.0) |> RoundF64();

    PrintF64(r1);   // 3.7 → Abs → 3.7 → Clamp → 3.0 → Round → 3.0
    PrintLn("");
    PrintF64(r2);   // identisch
    PrintLn("");

    return 0;
}

Pipe mit HOF

fn Double(x: int64): int64  { return x * 2; }
fn Negate(x: int64): int64  { return -x; }
fn IsEven(x: int64): bool   { return x % 2 == 0; }

fn main(): int64 {
    var v: int64 := 5 |> Double() |> Negate();   // -10

    if (10 |> IsEven()) {
        PrintLn("gerade");
    }

    return 0;
}


7. Sichtbarkeit und Modifizierer

Modifizierer Position Bedeutung
pub Vor fn Exportiert die Funktion — aus anderen Units importierbar
@inline Vor fn Compiler soll die Funktion inline expandieren
@no_opt Vor fn Keine Optimierungen — für Benchmarks, MMIO-Debugging
@extern Vor fn Externe C-Funktion ohne Implementierung in Lyx
@variadic Zusätzlich zu @extern Variadische Argumentliste im C-Stil

// Exportierte Hilfsfunktion
pub fn Clamp(val: int64, lo: int64, hi: int64): int64 {
    if (val < lo) { return lo; }
    if (val > hi) { return hi; }
    return val;
}

// Einfache Funktionen inlinet der Codegen selbst; ein Attribut dafuer gibt es nicht
fn Abs(x: int64): int64 {
    if (x < 0) { return -x; }
    return x;
}

// Externe C-Funktion — extern fn mit link-Klausel, kein @extern-Attribut
extern fn strlen(s: pchar): int64 link "libc.so.6";

 
@inline, @noinline, @extern und @variadic sind keine Attribute dieser Sprache — der Compiler weist sie mit unbekanntes Attribut ab. Externe Funktionen werden mit extern fn … link „&lt;bibliothek&gt;“ deklariert (→ FFI); über das Inlining entscheidet der Codegen.

→ Alle Attribute: Attribute & Pragmas · FFI: C-Interoperabilität


8. Vollständiges Beispiel: Auswertungs-Pipeline

Das folgende Beispiel kombiniert Tupel-Rückgabe, Funktionstypen und Higher-Order Functions in einem realistischen Muster:

import std.io;
import std.math;

// Funktionstypen
type Validator = fn(value: f64): bool;
type Transform = fn(value: f64): f64;

// Gibt (transformierterWert, erfolgreich) zurück
fn Process(value: f64,
           validate: Validator,
           transform: Transform): (f64, bool) {
    if (validate(value) == false) { return (0.0, false); }
    return (transform(value), true);
}

// Konkrete Implementierungen
fn IsPositive(v: f64): bool { return fGt(v, 0.0); }
fn Normalize(v: f64): f64   { return fDiv(v, 100.0); }

fn main(): int64 {
    var inputs: [4]f64 := [42.0, -5.0, 150.0, 0.0];
    var i: int64 := 0;

    while (i < 4) limit(4) {
        var out, ok := Process(inputs[i], IsPositive, Normalize);
        if (ok) {
            Print("OK: "); PrintF64(out); Print("\n");
        } else {
            Print("UNGUELTIG: "); PrintF64(inputs[i]); Print("\n");
        }
        i := i + 1;
    }
    return 0;
}

Ausgabe:

OK: 0.420000
UNGUELTIG: -5.000000
OK: 1.500000
UNGUELTIG: 0.000000

 
Funktionsparameter tragen kein fn vor dem Namen. Frühere Fassungen zeigten fn validate: Validator — das ist ein Parse-Fehler (expected IDENT, got fn). Der Parametername steht wie bei jedem anderen Typ direkt vor dem Doppelpunkt: validate: Validator.

Zusammenfassung

Konzept Syntax Beispiel
Einfache Funktion fn Name(p: T): R { return …; } fn Add(a: int64, b: int64): int64
Kein Rückgabewert Rückgabetyp weglassen fn Log(msg: pchar)
Exportiert pub fn … pub fn GetVersion(): pchar
Tupel-Rückgabe : (T1, T2) fn Divide(…): (int64, bool)
Destrukturierung var a, b := Fn(…) var result, ok := Divide(10, 3)
Anonyme Funktion fn(p: T): R { return …; } direkt als Argument
Funktionstyp-Alias type F = fn(T): R type Comparator = fn(int64, int64): int32
HOF-Parameter name: fn(T): R fn Apply(v: int64, f: fn(int64): int64)
Pipe-Operator wert |> Fn(args) -3.7 |> Abs() |> Round()
Funktion als Wert Name ohne () var f: Comparator := CompareAsc

Letzte Aktualisierung: 2026-09-05 (#1264, nachgemessen mit lyxc 1.2.2B) — Kasten präzisiert: importierte Funktionen werden geprüft, Builtins nicht.

Vorherige letzte Aktualisierung: 2026-08-30 — Aufrufkonvention für fn-Zeiger ergänzt (#1274, Bruch gegenüber 0.9.x).

Vorherige Aktualisierung: 2026-08-09

Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).