Lyx – Syntax-Referenz

Diese Seite ist die vollständige Syntax-Referenz für Lyx. Sie beschreibt alle lexikalischen Regeln, Operatoren, Kontrollstrukturen und Deklarationsformen. Für konzeptuelle Erläuterungen und Code-Beispiele zu einzelnen Themen existieren eigene Unterseiten (verlinkt am Ende jedes Abschnitts).

1. Lexikalische Regeln

Kommentare

// Einzeiliger Kommentar – bis zum Zeilenende

/* Mehrzeiliger Kommentar
   Nicht verschachtelbar: /* kein weiterer /* */ hier */

Identifier

Bezeichner folgen dem Muster [A-Za-z_][A-Za-z0-9_]*. Lyx ist case-sensitive: MyVar, myVar und MYVAR sind drei verschiedene Bezeichner.

Gültig Ungültig
counter, _tmp, Vec2 2fast (beginnt mit Zahl)
MAX_SPEED, isReady my-var (Bindestrich)
x64, uart0 for (Schlüsselwort)

Schlüsselwörter

Reservierte Wörter, die nicht als Identifier verwendet werden dürfen:

abstract   and        array      as         assert
break      case       catch      class      co
con        continue   default    dim        dispose
do         downto     else       enum       extends
extern     false      finally    fn         for
if         implements import     in         interface
is         layout     let        Map        match
new        not        null       or         override
panic      parallel   pool       private    protected
pub        public     repeat     return     RingBuffer
self       Set        signal     static     struct
super      switch     throw      to         true
try        type       unit       until      utype
var        virtual    where      while      widget

Zwei Sonderfälle:

  • self steht nicht in der Keyword-Tabelle des Lexers, sondern wird im Parser gesondert behandelt — reserviert ist es dennoch.
  • char steht umgekehrt in der Keyword-Tabelle, lässt sich aber als Bezeichner verwenden: es ist ein Typname, kein reserviertes Wort.
  • to ist reserviert und fällt in der Praxis auf, sobald jemand ein Paar from/to als Parameternamen schreibt: fn f(to: int64) bricht mit Parse error: expected IDENT, got reserved word 'to' ab. from ist frei — nur to nicht.
Nicht reserviert, auch wenn ältere Fassungen dieser Seite das behaupteten: flat, packed, check, limit und Self. Alle fünf sind als Bezeichner verwendbar.
default ist zwar reserviert, in match aber nicht verwendbar — der Wildcard-Fall lautet case _ ⇒. Guards werden mit if geschrieben (case p if cond ⇒), nicht mit when; when ist kein Schlüsselwort.

