Module und Import-System

Jede Lyx-Quelldatei ist gleichzeitig ein Modul (in Lyx-Terminologie: eine Unit). Die Unit-Deklaration am Dateianfang legt den Namensraum fest. import lädt eine andere Unit und macht ihre öffentlichen Symbole sichtbar. pub steuert, welche Symbole exportiert werden.

Das System ist bewusst einfach: keine Pakete, keine Versionsverwaltung im Sprachkern, keine zyklischen Importe. Eine Unit = eine Datei = ein Namensraum.

Syntax-Referenz · Erste Schritte · Standard Library


1. Unit-Deklaration

Jede .lyx-Datei beginnt mit einer unit-Deklaration:

unit my_module;

Pflichtregeln:

  • Der Unit-Name muss exakt mit dem Dateinamen übereinstimmen (ohne .lyx-Endung)
  • Unterverzeichnisse werden durch Punkte getrennt: Datei net/http_client.lyxunit net.http_client;
  • Erlaubte Zeichen: Kleinbuchstaben, Ziffern, Unterstriche. Keine Großbuchstaben, keine Bindestriche.
  • Die unit-Zeile muss die erste Zeile der Datei sein (vor jedem Import, vor jedem Kommentar).

// Datei: sensors/temp_reader.lyx
unit sensors.temp_reader;

import std.io;
import std.math;


2. Import-Syntax

Imports folgen direkt auf die Unit-Deklaration, vor allen anderen Deklarationen:

unit my_app;

// Standardbibliothek
import std.io;
import std.string;
import std.net.socket;

// Eigene Units
import sensors.temp_reader;
import utils.math_helpers;

  • Die Import-Reihenfolge spielt keine Rolle für den Compiler.
  • Mehrere Imports der gleichen Unit sind erlaubt, aber redundant.
  • Zirkuläre Importe (A importiert B, B importiert A) sind nicht erlaubt und erzeugen einen Compiler-Fehler.
  • Eine Unit kann sich nicht selbst importieren.

Qualifizierte Namen

Nach dem Import sind alle pub-Symbole der Ziel-Unit direkt (unqualifiziert) sichtbar:

import std.string;

fn Greet(name: pchar): void {
    var upper: pchar := alloc(256);
    StrToUpper(upper, name);    // kein "string." Prefix nötig
    Print(upper);
}

Wenn zwei importierte Units dasselbe Symbol exportieren, entsteht eine Namenskollision. Der Compiler meldet das als Fehler. Lösung: Einen der Importe weglassen oder die Symbole umbenennen (derzeit kein Alias-Import).


3. Sichtbarkeit mit pub

Standardmäßig ist alles privat — nur innerhalb der eigenen Unit sichtbar. pub macht ein Symbol exportierbar:

Funktionen

unit math_utils;

// Öffentlich — von anderen Units importierbar
pub fn Square(x: int64): int64 {
    return x * x;
}

// Privat — nur innerhalb math_utils sichtbar
fn SquareInternal(x: int64): int64 {
    return x * x;
}

Konstanten

unit constants;

pub con PI:       f64   := 3.14159265358979;
pub con MAX_CONN: int64 := 1024;

con INTERNAL_BUF: int64 := 4096;   // privat

Variablen

unit config;

pub var LogLevel: int64 := 2;   // Von außen lesbar und schreibbar

var _internalState: int64 := 0; // Privat

Öffentliche Variablen (pub var) sind selten sinnvoll — sie erzeugen globalen Zustand der von jeder importierenden Unit verändert werden kann. Bevorzuge pub fn Get…() / pub fn Set…() Accessoren.

Typen, Enums, Structs, Klassen

unit geometry;

// Öffentlicher Typ — andere Units können Point verwenden
pub type Point = struct {
    x: f64;
    y: f64;
};

// Öffentliches Enum
pub enum Axis { X, Y, Z }

// Privater Hilfstyp — nur intern
type InternalMatrix = struct { data: int64; };


4. Namensraum und Kollisionen

Lyx hat keine explizite Namespace-Syntax — jede Unit ist ihr Namensraum. Nach dem Import sind alle pub-Symbole direkt im lokalen Scope sichtbar.

import std.db.sqlite;    // exportiert: SQLiteOpen, SQLiteClose, SQLITE_ROW, ...
import std.db.postgres;  // exportiert: PGConnect, PGClose, PGQuery, ...

// Kein Konflikt — unterschiedliche Präfixe per Konvention (SQLite* vs. PG*)
var db:   int64 := SQLiteOpen("/data/app.db");
var conn: int64 := PGConnect("localhost", 5432, "mydb", "user", "pass");

Die Standardbibliothek nutzt konsequent Unit-spezifische Präfixe als Konvention, um Kollisionen ohne Namespace-Qualifier zu vermeiden:

