
---

# Projektplan: "Single-Map-Argument" (SMA) Architektur

*Datum: 23. Oktober 2025*

## 1. Motivation: Die "Visuelle Sprache"

Das primäre Entwicklungsziel ist **nicht** eine Text-basierte Programmiersprache, sondern ein **visueller Editor**, in dem Logik durch das Kombinieren von Blöcken erstellt wird. Der Text-Parser (`Myc.Ast.Script`) ist lediglich eine sekundäre Repräsentation.

Für einen visuellen Editor ist syntaktische Komplexität Gift. Jede Ausnahme, jedes Schlüsselwort und jede alternative Syntax (wie `[]` vs. `()`) erfordert einen neuen, speziellen visuellen Block, was die Benutzeroberfläche überlädt und die Konsistenz bricht.

Das ultimative Ziel ist eine **100% einheitliche Syntax**, bei der es nur noch *eine* Art gibt, eine Operation auszudrücken: den Funktionsaufruf. In einer S-Expression-Welt ist die konsistenteste Form dafür `(Funktionsname Argumente...)`.

## 2. Ziel: Das "Single-Map-Argument" (SMA) Modell

Um die visuelle Darstellung auf das absolute Minimum zu reduzieren (ein Block für "Funktion" und ein Slot für "Argumente"), führen wir das **"Single-Map-Argument" (SMA) Modell** ein.

Es gibt nur noch *eine* gültige Aufrufkonvention:
`(Funktionsname {Argument-Map})`

Jede Funktion, egal ob nativ (`+`) oder benutzerdefiniert (`my-lambda`), wird mit einem einzigen Argument aufgerufen: einem **Map-Literal** (das zu einem `TScalarRecord` ausgewertet wird). Dieses Literal definiert die Argumente über Key-Value-Paare.

**Beispiele:**

* **Arithmetik:** `(+ {:x 1 :y 2})`
* **RTL-Funktion:** `(Abs {:value -10})`
* **Lambda-Definition:** `(fn my-adder ({:x1 1 :x2 2}) ...)`
* **Lambda-Aufruf:** `(my-adder {:x1 5})`

Dieses Design erfüllt die Anforderung an die visuelle Konsistenz perfekt. Ein "Aufruf"-Block im Editor hat immer nur zwei definierte Slots: den Namen (z.B. `+`) und ein Map-Literal (z.B. `{:x ..., :y ...}`).

## 3. Analyse & Performance-Strategie

Unsere Diskussion hat ergeben, dass dieses Modell zwar visuell perfekt, aber in einer naiven Implementierung performancetechnisch inakzeptabel wäre.

### Das Problem: Die naive Implementierung (Verworfen)

Eine naive Implementierung würde jeden Aufruf zur Laufzeit gleich behandeln:
1.  Der `TEvaluator` wertet das Map-Literal `{:x 1 :y 2}` zu einem vollwertigen `TScalarRecord` aus (Heap-Allokation, Füllen einer Map/Dictionary-Struktur).
2.  Er ruft die native `+` Funktion mit diesem *einen* `TScalarRecord`-Argument auf.
3.  Die `+` Funktion (bzw. ihr Wrapper) müsste die Map parsen, die Keys `:x` und `:y` nachschlagen und die Werte extrahieren.

Für Operationen wie `+`, die millionenfach pro Sekunde aufgerufen werden, ist dieser Overhead (Heap-Allokation + Hashmap-Lookups) katastrophal und ein absoluter Showstopper.

### Die Lösung: Kompilierung von Aufrufsignaturen

Wir vermeiden diesen Overhead, indem wir den **`TAstBinder` (den "Compiler")** die "Dekonstruktion" der Argument-Maps zur Compile-Zeit durchführen lassen.

Wir implementieren eine **Drei-Pfade-Kompilierung** für `VisitFunctionCall`:

#### Pfad 1: "Fast Path" (Nativ / RTL)

Dieser Pfad optimiert alle Aufrufe an bekannte, fest verdrahtete RTL-Funktionen.