Soft Keywords — als Bezeichner tokenisiert und nur im jeweiligen Kontext wirksam: range, wraps, defer, limit, grant, restrict, ref. limit wird nur unmittelbar hinter der Bedingung eines while und vor dem Block erkannt, gefolgt von (; überall sonst ist es ein gewöhnlicher Bezeichner.

Die Liste der 70 reservierten Wörter steht seit lyxc 1.1.3H auch in der normativen Grammatik (ebnf.md, Abschnitt 2.1) und wird dort von tests/schluesselwoerter_test.sh bei jedem Testlauf gegen den Compiler geprüft — jedes harte Wort muss abgewiesen, jedes weiche angenommen werden (#1653). Der Parser nennt seitdem auch den Anlass:

Parse error at line 1: expected IDENT, got reserved word 'unit'

ref gilt nur unmittelbar vor einem Parameternamen, auf den ein Doppelpunkt folgt. Überall sonst bleibt es ein gewöhnlicher Bezeichner — var ref := 5 und ein Parameter namens ref: int64 sind beide zulässig.

2. Literale

Integer-Literale

Format Beispiel Typ
Dezimal 42, -7 int64
Dezimal mit Ziffern-Trenner 1_000, 9_000_000_000 int64
Hexadezimal 0xFF, 0x3FF44000 int64
Binär 0b1010 int64
Oktal 0o755 int64
Typsuffixe gibt es nicht. Schreibweisen mit angehängtem Typkürzel (42+i8, 255+u8, 1000+i32) sind ein Syntaxfehler. Der Zieltyp wird über die Deklaration bestimmt: var b: uint8 := 255;

Float-Literale

Format Beispiel Typ
Dezimal 3.14, -0.5, 1.0 f64
Mit Ziffern-Trenner 3.14_159, 1_000.5 f64
Wissenschaftlich 1.0e-9, 1.0e9 f64
Auch hier kein Suffix: 3.14f32 ist ungültig. Für f32 die Deklaration nutzen — var x: f32 := 3.14;
 
Sehr kleine Literale werden korrekt übersetzt — mit 1.1.0A nachgemessen (#1569 behoben):

^ Literal ^ Bitmuster ^
| 1.0e-25 | 4233087679066701273 |
| 1.0e-27 | 4202930039008934928 |
| 1.0e-28 | 4188260752279232537 |

Ältere Fassungen dieser Seite beschrieben eine Grenze bei Exponent −28, ab der solche Literale stillschweigend zu null wurden. Die gibt es nicht mehr; der dort empfohlene Umweg über eine Division ist unnötig.

Bei 1.0e-30 liegt das Ergebnis noch ein ULP unter dem exakten Wert. Für Toleranzrechnungen belanglos — wer Bitmuster vergleicht, prüft es mit FeqBits aus std.feq.

Sonstige Literale

Typ Literal Anmerkung
bool true, false
char 'a', '\n' ASCII, ein Zeichen
pchar „Hallo\n“ Nullterminierter String, Typ pchar
null null Entspricht der Adresse 0

String-Escape-Sequenzen

Sequenz Bedeutung
\n Zeilenumbruch (LF)
\t Tabulator
\r Wagenrücklauf (CR)
\\ Backslash
\„ Anführungszeichen
\0 Null-Byte (String-Terminator)

3. Speicherklassen & Variablen

→ Ausführlich: Variablen — Startwerte, Typableitung, Gültigkeitsbereich, Modulebene, Lebensdauer. Speicher und Lebensdauer vertieft Memory Management.

Jede Variable in Lyx trägt eine explizite Speicherklasse. Die Klasse bestimmt Mutabilität und Lebenszeit.

Keyword Mutabilität Speicherort Beschreibung
var Veränderlich Stack / Data-Segment Standard-Variable; Wert kann jederzeit geändert werden
let Einmalig Stack / Data-Segment Wert wird einmalig zur Laufzeit gesetzt, danach read-only
co Read-only Stack Schreibgeschützter Stack-Slot; ähnlich wie let, aber ohne Heap-Zugriff
con Compile-Zeit Code (Immediate) Compile-Zeit-Konstante; wird direkt in den Maschinencode eingebettet

Syntax

var counter: int64 := 0;           // Typ explizit, Wert zugewiesen
var name := "Lyx";                 // Typ inferiert: pchar
let max_val: int64 := ReadConfig(); // Einmalige Zuweisung
co PI: f64 := 3.14159265358979;    // Stack-Konstante
con MAX_BUFFER := 4096;            // Compile-Zeit-Konstante (int64 inferiert)

  • Der Zuweisungsoperator ist immer :=.
  • Typangabe ist optional wenn der Typ aus dem Initialisierer eindeutig inferierbar ist — auch bei String-Literalen (var name := „Lyx“; ergibt pchar) und bei new (var p := new Point();).
  • pub vor der Speicherklasse macht die Variable aus anderen Units sichtbar: pub var x: int64 := 0;
  • let und co müssen bei der Deklaration belegt werden. Eine spätere Zuweisung ist keine „einmalige“ mehr, sondern wird abgewiesen: assignment to let/co binding not allowed. let x: int64; ohne Initialisierer übersetzt zwar, ergibt aber einen Slot, der nie einen Wert bekommen kann.
  • con verlangt einen zur Compile-Zeit auswertbaren Ausdruck. Ein Funktionsaufruf wird abgelehnt (function call not allowed in const expression); die Ableitung aus anderen con-Werten ist erlaubt (con B: int64 := A * 2;). Eine Zuweisung an con meldet assignment to con constant not allowed.

4. Typsystem

Primitive Typen

Typ Bits Wertebereich
int8 8 −128 … 127
int16 16 −32 768 … 32 767
int32 32 −2 147 483 648 … 2 147 483 647
int64 / int 64 −9 223 372 036 854 775 808 … 9 223 372 036 854 775 807
uint8 8 0 … 255
uint16 16 0 … 65 535
uint32 32 0 … 4 294 967 295
uint64 64 0 … 18 446 744 073 709 551 615
f32 32 IEEE 754 Single
f64 64 IEEE 754 Double
bool 1 (8 im Speicher) true, false
char 8 Ein ASCII-Zeichen
pchar 64 (Pointer) Nullterminierter String (char*)
void Kein Rückgabewert
isize und usize standen hier früher ebenfalls; der Compiler kennt sie nicht (unknown type in var decl). Für Indizes und Größenangaben int64 bzw. uint64 verwenden. Ebenso entfallen ist qbool — der Typ existiert nicht.

Pointer

Lyx hat keinen Pointer-Typ in der Typgrammatik. Es gibt weder ^T als Typangabe noch einen Address-of-Operator (^x bzw. &x) oder einen Dereferenz-Operator (p^). Adressen werden als int64 geführt, der Zugriff läuft über Builtins:

var cell: int64 := alloc(8);   // 8 Byte anfordern
poke64(cell, 42);              // schreiben
var v: int64 := peek64(cell);  // lesen
free(cell, 8);

Builtin Bedeutung
alloc(n) / free(p, n) Speicher anfordern / freigeben — die Größe ist bei free Pflicht
peek8/16/32/64(p) Wert an Adresse lesen
poke8/16/32/64(p, v) Wert an Adresse schreiben

Ein Ausgabeparameter wird als Zelle übergeben: alloc(8), Adresse an die Funktion, danach peek64.

Nullable Typen

Das ?-Suffix markiert einen Typ als nullable — er darf zusätzlich null annehmen:

var x: int64? := null;
var name: pchar? := null;

Für den Zugriff auf möglicherweise nicht gesetzte Werte gibt es den Safe-Access-Operator ?. — er liefert den Feldwert, ohne bei null zu dereferenzieren:

var a: A := new A();
a.v := 3;
var x: int64 := a?.v;   // 3

Range-Typen

type Altitude = int64 range -1000..60000;
type Speed    = int64 range 0..300;

Die Grenzen werden auf zwei Ebenen durchgesetzt:

  • Compile-Zeit — steht der Wert bereits beim Übersetzen fest (Literal, con, konstanter Ausdruck), meldet der Compiler einen Fehler: Wert liegt ausserhalb des Bereichs des Typs.
  • Laufzeit — bei berechneten Werten prüft der erzeugte Code beim Zuweisen und bricht mit Bereichstyp <Name>: Wert ausserhalb ab.

Die Laufzeitprüfung greift überall dort, wo ein Wert den Bereichstyp annimmt — bei Zuweisung, als Parameter, als Rückgabewert und beim Schreiben in ein Strukturfeld:

type Alt = int64 range 0..100;

fn Setze(a: Alt): int64 { return a; }
fn Hole(): Alt { var x: int64 := 500; return x; }   // bricht ab

type S = struct { a: Alt; };

fn main(): int64 {
    var x: int64 := 500;
    var a: Alt := x;      // bricht ab
    Setze(x);             // bricht ab
    var s: S;
    s.a := x;             // bricht ab
    return 0;
}

5. Operatoren

Arithmetik

Operator Operation Beispiel
+ Addition a + b
- Subtraktion / Negation a - b, -x
* Multiplikation a * b
/ Division (ganzzahlig bei int) a / b
% Modulo (Rest) a % b
++ Inkrement (postfix) i++
Dekrement (postfix) i–

Vergleich

Operator Bedeutung
== Gleich
!= Ungleich
< Kleiner als
> Größer als
Kleiner oder gleich
>= Größer oder gleich
in Bereichsprüfung: x in 1..10 — beide Grenzen zählen mit
 
Wichtig: Der Vergleichsoperator ist ==, der Zuweisungsoperator :=. In einer Bedingung wird ein einzelnes = abgewiesen — if (x = 0) meldet Parse error at line N: expected ), got = '='. Damit ist die in C klassische versehentliche Zuweisung in einer Bedingung strukturell ausgeschlossen.

Auch als eigenständige Anweisung wird = abgewiesen (#1575 behoben). x = 42; meldet mit 1.1.2E Parse error at line N: `=` ist kein Zuweisungsoperator — gemeint ist `:=`. Ein = im Code ist damit nur noch ein Parametervorgabewert.

Logisch & Bitweise

Operator Bedeutung Anwendung
&& Logisches AND mit Kurzschluss Bedingungen; rechte Seite nur bei wahrer linker
|| Logisches OR mit Kurzschluss Bedingungen; rechte Seite nur bei falscher linker
& Logisches / Bitweises AND bool-Ausdrücke und Integer-Maskierung; wertet immer beide Seiten
| Logisches / Bitweises OR bool-Ausdrücke und Integer-Flags; wertet immer beide Seiten
! Logisches NOT Nur auf bool
~ Bitweises NOT (Komplement) Nur auf Integer
&#94; Bitweises XOR (Infix) a &#94; b
|~ Bitweises NOR 12 |~ 10 = -15 — gleichbedeutend mit ~(12 | 10)
« Bitshift links 1 « 3 = 8
» Bitshift rechts, arithmetisch 0x80 » 4 = 8; -16 » 2 = -4
 
Zwei Eigenheiten beim Schieben.

* >> zieht das Vorzeichenbit nach. -16 >> 2 ergibt -4, -1 >> 1 bleibt -1. Ein logisches Rechtsschieben, bei dem Nullen nachrücken, erhält man über die Umdeutung: (wert as uint64) >> n. Die Standardbibliothek nutzt genau diese Form, etwa in SwapEndian32.
* Die Schiebeweite wird modulo 64 genommen. 1 &lt;&lt; 64 ergibt 1, 1 &lt;&lt; 65 ergibt 2, 1 &lt;&lt; -1 ergibt das Vorzeichenbit. Das entspricht dem Verhalten der Prozessorbefehle; eine Warnung gibt es nicht. Stammt die Weite aus einer Rechnung, ist sie vorher gegen 0…63 zu prüfen.
 
^ ist ausschließlich XOR. Ältere Fassungen dieser Seite nannten zusätzlich einen Präfix-Gebrauch (^x als Adresse von x) und einen Postfix-Gebrauch (p^ als Dereferenz). Beide gibt es nicht — ^x ergibt expected expression, und einen Zeigertyp führt die Typgrammatik ohnehin nicht. 6 ^ 3 ergibt 5.

Spezialoperatoren

Operator Name Beschreibung Beispiel
:= Zuweisung Weist einen Wert zu x := 42
|> Pipe Ergebnis links als erstes Argument rechts val |> Abs()
?. Safe Call Memberzugriff nur wenn nicht null node?.Next
?? Null-Coalesce Fallback wenn null name ?? „Gast“
as Cast Explizite Typkonvertierung x as f64
is Typ-Test Prüft Laufzeit-Typ obj is Circle
.. Bereich In match-Mustern und Range-Typen 100..199

Operator-Präzedenz (absteigend)

Priorität Operatoren Assoziativität
1 (höchste) Unär: !, ~, - Rechts
2 *, /, % Links
3 +, - Links
4 &lt;&lt;, » Links
5 & Links
6 &#94; (XOR) Links
7 | Links
8 =, !=, <, >, , >= Nicht-assoziativ
9 as, is Links
10 ?. Links
11 ?? Rechts
12 |> Links
13 (niedrigste) := Rechts

6. Kontrollfluss

if / else

if (Bedingung) {
    // ...
} else if (andere_Bedingung) {
    // ...
} else {
    // ...
}

if ist kein Ausdruck – es gibt keinen ternären Operator ?:. Bedingte Werte werden über match oder Hilfsfunktionen ausgedrückt.

while

while (Bedingung) {
    // ...
}

// Bounded – garantierte Terminierung
while (Bedingung) limit(Konstante) {
    // ...
}

for

// Aufwärts (inklusive Grenzen)
for i := Startwert to Endwert do {
    // i läuft von Startwert bis einschließlich Endwert
}

// Abwärts
for i := Endwert downto Startwert do {
    // i läuft von Endwert bis einschließlich Startwert
}

// C-Stil — ohne Klammern, ohne var
for i := 0; i < n; i++ {
    // ...
}

// Bereichsform (seit 1.0.14), beide Grenzen einschließend
for i in 0..3 {
    // i läuft 0, 1, 2, 3
}

for … in erwartet einen Bereich, keine Sammlung — for v in a über ein Array wird mit for … in erwartet einen Bereich abgewiesen.

Die Laufvariable wird automatisch inkrementiert / dekrementiert. Ihr Typ wird vom Compiler inferiert. for-Schleifen sind immer bounded – kein limit erforderlich.

repeat-until

repeat {
    // Körper wird mindestens einmal ausgeführt
} until (Abbruchbedingung);

// Mit Bounded-Limit
repeat {
    // ...
} until (Bedingung) limit(Konstante);

break & continue

while (true) {
    if (DoneCondition()) { break; }    // verlässt die innerste Schleife
    if (SkipCondition()) { continue; } // springt zum nächsten Durchlauf
}

break und continue wirken immer auf die innerste umgebende Schleife.

match

match (Ausdruck) {
    case Wert       => Anweisung;
    case A | B      => Anweisung;      // OR-Muster
    case X if (Guard) => Anweisung;  // mit Guard-Bedingung
    case _          => Anweisung;
}

Bereichsmuster werden als case lo..hi ⇒ geschrieben; beide Grenzen zählen mit. Die obere Grenze darf entfallen (case lo.. ⇒).

match kann als Ausdruck verwendet werden (Ergebnis einer Case-Arm-Anweisung). Alle Fälle müssen abgedeckt sein (Exhaustivität). Details: Pattern Matching.

7. Funktionen

Deklaration

fn FunktionsName(param1: Typ1, param2: Typ2): RückgabeTyp {
    // Körper
    return Wert;
}

  • Kein Rückgabewert: Rückgabetyp und return werden weggelassen (implizit void).
  • Mehrere Rückgabewerte: Tupel-Syntax (Typ1, Typ2).
  • Öffentliche Sichtbarkeit: pub voranstellen.

Beispiele

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

// Keine Rückgabe (void)
fn Log(msg: pchar) {
    Print(msg);
}

// Tupel-Rückgabe (mehrere Werte)
fn Divide(a: int64, b: int64): (int64, bool) {
    if (b == 0) { return (0, false); }
    return (a / b, true);
}

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

Aufruf

var result := Add(3, 4);

var quotient, ok := Divide(10, 3);
if (ok) { Print(IntToStr(quotient)); }

// Pipe-Operator: Wert als erstes Argument
var v := -3.14 |> Abs() |> Round();

Funktionen (vertieft) — Tupel-Rückgabe, anonyme Funktionen, Higher-Order Functions, Pipe-Operator

8. Units & Imports

Jede Lyx-Quelldatei beginnt mit einer unit-Deklaration. Sie definiert den Namensraum der Datei.

unit my_module;

import std.io;
import std.math;
import my_project.utils;

  • unit-Name und Dateiname müssen übereinstimmen (my_module.lyxunit my_module;).
  • import macht alle pub-Symbole der Ziel-Unit sichtbar.
  • Standard-Bibliothek: std.io, std.math, std.string, std.alloc, std.result, std.error, …

9. Typdefinitionen

struct

Stack-allozierte Wertetypen. Zuweisung kopiert den gesamten Wert.

type Vec2 = struct {
    x: f64;
    y: f64;

    fn Length(): f64 {
        return Sqrt(self.x * self.x + self.y * self.y);
    }

    fn Scale(factor: f64) {
        self.x := self.x * factor;
        self.y := self.y * factor;
    }
};

class

Heap-allozierte Referenztypen. new erzeugt, dispose gibt frei.

type Animal = class {
    name: pchar;

    fn Create(n: pchar) {
        self.name := n;
    }

    fn Destroy() {
        // Aufräum-Logik
    }

    virtual fn Speak() {
        Print(self.name);
    }
};

type Dog = class extends Animal {
    override fn Speak() {
        Print("Wuff!");
    }
};

var d := new Dog("Bello");
d.Speak();    // "Wuff!"
dispose d;

Schlüsselwörter für Klassen:

Keyword Bedeutung
extends Einfachvererbung
virtual fn Überschreibbare Methode (V-Table-Eintrag)
override fn Überschreibt eine virtuelle Methode
abstract fn Muss in abgeleiteten Klassen implementiert werden
super.Methode() Aufruf der Eltern-Implementierung
self Referenz auf das aktuelle Objekt
new T(args) Heap-Allokation
dispose ptr Heap-Freigabe

enum

enum Richtung { Nord, Sued, Ost, West }

enum StatusCode {
    Ok     = 200,
    NotFound = 404,
    Error  = 500
}

// Zugriff über ::
var d := Richtung.Nord;
var s := StatusCode.Ok;

match über Enums prüft Exhaustivität: Fehlt ein Fall, erzeugt der Compiler einen Fehler.

interface & implements

type Druckbar = interface {
    fn Zeige(): int64;
};

type Punkt = class implements Druckbar {
    x: int64;
    y: int64;
    fn Zeige(): int64 { return self.x + self.y; }
};

Fehlt eine der Signaturen in der Klasse, meldet der Compiler class missing interface method. trait und impl gibt es nicht.

Generics mit Trait-Schranken:

fn PrintAll<T: Printable>(items: [16]T) {
    for i := 0 to 15 do {
        items[i].Print();
    }
}

Einheitentypen — dim und utype

dim benennt eine physikalische Dimension, utype eine Einheit darin, zusammen mit ihrem Faktor bezogen auf die Basiseinheit. Dimensionen lassen sich aus anderen ableiten:

dim Laenge;
dim Zeit;
dim Geschwindigkeit = Laenge / Zeit;    // * und / sind erlaubt

utype Meter:          Laenge          = 1;
utype Kilometer:      Laenge          = 1000;
utype MeterProSekunde: Geschwindigkeit = 1.0;   // Faktor auch als Float

fn main(): int64 {
    var strecke: Kilometer := 2;
    PrintLn(IntToStr(strecke as int64));
    return 0;
}

Die Standardbibliothek bringt mit std.units rund 40 fertige Einheiten mit.

Was Einheitentypen leisten

Die Dimensionsprüfung greift: Eine Länge lässt sich weder einer Zeit zuweisen noch mit ihr verrechnen.

var m: Meter := 5;
var s: Sekunde := m;        // sema error: Zuweisung ueber Dimensionsgrenzen hinweg
var x: Meter := m + s;      // sema error: Einheitentypen verschiedener Dimension verrechnet

 
Umrechnung, Vergleich und abgeleitete Dimensionen greifen — nachgemessen nach #1956, #1955 und #1964:

var a: Meter     := 500;
var b: Kilometer := 1;

var summe: Meter := a + b;   // 1500 — der Faktor wirkt
if (a > b) { }               // falsch — 500 m sind weniger als 1 km
var c: Meter := b;           // 1000

Auch die abgeleitete Dimension wird geprüft: aus dim Tempo = Laenge / Zeit; folgt, dass meter / sekunde ein Tempo ist — die Zuweisung an eine Länge wird mit Zuweisung ueber Dimensionsgrenzen hinweg abgewiesen. Ein as-Cast über Dimensionsgrenzen ebenfalls; die Meldung verweist auf as f64, wenn nur der Zahlenwert gemeint ist.

Was weiterhin nicht geht: ein Einheitentyp mit einer nackten Zahl verrechnet (b + 30Einheitentyp mit dimensionsloser Zahl verrechnet). Die Zahl braucht denselben Typ.

 
wraps rechnet zuverlässig (#2004 behoben, nachgemessen 2026-09-08). Der Bereich 0..360 umfasst 361 Werte, gewrappt wird darüber hinaus:

359 -> 359     361 -> 0     362 -> 1     370 -> 9     720 -> 359

Konstanten und Laufzeitwerte liefern jetzt dasselbe. Zuvor kam bei Laufzeitwerten ein f64-Bitmuster heraus.

Die Modifikatoren range und wraps begrenzen den Wertebereich. range bricht bei Überschreitung ab, wraps rechnet zyklisch:

utype Grad:    Winkel = 1 range 0..360;   // 400 -> Abbruch "unit value out of range"
utype GradW:   Winkel = 1 wraps 0..360;   // 370 -> 9

range greift zweimal: steht der Wert schon beim Übersetzen fest, meldet der Compiler Wert liegt ausserhalb der Grenzen des Einheitentyps; kommt er erst zur Laufzeit, bricht das Programm mit unit value out of range und Rückgabecode 1 ab.

Eine nackte int64-Zahl lässt sich einem Einheitentyp ohne Cast zuweisen (var m: Meter := raw;) — im Gegensatz zum Verrechnen, das abgewiesen wird.

Der Umrechnungsfaktor wirkt bei der Zuweisung zwischen Einheiten derselben Dimension: 3 Meter, einer Millimeter-Variablen zugewiesen, ergeben 3000. Nur dort — siehe den Kasten oben.

Seit lyxc 1.0.15C wirken auch Float-Faktoren: Der Compiler führt sie als gekürzten Bruch (1000.0 → 1000/1, 0.017453 → 17453/1000000). Ein Faktor, den er nicht vollständig liest, wird gemeldet statt still als 1 gerechnet. Ebenfalls seit 1.0.15C wird pub an dim und utype exportiert — std.units ist damit importierbar.

 
Die ganzzahlige Umrechnung schneidet ab. In die gröbere Einheit geht Genauigkeit verloren, ohne Hinweis: 2500 Meter werden zu 2 Kilometern, 500 Meter zu 0. In die feinere Einheit ist die Umrechnung verlustfrei.

wraps 0..360 rechnet modulo 361 — beide Grenzen zählen mit, wie bei range. Wer den Vollkreis meint, schreibt wraps 0..359.

10. Generics

// Generische Funktion
fn Max<T: Comparable>(a: T, b: T): T {
    if (a > b) { return a; }
    return b;
}

// Generischer Struct
type Stack<T> = struct {
    data: [64]T;
    top:  int64;

    fn Push(val: T) {
        self.data[self.top] := val;
        self.top++;
    }

    fn Pop(): T {
        self.top--;
        return self.data[self.top];
    }
};

// Mehrere Schranken mit +
fn Process<T: Printable + Comparable>(val: T) {
    val.Print();
}

11. Attribute & Pragmas

Attribute beginnen mit @ und stehen unmittelbar vor dem annotierten Element (Unit, Funktion, Variable).

Sicherheit & Zertifizierung

Attribut Ziel Beschreibung
@flight_crit Unit, Fn Strikte Luftfahrt-Regeln: kein Heap, keine unsafe-Blöcke