From 8041f7355f130ba467ab58187a849f1044c1ba39 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sun, 21 Sep 2025 12:51:06 +0200 Subject: [PATCH] Scripting refinement --- ASTPlayground/MainForm.pas | 30 ++++++++++++++++--------- Doc/Concurrency Model.md | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 Doc/Concurrency Model.md diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index 05aa447..ff590db 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -112,6 +112,7 @@ type function ExecuteAst(const ANode: IAstNode; const AParentScope: IExecutionScope): TDataValue; procedure UpdateScript; procedure ShowVizualization(X, Y: Single); + procedure PrintScript(const Node: IAstNode); public { Public declarations } end; @@ -631,6 +632,7 @@ begin ) ] ); + FLastAst := setupAst; // 1. Bind and execute the setup script. @@ -963,6 +965,21 @@ begin UpdateScript; end; +procedure TForm1.PrintScript(const Node: IAstNode); +begin + try + FScriptUpdate := true; + try + ScriptMemo.Lines.Text := ScriptMemo.Lines.Text + #10#13 + TAstScript.Print(Node); + finally + FScriptUpdate := false; + end; + except + on E: Exception do + ScriptMemo.Lines.Add(E.Message); + end; +end; + procedure TForm1.ScriptMemoChange(Sender: TObject); begin if FScriptUpdate then @@ -1006,17 +1023,8 @@ end; procedure TForm1.UpdateScript; begin - try - FScriptUpdate := true; - try - ScriptMemo.Lines.Text := TAstScript.Print(FLastAst); - finally - FScriptUpdate := false; - end; - except - on E: Exception do - ScriptMemo.Lines.Add(E.Message); - end; + Memo1.Lines.Clear; + PrintScript(FLastAst); FWorkspace.DeleteChildren; ShowVizualization(14, 14); diff --git a/Doc/Concurrency Model.md b/Doc/Concurrency Model.md new file mode 100644 index 0000000..240c623 --- /dev/null +++ b/Doc/Concurrency Model.md @@ -0,0 +1,46 @@ +### **Projektplan: "Magical & Safe" Concurrency-Modell** +**Datum:** 21. September 2025, 12:07 + +#### **Motivation** +Unser Interpreter besitzt ein solides Fundament für die single-threaded Ausführung. Moderne, datenintensive Anwendungen erfordern jedoch eine robuste und einfach zu handhabende Nebenläufigkeit. Traditionelle Locking-Mechanismen (`TCriticalSection`, Mutexe) sind komplex, extrem fehleranfällig (Race Conditions, Deadlocks) und skalieren schlecht. Ziel ist es, ein modernes Concurrency-Modell direkt in den Sprachkern zu integrieren, das diese Probleme per Design vermeidet. + +#### **Ziel** +Wir erweitern die Sprache um ein Nebenläufigkeits-Modell, das drei Kernziele verfolgt: + +1. **Sicherheit (Safe):** Es muss für den Programmierer unmöglich sein, durch konkurrierende Schreibzugriffe auf geteilten Zustand eine Race Condition zu erzeugen. Die Sprache garantiert die Atomarität von Zustandsänderungen. + +2. **"Magie" (Magical):** Die Sicherheitsmechanismen sollen für den Programmierer **transparent** sein. Er schreibt weiterhin einfachen, sequenziellen Code mit `def` und `assign`. Der Compiler/Binder kümmert sich automatisch um die notwendigen Schutzmaßnahmen, ohne dass der Programmierer explizite Synchronisierungs-Primitive wie `swap!` oder `atom` verwenden muss. + +3. **Performance:** Der durch die Sicherheitsmechanismen entstehende Overhead darf nur dort anfallen, wo er zwingend notwendig ist – also nur bei Zuständen, die tatsächlich geteilt *und* verändert werden. + +#### **Geplante Umsetzung & Architektur** +Um diese Ziele zu erreichen, führen wir eine klare semantische Trennung zwischen unveränderlichen Werten und veränderlichen Identitäten ein und implementieren die "Magie" im Binder. + +**1. Das Fundament: Unveränderliche Datenstrukturen (Values)** +Der Grundpfeiler für sichere Nebenläufigkeit ist, dass Werte (Values) per Definition unveränderlich (immutable) sind. Wenn Daten einmal erzeugt wurden, können sie sich niemals ändern. + +* **Todo:** Implementierung einer Kernbibliothek von **persistenten, unveränderlichen Datenstrukturen** (insbesondere Vektoren und Maps), die "Structural Sharing" für effiziente "Updates" nutzen. Bestehende `Series` müssen entweder durch diese ersetzt oder angepasst werden. + +**2. Veränderliche Identitäten (Refs)** +Der veränderliche Zustand wird über **Identitäten** (Referenzen) verwaltet. Eine Identität ist ein stabiler "Container", dessen enthaltener Wert atomar ausgetauscht werden kann. Dies entspricht exakt dem `atom`-Konzept von Clojure. + +* **Todo:** Implementierung einer generischen `TAtom`-Klasse in Delphi. Die `Swap`-Methode dieser Klasse wird **lock-frei** mittels einer **`TInterlocked.CompareExchange`-Retry-Schleife** implementiert, um maximale Performance und Skalierbarkeit zu gewährleisten. + +**3. Die "Magie": Automatische Promotion im Binder** +Hier wird der "magische" Aspekt umgesetzt. Der `TAstBinder` wird um eine intelligente Zustandsanalyse erweitert. + +* **Logik:** + 1. Standardmäßig wird jede Variable als einfacher, performanter Wert im Scope-Speicher behandelt. + 2. Der Binder analysiert die Verwendung von Variablen in untergeordneten Scopes (Closures). + 3. Sobald der Binder einen **Schreibzugriff (`assign`)** auf eine **Upvalue** (eine Variable aus einem äußeren Scope) entdeckt, wird diese Variable im äußeren Scope automatisch "promotet": Ihr Speicherplatz wird von einem einfachen Wert zu einer Instanz der sicheren `TAtom`-Klasse umgewandelt. + 4. Alle nachfolgenden Lese- und Schreibzugriffe auf diese Variable (sowohl im äußeren als auch in allen inneren Scopes) werden vom Binder automatisch in sichere Aufrufe auf dem `TAtom` umgeschrieben. + +* **Todo:** Erweiterung des `TAstBinder` um die Logik zur Erkennung von Upvalue-Schreibzugriffen, zur automatischen Promotion von Variablen und zur Umschreibung der entsprechenden AST-Zugriffsknoten. + +--- +### **Nächste Schritte (Todo-Liste)** + +* [ ] Kernbibliothek für persistente, unveränderliche Datenstrukturen (Vector, Map) entwerfen und implementieren. +* [ ] Lock-freie `TAtom`-Klasse als primäres Concurrency-Primitiv implementieren. +* [ ] `TAstBinder` um die "automatische Promotions"-Logik für Upvalues erweitern. +* [ ] Multi-threaded Unit-Tests schreiben, um die Korrektheit und Sicherheit des neuen Modells unter Last zu verifizieren. \ No newline at end of file