Unit Prefix-Konvention Beispiel
std.db.sqlite SQLite* SQLiteOpen, SQLITE_ROW
std.db.postgres PG* PGConnect, PGQuery
std.pdf.builder Pdf* PdfCreate, PdfSave
std.net.socket TCP* / UDP* / Socket* SocketTCPListen
std.string Str* / Char* StrFind, CharToUpper
std.crypto.aes AES* AESEncryptBlock

Eigene Units sollten dasselbe Muster verwenden — kurzer, eindeutiger Präfix vor allen öffentlichen Symbolen.


5. Standard Library importieren

Die Standardbibliothek liegt im std.-Namespace. Alle wichtigen Units:

// Basisfunktionalität
import std.io;          // Print, PrintLn, ReadLine, ...
import std.string;      // StrFind, StrReplace, StringBuilder, ...
import std.alloc;       // malloc, free_mem, ...
import std.math;        // Sin, Cos, Sqrt, Floor, ...
import std.result;      // Result<T, E>

// Netzwerk
import std.net.socket;  // TCP, UDP, Unix Sockets
import std.net.http;    // HTTP/1.1 Client
import std.net.dns;     // DNS-Auflösung

// Datenbanken
import std.db.sqlite;   // SQLite3
import std.db.postgres; // PostgreSQL
import std.db.redis;    // Redis

// PDF
import std.pdf;         // PDF erstellen (High-Level-Einstiegspunkt)

// Crypto
import std.crypto.aes;  // AES-Verschlüsselung
import std.hash;        // Hashing

// System
import std.fs;          // Dateisystem
import std.process;     // Prozessverwaltung
import std.thread;      // Threads
import std.time;        // Zeitfunktionen
import std.env;         // Kommandozeilenargumente

Alle verfügbaren Units: → Standard Library — vollständige Übersicht


6. Eigene Multi-Unit-Projekte strukturieren

Eine typische Projektstruktur mit mehreren Units:

my_project/
├── main.lyx               → unit main;
├── config.lyx             → unit config;
├── db/
│   ├── connection.lyx     → unit db.connection;
│   └── queries.lyx        → unit db.queries;
└── api/
    ├── handler.lyx        → unit api.handler;
    └── response.lyx       → unit api.response;

// db/connection.lyx
unit db.connection;

import std.db.postgres;

pub con DB_HOST: pchar := "localhost";
pub con DB_PORT: int64 := 5432;

pub fn Connect(dbName: pchar): int64 {
    var conn: int64 := PGConnect(DB_HOST, DB_PORT, dbName, "app", "secret");
    if (conn == 0 || PGIsConnected(conn) == 0) { return 0; }
    return conn;
}

// api/handler.lyx
unit api.handler;

import std.io;
import std.net.http;
import db.connection;    // eigene Unit — relativer Pfad

pub fn HandleGetUsers(conn: int64): void {
    // conn kommt aus db.connection.Connect(...)
    var res: int64 := PGQuery(conn, "SELECT id, name FROM users");
    // ...
}

// main.lyx
unit main;

import std.io;
import db.connection;
import api.handler;

pub fn main(): int64 {
    var conn: int64 := Connect("myapp");
    if (conn == 0) {
        PrintLn("Datenbankverbindung fehlgeschlagen");
        return 1;
    }
    HandleGetUsers(conn);
    PGClose(conn);
    return 0;
}


7. Suchpfad und Compilation

Der Compiler sucht Units in dieser Reihenfolge:

  1. Das Verzeichnis der aktuell compilierten Datei
  2. Alle Verzeichnisse in –include-path (lyxc –include-path=/my/libs …)
  3. Das Standard-Library-Verzeichnis (automatisch, std.*-Units)

# Einfacher Build
lyxc main.lyx -o my_app

# Mehrere Include-Pfade
lyxc main.lyx --include-path=./libs --include-path=/opt/lyx/contrib -o my_app

# Alle .lyx-Dateien angeben (bei kleinen Projekten)
lyxc main.lyx db/connection.lyx api/handler.lyx -o my_app


8. Best Practices

Empfehlungen für die Strukturierung von Lyx-Projekten:

Situation Empfehlung
Namenskollision zwischen Units Präfix-Konvention einhalten (MyUnit*)
Globaler Zustand Lieber pub fn Get() / pub fn Set() als pub var
Zyklische Abhängigkeit Unit aufteilen — gemeinsame Typen in eine separate types-Unit
Große Units (> 500 Zeilen) In Unterunits aufteilen: mylib.core, mylib.helpers, …
Init-Code beim Import Nicht in Unit-Scope — stattdessen pub fn Init() explizit aufrufen
Interne Hilfsfunktionen Privat lassen — nur was wirklich von außen gebraucht wird mit pub

Vollständige Syntax-Referenz
Erste Schritte — erstes Programm
Compiler-Parameter

Letzte Aktualisierung: 2026-06-05