JDL – Modulsystem und FFI¶
Status: Draft
Geltungsbereich: Sprachebene (keine VM-Implementierungsdetails)
Warum Dieses Dokument Existiert¶
Sobald aus Sprachfeatures echte Projekte werden, entstehen zwei Druckpunkte:
- Modulgrenzen müssen klar sein (Sichtbarkeit, Imports, API-Kontrolle).
- FFI muss sicher eingebettet werden, ohne das Effektsystem zu verwässern.
Dieses Dokument fixiert genau diese Übergänge.
0. Priorität¶
Ergänzt:
00-refinements.md01-grundlagen.md02-typsystem.md03-runtime.md
Bei Widerspruch gelten 00 bis 03.
1. Leitbild¶
- modulare Struktur über Dateipfade,
- klare Trennung zwischen
service(Vertrags-/Abstraktionsebene) undextern(FFI-Deklaration), - eine einzige Service-Zuordnungsform:
provide Service for Handler.
2. Modulsystem¶
2.1 Grundregeln¶
- Dateipfad bestimmt Modulname (
users/service.jdl->users::service). mod.jdlist optionales API-Root.- Sichtbarkeit folgt der Namespace-Spec: privat (default),
package,pub. - Zyklische Modulabhängigkeiten sind Compilerfehler.
2.2 Sichtbarkeit¶
// users/service.jdl
def validateEmail(email: str) -> bool { ... } // privat
package def normalizeEmail(email: str) -> str
pub def findUser(email: str) -> Result[User, UserError]
pub type User: struct { ... }
2.3 Importformen¶
import users::service
import users::service : User, findUser
import users::service : User as AppUser
Vollimport ist explizit, kein impliziter Wildcard-Trick.
2.4 mod.jdl als API-Schicht¶
// users/mod.jdl
pub import package::model : User, UserId
pub import package::service : findUser, registerUser
Damit kann öffentliche API bewusst geformt werden.
Module unter einem internal-Teilbaum folgen zusätzlich der Namespace-Spec und sind außerhalb des aktuellen Packages/Plugins nicht importierbar.
2.5 Lokale Imports¶
Erlaubt für lokale Lesbarkeit, aber kein Ersatz für explizite Service-Parameter
oder Effect[R, E, D]-Rückgabetypen.
3. Service vs. extern¶
3.1 Rollen¶
protocol: typbezogenes Verhalten,service: Vertrags-/Abstraktionsebene, die überprovide Service for Handleran konkrete Implementierungen gebunden wird,extern: rohe FFI-Bindings.
3.2 Harte Trennung¶
extern-Blöcke sind nie selbst Service-Abstraktionen,extern-Blöcke enthalten nurdef-Deklarationen,- Domänenlogik/Fehlermapping im Handler (
provide ... for ...), implementsexistiert nicht.
3.3 Verbindliche Zuordnung¶
Nicht zulässig:
provide HandlerType for ServiceNameextern X : implements Y
4. FFI-Modell¶
FFI wird in drei Ebenen getrennt. Das ist keine ästhetische Spielerei, sondern Überlebensschutz gegen C-Bibliotheken, die Ownership-Regeln gerne in Kommentaren verstecken und void* als Weltanschauung verwenden.
NativeLayer rohe ABI-/Symbolbeschreibung
BindingLayer Ownership, Marshaling, Error-Mapping, Callback-Regeln
ServiceLayer idiomatische JDL-Vertragsoberfläche
extern bleibt als kompakte Syntax erhalten, ist aber semantisch ein Native-/Binding-Blueprint, aus dem die FfiEngine Descriptoren erzeugt.
4.1 NativeLayer — rohe ABI-Beschreibung¶
type NativeLibrary : blueprint {
soname: str
abi: AbiKind
}
type NativeFunction : blueprint {
symbol: str
input: [NativeType]
output: NativeType
abi: AbiKind
}
Ein extern-Block ist syntaktischer Zucker für eine NativeLibrary mit mehreren NativeFunction-Einträgen:
extern LibSQLite {
def sqlite3_exec(db: OpaqueHandle, sql: CString, cb: Callback, userdata: OpaquePtr, err: Out[CString]) -> CInt
:> CSymbol("sqlite3_exec")
} :> FFILink("sqlite3")
Semantisch entsteht daraus ein NativeLibraryDescriptor mit FfiCallDescriptor-Einträgen.
4.2 BindingLayer — Ownership, Marshaling, Fehler¶
Der BindingLayer beschreibt, wie rohe ABI-Realität in Jade-Semantik überführt wird.
type NativeBinding : blueprint {
library: NativeLibrary
functions: [NativeFunction]
ownership: [OwnershipRule]
marshaling: [MarshalRule]
errors: [ErrorMapping]
callbacks: [CallbackRule]
}
Diese Ebene modelliert unter anderem:
out- undinout-Parameter,- nullable Pointer,
- borrowed/owned Handles,
- opaque Handles,
- errno und Return-Code-Fehler,
- Callback + userdata,
- Thread-Affinity,
- blockierende Calls,
- optionale oder versionierte Symbole,
- custom Allocator-Regeln.
4.3 ServiceLayer — idiomatische JDL-API¶
Services beschreiben den Vertrag, den User-Code sieht. Sie referenzieren keine nativen Symbole direkt.
service Db {
def query(sql: str) -> Result[RowSet, DbError]
}
type SqliteHandler: struct { db: DbHandle }
provide Db for SqliteHandler {
def query(self, sql: str) -> Result[RowSet, DbError] {
LibSQLite.sqlite3_exec(self.db, sql, Callback.none, OpaquePtr.null, Out.none)
|> Result.mapErr(DbError.from)
}
}
Die Service-Schicht ist die Effect-relevante Grenze. Ein Effect[R, E, D] referenziert D = Db, nicht LibSQLite.sqlite3_exec.
4.4 Ring-0-Bridge und Descriptoren¶
Die FfiEngine validiert NativeLayer und BindingLayer und erzeugt Descriptoren:
NativeLibraryDescriptor
FfiCallDescriptor
MarshalDescriptor
OwnershipDescriptor
ErrorMappingDescriptor
CallbackDescriptor
Die Ring-0-JadeValue-Bridge führt diese Descriptoren mechanisch aus: dlopen, dlsym, ABI-Call, Register-/JadeValue-Marshalling, Handle-Pinning, Trap-Grenzen. Sie entscheidet nicht, was ein SQLite-Fehler bedeutet oder wem ein Pointer gehört.
4.5 Syntaxkonsistenz¶
def innerhalb von extern-Blöcken, nicht fn.
4.6 FFI-Typsicherheit¶
Erlaubt:
- primitive Skalare,
ptr[T]nur an expliziten FFI-Grenzen,- opaque Handles,
- ABI-kompatible Struct/Enum-Repräsentationen,
- explizite Native-/Binding-Blueprints.
Nicht erlaubt:
- captured Closures,
- arena-gebundene Typen über falsche Grenzen,
- lokale Share-Typen über unzulässige Übergänge,
- unklare generische ABI-Signaturen,
- Effects die native Symbole direkt als Dependency exportieren.
5. Normative Invarianten¶
- Service-Zuordnung nur via
provide Service for Handler. implementsist kein Sprachbestandteil.extern-Blöcke sind keine Service-Abstraktionen und werden nicht direkt als Vertragsoberfläche verwendet.extern-Blöcke enthalten keine Domänenlogik.- FFI-Einstieg benutzt
definnerhalb vonextern-Blöcken. - Symbolbindung läuft über Refinements (
:> CSymbol(...)) oder überNativeFunction.symbol. - Library-Linkage läuft über
:> FFILink(...)auf demextern-Block oder überNativeLibrary.soname. externdesugared zu Native-/Binding-Blueprints und erzeugt FFI-Descriptoren.- Services sind die Effect-relevante Grenze; Effects referenzieren Services, nicht native Symbole.
- Die JadeValue Bridge bleibt Ring 0 und führt ausschließlich mechanisch aus.
6. Offene Punkte (Phase 2)¶
- Callback-Brücken,
- detaillierte ABI/Calling-Convention-Policies,
- formale
repr: C-Regeln, - Paketmanager-/Versionsauflösung außerhalb Sprachkern.