* **Aktion (Binder):**
    1.  Der `TAstBinder` erhält ein **statisches Registry nativer Signaturen** (z.B. `TDictionary<string, TArray<string>>`). Dieses mappt Namen auf *geordnete* Key-Listen: `'+' -> [':x', ':y']`, `'Abs' -> [':value']`.
    2.  Bei `(sub {:a 5 :b 3})` schlägt er `sub` nach. Treffer! Signatur ist `[':a', ':b']`.
    3.  Der Binder validiert das `IMapLiteralNode` (alle Keys da? unbekannte Keys?).
    4.  **Argument-Umschreibung (Rewriting):** Der Binder *ignoriert* die Map-Struktur und erzeugt einen neuen, *positionalen* `TArray<IAstNode>`: `[ (Node 5), (Node 3) ]`.
    5.  Er erzeugt einen `TBoundFunctionCallNode`, der auf die native `sub`-Funktion zeigt, aber das *neue positionale Array* als Argumentenliste enthält.
* **Aktion (Evaluator):**
    1.  Der Evaluator sieht einen normalen, positionalen Aufruf.
    2.  Er wertet die Argumente `5` und `3` aus und ruft die `TRtlFunctions.Subtract` direkt mit einem `TArray<TDataValue>` auf.
* **Ergebnis:** Keinerlei Map-Allokation zur Laufzeit. Maximale Performance.

#### Pfad 2: "Fast Path" (Direkte Lambda)

Dieser Pfad optimiert direkte Aufrufe an Lambdas, deren Definition dem Binder bereits bekannt ist.

* **Aktion (Binder):**
    1.  Bei `(fn my-adder ({:x1 1 :x2 2}) ...)` parst der Binder die Signatur `({:x1 1, :x2 2})`.
    2.  Er speichert diese Signatur-Metadaten (Keys und Default-Wert-Nodes) im `IScopeDescriptor` als Metadatum für die Variable `my-adder`.
    3.  Bei einem späteren Aufruf `(my-adder {:x1 5})`:
    4.  Der Binder schlägt `my-adder` im Scope nach. Treffer! Er findet die Variable *und* die gespeicherte Signatur.
    5.  **Argument-Umschreibung:** Er führt die *gleiche* Optimierung wie bei nativen Aufrufen durch. Er parst das `IMapLiteralNode`, füllt fehlende Keys mit den Default-Nodes (z.B. `:x2` -> `(Node 2)`) und erzeugt einen positionalen `TArray<IAstNode>`: `[ (Node 5), (Node 2) ]`.
    6.  Er erzeugt einen `TBoundFunctionCallNode`, der das positionale Array enthält.
* **Aktion (Evaluator):**
    1.  Der Evaluator wertet die Closure `my-adder` aus.
    2.  Er wertet die Argumente `5` und `2` aus.
    3.  Er ruft die Closure mit einem *positionalen* `TArray<TDataValue>` auf.
* **Ergebnis:** Auch hier: Keinerlei Map-Allokation zur Laufzeit.

#### Pfad 3: "Slow Path" (Dynamisch / Polymorph)

Dies ist der Fallback für alle Aufrufe, die der Binder zur Compile-Zeit *unmöglich* auflösen kann.

* **Szenarien:**
    * **Funktionen höherer Ordnung (HOFs):** `(Map my-series (fn ({:item}) ...))` -> Die `Map`-Funktion *muss* die Lambda dynamisch aufrufen.
    * **Indirekte Aufrufe:** `(fn call-it (func) (func {:a 1}))` -> `func` ist zur Compile-Zeit unbekannt.
    * **Späte Bindung / Forward-Deklarationen.**
* **Aktion (Binder):**
    1.  Der Binder kann die Signatur nicht finden.
    2.  Er kann *nicht* optimieren. Er behandelt das `IMapLiteralNode` `{:a 1}` als regulären Wert.
    3.  Er erzeugt einen `TBoundFunctionCallNode` mit einem Argumenten-Array, das *nur dieses eine* `IMapLiteralNode` enthält.
