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:
selfsteht nicht in der Keyword-Tabelle des Lexers, sondern wird im Parser gesondert behandelt — reserviert ist es dennoch.charsteht umgekehrt in der Keyword-Tabelle, lässt sich aber als Bezeichner verwenden: es ist ein Typname, kein reserviertes Wort.toist reserviert und fällt in der Praxis auf, sobald jemand ein Paarfrom/toals Parameternamen schreibt:fn f(to: int64)bricht mitParse error: expected IDENT, got reserved word 'to' ab.fromist frei — nurtonicht.
Nicht reserviert, auch wenn ältere Fassungen dieser Seite das behaupteten:flat,packed,check,limitundSelf. Alle fünf sind als Bezeichner verwendbar.
defaultist zwar reserviert, inmatchaber nicht verwendbar — der Wildcard-Fall lautetcase _ ⇒. Guards werden mitifgeschrieben (case p if cond ⇒), nicht mitwhen;whenist 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.14f32ist ungültig. Fürf32die 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.
Bei1.0e-30liegt das Ergebnis noch ein ULP unter dem exakten Wert. Für Toleranzrechnungen belanglos — wer Bitmuster vergleicht, prüft es mitFeqBitsaus 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“;ergibtpchar) und beinew(var p := new Point();). pubvor der Speicherklasse macht die Variable aus anderen Units sichtbar:pub var x: int64 := 0;letundcomü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.converlangt einen zur Compile-Zeit auswertbaren Ausdruck. Ein Funktionsaufruf wird abgelehnt (function call not allowed in const expression); die Ableitung aus anderencon-Werten ist erlaubt (con B: int64 := A * 2;). Eine Zuweisung anconmeldetassignment 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 |
isizeundusizestanden hier früher ebenfalls; der Compiler kennt sie nicht (unknown type in var decl). Für Indizes und Größenangabenint64bzw.uint64verwenden. Ebenso entfallen istqbool— 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 ausserhalbab.
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)meldetParse 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.2EParse 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 |
^ | Bitweises XOR (Infix) | a ^ 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 >> 2ergibt-4,-1 >> 1bleibt-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 inSwapEndian32.
* Die Schiebeweite wird modulo 64 genommen.1 << 64ergibt1,1 << 65ergibt2,1 << -1ergibt das Vorzeichenbit. Das entspricht dem Verhalten der Prozessorbefehle; eine Warnung gibt es nicht. Stammt die Weite aus einer Rechnung, ist sie vorher gegen0…63zu prüfen.
^ist ausschließlich XOR. Ältere Fassungen dieser Seite nannten zusätzlich einen Präfix-Gebrauch (^xals Adresse von x) und einen Postfix-Gebrauch (p^als Dereferenz). Beide gibt es nicht —^xergibtexpected expression, und einen Zeigertyp führt die Typgrammatik ohnehin nicht.6 ^ 3ergibt5.
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 | <<, » | Links |
| 5 | & | Links |
| 6 | ^ (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 alscase 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
returnwerden weggelassen (implizitvoid). - Mehrere Rückgabewerte: Tupel-Syntax
(Typ1, Typ2). - Öffentliche Sichtbarkeit:
pubvoranstellen.
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.lyx→unit my_module;).importmacht allepub-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
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 + 30 → Einheitentyp 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..360rechnet modulo 361 — beide Grenzen zählen mit, wie beirange. Wer den Vollkreis meint, schreibtwraps 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 |
