JadeResult — Bootstrap-Compiler Ergebnistyp¶
Status: Normativ
Version: 0.1.0
Scope: Bootstrap-Compiler (D), alle Compiler-Subsysteme
Abhängigkeiten: jade-compiler-db-spec.md, jade-design-decisions.md
1. Motivation¶
Der Bootstrap-Compiler braucht einen einheitlichen Ergebnistyp der drei fundamentale Zustände ausdrückt:
| Zustand | Bedeutung |
|---|---|
Ok(T) |
Query/Operation erfolgreich, Wert vorhanden |
Err(Diagnostic) |
Fehler mit strukturierter Beschreibung |
Empty |
Korrekt ausgeführt, aber kein Wert vorhanden — kein Fehler |
Empty ist kein Fehler. Es bedeutet "nicht gefunden" oder "nicht vorhanden" —
zum Beispiel eine GetDocComment-Query auf eine Funktion ohne Dokumentation.
Warum kein generisches Result!(T, E):
Im Bootstrap-Compiler ist E immer Diagnostic. Ein generischer Fehlertyp
erzeugt nur Template-Komplexität ohne Nutzen.
Warum kein separates Option(T):
Empty macht Option überflüssig. Alle drei Zustände laufen durch JadeResult(T).
Warum kein std.sumtype:
alias-basierte SumType-Wrapper verlieren ihre Typidentität — UFCS-Methoden
werden nicht gefunden. Ein eigenes struct gibt volle Kontrolle über Ergonomie.
2. Implementierung¶
// jade/types.d
enum JadeResultTag { Ok, Err, Empty }
struct JadeResult(T) {
private JadeResultTag _tag;
private union {
T _value;
Diagnostic _diag;
}
// --- Konstruktion ---
static JadeResult ok(T value) @nogc nothrow {
JadeResult r;
r._tag = JadeResultTag.Ok;
r._value = value;
return r;
}
static JadeResult err(Diagnostic d) @nogc nothrow {
JadeResult r;
r._tag = JadeResultTag.Err;
r._diag = d;
return r;
}
static JadeResult empty() @nogc nothrow {
JadeResult r;
r._tag = JadeResultTag.Empty;
return r;
}
// --- Abfrage ---
bool isOk() @nogc nothrow { return _tag == JadeResultTag.Ok; }
bool isErr() @nogc nothrow { return _tag == JadeResultTag.Err; }
bool isEmpty() @nogc nothrow { return _tag == JadeResultTag.Empty; }
T value() @nogc nothrow { assert(isOk()); return _value; }
Diagnostic diag() @nogc nothrow { assert(isErr()); return _diag; }
T valueOr(T defaultValue) @nogc nothrow {
return isOk() ? _value : defaultValue;
}
// --- Exhaustive Match ---
auto match(alias onOk, alias onErr, alias onEmpty)() @nogc nothrow {
final switch (_tag) {
case JadeResultTag.Ok: return onOk(_value);
case JadeResultTag.Err: return onErr(_diag);
case JadeResultTag.Empty: return onEmpty();
}
}
}
3. Verwendung¶
Konstruktion¶
// Erfolg
JadeResult!TypeNode r = JadeResult!TypeNode.ok(node);
// Fehler
JadeResult!TypeNode s = JadeResult!TypeNode.err(Diagnostic {
phase: Phase.TypeEngine,
severity: Severity.Error,
message: "Type not found: Foo",
span: sourceSpan
});
// Leer — korrekt aber kein Wert
JadeResult!DocNode t = JadeResult!DocNode.empty();
Exhaustive Match — final switch erzwingt alle Fälle¶
r.match!(
(TypeNode node) => writeln("Ok: ", node.name),
(Diagnostic d) => writeln("Err: ", d.message),
() => writeln("Kein Wert")
);
Einfache Abfragen¶
if (r.isOk()) auto node = r.value();
if (r.isErr()) auto d = r.diag();
if (r.isEmpty()) // nicht gefunden, kein Fehler
auto node = r.valueOr(TypeNode.unknown);
In Handler-Funktionen¶
@handles!ResolveType
JadeResult!TypeNode resolveType(ResolveType q, CompilerDb* db) @nogc nothrow pure {
if (!found) return JadeResult!TypeNode.err(Diagnostic {
phase: Phase.TypeEngine,
severity: Severity.Error,
message: "Type not found: " ~ symbolName,
span: sourceSpan
});
return JadeResult!TypeNode.ok(node);
}
@handles!GetDocComment
JadeResult!DocNode getDocComment(GetDocComment q, CompilerDb* db) @nogc nothrow pure {
if (!hasComment) return JadeResult!DocNode.empty(); // kein Fehler — einfach nicht vorhanden
return JadeResult!DocNode.ok(docNode);
}
4. Abgrenzung zu JDL-Typen¶
JadeResult(T) ist ein D-Typ für den Bootstrap-Compiler — kein JDL-Typ.
In JDL selbst existieren Result[T, E] und Option[T] als Stdlib-Typen
unverändert weiter. JadeResult hat keinen Einfluss auf die JDL-Sprachspezifikation.
5. Invarianten¶
value()darf nur aufgerufen werden wennisOk() == true— sonstassert-Fehler.diag()darf nur aufgerufen werden wennisErr() == true— sonstassert-Fehler.match!mitfinal switcherzwingt exhaustive Behandlung aller drei Zustände — Compiler-Fehler wenn ein Fall fehlt.Emptyist kein Fehler und erzeugt keineDiagnostic.JadeResultist@nogcundnothrow— kein Exception-Mechanismus.
6. Änderungsprotokoll¶
Version 0.1.0 — Initiale Definition:
- Drei Zustände: Ok(T), Err(Diagnostic), Empty
- match! mit final switch für exhaustive Behandlung
- valueOr als sicherer Default-Zugriff
- Option(T) durch Empty ersetzt
- Abgrenzung zu JDL-Typen dokumentiert