* **Aktion (Evaluator):**
    1.  Der Evaluator *muss* nun das `IMapLiteralNode` zu einem echten `TScalarRecord` auswerten (der "Overhead" entsteht hier).
    2.  Er ruft die Closure (z.B. `func`) mit *einem* Argument auf (dem `TScalarRecord`).
    3.  Die Closure selbst muss die **Laufzeit-Destrukturierung** durchführen: Sie parst die Map, extrahiert die Keys (`:a`) und wendet ihre Defaults an.
* **Ergebnis:** Das System bleibt voll funktionsfähig und konsistent, nutzt aber den langsameren Pfad nur, wenn es semantisch unvermeidbar ist.

---

## 4. TODOs (Detailliert)

1.  **Parser (`Myc.Ast.Script`)**
    * [ ] `TLexer`: `tkLeftBracket`, `tkRightBracket` entfernen. `tkLBrace` (`{`), `tkRBrace` (`}`), `tkColon` (`:`) hinzufügen.
    * [ ] `IAstNode`: `IKeywordNode` (für `:key`) und `IMapLiteralNode` (enthält `TArray<TPair<IKeywordNode, IAstNode>>`) definieren.
    * [ ] `TParser`: `ParseExpression` erweitern, um `{...}` zu `IMapLiteralNode` und `:...` zu `IKeywordNode` zu parsen.
    * [ ] `TParser`: `ParseList` anpassen. Die `fn`- und `defmacro`-Logik muss die Parameterliste jetzt als `IMapLiteralNode` (für die Destrukturierung) statt einer Liste von Identifiern parsen.

2.  **Binder (`Myc.Ast.Binding`)**
    * [ ] `TAstBinder.Create`: Das **Native Signature Registry** (`TDictionary<string, TArray<string>>`) initialisieren.
    * [ ] `TAstBinder.VisitLambdaExpression`: Die `IMapLiteralNode`-Signatur parsen. Die Metadaten (geordnete Keys und Default-`IAstNode`s) müssen in der `TBoundLambdaExpressionNode` oder im `IScopeDescriptor` gespeichert werden.
    * [ ] `TAstBinder.VisitFunctionCall`: Die **Kern-Drei-Pfade-Logik** implementieren:
        1.  Lookup im Native Registry (Pfad 1).
        2.  Lookup im `IScopeDescriptor` nach Lambda-Metadaten (Pfad 2).
        3.  Fallback auf "Slow Path" (Pfad 3).
    * [ ] `TAstBinder`: Eine private `function RewriteArguments(const Signature: ...; const CallMap: IMapLiteralNode): TArray<IAstNode>` implementieren, die die "Fast Path"-Dekonstruktion durchführt.

3.  **Evaluator (`Myc.Ast.Evaluator`)**
    * [ ] `TEvaluatorVisitor`: `VisitMapLiteral` implementieren. Diese Methode wertet ein `IMapLiteralNode` zu einem `TDataValue (vkRecord)` aus (der "Slow Path"-Overhead).
    * [ ] `TEvaluatorVisitor.VisitLambdaExpression`: Die *Laufzeit*-Destrukturierungslogik implementieren. Diese wird aktiv, wenn die Closure (TFunc) mit einem `TDataValue (vkRecord)` (Pfad 3) anstelle eines `TArray<TDataValue>` (Pfad 2) aufgerufen wird. (Benötigt Anpassung der Closure-Signatur oder -Logik).

4.  **RTL (Anpassung & Registrierung)**
    * [ ] `Myc.Ast.RTL.Core`: Die Implementierungen (`TRtlFunctions.Add` etc.) bleiben **unverändert**. Sie erwarten weiterhin `TArray<TDataValue>`, da der Binder für sie übersetzt.
    * [ ] `Myc.Ast.RTL`: Die RTTI-Registrierung muss erweitert werden, um dem Binder die Signaturen bereitzustellen. `TRtlFunctionAttribute` könnte erweitert werden: `[TRtlFunction('+', ':x,:y')]`. Diese Infos füllen das Native Registry im Binder.