Translate project content to English
Make English the project-wide language: all comments, string literals, CLI help text, design docs, journal, agent prompts, and README. Only CLAUDE.md (the user's own instruction file) stays German, and the live conversation between user and Claude continues in German. Adds a new "Project language: English" section to docs/DESIGN.md as the durable convention. No logic changes — translation only. Four internal error strings in the typechecker were retranslated; no test asserts on their wording. Verified: cargo test --workspace passes (44/44). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+138
-126
@@ -1,136 +1,148 @@
|
||||
# AILang — Designentscheidungen
|
||||
# AILang — design decisions
|
||||
|
||||
Dieses Dokument hält die Kernentscheidungen für AILang fest. Es ist mein Vertrag mit
|
||||
mir selbst über künftige Iterationen. Kürzungen statt Wachstum bevorzugen.
|
||||
This document records the core decisions for AILang. It is my contract with
|
||||
myself across future iterations. Prefer cuts over growth.
|
||||
|
||||
## Zielsetzung
|
||||
## Goal
|
||||
|
||||
AILang ist eine Programmiersprache für LLM-Autoren. Sie wird zu LLVM IR kompiliert.
|
||||
Performance: nativ, ohne GC für den MVP.
|
||||
AILang is a programming language for LLM authors. It compiles to LLVM IR.
|
||||
Performance: native, no GC for the MVP.
|
||||
|
||||
Optimiert für:
|
||||
Optimised for:
|
||||
|
||||
- **Maschinenlesbarkeit** statt menschlicher Ergonomie. Quelle ist strukturiert.
|
||||
- **Lokales Reasoning.** Jede Definition trägt ihren vollständigen Typ und ihre Effekte.
|
||||
- **Beweisbarkeit.** Reine Kernsprache, explizite Effekte, optionale Refinements.
|
||||
- **Robustheit gegen Halluzinationen.** Symbole sind hashbar; Tools können Existenz
|
||||
verifizieren, ohne Kontextfenster zu verbrauchen.
|
||||
- **Machine readability** over human ergonomics. The source is structured.
|
||||
- **Local reasoning.** Every definition carries its full type and effects.
|
||||
- **Provability.** Pure core language, explicit effects, optional refinements.
|
||||
- **Robustness against hallucinations.** Symbols are hashable; tools can verify
|
||||
existence without spending context window.
|
||||
|
||||
## Projekt-Ökosystem
|
||||
## Project ecosystem
|
||||
|
||||
AILang ist nicht nur eine Sprache, sondern ein Ökosystem. Die Sprache an sich
|
||||
ist nur dann wertvoll, wenn das Drumherum sie für ihren Zielnutzer (LLM-Autoren)
|
||||
benutzbar, prüfbar und erweiterbar macht. Das Repo enthält daher mehrere
|
||||
gleichwertige Komponenten — keine davon ist optional, alle entwickeln sich
|
||||
parallel mit der Sprache:
|
||||
AILang is not just a language but an ecosystem. The language on its own is
|
||||
only valuable when its surroundings make it usable, checkable, and
|
||||
extensible for its target user (LLM authors). The repo therefore contains
|
||||
several equally important components — none of them optional, all of them
|
||||
evolving in lockstep with the language:
|
||||
|
||||
- **Sprachkern** (`crates/ailang-core`, `crates/ailang-check`,
|
||||
`crates/ailang-codegen`): AST, Typsystem, Codegen.
|
||||
- **CLI** (`crates/ail`): Toolchain für Tooling-Konsumenten — `manifest`,
|
||||
`describe`, `deps`, `check`, `build`, etc., bevorzugt mit `--json` für
|
||||
maschinelle Konsumption.
|
||||
- **Beispiele** (`examples/`): kanonische `.ail.json`-Programme. Sie sind
|
||||
Spezifikationsanker, nicht Demos — die E2E-Suite hängt an ihnen.
|
||||
- **Agenten** (`agents/`): spezialisierte Sub-Prompts (Implementer,
|
||||
Architect, Tester, Debugger), die das Projekt-eigene LLM-Tooling bilden.
|
||||
Sie sind versionierter Bestandteil des Repos. Siehe `agents/README.md`.
|
||||
- **Doku** (`docs/`): DESIGN.md (was und warum), JOURNAL.md (Verlauf).
|
||||
- **Tests**: Unit pro Crate + E2E in `crates/ail/tests/e2e.rs`. Jeder neue
|
||||
Compiler-Pfad braucht einen Test, sonst zählt das Feature nicht als fertig.
|
||||
- **Language core** (`crates/ailang-core`, `crates/ailang-check`,
|
||||
`crates/ailang-codegen`): AST, type system, codegen.
|
||||
- **CLI** (`crates/ail`): toolchain for tooling consumers — `manifest`,
|
||||
`describe`, `deps`, `check`, `build`, etc., preferably with `--json` for
|
||||
machine consumption.
|
||||
- **Examples** (`examples/`): canonical `.ail.json` programs. They are
|
||||
specification anchors, not demos — the E2E suite hangs off them.
|
||||
- **Agents** (`agents/`): specialised sub-prompts (implementer,
|
||||
architect, tester, debugger) that form the project's own LLM tooling.
|
||||
They are a versioned part of the repo. See `agents/README.md`.
|
||||
- **Docs** (`docs/`): DESIGN.md (what and why), JOURNAL.md (history).
|
||||
- **Tests**: unit tests per crate plus E2E in `crates/ail/tests/e2e.rs`. Every
|
||||
new compiler path needs a test, otherwise the feature does not count as done.
|
||||
|
||||
Wenn die Sprache wächst, wachsen diese Komponenten mit. Neue Tools, die das
|
||||
LLM-Tooling stärken (z. B. `ail diff`, IR-Snapshot-Diffs, neue Agenten),
|
||||
gehören explizit ins Ökosystem-Inventar dieses Abschnitts und werden hier
|
||||
ergänzt, sobald sie etabliert sind.
|
||||
When the language grows, these components grow with it. New tools that
|
||||
strengthen the LLM tooling (e.g. `ail diff`, IR snapshot diffs, new agents)
|
||||
explicitly belong in the ecosystem inventory of this section and are added
|
||||
here as soon as they are established.
|
||||
|
||||
## Entscheidung 1: Quelle = Daten, nicht Text
|
||||
## Project language: English
|
||||
|
||||
Ein Modul ist ein JSON-Objekt mit einem festen Schema. Es gibt keinen Parser für
|
||||
Freitext. Tippfehler in Bezeichnern werden zu Hash-Lookup-Fehlern, die der Compiler
|
||||
direkt vorschlägt zu fixen.
|
||||
All in-tree content is written in English: source code (identifiers,
|
||||
comments, string literals, CLI help), design documents, the journal, agent
|
||||
prompts, READMEs, commit messages, and new examples. The only exception is
|
||||
`CLAUDE.md`, which is the user's own instruction file. The live conversation
|
||||
between user and me stays German for ergonomic reasons; everything that
|
||||
lands in git is English. This keeps diffs and tooling output uniform and
|
||||
matches the audience for AILang (LLM authors), for whom English is the
|
||||
default.
|
||||
|
||||
Eine Textform existiert (`.ail`, S-Expression-artig), aber nur als bidirektionale
|
||||
Projektion der JSON-Form. Sie ist für Menschen-Reviews und Diffs gedacht.
|
||||
## Decision 1: source = data, not text
|
||||
|
||||
**Kanonisches Format:** `.ail.json` mit deterministischer Schlüsselreihenfolge.
|
||||
A module is a JSON object with a fixed schema. There is no parser for
|
||||
free-form text. Typos in identifiers turn into hash-lookup errors that the
|
||||
compiler proposes a fix for directly.
|
||||
|
||||
## Entscheidung 2: Content-addressed Definitionen
|
||||
A textual form exists (`.ail`, S-expression-like), but only as a
|
||||
bidirectional projection of the JSON form. It is intended for human reviews
|
||||
and diffs.
|
||||
|
||||
Jede Top-Level-Definition hat einen `hash`-Wert (BLAKE3 über kanonisches JSON ohne
|
||||
das `hash`-Feld selbst). Verweise zwischen Definitionen erfolgen primär per Name —
|
||||
Namen sind für Lesbarkeit. Der Hash ist die kanonische Identität.
|
||||
**Canonical format:** `.ail.json` with deterministic key order.
|
||||
|
||||
Vorteile:
|
||||
## Decision 2: content-addressed definitions
|
||||
|
||||
- Refactoring durch Hinzufügen neuer Defs, nicht durch In-place-Änderung. Alte
|
||||
Versionen bleiben aufrufbar, bis manuell entfernt.
|
||||
- Caching von Typcheck-Ergebnissen und Codegen pro Hash.
|
||||
- Diffs zeigen exakt, welche Def sich geändert hat.
|
||||
Every top-level definition has a `hash` value (BLAKE3 over canonical JSON
|
||||
without the `hash` field itself). References between definitions go primarily
|
||||
by name — names are for readability. The hash is the canonical identity.
|
||||
|
||||
## Entscheidung 3: Reine Kernsprache + algebraische Effekte
|
||||
Advantages:
|
||||
|
||||
Default sind totale, reine Funktionen. Effekte werden als Set im Funktionstyp
|
||||
deklariert: `(Int) -> Int ![IO]`. Die Effektmenge ist row-polymorph
|
||||
(`![IO | r]`). Im MVP sind nur die Effekte `IO` und `Diverge` (für Endlosschleifen)
|
||||
verbaut.
|
||||
- Refactoring by adding new defs, not by in-place change. Old versions stay
|
||||
callable until manually removed.
|
||||
- Caching of typecheck results and codegen per hash.
|
||||
- Diffs show exactly which def has changed.
|
||||
|
||||
Dies ist die wichtigste LLM-Eigenschaft: Wenn ich eine Funktion lese, kann ich
|
||||
ihrer Signatur trauen, ohne den Body zu lesen.
|
||||
## Decision 3: pure core language + algebraic effects
|
||||
|
||||
## Entscheidung 4: Hindley-Milner + optionale Refinements
|
||||
The default is total, pure functions. Effects are declared as a set in the
|
||||
function type: `(Int) -> Int ![IO]`. The effect set is row-polymorphic
|
||||
(`![IO | r]`). In the MVP only the effects `IO` and `Diverge` (for infinite
|
||||
loops) are wired up.
|
||||
|
||||
MVP: HM mit Let-Polymorphismus. Alle Typen sind inferierbar, müssen aber im
|
||||
Top-Level immer explizit annotiert sein (für lokales Reasoning).
|
||||
This is the most important LLM property: when I read a function, I can trust
|
||||
its signature without reading the body.
|
||||
|
||||
Später: Refinement-Annotationen, die zu SMT escalieren. `(i: Int | i >= 0)`. Vom
|
||||
Anfang an im AST vorgesehen, aber im MVP einfach als opake Strings durchgereicht.
|
||||
## Decision 4: Hindley-Milner + optional refinements
|
||||
|
||||
## Entscheidung 5: LLVM IR als Text emittieren
|
||||
MVP: HM with let-polymorphism. All types are inferable, but at the top level
|
||||
they must always be explicitly annotated (for local reasoning).
|
||||
|
||||
Statt `inkwell` oder `llvm-sys`: AILang erzeugt `.ll`-Dateien als Strings und
|
||||
übergibt an `clang` zum Linken.
|
||||
Later: refinement annotations that escalate to SMT. `(i: Int | i >= 0)`. They
|
||||
are reserved in the AST from the start, but in the MVP they are simply passed
|
||||
through as opaque strings.
|
||||
|
||||
Begründung:
|
||||
## Decision 5: emit LLVM IR as text
|
||||
|
||||
- LLVM-IR-Textsyntax ist über Versionen weitgehend stabil.
|
||||
- Keine Build-Abhängigkeit von einer bestimmten libllvm-Version.
|
||||
- Generierter Code ist trivial inspizierbar, was Debugging massiv vereinfacht.
|
||||
- LLM kann generierten IR direkt lesen, was bei opaken Bibliothekscalls schwerer ist.
|
||||
Instead of `inkwell` or `llvm-sys`: AILang produces `.ll` files as strings
|
||||
and hands them to `clang` for linking.
|
||||
|
||||
Trade-off: keine Inline-Optimierungen über die LLVM-API. Wir setzen auf
|
||||
`clang -O2` als Standard-Pipeline.
|
||||
Rationale:
|
||||
|
||||
## Mangling-Schema (Iter 5c)
|
||||
- The LLVM IR text syntax is largely stable across versions.
|
||||
- No build dependency on a specific libllvm version.
|
||||
- Generated code is trivially inspectable, which makes debugging much easier.
|
||||
- An LLM can read the generated IR directly, which is harder with opaque
|
||||
library calls.
|
||||
|
||||
Alle AILang-Funktionen werden zu `@ail_<modul>_<def>` gemangelt — auch im
|
||||
Single-Modul-Fall. Konstanten ebenfalls (`@ail_<modul>_<const>`). Globale
|
||||
String-Literale tragen einen kurzen Hint zur Lesbarkeit:
|
||||
`@.str_<modul>_<hint>_<idx>` (z. B. `@.str_sum_fmt_int_0`). Eintrittspunkt
|
||||
ist eine `define i32 @main()`-Trampoline (C-/LLVM-ABI), die
|
||||
`@ail_<entry-modul>_main()` aufruft. `source_filename` existiert genau
|
||||
einmal pro Workspace und trägt den Eintrittsmodulnamen
|
||||
(`<entry-modul>.ail`).
|
||||
Trade-off: no inline optimisations through the LLVM API. We rely on
|
||||
`clang -O2` as the standard pipeline.
|
||||
|
||||
## Konvention: Qualifizierte Cross-Module-Verweise (Iter 5b)
|
||||
## Mangling scheme (Iter 5c)
|
||||
|
||||
Cross-Module-Aufrufe nutzen **keinen** neuen AST-Knoten. Stattdessen ist ein
|
||||
`Term::Var { name }` mit genau einem Punkt im Namen ein qualifizierter
|
||||
Verweis: `<prefix>.<def>`.
|
||||
All AILang functions are mangled to `@ail_<module>_<def>` — even in the
|
||||
single-module case. Constants likewise (`@ail_<module>_<const>`). Global
|
||||
string literals carry a short hint for readability:
|
||||
`@.str_<module>_<hint>_<idx>` (e.g. `@.str_sum_fmt_int_0`). The entry point
|
||||
is a `define i32 @main()` trampoline (C / LLVM ABI) that calls
|
||||
`@ail_<entry-module>_main()`. `source_filename` exists exactly once per
|
||||
workspace and carries the entry-module name (`<entry-module>.ail`).
|
||||
|
||||
- `<prefix>` ist ein Import-Alias (`import { module: "X", as: "<prefix>" }`)
|
||||
oder, falls ohne Alias importiert, der Modulname selbst.
|
||||
- `<def>` ist der Name einer Top-Level-Definition im Zielmodul.
|
||||
- Def-Namen DÜRFEN keinen Punkt enthalten — der Typchecker meldet
|
||||
`invalid-def-name` mit `ctx: { "reason": "contains-dot" }`.
|
||||
- Der Workspace-Loader (Iter 5a) findet alle erreichbaren Module; der
|
||||
Typchecker (Iter 5b, `check_workspace`) löst Punkt-Namen über die
|
||||
Import-Map auf. Diagnostic-Codes: `unknown-module` (Prefix nicht
|
||||
importiert), `unknown-import` (Modul gefunden, Def nicht).
|
||||
## Convention: qualified cross-module references (Iter 5b)
|
||||
|
||||
Hash-Stabilität: kein neuer AST-Knoten, keine umbenannten Felder — alle
|
||||
bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
Cross-module calls use **no** new AST node. Instead, a `Term::Var { name }`
|
||||
with exactly one dot in the name is a qualified reference: `<prefix>.<def>`.
|
||||
|
||||
## Datenmodell (MVP)
|
||||
- `<prefix>` is an import alias (`import { module: "X", as: "<prefix>" }`)
|
||||
or, when imported without an alias, the module name itself.
|
||||
- `<def>` is the name of a top-level definition in the target module.
|
||||
- Def names MUST NOT contain a dot — the typechecker reports
|
||||
`invalid-def-name` with `ctx: { "reason": "contains-dot" }`.
|
||||
- The workspace loader (Iter 5a) finds all reachable modules; the
|
||||
typechecker (Iter 5b, `check_workspace`) resolves dotted names through the
|
||||
import map. Diagnostic codes: `unknown-module` (prefix not imported),
|
||||
`unknown-import` (module found, def not).
|
||||
|
||||
Hash stability: no new AST node, no renamed fields — all previous module
|
||||
hashes stay bit-identical.
|
||||
|
||||
## Data model (MVP)
|
||||
|
||||
### Module
|
||||
|
||||
@@ -145,7 +157,7 @@ bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
|
||||
### Def
|
||||
|
||||
`kind ∈ { "fn", "type", "effect", "const" }`. Im MVP nur `fn` und `const`.
|
||||
`kind ∈ { "fn", "type", "effect", "const" }`. In the MVP only `fn` and `const`.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -158,7 +170,7 @@ bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
}
|
||||
```
|
||||
|
||||
### Term (Expression)
|
||||
### Term (expression)
|
||||
|
||||
```jsonc
|
||||
{ "t": "lit", "lit": { "kind": "int" | "bool" | "unit", "value": ... } }
|
||||
@@ -169,7 +181,7 @@ bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
{ "t": "do", "op": "<eff>/<op>", "args": [Term...] }
|
||||
```
|
||||
|
||||
`do` ist im MVP nur ein direkter Aufruf eines Built-in-Effekt-Ops (kein Handler).
|
||||
In the MVP, `do` is only a direct call to a built-in effect op (no handler).
|
||||
|
||||
### Type
|
||||
|
||||
@@ -189,7 +201,7 @@ bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
├─ load + validate schema
|
||||
├─ resolve names + assign hashes
|
||||
├─ typecheck (HM, effect rows)
|
||||
├─ lower to MIR (SSA-ähnlich, named SSA-Werte)
|
||||
├─ lower to MIR (SSA-like, named SSA values)
|
||||
├─ emit LLVM IR (.ll)
|
||||
└─ clang -O2 *.ll -o binary
|
||||
```
|
||||
@@ -197,33 +209,33 @@ bisherigen Modul-Hashes bleiben bitidentisch.
|
||||
## CLI
|
||||
|
||||
```
|
||||
ail check <module.ail.json> — Lädt, validiert, typecheckt
|
||||
ail manifest <module.ail.json> — Tabelle: name :: type !effects [hash]
|
||||
ail describe <module> <name> — Detail einer Definition
|
||||
ail render <module> — JSON → Pretty-Text
|
||||
ail parse <module.ail> — Pretty-Text → JSON (für Bootstrapping)
|
||||
ail emit-ir <module> — schreibt .ll
|
||||
ail build <module> — komplette Pipeline → Binary
|
||||
ail check <module.ail.json> — loads, validates, typechecks
|
||||
ail manifest <module.ail.json> — table: name :: type !effects [hash]
|
||||
ail describe <module> <name> — detail of a definition
|
||||
ail render <module> — JSON → pretty-print
|
||||
ail parse <module.ail> — pretty-print → JSON (for bootstrapping)
|
||||
ail emit-ir <module> — writes .ll
|
||||
ail build <module> — full pipeline → binary
|
||||
```
|
||||
|
||||
## Verifikation und Korrektheit (über Zyklen)
|
||||
## Verification and correctness (across cycles)
|
||||
|
||||
1. **Snapshot-Tests** für Pretty-Printer und IR-Emit. Diff macht Regressions sofort
|
||||
sichtbar.
|
||||
2. **Property-Tests** für Roundtrip JSON ↔ Pretty.
|
||||
3. **End-to-End-Tests** für `examples/` mit erwartetem Programmoutput.
|
||||
4. **Hash-Stabilität**: Test stellt sicher, dass dieselbe Def stets denselben Hash
|
||||
produziert.
|
||||
5. **CI-Pin** der Outputs in `tests/expected/`.
|
||||
1. **Snapshot tests** for the pretty-printer and IR emit. The diff makes
|
||||
regressions visible immediately.
|
||||
2. **Property tests** for the JSON ↔ pretty-print roundtrip.
|
||||
3. **End-to-end tests** for `examples/` with expected program output.
|
||||
4. **Hash stability**: a test ensures the same def always produces the same
|
||||
hash.
|
||||
5. **CI pin** of the outputs in `tests/expected/`.
|
||||
|
||||
## Was MVP NICHT ist
|
||||
## What the MVP is NOT
|
||||
|
||||
- Keine ADTs / Pattern Matching (Phase 2).
|
||||
- Keine Closures / höhere Funktionen (Phase 2).
|
||||
- Keine Effekt-Handler (Phase 3).
|
||||
- Keine Refinements / SMT (Phase 4).
|
||||
- Kein Modulsystem über Imports hinaus (Phase 2).
|
||||
- Keine Strings als first-class. Nur ints + bools + unit.
|
||||
- No ADTs / pattern matching (Phase 2).
|
||||
- No closures / higher-order functions (Phase 2).
|
||||
- No effect handlers (Phase 3).
|
||||
- No refinements / SMT (Phase 4).
|
||||
- No module system beyond imports (Phase 2).
|
||||
- No first-class strings. Only ints + bools + unit.
|
||||
|
||||
Der MVP ist erfolgreich, wenn `examples/sum.ail.json` ein Binary erzeugt, das die
|
||||
Summe 1..10 = 55 druckt.
|
||||
The MVP is successful when `examples/sum.ail.json` produces a binary that
|
||||
prints the sum 1..10 = 55.
|
||||
|
||||
Reference in New Issue
Block a user