From 833ce8aada4f1b58677d44e4fc1296351350f853 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Fri, 28 Nov 2025 13:45:33 +0100 Subject: [PATCH] Ast editor unit refactoring --- ASTPlayground/ASTPlayground.delphilsp.json | 2 +- ASTPlayground/ASTPlayground.dpr | 9 +- ASTPlayground/ASTPlayground.dproj | 7 +- ASTPlayground/MainForm.pas | 2 +- ASTPlayground/Myc.Fmx.AstEditor.Node.pas | 2361 ----------------- ASTPlayground/Myc.Fmx.AstEditor.Text.pas | 265 -- Src/AST/Myc.Fmx.AstEditor.Core.pas | 706 +++++ Src/AST/Myc.Fmx.AstEditor.Handlers.pas | 1085 ++++++++ Src/AST/Myc.Fmx.AstEditor.Visualizer.pas | 249 ++ .../AST}/Myc.Fmx.AstEditor.Workspace.pas | 20 +- .../Test.Myc.Ast.Compiler.Binder.pas | 0 11 files changed, 2063 insertions(+), 2643 deletions(-) delete mode 100644 ASTPlayground/Myc.Fmx.AstEditor.Node.pas delete mode 100644 ASTPlayground/Myc.Fmx.AstEditor.Text.pas create mode 100644 Src/AST/Myc.Fmx.AstEditor.Core.pas create mode 100644 Src/AST/Myc.Fmx.AstEditor.Handlers.pas create mode 100644 Src/AST/Myc.Fmx.AstEditor.Visualizer.pas rename {ASTPlayground => Src/AST}/Myc.Fmx.AstEditor.Workspace.pas (90%) rename {Src/AST => Test}/Test.Myc.Ast.Compiler.Binder.pas (100%) diff --git a/ASTPlayground/ASTPlayground.delphilsp.json b/ASTPlayground/ASTPlayground.delphilsp.json index 2f9040e..c8efac4 100644 --- a/ASTPlayground/ASTPlayground.delphilsp.json +++ b/ASTPlayground/ASTPlayground.delphilsp.json @@ -1 +1 @@ -{ "settings": { "project": "file:///T%3A/Myc/ASTPlayground/ASTPlayground.dpr", "dllname": "dcc64370.dll", "dccOptions": "-$O- -$W+ --inline:off -$R+ -$Q+ --no-config -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG;;FRAMEWORK_FMX -E.\\Win64\\Debug -I\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -LEC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Bpl\\Win64 -LNC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NU.\\Win64\\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;System;Xml;Data;Datasnap;Web;Soap; -OT:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -R\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -U\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -V -VN -VR -NBC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NHC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\hpp\\Win64 -NO.\\Win64\\Debug -LU" , "projectFiles":[ { "name": "MainForm", "file": "file:///T%3A/Myc/ASTPlayground/MainForm.pas" }, { "name": "Myc.Ast.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Nodes.pas" }, { "name": "Myc.Ast.Scope", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Scope.pas" }, { "name": "Myc.Data.Value", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Data.Value.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Text", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Text.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Compiler.TCO", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TCO.pas" }, { "name": "Myc.Ast.Compiler.Binder", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Binder.pas" }, { "name": "Myc.Ast.Compiler.Lowering", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Lowering.pas" }, { "name": "Myc.Ast.Compiler.TypeChecker", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TypeChecker.pas" }, { "name": "Myc.Ast.Compiler.Macros", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Macros.pas" }, { "name": "Myc.Ast.Compiler.Specializer", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Specializer.pas" }, { "name": "Myc.Ast.Environment", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Environment.pas" }, { "name": "Myc.Ast.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Analysis.Purity", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Analysis.Purity.pas" }, { "name": "Myc.Ast.Identities", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Identities.pas" } ] , "includeDCUsInUsesCompletion": true, "enableKeyWordCompletion": false, "browsingPaths": [ "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/OCX/Servers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/VCL","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/RTL/SYS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win/winrt","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/ToolsAPI","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/IBX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Internet","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/PROPERTY%20EDITORS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/XML","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Core","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/System","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Protocols","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/fmx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/components","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/engine","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/graph","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ado","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/cloud","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dbx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dsnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/vclctrls","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/connectors","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/proxygen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DataExplorer","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/src","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/tests","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Experts","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/abstraction","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/implementation","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indyimpl","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Property%20Editors/Indy10","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap/wsdlimporter","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Visualizers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XMLReporting","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XPGen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/rest","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/firedac","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/tethering","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnitX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ems","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/net","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/FlatBox2D","file:///C%3A/Users/Public/Documents/Embarcadero/Studio/37.0/Dcp/%25PLATFORM%25","file:///%25TP%25/runtime/vcl","file:///S%3A/sc_famos_src/svn_vcl/cpxedits","file:///S%3A/sc_famos_src/svn_vcl/dzChart","file:///S%3A/sc_famos_src/svn_vcl/eaeditor","file:///S%3A/sc_famos_src/svn_vcl/FamosEvents","file:///S%3A/sc_famos_src/svn_vcl/HTML_Viewer/source","file:///S%3A/sc_famos_src/svn_vcl/Myc_ChartEdit","file:///S%3A/sc_famos_src/svn_vcl/Myc_HemiDrag","file:///S%3A/sc_famos_src/svn_vcl/Myc_SplitControl","file:///S%3A/sc_famos_src/svn_vcl/NiceChart","file:///S%3A/sc_famos_src/svn_vcl/plotter","file:///S%3A/sc_famos_src/svn_vcl/SimpleIPC","file:///S%3A/sc_famos_src/svn_vcl/SynEdit-master/Source","file:///S%3A/sc_famos_src/svn_vcl/ValEdits","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib/win32","file:///S%3A/sc_famos_src/svn_vcl/Virtual-TreeView/Source","file:///S%3A/sc_famos_src/svn_common/caHelpSys","file:///S%3A/sc_famos_src/svn_common/Misc","file:///S%3A/sc_famos_src/svn_common/Myc_VecMath","file:///S%3A/sc_famos_src/svn_common/PascalScript/source","file:///S%3A/sc_famos_src/svn_common/TreeBase","file:///S%3A/sc_famos_src/svn_common/TreeBase/Medien","file:///S%3A/3rdParty/spring4d/Source","file:///S%3A/3rdParty/spring4d/Source/Base","file:///S%3A/3rdParty/spring4d/Source/Base/Collections","file:///S%3A/3rdParty/spring4d/Source/Base/Logging","file:///S%3A/3rdParty/spring4d/Source/Base/Patches","file:///S%3A/3rdParty/spring4d/Source/Core/Container","file:///S%3A/3rdParty/spring4d/Source/Core/Interception","file:///S%3A/3rdParty/spring4d/Source/Core/Logging","file:///S%3A/3rdParty/spring4d/Source/Core/Mocking","file:///S%3A/3rdParty/spring4d/Source/Core/Services","file:///S%3A/3rdParty/spring4d/Source/Extensions/Cryptography","file:///S%3A/3rdParty/spring4d/Source/Extensions/Utils","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCommon%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressGDI%2B%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLibrary/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/XP%20Theme%20Manager/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLayout%20Control/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressPageControl/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressEditors%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDocking%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressBars/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressOfficeCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressMemData/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDataController/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressNavBar/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressSkins%20Library/Sources","file:///T%3A/Myc/Src","file:///T%3A/Myc/Src/Data","file:///T%3A/Myc/Src/AST" ] , "CommonAppData": "file:///C%3A/Users/Brummel/AppData/Roaming/Embarcadero/BDS/37.0/" , "Templates": "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/ObjRepos/" } } \ No newline at end of file +{ "settings": { "project": "file:///T%3A/Myc/ASTPlayground/ASTPlayground.dpr", "dllname": "dcc64370.dll", "dccOptions": "-$O- -$W+ --inline:off -$R+ -$Q+ --no-config -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG;;FRAMEWORK_FMX -E.\\Win64\\Debug -I\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -LEC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Bpl\\Win64 -LNC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NU.\\Win64\\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;System;Xml;Data;Datasnap;Web;Soap; -OT:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -R\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -U\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -V -VN -VR -NBC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NHC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\hpp\\Win64 -NO.\\Win64\\Debug -LU" , "projectFiles":[ { "name": "MainForm", "file": "file:///T%3A/Myc/ASTPlayground/MainForm.pas" }, { "name": "Myc.Ast.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Nodes.pas" }, { "name": "Myc.Ast.Scope", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Scope.pas" }, { "name": "Myc.Data.Value", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Data.Value.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Compiler.TCO", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TCO.pas" }, { "name": "Myc.Ast.Compiler.Binder", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Binder.pas" }, { "name": "Myc.Ast.Compiler.Lowering", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Lowering.pas" }, { "name": "Myc.Ast.Compiler.TypeChecker", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TypeChecker.pas" }, { "name": "Myc.Ast.Compiler.Macros", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Macros.pas" }, { "name": "Myc.Ast.Compiler.Specializer", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Specializer.pas" }, { "name": "Myc.Ast.Environment", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Environment.pas" }, { "name": "Myc.Ast.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Analysis.Purity", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Analysis.Purity.pas" }, { "name": "Myc.Ast.Identities", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Identities.pas" }, { "name": "Myc.Fmx.AstEditor.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Handlers", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Handlers.pas" }, { "name": "Myc.Fmx.AstEditor.Visualizer", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Workspace.pas" } ] , "includeDCUsInUsesCompletion": true, "enableKeyWordCompletion": true, "browsingPaths": [ "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/OCX/Servers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/VCL","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/RTL/SYS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win/winrt","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/ToolsAPI","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/IBX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Internet","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/PROPERTY%20EDITORS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/XML","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Core","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/System","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Protocols","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/fmx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/components","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/engine","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/graph","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ado","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/cloud","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dbx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dsnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/vclctrls","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/connectors","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/proxygen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DataExplorer","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/src","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/tests","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Experts","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/abstraction","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/implementation","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indyimpl","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Property%20Editors/Indy10","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap/wsdlimporter","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Visualizers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XMLReporting","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XPGen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/rest","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/firedac","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/tethering","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnitX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ems","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/net","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/FlatBox2D","file:///C%3A/Users/Public/Documents/Embarcadero/Studio/37.0/Dcp/%25PLATFORM%25","file:///%25TP%25/runtime/vcl","file:///S%3A/sc_famos_src/svn_vcl/cpxedits","file:///S%3A/sc_famos_src/svn_vcl/dzChart","file:///S%3A/sc_famos_src/svn_vcl/eaeditor","file:///S%3A/sc_famos_src/svn_vcl/FamosEvents","file:///S%3A/sc_famos_src/svn_vcl/HTML_Viewer/source","file:///S%3A/sc_famos_src/svn_vcl/Myc_ChartEdit","file:///S%3A/sc_famos_src/svn_vcl/Myc_HemiDrag","file:///S%3A/sc_famos_src/svn_vcl/Myc_SplitControl","file:///S%3A/sc_famos_src/svn_vcl/NiceChart","file:///S%3A/sc_famos_src/svn_vcl/plotter","file:///S%3A/sc_famos_src/svn_vcl/SimpleIPC","file:///S%3A/sc_famos_src/svn_vcl/SynEdit-master/Source","file:///S%3A/sc_famos_src/svn_vcl/ValEdits","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib/win32","file:///S%3A/sc_famos_src/svn_vcl/Virtual-TreeView/Source","file:///S%3A/sc_famos_src/svn_common/caHelpSys","file:///S%3A/sc_famos_src/svn_common/Misc","file:///S%3A/sc_famos_src/svn_common/Myc_VecMath","file:///S%3A/sc_famos_src/svn_common/PascalScript/source","file:///S%3A/sc_famos_src/svn_common/TreeBase","file:///S%3A/sc_famos_src/svn_common/TreeBase/Medien","file:///S%3A/3rdParty/spring4d/Source","file:///S%3A/3rdParty/spring4d/Source/Base","file:///S%3A/3rdParty/spring4d/Source/Base/Collections","file:///S%3A/3rdParty/spring4d/Source/Base/Logging","file:///S%3A/3rdParty/spring4d/Source/Base/Patches","file:///S%3A/3rdParty/spring4d/Source/Core/Container","file:///S%3A/3rdParty/spring4d/Source/Core/Interception","file:///S%3A/3rdParty/spring4d/Source/Core/Logging","file:///S%3A/3rdParty/spring4d/Source/Core/Mocking","file:///S%3A/3rdParty/spring4d/Source/Core/Services","file:///S%3A/3rdParty/spring4d/Source/Extensions/Cryptography","file:///S%3A/3rdParty/spring4d/Source/Extensions/Utils","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCommon%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressGDI%2B%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLibrary/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/XP%20Theme%20Manager/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLayout%20Control/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressPageControl/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressEditors%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDocking%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressBars/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressOfficeCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressMemData/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDataController/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressNavBar/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressSkins%20Library/Sources","file:///T%3A/Myc/Src","file:///T%3A/Myc/Src/Data","file:///T%3A/Myc/Src/AST" ] , "CommonAppData": "file:///C%3A/Users/Brummel/AppData/Roaming/Embarcadero/BDS/37.0/" , "Templates": "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/ObjRepos/" } } \ No newline at end of file diff --git a/ASTPlayground/ASTPlayground.dpr b/ASTPlayground/ASTPlayground.dpr index afcbf5b..8404838 100644 --- a/ASTPlayground/ASTPlayground.dpr +++ b/ASTPlayground/ASTPlayground.dpr @@ -12,9 +12,6 @@ uses Myc.Ast.RTL in '..\Src\AST\Myc.Ast.RTL.pas', Myc.Ast.Dumper in '..\Src\AST\Myc.Ast.Dumper.pas', Myc.Ast.RTL.Core in '..\Src\AST\Myc.Ast.RTL.Core.pas', - Myc.Fmx.AstEditor.Node in 'Myc.Fmx.AstEditor.Node.pas', - Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas', - Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas', Myc.Utils in '..\Src\Myc.Utils.pas', Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas', Myc.Ast.Types in '..\Src\AST\Myc.Ast.Types.pas', @@ -28,7 +25,11 @@ uses Myc.Ast.Environment in '..\Src\AST\Myc.Ast.Environment.pas', Myc.Ast.Debugger in '..\Src\AST\Myc.Ast.Debugger.pas', Myc.Ast.Analysis.Purity in '..\Src\AST\Myc.Ast.Analysis.Purity.pas', - Myc.Ast.Identities in '..\Src\AST\Myc.Ast.Identities.pas'; + Myc.Ast.Identities in '..\Src\AST\Myc.Ast.Identities.pas', + Myc.Fmx.AstEditor.Core in '..\Src\AST\Myc.Fmx.AstEditor.Core.pas', + Myc.Fmx.AstEditor.Handlers in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.pas', + Myc.Fmx.AstEditor.Visualizer in '..\Src\AST\Myc.Fmx.AstEditor.Visualizer.pas', + Myc.Fmx.AstEditor.Workspace in '..\Src\AST\Myc.Fmx.AstEditor.Workspace.pas'; {$R *.res} diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj index 261a978..3e51201 100644 --- a/ASTPlayground/ASTPlayground.dproj +++ b/ASTPlayground/ASTPlayground.dproj @@ -142,9 +142,6 @@ - - - @@ -159,6 +156,10 @@ + + + + Base diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index c826914..54af9c6 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -32,7 +32,7 @@ uses Myc.Ast.Script, FMX.Layouts, FMX.Objects, - Myc.Fmx.AstEditor.Node, + Myc.Fmx.AstEditor.Core, Myc.Fmx.AstEditor.Workspace, FMX.DialogService, FMX.ListView.Types, diff --git a/ASTPlayground/Myc.Fmx.AstEditor.Node.pas b/ASTPlayground/Myc.Fmx.AstEditor.Node.pas deleted file mode 100644 index 07df5a4..0000000 --- a/ASTPlayground/Myc.Fmx.AstEditor.Node.pas +++ /dev/null @@ -1,2361 +0,0 @@ -unit Myc.Fmx.AstEditor.Node; - -interface - -uses - System.SysUtils, - System.Classes, - System.UITypes, - System.Types, - System.Math.Vectors, - System.Math, - System.Generics.Defaults, - System.Generics.Collections, - FMX.Types, - FMX.Controls, - FMX.Objects, - FMX.Graphics, - FMX.StdCtrls, - Myc.Data.Scalar, - Myc.Data.Value, - Myc.Data.Keyword, - Myc.Ast.Nodes, - Myc.Ast.Visitor, - Myc.Ast.Identities, // NEU: Für Casts - Myc.Ast, - Myc.Fmx.AstEditor.Workspace; - -const - cNodePadding = 10; - cTitleTopPadding = 2; - cTitleBottomPadding = 4; - cMinNodeWidth = 10; - cMinNodeHeight = 10; - -type - TAuraNode = class; // Forward declaration - - // This aggregate interface encapsulates all node-specific logic. - IAuraNodeHandler = interface - ['{B66291B7-14A1-4638-927A-05B1623C83A6}'] - // Gets the original logical AST node - function GetAstNode: IAstNode; - // Creates the specific FMX UI for this node - procedure BuildUI(OwnerNode: TAuraNode); - // Reconstructs the logical AST node from the FMX UI state - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - // The original logical AST node - property Node: IAstNode read GetAstNode; - end; - - IAstVisualizer = interface - {$region 'private'} - function GetExprDepth: Integer; - function GetParentControl: TControl; - {$endregion} - - function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; - function CallAccept(const Node: IAstNode): TAuraNode; - function GetWorkspace: TAuraWorkspace; - - property ExprDepth: Integer read GetExprDepth; - property ParentControl: TControl read GetParentControl; - property Workspace: TAuraWorkspace read GetWorkspace; - end; - - // Inherits from the new generic TAstVisitor - TAstVisualizer = class(TAstVisitor, IAstVisualizer) - private - FExprDepth: Integer; - FParentControl: TControl; - FWorkspace: TAuraWorkspace; - // Calls Accept on the node and returns the resulting TAuraNode. - function CallAccept(const Node: IAstNode): TAuraNode; - function GetExprDepth: Integer; - function GetParentControl: TControl; - function GetWorkspace: TAuraWorkspace; - procedure SetExprDepth(const Value: Integer); - procedure SetParentControl(const Value: TControl); - protected - // Visitor implementations for each AST node type. - function VisitConstant(const Node: IConstantNode): TAuraNode; override; - function VisitIdentifier(const Node: IIdentifierNode): TAuraNode; override; - function VisitKeyword(const Node: IKeywordNode): TAuraNode; override; - function VisitIfExpression(const Node: IIfExpressionNode): TAuraNode; override; - function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAuraNode; override; - function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAuraNode; override; - function VisitFunctionCall(const Node: IFunctionCallNode): TAuraNode; override; - function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAuraNode; override; - function VisitBlockExpression(const Node: IBlockExpressionNode): TAuraNode; override; - function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAuraNode; override; - function VisitAssignment(const Node: IAssignmentNode): TAuraNode; override; - function VisitMacroDefinition(const Node: IMacroDefinitionNode): TAuraNode; override; - function VisitQuasiquote(const Node: IQuasiquoteNode): TAuraNode; override; - function VisitUnquote(const Node: IUnquoteNode): TAuraNode; override; - function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAuraNode; override; - function VisitIndexer(const Node: IIndexerNode): TAuraNode; override; - function VisitMemberAccess(const Node: IMemberAccessNode): TAuraNode; override; - function VisitRecordLiteral(const Node: IRecordLiteralNode): TAuraNode; override; - function VisitCreateSeries(const Node: ICreateSeriesNode): TAuraNode; override; - function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAuraNode; override; - function VisitSeriesLength(const Node: ISeriesLengthNode): TAuraNode; override; - function VisitRecurNode(const Node: IRecurNode): TAuraNode; override; - function VisitNop(const Node: INopNode): TAuraNode; override; - - public - constructor Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer); - destructor Destroy; override; - - function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; - - property ExprDepth: Integer read GetExprDepth write SetExprDepth; - property ParentControl: TControl read GetParentControl write SetParentControl; - property Workspace: TAuraWorkspace read GetWorkspace; - end; - - // Defines the layout direction for children within TAutoFitControl - TLayoutOrientation = (loVertical, loHorizontal); - - // Defines the alignment of children on the cross-axis - TLayoutAlignment = (laCenter, laFlush); - - // A styled control that automatically adjusts its size to fit its children, including padding. - TAutoFitControl = class(TStyledControl) - private - FUpdatingOwnSize: Boolean; // Recursion guard - FNeedRecalcSize: Boolean; // Flag for EndUpdate - FOrientation: TLayoutOrientation; // Storage for Orientation - FAlignment: TLayoutAlignment; // Storage for Alignment - procedure RecalcOwnSize; - procedure SetOrientation(const Value: TLayoutOrientation); - procedure SetAlignment(const Value: TLayoutAlignment); - protected - - // Called by children when their size, position, or visibility changes - procedure ParentContentChanged; override; - // Called when our own padding changes - procedure PaddingChanged; override; - // Called after children list has changed (add/remove) - procedure ChangeChildren; override; - // Initial calculation after loading - procedure Loaded; override; - // Handle pending recalc after updates - procedure DoEndUpdate; override; - public - constructor Create(AOwner: TComponent); override; - - published - // Make Padding published if needed - property Padding; - property Orientation: TLayoutOrientation read FOrientation write SetOrientation default TLayoutOrientation.loHorizontal; - property Alignment: TLayoutAlignment read FAlignment write SetAlignment default TLayoutAlignment.laCenter; - end; - - // A movable panel with a custom-painted border. Content (like title) is added externally. - TAuraNode = class(TAutoFitControl) - private - FBackgroundColor: TAlphaColor; - // Flag to indicate if the control is currently being dragged. - FIsDragging: Boolean; - // Stores the mouse coordinates at the beginning of the drag operation. - FDownPos: TPointF; - // Properties for the custom-drawn border. - FBorderColor: TAlphaColor; - FBorderWidth: Single; - FBorderRadius: Single; - // If true, the node is drawn without a border and with a transparent background. - FFrameless: Boolean; - FVisualizer: IAstVisualizer; - FHandler: IAuraNodeHandler; // *** NEW: Strategy/Aggregate *** - procedure SetBackgroundColor(const Value: TAlphaColor); - procedure SetBorderColor(const Value: TAlphaColor); - procedure SetBorderWidth(const Value: Single); - procedure SetBorderRadius(const Value: Single); - procedure SetFrameless(const Value: Boolean); - function GetNode: IAstNode; - protected - procedure Paint; override; - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; - procedure MouseMove(Shift: TShiftState; X, Y: Single); override; - procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; - procedure SetupNode; - - function AddLabel(Parent: TControl; const Txt: String): TLabel; - function AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; - function AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAuraNode; - - public - constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAuraNodeHandler); reintroduce; - destructor Destroy; override; - - procedure AfterConstruction; override; - - // *** CHANGED: Now non-virtual, delegates to handler *** - function CreateAst: IAstNode; - - property Visualizer: IAstVisualizer read FVisualizer; - // *** NEW: Access to the original logical node via the handler *** - property Node: IAstNode read GetNode; - - published - // Custom border properties - property BorderColor: TAlphaColor read FBorderColor write SetBorderColor; - property BorderWidth: Single read FBorderWidth write SetBorderWidth; - property BorderRadius: Single read FBorderRadius write SetBorderRadius; - property BackgroundColor: TAlphaColor read FBackgroundColor write SetBackgroundColor; - - // Behavior properties - property Frameless: Boolean read FFrameless write SetFrameless; - - // Standard control properties - property Align; - property Anchors; - property ClipChildren default True; - property Cursor default crDefault; - property DragMode default TDragMode.dmManual; - property Enabled; - property Height; - property Hint; - property HitTest default True; - property Locked; - property Margins; - property Opacity; - property Padding; - property PopupMenu; - property Position; - property RotationAngle; - property RotationCenter; - property Scale; - property Size; - property Visible; - property Width; - property OnClick; - property OnDblClick; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnMouseEnter; - property OnMouseLeave; - end; - -implementation - -// We declare the handler classes here in the implementation -// as they are private details of the visualizer. - -type - { TConstantNodeHandler } - TConstantNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IConstantNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IConstantNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraIdentifierNode } - TIdentifierNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IIdentifierNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IIdentifierNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraKeywordNode } - TKeywordNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IKeywordNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IKeywordNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraBlockExpressionNode } - TBlockExpressionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IBlockExpressionNode; - FChildNodes: TList; // To store children for CreateAst - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IBlockExpressionNode); - destructor Destroy; override; - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraIfExpressionNode } - TIfExpressionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IIfExpressionNode; - FConditionNode: TAuraNode; - FThenNode: TAuraNode; - FElseNode: TAuraNode; // Can be nil - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IIfExpressionNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraTernaryExpressionNode } - TTernaryExpressionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: ITernaryExpressionNode; - FConditionNode: TAuraNode; - FThenNode: TAuraNode; - FElseNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: ITernaryExpressionNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraLambdaExpressionNode } - TLambdaExpressionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: ILambdaExpressionNode; - FBodyNode: TAuraNode; - FParamLabels: TList; // To store param labels - function GetAstNode: IAstNode; - public - constructor Create(const ANode: ILambdaExpressionNode); - destructor Destroy; override; - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraFunctionCallNode } - TFunctionCallNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IFunctionCallNode; - FCalleeNode: TAuraNode; - FArgumentNodes: TList; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IFunctionCallNode); - destructor Destroy; override; - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraMacroExpansionNode } - TMacroExpansionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IMacroExpansionNode; - FExpandedBodyNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IMacroExpansionNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraRecurNode } - TRecurNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IRecurNode; - FArgumentNodes: TList; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IRecurNode); - destructor Destroy; override; - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraVariableDeclarationNode } - TVariableDeclarationNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IVariableDeclarationNode; - FTargetNode: TAuraNode; - FInitializerNode: TAuraNode; // Can be nil - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IVariableDeclarationNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraAssignmentNode } - TAssignmentNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IAssignmentNode; - FTargetNode: TAuraNode; - FValueNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IAssignmentNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraMacroDefinitionNode } - TMacroDefinitionNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IMacroDefinitionNode; - FBodyNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IMacroDefinitionNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraQuasiquoteNode } - TQuasiquoteNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IQuasiquoteNode; - FExpressionNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IQuasiquoteNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraUnquoteNode } - TUnquoteNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IUnquoteNode; - FExpressionNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IUnquoteNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraUnquoteSplicingNode } - TUnquoteSplicingNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IUnquoteSplicingNode; - FExpressionNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IUnquoteSplicingNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraIndexerNode } - TIndexerNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IIndexerNode; - FBaseNode: TAuraNode; - FIndexNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IIndexerNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraMemberAccessNode } - TMemberAccessNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IMemberAccessNode; - FBaseNode: TAuraNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IMemberAccessNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraRecordLiteralNode } - TRecordLiteralNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IRecordLiteralNode; - FFieldNodes: TDictionary; // Map KeyName -> ValueNode - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IRecordLiteralNode); - destructor Destroy; override; - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraCreateSeriesNode } - TCreateSeriesNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: ICreateSeriesNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: ICreateSeriesNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraAddSeriesItemNode } - TAddSeriesItemNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: IAddSeriesItemNode; - FValueNode: TAuraNode; - FLookbackNode: TAuraNode; // Can be nil - function GetAstNode: IAstNode; - public - constructor Create(const ANode: IAddSeriesItemNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraSeriesLengthNode } - TSeriesLengthNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: ISeriesLengthNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: ISeriesLengthNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - - { TAuraNopNode } - TNopNodeHandler = class(TInterfacedObject, IAuraNodeHandler) - private - FNode: INopNode; - function GetAstNode: IAstNode; - public - constructor Create(const ANode: INopNode); - procedure BuildUI(OwnerNode: TAuraNode); - function ReconstructAst(OwnerNode: TAuraNode): IAstNode; - end; - -{ TAstVisualizer } - -constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer); -begin - inherited Create; - FWorkspace := AWorkspace; - FParentControl := AParentControl; - FExprDepth := AExprDepth; -end; - -destructor TAstVisualizer.Destroy; -begin - inherited; -end; - -// Calls Accept on the node and returns the resulting TAuraNode. -function TAstVisualizer.CallAccept(const Node: IAstNode): TAuraNode; -var - DataValue: TDataValue; -begin - if not Assigned(Node) then - Exit(nil); // Handle nil input node gracefully - - DataValue := Node.Accept(Self); - - // Check if the result is actually a TAuraNode before casting - if DataValue.Kind = TDataValueKind.vkGeneric then - begin - // Assuming the visitor correctly returns TAuraNode wrapped in TDataValue. - Result := DataValue.AsGeneric; - end - else - begin - Result := nil; - end; -end; - -function TAstVisualizer.Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; -begin - Result := TAstVisualizer.Create(FWorkspace, ParentControl, ExprDepth); -end; - -function TAstVisualizer.GetExprDepth: Integer; -begin - Result := FExprDepth; -end; - -function TAstVisualizer.GetParentControl: TControl; -begin - Result := FParentControl; -end; - -function TAstVisualizer.GetWorkspace: TAuraWorkspace; -begin - Result := FWorkspace; -end; - -procedure TAstVisualizer.SetExprDepth(const Value: Integer); -begin - FExprDepth := Value; -end; - -procedure TAstVisualizer.SetParentControl(const Value: TControl); -begin - FParentControl := Value; -end; - -// --- Visitor Implementations --- - -function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TConstantNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitIdentifier(const Node: IIdentifierNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TIdentifierNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitKeyword(const Node: IKeywordNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TKeywordNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TBlockExpressionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitIfExpression(const Node: IIfExpressionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TIfExpressionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TTernaryExpressionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TLambdaExpressionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitFunctionCall(const Node: IFunctionCallNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TFunctionCallNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TMacroExpansionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TVariableDeclarationNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitAssignment(const Node: IAssignmentNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TAssignmentNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TMacroDefinitionNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitQuasiquote(const Node: IQuasiquoteNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TQuasiquoteNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitUnquote(const Node: IUnquoteNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TUnquoteNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TUnquoteSplicingNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitIndexer(const Node: IIndexerNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TIndexerNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitMemberAccess(const Node: IMemberAccessNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TMemberAccessNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitRecordLiteral(const Node: IRecordLiteralNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TRecordLiteralNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitCreateSeries(const Node: ICreateSeriesNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TCreateSeriesNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TAddSeriesItemNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitSeriesLength(const Node: ISeriesLengthNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TSeriesLengthNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitRecurNode(const Node: IRecurNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TRecurNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -function TAstVisualizer.VisitNop(const Node: INopNode): TAuraNode; -var - Handler: IAuraNodeHandler; -begin - Handler := TNopNodeHandler.Create(Node); - Result := TAuraNode.Create(Self, Handler); -end; - -{ TAutoFitControl } - -constructor TAutoFitControl.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - HitTest := True; - FOrientation := TLayoutOrientation.loHorizontal; - FAlignment := TLayoutAlignment.laCenter; // Default alignment -end; - -procedure TAutoFitControl.SetAlignment(const Value: TLayoutAlignment); -begin - if FAlignment <> Value then - begin - FAlignment := Value; - RecalcOwnSize; // Re-layout on alignment change - end; -end; - -procedure TAutoFitControl.SetOrientation(const Value: TLayoutOrientation); -begin - if FOrientation <> Value then - begin - FOrientation := Value; - RecalcOwnSize; // Recalculate layout when orientation changes - end; -end; - -procedure TAutoFitControl.RecalcOwnSize; -var - I: Integer; - Child: TControl; - ChildrenToLayout: TList; // Still used to filter relevant children - CurrentX, CurrentY: Single; - RequiredWidth, RequiredHeight: Single; - ChildWidthWithMargins, ChildHeightWithMargins: Single; - HasVisibleChild: Boolean; -begin - if FUpdatingOwnSize then - Exit; - if IsUpdating then - begin - FNeedRecalcSize := True; - Exit; - end; - - FUpdatingOwnSize := True; - ChildrenToLayout := nil; - try - RequiredWidth := Padding.Left + Padding.Right; - RequiredHeight := Padding.Top + Padding.Bottom; - CurrentX := Padding.Left; - CurrentY := Padding.Top; - HasVisibleChild := False; - - // Collect relevant children - ChildrenToLayout := TList.Create; - for I := 0 to ChildrenCount - 1 do - begin - if Children[I] is TControl then - begin - Child := TControl(Children[I]); - if Child.Visible and (Child.Align = TAlignLayout.None) then - begin - ChildrenToLayout.Add(Child); - HasVisibleChild := True; - end; - end; - end; - - if HasVisibleChild then - begin - // Perform layout based on orientation - if FOrientation = TLayoutOrientation.loVertical then - begin - // Pass 1: Calculate total height and max width. Set Y pos. - for Child in ChildrenToLayout do - begin - // Store Y position - Child.Position.Y := CurrentY + Child.Margins.Top; - CurrentY := Child.Position.Y + Child.Height + Child.Margins.Bottom; - - // Calculate max width - ChildWidthWithMargins := Padding.Left + Child.Margins.Left + Child.Width + Child.Margins.Right + Padding.Right; - RequiredWidth := System.Math.Max(RequiredWidth, ChildWidthWithMargins); - end; - RequiredHeight := CurrentY + Padding.Bottom; - - // Pass 2: Align children horizontally based on FAlignment - if FAlignment = TLayoutAlignment.laFlush then - begin - // Flush (left-aligned) - for Child in ChildrenToLayout do - begin - Child.Position.X := Padding.Left + Child.Margins.Left; - end; - end - else - begin - // Center-aligned - var contentWidth := RequiredWidth - Padding.Left - Padding.Right; - for Child in ChildrenToLayout do - begin - var childTotalWidth := Child.Width + Child.Margins.Left + Child.Margins.Right; - var childX := Padding.Left + ((contentWidth - childTotalWidth) / 2) + Child.Margins.Left; - Child.Position.X := childX; - end; - end; - end - else // loHorizontal - begin - // Pass 1: Calculate total width and max height. Set X pos. - for Child in ChildrenToLayout do - begin - // Store X position - Child.Position.X := CurrentX + Child.Margins.Left; - CurrentX := Child.Position.X + Child.Width + Child.Margins.Right; - - // Calculate max height - ChildHeightWithMargins := Padding.Top + Child.Margins.Top + Child.Height + Child.Margins.Bottom + Padding.Bottom; - RequiredHeight := System.Math.Max(RequiredHeight, ChildHeightWithMargins); - end; - RequiredWidth := CurrentX + Padding.Right; - - // Pass 2: Align children vertically based on FAlignment - if FAlignment = TLayoutAlignment.laFlush then - begin - // Flush (top-aligned) - for Child in ChildrenToLayout do - begin - Child.Position.Y := Padding.Top + Child.Margins.Top; - end; - end - else - begin - // Center-aligned - var contentHeight := RequiredHeight - Padding.Top - Padding.Bottom; - for Child in ChildrenToLayout do - begin - var childTotalHeight := Child.Height + Child.Margins.Top + Child.Margins.Bottom; - var childY := Padding.Top + ((contentHeight - childTotalHeight) / 2) + Child.Margins.Top; - Child.Position.Y := childY; - end; - end; - end; - end - else - begin - RequiredWidth := Padding.Left + Padding.Right; - RequiredHeight := Padding.Top + Padding.Bottom; - end; - - RequiredWidth := System.Math.Max(0, RequiredWidth); - RequiredHeight := System.Math.Max(0, RequiredHeight); - - if not SameValue(RequiredWidth, Width, TEpsilon.Position) or not SameValue(RequiredHeight, Height, TEpsilon.Position) then - begin - FSize.SetSizeWithoutNotification(TSizeF.Create(RequiredWidth, RequiredHeight)); - HandleSizeChanged; - end; - - finally - ChildrenToLayout.Free; - FUpdatingOwnSize := False; - end; -end; - -procedure TAutoFitControl.Loaded; -begin - inherited Loaded; - // Perform initial size calculation after all children are loaded - RecalcOwnSize; -end; - -procedure TAutoFitControl.ChangeChildren; -begin - inherited ChangeChildren; - // Recalculate size when children are added or removed - RecalcOwnSize; -end; - -procedure TAutoFitControl.PaddingChanged; -begin - inherited PaddingChanged; - // Recalculate size when padding changes - RecalcOwnSize; -end; - -procedure TAutoFitControl.ParentContentChanged; -begin - inherited ParentContentChanged; - // Recalculate size when a child signals a potential layout change - RecalcOwnSize; -end; - -procedure TAutoFitControl.DoEndUpdate; -begin - inherited; - // If a recalc was deferred during BeginUpdate/EndUpdate, do it now - if FNeedRecalcSize then - begin - FNeedRecalcSize := False; - RecalcOwnSize; - end; -end; - -{ TAuraNode } - -constructor TAuraNode.Create(const AVisualizer: IAstVisualizer; const AHandler: IAuraNodeHandler); -begin - inherited Create(AVisualizer.Workspace); - - Parent := AVisualizer.ParentControl; - - FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth); - FHandler := AHandler; // *** Store the injected handler *** - - FIsDragging := False; - - // Default border settings - FBorderColor := TAlphaColors.Gray; - FBorderWidth := 1; - FBorderRadius := 9; // Rounded corners by default - FBackgroundColor := $080a0a0a; - - // Default state for frameless mode - FFrameless := False; - - // Set a default minimum size, will be adjusted later - Width := cMinNodeWidth; - Height := cMinNodeHeight; - - // The panel must be able to receive mouse events. - HitTest := True; // Make sure HitTest is True to receive mouse events - // Clip children to the panel's bounds. - ClipChildren := True; - - Margins.Left := 4; - Margins.Top := 4; - Margins.Right := 4; - Margins.Bottom := 4; - Padding.Left := 3; - Padding.Top := 3; - Padding.Right := 3; - Padding.Bottom := 3; - - var cn: cardinal := $ea - (7 * FVisualizer.ExprDepth); - var c: cardinal := $ff000000 or (cn shl 16) or (cn shl 8) or cn; - BackgroundColor := c; -end; - -destructor TAuraNode.Destroy; -begin - FHandler := nil; // Release the handler interface - inherited; -end; - -function TAuraNode.AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; -begin - Result := TAutoFitControl.Create(Self); - Result.Parent := Parent; - Result.Orientation := Orientation; - Result.Alignment := Alignment; - Result.HitTest := False; // Pass clicks to parent -end; - -function TAuraNode.AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAuraNode; -begin - var cont := AddContainer(Parent, loHorizontal, laCenter); - - var lbl := AddLabel(cont, Title); - lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; - - Result := FVisualizer.Clone(cont, FVisualizer.ExprDepth + 1).CallAccept(Node); -end; - -function TAuraNode.AddLabel(Parent: TControl; const Txt: String): TLabel; -begin - Result := TLabel.Create(Self); // Owner is the node itself - Result.Parent := Parent; - - Result.Position.Point := TPoint.Create(cNodePadding, cNodePadding); - Result.Margins.Left := cNodePadding; - Result.Margins.Right := cNodePadding; - Result.Margins.Top := cTitleTopPadding; - Result.Margins.Bottom := cTitleBottomPadding; - Result.WordWrap := false; - Result.AutoSize := True; // Let label determine its own size initially (do NOT use Align, because it will override AutoSize) - Result.HitTest := False; // Title label should not intercept clicks intended for the node - - Result.StyledSettings := Result.StyledSettings - [TStyledSetting.Style]; // Tell FMX not to manage Font.Style via styles - - Result.Text := Txt; - Result.ApplyStyleLookup; -end; - -procedure TAuraNode.AfterConstruction; -begin - inherited; - SetupNode; -end; - -function TAuraNode.CreateAst: IAstNode; -begin - // *** CHANGED: Delegate AST reconstruction to the handler *** - if Assigned(FHandler) then - Result := FHandler.ReconstructAst(Self) - else - Result := TAst.Nop; // Fallback if handler is missing -end; - -function TAuraNode.GetNode: IAstNode; -begin - // *** NEW: Get the logical node from the handler *** - if Assigned(FHandler) then - Result := FHandler.Node - else - Result := nil; -end; - -procedure TAuraNode.Paint; -var - rect: TRectF; -begin - inherited; // Allow styled painting to occur first (if any) - - // Clear background before drawing custom border/fill - Canvas.Fill.Kind := TBrushKind.None; // Make sure default fill is cleared if needed - - if FFrameless then - begin - Canvas.Fill.Kind := TBrushKind.Solid; - Canvas.Fill.Color := FBackgroundColor; - Canvas.Stroke.Kind := TBrushKind.None; - Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); - Canvas.Stroke.Kind := TBrushKind.Solid; - Canvas.Stroke.Color := FBorderColor; - Canvas.Stroke.Thickness := FBorderWidth; - Canvas.Stroke.Dash := TStrokeDash.Dot; - Canvas.DrawRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); - end - else - begin - // Draw background fill first - Canvas.Fill.Kind := TBrushKind.Solid; - Canvas.Fill.Color := FBackgroundColor; - rect := TRectF.Create(0, 0, Width, Height); - // Inflate inwards slightly if border exists to avoid overlap issues - if (FBorderWidth > 0) then - rect.Inflate(-FBorderWidth / 2, -FBorderWidth / 2); - Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); - - // Custom painting for the border - if (FBorderWidth > 0) and (FBorderColor <> TAlphaColors.Null) then - begin - rect := TRectF.Create(0, 0, Width, Height); - // Inflate inwards so the border is fully visible within the control's bounds - rect.Inflate(-FBorderWidth / 2, -FBorderWidth / 2); - - Canvas.Stroke.Kind := TBrushKind.Solid; - Canvas.Stroke.Color := FBorderColor; - Canvas.Stroke.Thickness := FBorderWidth; - Canvas.Stroke.Dash := TStrokeDash.Solid; - Canvas.DrawRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); - end; - end; -end; - -procedure TAuraNode.SetBorderColor(const Value: TAlphaColor); -begin - if FBorderColor <> Value then - begin - FBorderColor := Value; - Repaint; - end; -end; - -procedure TAuraNode.SetBorderRadius(const Value: Single); -begin - if FBorderRadius <> Value then - begin - FBorderRadius := Value; - Repaint; - end; -end; - -procedure TAuraNode.SetBorderWidth(const Value: Single); -begin - if FBorderWidth <> Value then - begin - FBorderWidth := Value; - Repaint; - end; -end; - -procedure TAuraNode.SetFrameless(const Value: Boolean); -begin - if FFrameless <> Value then - begin - FFrameless := Value; - Repaint; - end; -end; - -procedure TAuraNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); -begin - inherited; - if Button = TMouseButton.mbLeft then - begin - // Only start dragging if the click is on the node itself, not its children - var LControl := ObjectAtPoint(LocalToScreen(TPointF.Create(X, Y))); - if Assigned(LControl) and (LControl.GetObject = Self) then - begin - FIsDragging := True; - FDownPos := TPointF.Create(X, Y); - Capture; - BringToFront; // Bring node to front when dragging starts - end - else - FIsDragging := False; // Ensure dragging stops if click is on a child - end; -end; - -procedure TAuraNode.MouseMove(Shift: TShiftState; X, Y: Single); -begin - inherited; - - if FIsDragging then - begin - var deltaX := X - FDownPos.X; - var deltaY := Y - FDownPos.Y; - - Position.X := Position.X + deltaX; - Position.Y := Position.Y + deltaY; - - if ParentControl <> nil then - ParentControl.Repaint; // Repaint the workspace to update connections - end; -end; - -procedure TAuraNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); -begin - inherited; - if (Button = TMouseButton.mbLeft) and (FIsDragging) then - begin - ReleaseCapture; - FIsDragging := False; - if ParentControl <> nil then // Repaint one last time after drag ends - ParentControl.Repaint; - end; -end; - -procedure TAuraNode.SetBackgroundColor(const Value: TAlphaColor); -begin - FBackgroundColor := Value; - Repaint; -end; - -procedure TAuraNode.SetupNode; -begin - if Assigned(FHandler) then - FHandler.BuildUI(Self); -end; - -{ TConstantNodeHandler } - -constructor TConstantNodeHandler.Create(const ANode: IConstantNode); -begin - inherited Create; - FNode := ANode; -end; - -function TConstantNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TConstantNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - valueStr: string; - isConcise: Boolean; -begin - OwnerNode.BeginUpdate; - try - valueStr := FNode.Value.ToString; - // Check if it's a number or a single-line text and not excessively long - isConcise := ((FNode.Value.Kind = TDataValueKind.vkScalar) or (Pos(sLineBreak, valueStr) = 0)) and (Length(valueStr) < 40); - - if isConcise then - begin - // Display value directly in a centered label, frameless node - OwnerNode.Frameless := true; - OwnerNode.AddLabel(OwnerNode, valueStr); - end - else - begin - // Use standard framed node with Title label + Value label - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - - var titleLabel := OwnerNode.AddLabel(OwnerNode, 'Const'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - - // Value Label - var valueLabel := OwnerNode.AddLabel(OwnerNode, valueStr); - valueLabel.AutoSize := False; - valueLabel.WordWrap := True; - end; - finally - OwnerNode.EndUpdate; - end; -end; - -function TConstantNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Reuse Identity: FNode.Identity.AsConstant - Result := TAst.Constant(FNode.Identity.AsConstant, FNode.StaticType); -end; - -{ TIdentifierNodeHandler } - -constructor TIdentifierNodeHandler.Create(const ANode: IIdentifierNode); -begin - inherited Create; - FNode := ANode; -end; - -function TIdentifierNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TIdentifierNodeHandler.BuildUI(OwnerNode: TAuraNode); -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := true; // Identifiers are frameless - OwnerNode.AddLabel(OwnerNode, FNode.Name); // Add label with the identifier name - finally - OwnerNode.EndUpdate; - end; -end; - -function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Reusing identity guarantees the same name and source location - Result := TAst.Identifier(FNode.Identity.AsNamed, FNode.Address, FNode.StaticType); -end; - -{ TKeywordNodeHandler } - -constructor TKeywordNodeHandler.Create(const ANode: IKeywordNode); -begin - inherited Create; - FNode := ANode; -end; - -function TKeywordNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TKeywordNodeHandler.BuildUI(OwnerNode: TAuraNode); -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := true; - var lbl := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Value.Name); - lbl.StyledSettings := lbl.StyledSettings - [TStyledSetting.FontColor]; - lbl.FontColor := TAlphaColors.Mediumvioletred; - finally - OwnerNode.EndUpdate; - end; -end; - -function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.Keyword(FNode.Identity.AsKeyword); -end; - -{ TBlockExpressionNodeHandler } - -constructor TBlockExpressionNodeHandler.Create(const ANode: IBlockExpressionNode); -begin - inherited Create; - FNode := ANode; - FChildNodes := TList.Create; -end; - -destructor TBlockExpressionNodeHandler.Destroy; -begin - FChildNodes.Free; - inherited Destroy; -end; - -function TBlockExpressionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - childNode: TAuraNode; - expr: IAstNode; - titleLabel: TLabel; - i: Integer; - returnContainer: TAutoFitControl; - visuReturn: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := true; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - - for i := 0 to High(FNode.Expressions) do - begin - expr := FNode.Expressions[i]; - - if i = High(FNode.Expressions) then - begin - returnContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - titleLabel := OwnerNode.AddLabel(returnContainer, 'return'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - visuReturn := OwnerNode.Visualizer.Clone(returnContainer, OwnerNode.Visualizer.ExprDepth + 1); - childNode := visuReturn.CallAccept(expr); - FChildNodes.Add(childNode); - end - else - begin - childNode := visu.CallAccept(expr); - FChildNodes.Add(childNode); - end; - end; - finally - OwnerNode.EndUpdate; - end; -end; - -function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - exprs: TArray; - childNode: TAuraNode; - i: Integer; -begin - SetLength(exprs, FChildNodes.Count); - for i := 0 to FChildNodes.Count - 1 do - begin - childNode := FChildNodes[i]; - if Assigned(childNode) then - exprs[i] := childNode.CreateAst - else - exprs[i] := TAst.Nop; // Use Nop as placeholder - end; - - // Reuse structural identity - Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType); -end; - -{ TIfExpressionNodeHandler } - -constructor TIfExpressionNodeHandler.Create(const ANode: IIfExpressionNode); -begin - inherited Create; - FNode := ANode; - FElseNode := nil; -end; - -function TIfExpressionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TIfExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - - FConditionNode := OwnerNode.AddExpr(OwnerNode, 'if', FNode.Condition); - FThenNode := OwnerNode.AddExpr(OwnerNode, 'then', FNode.ThenBranch); - if Assigned(FNode.ElseBranch) then - FElseNode := OwnerNode.AddExpr(OwnerNode, 'else', FNode.ElseBranch); - finally - OwnerNode.EndUpdate; - end; -end; - -function TIfExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - elseAst: IAstNode; -begin - if Assigned(FElseNode) then - elseAst := FElseNode.CreateAst - else - elseAst := nil; - - Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType); -end; - -{ TTernaryExpressionNodeHandler } - -constructor TTernaryExpressionNodeHandler.Create(const ANode: ITernaryExpressionNode); -begin - inherited Create; - FNode := ANode; -end; - -function TTernaryExpressionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TTernaryExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FConditionNode := visu.CallAccept(FNode.Condition); - OwnerNode.AddLabel(OwnerNode, '?'); - FThenNode := visu.CallAccept(FNode.ThenBranch); - OwnerNode.AddLabel(OwnerNode, ':'); - FElseNode := visu.CallAccept(FNode.ElseBranch); - finally - OwnerNode.EndUpdate; - end; -end; - -function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.TernaryExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst, FNode.StaticType); -end; - -{ TLambdaExpressionNodeHandler } - -constructor TLambdaExpressionNodeHandler.Create(const ANode: ILambdaExpressionNode); -begin - inherited Create; - FNode := ANode; - FParamLabels := TList.Create; -end; - -destructor TLambdaExpressionNodeHandler.Destroy; -begin - FParamLabels.Free; - inherited Destroy; -end; - -function TLambdaExpressionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleContainer: TAutoFitControl; - paramLabel: TLabel; - i: Integer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, 0); // Reset depth for body - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - OwnerNode.BackgroundColor := $090000ff; - - titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - - paramLabel := OwnerNode.AddLabel(titleContainer, 'fn'); // ASCII replacement for Lambda - paramLabel.Font.Style := paramLabel.Font.Style + [TFontStyle.fsBold]; - FParamLabels.Add(paramLabel); // Add to list (though not really needed for CreateAst) - - paramLabel := OwnerNode.AddLabel(titleContainer, '('); - FParamLabels.Add(paramLabel); - - for i := 0 to High(FNode.Parameters) do - begin - paramLabel := OwnerNode.AddLabel(titleContainer, FNode.Parameters[i].Name); - FParamLabels.Add(paramLabel); - - if i < High(FNode.Parameters) then - begin - paramLabel := OwnerNode.AddLabel(titleContainer, ','); - FParamLabels.Add(paramLabel); - end; - end; - - paramLabel := OwnerNode.AddLabel(titleContainer, ')'); - FParamLabels.Add(paramLabel); - - FBodyNode := visu.CallAccept(FNode.Body); - FBodyNode.Frameless := false; - - finally - OwnerNode.EndUpdate; - end; -end; - -function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Params are read from FNode (assuming they are not editable via UI labels for now) - // Reuse Identity & Metadata - Result := - TAst.LambdaExpr( - FNode.Identity, - FNode.Parameters, - FBodyNode.CreateAst, - FNode.Layout, - FNode.Descriptor, - FNode.Upvalues, - FNode.HasNestedLambdas, - FNode.IsPure, - FNode.StaticType - ); -end; - -{ TFunctionCallNodeHandler } - -constructor TFunctionCallNodeHandler.Create(const ANode: IFunctionCallNode); -begin - inherited Create; - FNode := ANode; - FArgumentNodes := TList.Create; -end; - -destructor TFunctionCallNodeHandler.Destroy; -begin - FArgumentNodes.Free; - inherited Destroy; -end; - -function TFunctionCallNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - i: Integer; - argNode: TAuraNode; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - - var callLabel := OwnerNode.AddLabel(OwnerNode, 'call '); - callLabel.Font.Style := callLabel.Font.Style + [TFontStyle.fsBold]; - - FCalleeNode := visu.CallAccept(FNode.Callee); - - if Length(FNode.Arguments) > 0 then - begin - OwnerNode.AddLabel(OwnerNode, '('); - for i := 0 to High(FNode.Arguments) do - begin - argNode := visu.CallAccept(FNode.Arguments[i]); - FArgumentNodes.Add(argNode); - if i < High(FNode.Arguments) then - OwnerNode.AddLabel(OwnerNode, ','); - end; - OwnerNode.AddLabel(OwnerNode, ')'); - end; - finally - OwnerNode.EndUpdate; - end; -end; - -function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - args: TArray; - i: Integer; -begin - SetLength(args, FArgumentNodes.Count); - for i := 0 to FArgumentNodes.Count - 1 do - args[i] := FArgumentNodes[i].CreateAst; - - Result := - TAst.FunctionCall( - FNode.Identity, - FCalleeNode.CreateAst, - args, - FNode.StaticType, - FNode.IsTailCall, - FNode.StaticTarget, - FNode.IsTargetPure - ); -end; - -{ TMacroExpansionNodeHandler } - -constructor TMacroExpansionNodeHandler.Create(const ANode: IMacroExpansionNode); -begin - inherited Create; - FNode := ANode; -end; - -function TMacroExpansionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Expansion'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - FExpandedBodyNode := visu.CallAccept(FNode.ExpandedBody); - finally - OwnerNode.EndUpdate; - end; -end; - -function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := - TAst.MacroExpansionNode( - FNode.Identity, - FNode.CallNode, - FExpandedBodyNode.CreateAst.AsTypedNode // TODO: Check if AsTypedNode is correct/safe - ); -end; - -{ TRecurNodeHandler } - -constructor TRecurNodeHandler.Create(const ANode: IRecurNode); -begin - inherited Create; - FNode := ANode; - FArgumentNodes := TList.Create; -end; - -destructor TRecurNodeHandler.Destroy; -begin - FArgumentNodes.Free; - inherited Destroy; -end; - -function TRecurNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TRecurNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - i: Integer; - argNode: TAuraNode; - titleLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - - titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); // ASCII text - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - - OwnerNode.AddLabel(OwnerNode, '('); - for i := 0 to High(FNode.Arguments) do - begin - argNode := visu.CallAccept(FNode.Arguments[i]); - FArgumentNodes.Add(argNode); - if i < High(FNode.Arguments) then - OwnerNode.AddLabel(OwnerNode, ','); - end; - OwnerNode.AddLabel(OwnerNode, ')'); - finally - OwnerNode.EndUpdate; - end; -end; - -function TRecurNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - args: TArray; - i: Integer; -begin - SetLength(args, FArgumentNodes.Count); - for i := 0 to FArgumentNodes.Count - 1 do - args[i] := FArgumentNodes[i].CreateAst; - Result := TAst.Recur(FNode.Identity, args, FNode.StaticType); -end; - -{ TVariableDeclarationNodeHandler } - -constructor TVariableDeclarationNodeHandler.Create(const ANode: IVariableDeclarationNode); -begin - inherited Create; - FNode := ANode; - FInitializerNode := nil; -end; - -function TVariableDeclarationNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TVariableDeclarationNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - varLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - - varLabel := OwnerNode.AddLabel(OwnerNode, 'var'); - - varLabel.Font.Style := varLabel.Font.Style + [TFontStyle.fsBold]; - FTargetNode := visu.CallAccept(FNode.Target); - - if Assigned(FNode.Initializer) then - begin - OwnerNode.AddLabel(OwnerNode, ':='); - FInitializerNode := visu.CallAccept(FNode.Initializer); - end; - finally - OwnerNode.EndUpdate; - end; -end; - -function TVariableDeclarationNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - initAst: IAstNode; -begin - if Assigned(FInitializerNode) then - initAst := FInitializerNode.CreateAst - else - initAst := nil; - Result := TAst.VarDecl(FNode.Identity, FTargetNode.CreateAst, initAst, FNode.StaticType, FNode.IsBoxed); -end; - -{ TAssignmentNodeHandler } - -constructor TAssignmentNodeHandler.Create(const ANode: IAssignmentNode); -begin - inherited Create; - FNode := ANode; -end; - -function TAssignmentNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TAssignmentNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FTargetNode := visu.CallAccept(FNode.Target); - OwnerNode.AddLabel(OwnerNode, ':='); - FValueNode := visu.CallAccept(FNode.Value); - finally - OwnerNode.EndUpdate; - end; -end; - -function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.Assign(FNode.Identity, FTargetNode.CreateAst, FValueNode.CreateAst, FNode.StaticType); -end; - -{ TMacroDefinitionNodeHandler } - -constructor TMacroDefinitionNodeHandler.Create(const ANode: IMacroDefinitionNode); -begin - inherited Create; - FNode := ANode; -end; - -function TMacroDefinitionNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleLabel: TLabel; - paramStr: string; - i: Integer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - - paramStr := ''; - for i := 0 to High(FNode.Parameters) do - begin - if i > 0 then - paramStr := paramStr + ', '; - paramStr := paramStr + FNode.Parameters[i].Name; - end; - - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Def: ' + FNode.Name.Name + ' (' + paramStr + ')'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - - FBodyNode := visu.CallAccept(FNode.Body); - finally - OwnerNode.EndUpdate; - end; -end; - -function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Note: Identifier is recreated from raw name here, losing Location if we don't be careful. - // Ideally FNode.Name would be reused. - // For now, we reconstruct the MacroDef using the original identity and parameters. - Result := - TAst.MacroDef( - FNode.Identity, - FNode.Name, // Reuse Identifier Node - FNode.Parameters, // Reuse Parameters - FBodyNode.CreateAst - ); -end; - -{ TQuasiquoteNodeHandler } - -constructor TQuasiquoteNodeHandler.Create(const ANode: IQuasiquoteNode); -begin - inherited Create; - FNode := ANode; -end; - -function TQuasiquoteNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TQuasiquoteNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - FExpressionNode := visu.CallAccept(FNode.Expression); - finally - OwnerNode.EndUpdate; - end; -end; - -function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.Quasiquote(FNode.Identity, FExpressionNode.CreateAst); -end; - -{ TUnquoteNodeHandler } - -constructor TUnquoteNodeHandler.Create(const ANode: IUnquoteNode); -begin - inherited Create; - FNode := ANode; -end; - -function TUnquoteNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TUnquoteNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - - var leftBracket := OwnerNode.AddLabel(OwnerNode, '<'); - leftBracket.Padding.Right := 0; - leftBracket.Margins.Right := 0; - - FExpressionNode := visu.CallAccept(FNode.Expression); - - var rightBracket := OwnerNode.AddLabel(OwnerNode, '>'); - rightBracket.Padding.Left := 0; - rightBracket.Margins.Left := 0; - finally - OwnerNode.EndUpdate; - end; -end; - -function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.Unquote(FNode.Identity, FExpressionNode.CreateAst); -end; - -{ TUnquoteSplicingNodeHandler } - -constructor TUnquoteSplicingNodeHandler.Create(const ANode: IUnquoteSplicingNode); -begin - inherited Create; - FNode := ANode; -end; - -function TUnquoteSplicingNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TUnquoteSplicingNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - // Note: FNode.Expression is a IQuasiquoteNode - FExpressionNode := visu.CallAccept(FNode.Expression); - finally - OwnerNode.EndUpdate; - end; -end; - -function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Note: We assume the child node is still a QuasiquoteNode. If user changed it to something else, - // this cast might fail or we need validation logic. - Result := TAst.UnquoteSplicing(FNode.Identity, FExpressionNode.CreateAst.AsQuasiquote); -end; - -{ TIndexerNodeHandler } - -constructor TIndexerNodeHandler.Create(const ANode: IIndexerNode); -begin - inherited Create; - FNode := ANode; -end; - -function TIndexerNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TIndexerNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FBaseNode := visu.CallAccept(FNode.Base); - OwnerNode.AddLabel(OwnerNode, '['); - FIndexNode := visu.CallAccept(FNode.Index); - OwnerNode.AddLabel(OwnerNode, ']'); - finally - OwnerNode.EndUpdate; - end; -end; - -function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.Indexer(FNode.Identity, FBaseNode.CreateAst, FIndexNode.CreateAst, FNode.StaticType); -end; - -{ TMemberAccessNodeHandler } - -constructor TMemberAccessNodeHandler.Create(const ANode: IMemberAccessNode); -begin - inherited Create; - FNode := ANode; -end; - -function TMemberAccessNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TMemberAccessNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FBaseNode := visu.CallAccept(FNode.Base); - OwnerNode.AddLabel(OwnerNode, '.'); - OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name); - finally - OwnerNode.EndUpdate; - end; -end; - -function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Reuse Identifier, Reuse Member Keyword (via TAst.Keyword with Identity) - Result := TAst.MemberAccess(FNode.Identity, FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Identity.AsKeyword), FNode.StaticType); -end; - -{ TRecordLiteralNodeHandler } - -constructor TRecordLiteralNodeHandler.Create(const ANode: IRecordLiteralNode); -begin - inherited Create; - FNode := ANode; - FFieldNodes := TDictionary.Create; -end; - -destructor TRecordLiteralNodeHandler.Destroy; -begin - FFieldNodes.Free; - inherited Destroy; -end; - -function TRecordLiteralNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - field: TRecordFieldLiteral; - fieldContainer: TAutoFitControl; - valueNode: TAuraNode; - keyLabel: TLabel; -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - - if Length(FNode.Fields) = 0 then - begin - OwnerNode.AddLabel(OwnerNode, '{}'); - end - else - begin - for field in FNode.Fields do - begin - fieldContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - keyLabel := OwnerNode.AddLabel(fieldContainer, ':' + field.Key.Value.Name); - keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold]; - keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor]; - keyLabel.FontColor := TAlphaColors.Mediumvioletred; - - valueNode := OwnerNode.Visualizer.Clone(fieldContainer, OwnerNode.Visualizer.ExprDepth + 1).CallAccept(field.Value); - FFieldNodes.Add(field.Key.Value, valueNode); - end; - end; - finally - OwnerNode.EndUpdate; - end; -end; - -function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - fields: TArray; - i: Integer; - valueNode: TAuraNode; - pair: TPair; -begin - SetLength(fields, FFieldNodes.Count); - i := 0; - for pair in FFieldNodes do - begin - valueNode := pair.Value; - // Note: We construct a new keyword node here for the key, losing location unless we stored it. - // For simplicity, we use Creation Path for the Key, but Reuse Identity for the RecordLiteral itself. - fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst); - inc(i); - end; - Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType); -end; - -{ TCreateSeriesNodeHandler } - -constructor TCreateSeriesNodeHandler.Create(const ANode: ICreateSeriesNode); -begin - inherited Create; - FNode := ANode; -end; - -function TCreateSeriesNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TCreateSeriesNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - titleLabel: TLabel; -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Create Series: ' + FNode.Definition); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - finally - OwnerNode.EndUpdate; - end; -end; - -function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - // Identity.AsDefinition check needed? Or trust CreateSeries overload - Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType); -end; - -{ TAddSeriesItemNodeHandler } - -constructor TAddSeriesItemNodeHandler.Create(const ANode: IAddSeriesItemNode); -begin - inherited Create; - FNode := ANode; - FLookbackNode := nil; -end; - -function TAddSeriesItemNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TAddSeriesItemNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - visu: IAstVisualizer; - titleLabel: TLabel; -begin - visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - - FValueNode := visu.CallAccept(FNode.Value); - if Assigned(FNode.Lookback) then - FLookbackNode := visu.CallAccept(FNode.Lookback); - finally - OwnerNode.EndUpdate; - end; -end; - -function TAddSeriesItemNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -var - lookbackAst: IAstNode; -begin - if Assigned(FLookbackNode) then - lookbackAst := FLookbackNode.CreateAst - else - lookbackAst := nil; - - // Reusing identifier identity requires access to it. - // Here we create a new identifier with same name but lose location of series ident. - // Optimization: FNode.Series is available, we can reuse it! - - // Wait, TAst.AddSeriesItem takes IIdentifierNode. We can just reuse FNode.Series? - // Yes, if the series name is not editable in UI. - - Result := - TAst.AddSeriesItem( - FNode.Identity, - FNode.Series, // Reuse original Series Identifier Node - FValueNode.CreateAst, - lookbackAst, - FNode.StaticType - ); -end; - -{ TSeriesLengthNodeHandler } - -constructor TSeriesLengthNodeHandler.Create(const ANode: ISeriesLengthNode); -begin - inherited Create; - FNode := ANode; -end; - -function TSeriesLengthNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TSeriesLengthNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - titleLabel: TLabel; -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - finally - OwnerNode.EndUpdate; - end; -end; - -function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := TAst.SeriesLength(FNode.Identity, FNode.Series, FNode.StaticType); -end; - -{ TNopNodeHandler } - -constructor TNopNodeHandler.Create(const ANode: INopNode); -begin - inherited Create; - FNode := ANode; -end; - -function TNopNodeHandler.GetAstNode: IAstNode; -begin - Result := FNode; -end; - -procedure TNopNodeHandler.BuildUI(OwnerNode: TAuraNode); -var - lbl: TLabel; -begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := true; - OwnerNode.Alignment := TLayoutAlignment.laCenter; - OwnerNode.Orientation := TLayoutOrientation.loHorizontal; - lbl := OwnerNode.AddLabel(OwnerNode, '...'); - lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; - lbl.Margins.Rect := TRectF.Create(8, 4, 8, 4); - finally - OwnerNode.EndUpdate; - end; -end; - -function TNopNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; -begin - Result := FNode; -end; - -end. diff --git a/ASTPlayground/Myc.Fmx.AstEditor.Text.pas b/ASTPlayground/Myc.Fmx.AstEditor.Text.pas deleted file mode 100644 index 6df89da..0000000 --- a/ASTPlayground/Myc.Fmx.AstEditor.Text.pas +++ /dev/null @@ -1,265 +0,0 @@ -unit Myc.Fmx.AstEditor.Text; - -interface - -uses - System.SysUtils, - Myc.Data.Value, - Myc.Data.Scalar, - Myc.Ast.Visitor, - Myc.Ast.Nodes; - -type - // This visitor converts an AST expression subtree into a single string. - // It inherits from the generic visitor, returning a 'string' for each node. - TAstToTextVisitor = class(TAstVisitor) - protected - function VisitConstant(const Node: IConstantNode): string; override; - function VisitIdentifier(const Node: IIdentifierNode): string; override; - function VisitKeyword(const Node: IKeywordNode): string; override; - function VisitIfExpression(const Node: IIfExpressionNode): string; override; - function VisitTernaryExpression(const Node: ITernaryExpressionNode): string; override; - function VisitLambdaExpression(const Node: ILambdaExpressionNode): string; override; - function VisitMacroDefinition(const Node: IMacroDefinitionNode): string; override; - function VisitFunctionCall(const Node: IFunctionCallNode): string; override; - function VisitMacroExpansionNode(const Node: IMacroExpansionNode): string; override; - function VisitBlockExpression(const Node: IBlockExpressionNode): string; override; - function VisitVariableDeclaration(const Node: IVariableDeclarationNode): string; override; - function VisitAssignment(const Node: IAssignmentNode): string; override; - function VisitIndexer(const Node: IIndexerNode): string; override; - function VisitMemberAccess(const Node: IMemberAccessNode): string; override; - function VisitQuasiquote(const Node: IQuasiquoteNode): string; override; - function VisitUnquote(const Node: IUnquoteNode): string; override; - function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): string; override; - function VisitCreateSeries(const Node: ICreateSeriesNode): string; override; - function VisitAddSeriesItem(const Node: IAddSeriesItemNode): string; override; - function VisitSeriesLength(const Node: ISeriesLengthNode): string; override; - function VisitRecurNode(const Node: IRecurNode): string; override; - function VisitRecordLiteral(const Node: IRecordLiteralNode): string; override; - end; - -implementation - -uses - System.Classes, // For TStringBuilder - Myc.Data.Keyword; - -{ TAstToTextVisitor } - -function TAstToTextVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): string; -var - seriesStr, valueStr, lookbackStr: string; -begin - seriesStr := Accept(Node.Series); - valueStr := Accept(Node.Value); - lookbackStr := ''; - if Assigned(Node.Lookback) then - lookbackStr := ', ' + Accept(Node.Lookback); - Result := Format('%s.add(%s%s)', [seriesStr, valueStr, lookbackStr]); -end; - -function TAstToTextVisitor.VisitAssignment(const Node: IAssignmentNode): string; -begin - Result := Accept(Node.Target) + ' := ' + Accept(Node.Value); -end; - -function TAstToTextVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): string; -begin - Result := '{...}'; -end; - -function TAstToTextVisitor.VisitConstant(const Node: IConstantNode): string; -begin - Result := Node.Value.ToString; -end; - -function TAstToTextVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): string; -begin - Result := 'new series(' + Node.Definition + ')'; -end; - -function TAstToTextVisitor.VisitFunctionCall(const Node: IFunctionCallNode): string; -var - i: Integer; - sb: TStringBuilder; - calleeStr: string; -begin - calleeStr := Accept(Node.Callee); - - sb := TStringBuilder.Create; - try - sb.Append(calleeStr); - sb.Append('('); - for i := 0 to High(Node.Arguments) do - begin - sb.Append(Accept(Node.Arguments[i])); - if i < High(Node.Arguments) then - sb.Append(', '); - end; - sb.Append(')'); - Result := sb.ToString; - finally - sb.Free; - end; -end; - -function TAstToTextVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode): string; -begin - // To represent a macro expansion as a single line of text, the most - // informative representation is the original call itself. We can simply - // delegate to the VisitFunctionCall implementation to format it. - Result := VisitFunctionCall(Node.CallNode); -end; - -function TAstToTextVisitor.VisitRecurNode(const Node: IRecurNode): string; -var - i: Integer; - sb: TStringBuilder; -begin - sb := TStringBuilder.Create; - try - sb.Append('recur('); - for i := 0 to High(Node.Arguments) do - begin - sb.Append(Accept(Node.Arguments[i])); - if i < High(Node.Arguments) then - sb.Append(', '); - end; - sb.Append(')'); - Result := sb.ToString; - finally - sb.Free; - end; -end; - -function TAstToTextVisitor.VisitIdentifier(const Node: IIdentifierNode): string; -begin - Result := Node.Name; -end; - -function TAstToTextVisitor.VisitIfExpression(const Node: IIfExpressionNode): string; -begin - Result := Accept(Node.Condition); -end; - -function TAstToTextVisitor.VisitIndexer(const Node: IIndexerNode): string; -var - baseStr, indexStr: string; -begin - baseStr := Accept(Node.Base); - indexStr := Accept(Node.Index); - Result := Format('%s[%s]', [baseStr, indexStr]); -end; - -function TAstToTextVisitor.VisitKeyword(const Node: IKeywordNode): string; -begin - Result := ':' + Node.Value.Name; -end; - -function TAstToTextVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): string; -var - i: Integer; - sb: TStringBuilder; -begin - sb := TStringBuilder.Create; - try - sb.Append(WideChar($03BB) + '('); // Lambda char - if Length(Node.Parameters) > 0 then - begin - for i := 0 to High(Node.Parameters) do - begin - sb.Append(Node.Parameters[i].Name); - if i < High(Node.Parameters) then - sb.Append(', '); - end; - end; - sb.Append(') => {...}'); - Result := sb.ToString; - finally - sb.Free; - end; -end; - -function TAstToTextVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): string; -var - i: Integer; - sb: TStringBuilder; -begin - // Added text representation for macro definitions. - sb := TStringBuilder.Create; - try - sb.Append('defmacro '); - sb.Append(Node.Name.Name); - sb.Append('('); - if Length(Node.Parameters) > 0 then - begin - for i := 0 to High(Node.Parameters) do - begin - sb.Append(Node.Parameters[i].Name); - if i < High(Node.Parameters) then - sb.Append(', '); - end; - end; - sb.Append(') => {...}'); - Result := sb.ToString; - finally - sb.Free; - end; -end; - -function TAstToTextVisitor.VisitMemberAccess(const Node: IMemberAccessNode): string; -var - baseStr: string; -begin - baseStr := Accept(Node.Base); - Result := Format('%s.%s', [baseStr, Node.Member.Value.Name]); -end; - -function TAstToTextVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): string; -begin - Result := '`' + Accept(Node.Expression); -end; - -function TAstToTextVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): string; -begin - Result := '{...}'; -end; - -function TAstToTextVisitor.VisitUnquote(const Node: IUnquoteNode): string; -begin - Result := '~' + Accept(Node.Expression); -end; - -function TAstToTextVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): string; -begin - Result := '~@' + Accept(Node.Expression); -end; - -function TAstToTextVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): string; -var - seriesStr: string; -begin - seriesStr := Accept(Node.Series); - Result := Format('length(%s)', [seriesStr]); -end; - -function TAstToTextVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): string; -begin - var condStr := Accept(Node.Condition); - var thenStr := Accept(Node.ThenBranch); - var elseStr := Accept(Node.ElseBranch); - Result := Format('(%s ? %s : %s)', [condStr, thenStr, elseStr]); -end; - -function TAstToTextVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): string; -var - initStr: string; -begin - if Assigned(Node.Initializer) then - initStr := ' := ' + Accept(Node.Initializer) - else - initStr := ''; - Result := 'var ' + Accept(Node.Target) + initStr; -end; - -end. diff --git a/Src/AST/Myc.Fmx.AstEditor.Core.pas b/Src/AST/Myc.Fmx.AstEditor.Core.pas new file mode 100644 index 0000000..83aee32 --- /dev/null +++ b/Src/AST/Myc.Fmx.AstEditor.Core.pas @@ -0,0 +1,706 @@ +unit Myc.Fmx.AstEditor.Core; + +interface + +uses + System.SysUtils, + System.Classes, + System.UITypes, + System.Types, + System.Math, + System.Math.Vectors, + System.Generics.Defaults, + System.Generics.Collections, + FMX.Types, + FMX.Controls, + FMX.Objects, + FMX.Graphics, + FMX.StdCtrls, + Myc.Ast.Nodes, + Myc.Fmx.AstEditor.Workspace; + +const + cNodePadding = 10; + cTitleTopPadding = 2; + cTitleBottomPadding = 4; + cMinNodeWidth = 10; + cMinNodeHeight = 10; + +type + TAuraNode = class; // Forward declaration + + // This aggregate interface encapsulates all node-specific logic. + IAuraNodeHandler = interface + // Gets the original logical AST node + function GetAstNode: IAstNode; + // Creates the specific FMX UI for this node + procedure BuildUI(OwnerNode: TAuraNode); + // Reconstructs the logical AST node from the FMX UI state + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; + // The original logical AST node + property Node: IAstNode read GetAstNode; + end; + + IAstVisualizer = interface + {$region 'private'} + function GetExprDepth: Integer; + function GetParentControl: TControl; + function GetWorkspace: TAuraWorkspace; + {$endregion} + + function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; + function CallAccept(const Node: IAstNode): TAuraNode; + + property ExprDepth: Integer read GetExprDepth; + property ParentControl: TControl read GetParentControl; + property Workspace: TAuraWorkspace read GetWorkspace; + end; + + // Defines the layout direction for children within TAutoFitControl + TLayoutOrientation = (loVertical, loHorizontal); + + // Defines the alignment of children on the cross-axis + TLayoutAlignment = (laCenter, laFlush); + + // A styled control that automatically adjusts its size to fit its children, including padding. + TAutoFitControl = class(TStyledControl) + private + FUpdatingOwnSize: Boolean; // Recursion guard + FNeedRecalcSize: Boolean; // Flag for EndUpdate + FOrientation: TLayoutOrientation; // Storage for Orientation + FAlignment: TLayoutAlignment; // Storage for Alignment + procedure RecalcOwnSize; + procedure SetOrientation(const Value: TLayoutOrientation); + procedure SetAlignment(const Value: TLayoutAlignment); + protected + procedure ParentContentChanged; override; + procedure PaddingChanged; override; + procedure ChangeChildren; override; + procedure Loaded; override; + procedure DoEndUpdate; override; + public + constructor Create(AOwner: TComponent); override; + + published + property Padding; + property Orientation: TLayoutOrientation read FOrientation write SetOrientation default TLayoutOrientation.loHorizontal; + property Alignment: TLayoutAlignment read FAlignment write SetAlignment default TLayoutAlignment.laCenter; + end; + + // A movable panel with a custom-painted border. Content (like title) is added externally. + TAuraNode = class(TAutoFitControl) + private + FBackgroundColor: TAlphaColor; + FIsDragging: Boolean; + FDownPos: TPointF; + FBorderColor: TAlphaColor; + FBorderWidth: Single; + FBorderRadius: Single; + FFrameless: Boolean; + FVisualizer: IAstVisualizer; + FHandler: IAuraNodeHandler; + + // --- Visual State Fields --- + FErrorMessage: string; + FTypeInfoText: string; + + procedure SetBackgroundColor(const Value: TAlphaColor); + procedure SetBorderColor(const Value: TAlphaColor); + procedure SetBorderWidth(const Value: Single); + procedure SetBorderRadius(const Value: Single); + procedure SetFrameless(const Value: Boolean); + function GetNode: IAstNode; + + // New Setters + procedure SetErrorMessage(const Value: string); + procedure SetTypeInfoText(const Value: string); + procedure UpdateVisualState; + + protected + procedure Paint; override; + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; + procedure MouseMove(Shift: TShiftState; X, Y: Single); override; + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; + procedure SetupNode; + + public + constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAuraNodeHandler); reintroduce; + destructor Destroy; override; + + procedure AfterConstruction; override; + + function AddLabel(Parent: TControl; const Txt: String): TLabel; + function AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; + function AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAuraNode; + + function CreateAst: IAstNode; + + property Visualizer: IAstVisualizer read FVisualizer; + property Node: IAstNode read GetNode; + + // --- Visual State Properties --- + property ErrorMessage: string read FErrorMessage write SetErrorMessage; + property TypeInfoText: string read FTypeInfoText write SetTypeInfoText; + + published + property BorderColor: TAlphaColor read FBorderColor write SetBorderColor; + property BorderWidth: Single read FBorderWidth write SetBorderWidth; + property BorderRadius: Single read FBorderRadius write SetBorderRadius; + property BackgroundColor: TAlphaColor read FBackgroundColor write SetBackgroundColor; + property Frameless: Boolean read FFrameless write SetFrameless; + + property Align; + property Anchors; + property ClipChildren default True; + property Cursor default crDefault; + property DragMode default TDragMode.dmManual; + property Enabled; + property Height; + property Hint; + property HitTest default True; + property Locked; + property Margins; + property Opacity; + property Padding; + property PopupMenu; + property Position; + property RotationAngle; + property RotationCenter; + property Scale; + property Size; + property Visible; + property Width; + property OnClick; + property OnDblClick; + property OnMouseDown; + property OnMouseMove; + property OnMouseUp; + property OnMouseWheel; + property OnMouseEnter; + property OnMouseLeave; + end; + + // Helper base class to reduce boilerplate in specific handlers + TBaseNodeHandler = class(TInterfacedObject, IAuraNodeHandler) + protected + FNode: T; + function GetAstNode: IAstNode; + public + constructor Create(const ANode: T); + procedure BuildUI(OwnerNode: TAuraNode); virtual; abstract; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; virtual; abstract; + end; + +implementation + +uses + Myc.Ast; + +{ TAutoFitControl } + +constructor TAutoFitControl.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + HitTest := True; + FOrientation := TLayoutOrientation.loHorizontal; + FAlignment := TLayoutAlignment.laCenter; +end; + +procedure TAutoFitControl.SetAlignment(const Value: TLayoutAlignment); +begin + if FAlignment <> Value then + begin + FAlignment := Value; + RecalcOwnSize; + end; +end; + +procedure TAutoFitControl.SetOrientation(const Value: TLayoutOrientation); +begin + if FOrientation <> Value then + begin + FOrientation := Value; + RecalcOwnSize; + end; +end; + +procedure TAutoFitControl.RecalcOwnSize; +var + i: Integer; + child: TControl; + childrenToLayout: TList; + currentX, currentY: Single; + requiredWidth, requiredHeight: Single; + childWidthWithMargins, childHeightWithMargins: Single; + hasVisibleChild: Boolean; +begin + if FUpdatingOwnSize then + exit; + if IsUpdating then + begin + FNeedRecalcSize := True; + exit; + end; + + FUpdatingOwnSize := True; + childrenToLayout := nil; + try + requiredWidth := Padding.Left + Padding.Right; + requiredHeight := Padding.Top + Padding.Bottom; + currentX := Padding.Left; + currentY := Padding.Top; + hasVisibleChild := False; + + childrenToLayout := TList.Create; + for i := 0 to ChildrenCount - 1 do + begin + if Children[i] is TControl then + begin + child := TControl(Children[i]); + if child.Visible and (child.Align = TAlignLayout.None) then + begin + childrenToLayout.Add(child); + hasVisibleChild := True; + end; + end; + end; + + if hasVisibleChild then + begin + if FOrientation = TLayoutOrientation.loVertical then + begin + for child in childrenToLayout do + begin + child.Position.Y := currentY + child.Margins.Top; + currentY := child.Position.Y + child.Height + child.Margins.Bottom; + + childWidthWithMargins := Padding.Left + child.Margins.Left + child.Width + child.Margins.Right + Padding.Right; + requiredWidth := System.Math.Max(requiredWidth, childWidthWithMargins); + end; + requiredHeight := currentY + Padding.Bottom; + + if FAlignment = TLayoutAlignment.laFlush then + begin + for child in childrenToLayout do + begin + child.Position.X := Padding.Left + child.Margins.Left; + end; + end + else + begin + var contentWidth := requiredWidth - Padding.Left - Padding.Right; + for child in childrenToLayout do + begin + var childTotalWidth := child.Width + child.Margins.Left + child.Margins.Right; + var childX := Padding.Left + ((contentWidth - childTotalWidth) / 2) + child.Margins.Left; + child.Position.X := childX; + end; + end; + end + else + begin + for child in childrenToLayout do + begin + child.Position.X := currentX + child.Margins.Left; + currentX := child.Position.X + child.Width + child.Margins.Right; + + childHeightWithMargins := Padding.Top + child.Margins.Top + child.Height + child.Margins.Bottom + Padding.Bottom; + requiredHeight := System.Math.Max(requiredHeight, childHeightWithMargins); + end; + requiredWidth := currentX + Padding.Right; + + if FAlignment = TLayoutAlignment.laFlush then + begin + for child in childrenToLayout do + begin + child.Position.Y := Padding.Top + child.Margins.Top; + end; + end + else + begin + var contentHeight := requiredHeight - Padding.Top - Padding.Bottom; + for child in childrenToLayout do + begin + var childTotalHeight := child.Height + child.Margins.Top + child.Margins.Bottom; + var childY := Padding.Top + ((contentHeight - childTotalHeight) / 2) + child.Margins.Top; + child.Position.Y := childY; + end; + end; + end; + end + else + begin + requiredWidth := Padding.Left + Padding.Right; + requiredHeight := Padding.Top + Padding.Bottom; + end; + + requiredWidth := System.Math.Max(0, requiredWidth); + requiredHeight := System.Math.Max(0, requiredHeight); + + if not SameValue(requiredWidth, Width, TEpsilon.Position) or not SameValue(requiredHeight, Height, TEpsilon.Position) then + begin + FSize.SetSizeWithoutNotification(TSizeF.Create(requiredWidth, requiredHeight)); + HandleSizeChanged; + end; + + finally + childrenToLayout.Free; + FUpdatingOwnSize := False; + end; +end; + +procedure TAutoFitControl.Loaded; +begin + inherited Loaded; + RecalcOwnSize; +end; + +procedure TAutoFitControl.ChangeChildren; +begin + inherited ChangeChildren; + RecalcOwnSize; +end; + +procedure TAutoFitControl.PaddingChanged; +begin + inherited PaddingChanged; + RecalcOwnSize; +end; + +procedure TAutoFitControl.ParentContentChanged; +begin + inherited ParentContentChanged; + RecalcOwnSize; +end; + +procedure TAutoFitControl.DoEndUpdate; +begin + inherited; + if FNeedRecalcSize then + begin + FNeedRecalcSize := False; + RecalcOwnSize; + end; +end; + +{ TAuraNode } + +constructor TAuraNode.Create(const AVisualizer: IAstVisualizer; const AHandler: IAuraNodeHandler); +begin + inherited Create(AVisualizer.Workspace); + + Parent := AVisualizer.ParentControl; + + FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth); + FHandler := AHandler; + + FIsDragging := False; + + FBorderColor := TAlphaColors.Gray; + FBorderWidth := 1; + FBorderRadius := 9; + FBackgroundColor := $080a0a0a; + + FFrameless := False; + + Width := cMinNodeWidth; + Height := cMinNodeHeight; + + HitTest := True; + ClipChildren := True; + + Margins.Left := 4; + Margins.Top := 4; + Margins.Right := 4; + Margins.Bottom := 4; + Padding.Left := 3; + Padding.Top := 3; + Padding.Right := 3; + Padding.Bottom := 3; + + var cn: Cardinal := $ea - (7 * FVisualizer.ExprDepth); + var c: Cardinal := $ff000000 or (cn shl 16) or (cn shl 8) or cn; + BackgroundColor := c; +end; + +destructor TAuraNode.Destroy; +begin + FHandler := nil; + inherited; +end; + +function TAuraNode.AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; +begin + Result := TAutoFitControl.Create(Self); + Result.Parent := Parent; + Result.Orientation := Orientation; + Result.Alignment := Alignment; + Result.HitTest := False; +end; + +function TAuraNode.AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAuraNode; +begin + var cont := AddContainer(Parent, loHorizontal, laCenter); + + var lbl := AddLabel(cont, Title); + lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; + + Result := FVisualizer.Clone(cont, FVisualizer.ExprDepth + 1).CallAccept(Node); +end; + +function TAuraNode.AddLabel(Parent: TControl; const Txt: String): TLabel; +begin + Result := TLabel.Create(Self); + Result.Parent := Parent; + + Result.Position.Point := TPoint.Create(cNodePadding, cNodePadding); + Result.Margins.Left := cNodePadding; + Result.Margins.Right := cNodePadding; + Result.Margins.Top := cTitleTopPadding; + Result.Margins.Bottom := cTitleBottomPadding; + Result.WordWrap := False; + Result.AutoSize := True; + Result.HitTest := False; + + Result.StyledSettings := Result.StyledSettings - [TStyledSetting.Style]; + + Result.Text := Txt; + Result.ApplyStyleLookup; +end; + +procedure TAuraNode.AfterConstruction; +begin + inherited; + SetupNode; +end; + +function TAuraNode.CreateAst: IAstNode; +begin + if Assigned(FHandler) then + Result := FHandler.ReconstructAst(Self) + else + Result := TAst.Nop; +end; + +function TAuraNode.GetNode: IAstNode; +begin + if Assigned(FHandler) then + Result := FHandler.Node + else + Result := nil; +end; + +procedure TAuraNode.SetErrorMessage(const Value: string); +begin + if FErrorMessage <> Value then + begin + FErrorMessage := Value; + UpdateVisualState; + Repaint; + end; +end; + +procedure TAuraNode.SetTypeInfoText(const Value: string); +begin + if FTypeInfoText <> Value then + begin + FTypeInfoText := Value; + UpdateVisualState; + // Type Info usually doesn't change painting, just hint + end; +end; + +procedure TAuraNode.UpdateVisualState; +begin + if FErrorMessage <> '' then + begin + Hint := 'Error: ' + FErrorMessage; + ShowHint := True; + end + else if FTypeInfoText <> '' then + begin + Hint := 'Type: ' + FTypeInfoText; + ShowHint := True; + end + else + begin + Hint := ''; + ShowHint := False; + end; +end; + +procedure TAuraNode.Paint; +var + rect: TRectF; + effBorderColor: TAlphaColor; + effBorderWidth: Single; + effDash: TStrokeDash; +begin + inherited; + + Canvas.Fill.Kind := TBrushKind.None; + + // Determine styles based on state (Error > Standard) + if FErrorMessage <> '' then + begin + effBorderColor := TAlphaColors.Red; + effBorderWidth := 2.0; + effDash := TStrokeDash.Solid; + end + else + begin + effBorderColor := FBorderColor; + effBorderWidth := FBorderWidth; + if FFrameless then + effDash := TStrokeDash.Dot + else + effDash := TStrokeDash.Solid; + end; + + if FFrameless and (FErrorMessage = '') then + begin + // Standard frameless drawing (only if no error) + Canvas.Fill.Kind := TBrushKind.Solid; + Canvas.Fill.Color := FBackgroundColor; + Canvas.Stroke.Kind := TBrushKind.None; + Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); + Canvas.Stroke.Kind := TBrushKind.Solid; + Canvas.Stroke.Color := effBorderColor; + Canvas.Stroke.Thickness := effBorderWidth; + Canvas.Stroke.Dash := effDash; + Canvas.DrawRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); + end + else + begin + // Draw background fill first + Canvas.Fill.Kind := TBrushKind.Solid; + Canvas.Fill.Color := FBackgroundColor; + rect := TRectF.Create(0, 0, Width, Height); + if (effBorderWidth > 0) then + rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2); + Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); + + // Draw border (Custom or Error) + if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then + begin + rect := TRectF.Create(0, 0, Width, Height); + rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2); + + Canvas.Stroke.Kind := TBrushKind.Solid; + Canvas.Stroke.Color := effBorderColor; + Canvas.Stroke.Thickness := effBorderWidth; + Canvas.Stroke.Dash := effDash; + Canvas.DrawRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); + end; + end; +end; + +procedure TAuraNode.SetBorderColor(const Value: TAlphaColor); +begin + if FBorderColor <> Value then + begin + FBorderColor := Value; + Repaint; + end; +end; + +procedure TAuraNode.SetBorderRadius(const Value: Single); +begin + if FBorderRadius <> Value then + begin + FBorderRadius := Value; + Repaint; + end; +end; + +procedure TAuraNode.SetBorderWidth(const Value: Single); +begin + if FBorderWidth <> Value then + begin + FBorderWidth := Value; + Repaint; + end; +end; + +procedure TAuraNode.SetFrameless(const Value: Boolean); +begin + if FFrameless <> Value then + begin + FFrameless := Value; + Repaint; + end; +end; + +procedure TAuraNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +begin + inherited; + if Button = TMouseButton.mbLeft then + begin + var lControl := ObjectAtPoint(LocalToScreen(TPointF.Create(X, Y))); + if Assigned(lControl) and (lControl.GetObject = Self) then + begin + FIsDragging := True; + FDownPos := TPointF.Create(X, Y); + Capture; + BringToFront; + end + else + FIsDragging := False; + end; +end; + +procedure TAuraNode.MouseMove(Shift: TShiftState; X, Y: Single); +begin + inherited; + + if FIsDragging then + begin + var deltaX := X - FDownPos.X; + var deltaY := Y - FDownPos.Y; + + Position.X := Position.X + deltaX; + Position.Y := Position.Y + deltaY; + + if ParentControl <> nil then + ParentControl.Repaint; + end; +end; + +procedure TAuraNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +begin + inherited; + if (Button = TMouseButton.mbLeft) and (FIsDragging) then + begin + ReleaseCapture; + FIsDragging := False; + if ParentControl <> nil then + ParentControl.Repaint; + end; +end; + +procedure TAuraNode.SetBackgroundColor(const Value: TAlphaColor); +begin + FBackgroundColor := Value; + Repaint; +end; + +procedure TAuraNode.SetupNode; +begin + if Assigned(FHandler) then + FHandler.BuildUI(Self); +end; + +{ TBaseNodeHandler } + +constructor TBaseNodeHandler.Create(const ANode: T); +begin + inherited Create; + FNode := ANode; +end; + +function TBaseNodeHandler.GetAstNode: IAstNode; +begin + Result := FNode; +end; + +end. diff --git a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas new file mode 100644 index 0000000..0b028c3 --- /dev/null +++ b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas @@ -0,0 +1,1085 @@ +unit Myc.Fmx.AstEditor.Handlers; + +interface + +uses + System.SysUtils, + System.Classes, + System.UITypes, + System.Generics.Collections, + System.Types, + FMX.Types, + FMX.Controls, + FMX.StdCtrls, + FMX.Graphics, + Myc.Data.Value, + Myc.Data.Keyword, + Myc.Ast, + Myc.Ast.Nodes, + Myc.Ast.Identities, + Myc.Fmx.AstEditor.Core; + +type + // --- Basic Handlers --- + + TConstantNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TIdentifierNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TKeywordNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TNopNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Logic & Control Flow --- + + TBlockExpressionNodeHandler = class(TBaseNodeHandler) + private + FChildNodes: TList; + public + constructor Create(const ANode: IBlockExpressionNode); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TIfExpressionNodeHandler = class(TBaseNodeHandler) + private + FConditionNode: TAuraNode; + FThenNode: TAuraNode; + FElseNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TTernaryExpressionNodeHandler = class(TBaseNodeHandler) + private + FConditionNode: TAuraNode; + FThenNode: TAuraNode; + FElseNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Functions & Calls --- + + TLambdaExpressionNodeHandler = class(TBaseNodeHandler) + private + FBodyNode: TAuraNode; + FParamLabels: TList; + public + constructor Create(const ANode: ILambdaExpressionNode); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TFunctionCallNodeHandler = class(TBaseNodeHandler) + private + FCalleeNode: TAuraNode; + FArgumentNodes: TList; + public + constructor Create(const ANode: IFunctionCallNode); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TMacroExpansionNodeHandler = class(TBaseNodeHandler) + private + FExpandedBodyNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TRecurNodeHandler = class(TBaseNodeHandler) + private + FArgumentNodes: TList; + public + constructor Create(const ANode: IRecurNode); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Declarations & Assignments --- + + TVariableDeclarationNodeHandler = class(TBaseNodeHandler) + private + FTargetNode: TAuraNode; + FInitializerNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TAssignmentNodeHandler = class(TBaseNodeHandler) + private + FTargetNode: TAuraNode; + FValueNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TMacroDefinitionNodeHandler = class(TBaseNodeHandler) + private + FBodyNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Metaprogramming --- + + TQuasiquoteNodeHandler = class(TBaseNodeHandler) + private + FExpressionNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TUnquoteNodeHandler = class(TBaseNodeHandler) + private + FExpressionNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TUnquoteSplicingNodeHandler = class(TBaseNodeHandler) + private + FExpressionNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Data Access & Structures --- + + TIndexerNodeHandler = class(TBaseNodeHandler) + private + FBaseNode: TAuraNode; + FIndexNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TMemberAccessNodeHandler = class(TBaseNodeHandler) + private + FBaseNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TRecordLiteralNodeHandler = class(TBaseNodeHandler) + private + FFieldNodes: TDictionary; + public + constructor Create(const ANode: IRecordLiteralNode); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + // --- Series Operations --- + + TCreateSeriesNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TAddSeriesItemNodeHandler = class(TBaseNodeHandler) + private + FValueNode: TAuraNode; + FLookbackNode: TAuraNode; + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + + TSeriesLengthNodeHandler = class(TBaseNodeHandler) + public + procedure BuildUI(OwnerNode: TAuraNode); override; + function ReconstructAst(OwnerNode: TAuraNode): IAstNode; override; + end; + +implementation + +{ TConstantNodeHandler } + +procedure TConstantNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + valueStr: string; + isConcise: Boolean; + titleLabel: TLabel; + valueLabel: TLabel; +begin + OwnerNode.BeginUpdate; + try + valueStr := FNode.Value.ToString; + isConcise := ((FNode.Value.Kind = TDataValueKind.vkScalar) or (Pos(sLineBreak, valueStr) = 0)) and (Length(valueStr) < 40); + + if isConcise then + begin + OwnerNode.Frameless := True; + OwnerNode.AddLabel(OwnerNode, valueStr); + end + else + begin + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Const'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + + valueLabel := OwnerNode.AddLabel(OwnerNode, valueStr); + valueLabel.AutoSize := False; + valueLabel.WordWrap := True; + end; + finally + OwnerNode.EndUpdate; + end; +end; + +function TConstantNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Constant(FNode.Identity.AsConstant, FNode.StaticType); +end; + +{ TIdentifierNodeHandler } + +procedure TIdentifierNodeHandler.BuildUI(OwnerNode: TAuraNode); +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.AddLabel(OwnerNode, FNode.Name); + finally + OwnerNode.EndUpdate; + end; +end; + +function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Identifier(FNode.Identity.AsNamed, FNode.Address, FNode.StaticType); +end; + +{ TKeywordNodeHandler } + +procedure TKeywordNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + lbl: TLabel; +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + lbl := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Value.Name); + lbl.StyledSettings := lbl.StyledSettings - [TStyledSetting.FontColor]; + lbl.FontColor := TAlphaColors.Mediumvioletred; + finally + OwnerNode.EndUpdate; + end; +end; + +function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Keyword(FNode.Identity.AsKeyword); +end; + +{ TNopNodeHandler } + +procedure TNopNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + lbl: TLabel; +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Alignment := TLayoutAlignment.laCenter; + OwnerNode.Orientation := TLayoutOrientation.loHorizontal; + lbl := OwnerNode.AddLabel(OwnerNode, '...'); + lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; + lbl.Margins.Rect := TRectF.Create(8, 4, 8, 4); + finally + OwnerNode.EndUpdate; + end; +end; + +function TNopNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := FNode; +end; + +{ TBlockExpressionNodeHandler } + +constructor TBlockExpressionNodeHandler.Create(const ANode: IBlockExpressionNode); +begin + inherited Create(ANode); + FChildNodes := TList.Create; +end; + +destructor TBlockExpressionNodeHandler.Destroy; +begin + FChildNodes.Free; + inherited; +end; + +procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + childNode: TAuraNode; + expr: IAstNode; + titleLabel: TLabel; + i: Integer; + returnContainer: TAutoFitControl; + visuReturn: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + + for i := 0 to High(FNode.Expressions) do + begin + expr := FNode.Expressions[i]; + + if i = High(FNode.Expressions) then + begin + returnContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + titleLabel := OwnerNode.AddLabel(returnContainer, 'return'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + visuReturn := OwnerNode.Visualizer.Clone(returnContainer, OwnerNode.Visualizer.ExprDepth + 1); + childNode := visuReturn.CallAccept(expr); + FChildNodes.Add(childNode); + end + else + begin + childNode := visu.CallAccept(expr); + FChildNodes.Add(childNode); + end; + end; + finally + OwnerNode.EndUpdate; + end; +end; + +function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + exprs: TArray; + childNode: TAuraNode; + i: Integer; +begin + SetLength(exprs, FChildNodes.Count); + for i := 0 to FChildNodes.Count - 1 do + begin + childNode := FChildNodes[i]; + if Assigned(childNode) then + exprs[i] := childNode.CreateAst + else + exprs[i] := TAst.Nop; + end; + + Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType); +end; + +{ TIfExpressionNodeHandler } + +procedure TIfExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + + FConditionNode := OwnerNode.AddExpr(OwnerNode, 'if', FNode.Condition); + FThenNode := OwnerNode.AddExpr(OwnerNode, 'then', FNode.ThenBranch); + if Assigned(FNode.ElseBranch) then + FElseNode := OwnerNode.AddExpr(OwnerNode, 'else', FNode.ElseBranch); + finally + OwnerNode.EndUpdate; + end; +end; + +function TIfExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + elseAst: IAstNode; +begin + if Assigned(FElseNode) then + elseAst := FElseNode.CreateAst + else + elseAst := nil; + + Result := TAst.IfExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, elseAst, FNode.StaticType); +end; + +{ TTernaryExpressionNodeHandler } + +procedure TTernaryExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FConditionNode := visu.CallAccept(FNode.Condition); + OwnerNode.AddLabel(OwnerNode, '?'); + FThenNode := visu.CallAccept(FNode.ThenBranch); + OwnerNode.AddLabel(OwnerNode, ':'); + FElseNode := visu.CallAccept(FNode.ElseBranch); + finally + OwnerNode.EndUpdate; + end; +end; + +function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.TernaryExpr(FNode.Identity, FConditionNode.CreateAst, FThenNode.CreateAst, FElseNode.CreateAst, FNode.StaticType); +end; + +{ TLambdaExpressionNodeHandler } + +constructor TLambdaExpressionNodeHandler.Create(const ANode: ILambdaExpressionNode); +begin + inherited Create(ANode); + FParamLabels := TList.Create; +end; + +destructor TLambdaExpressionNodeHandler.Destroy; +begin + FParamLabels.Free; + inherited; +end; + +procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleContainer: TAutoFitControl; + paramLabel: TLabel; + i: Integer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, 0); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + OwnerNode.BackgroundColor := $090000ff; + + titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + + paramLabel := OwnerNode.AddLabel(titleContainer, 'fn'); + paramLabel.Font.Style := paramLabel.Font.Style + [TFontStyle.fsBold]; + FParamLabels.Add(paramLabel); + + paramLabel := OwnerNode.AddLabel(titleContainer, '('); + FParamLabels.Add(paramLabel); + + for i := 0 to High(FNode.Parameters) do + begin + paramLabel := OwnerNode.AddLabel(titleContainer, FNode.Parameters[i].Name); + FParamLabels.Add(paramLabel); + + if i < High(FNode.Parameters) then + begin + paramLabel := OwnerNode.AddLabel(titleContainer, ','); + FParamLabels.Add(paramLabel); + end; + end; + + paramLabel := OwnerNode.AddLabel(titleContainer, ')'); + FParamLabels.Add(paramLabel); + + FBodyNode := visu.CallAccept(FNode.Body); + FBodyNode.Frameless := False; + + finally + OwnerNode.EndUpdate; + end; +end; + +function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := + TAst.LambdaExpr( + FNode.Identity, + FNode.Parameters, + FBodyNode.CreateAst, + FNode.Layout, + FNode.Descriptor, + FNode.Upvalues, + FNode.HasNestedLambdas, + FNode.IsPure, + FNode.StaticType + ); +end; + +{ TFunctionCallNodeHandler } + +constructor TFunctionCallNodeHandler.Create(const ANode: IFunctionCallNode); +begin + inherited Create(ANode); + FArgumentNodes := TList.Create; +end; + +destructor TFunctionCallNodeHandler.Destroy; +begin + FArgumentNodes.Free; + inherited; +end; + +procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + i: Integer; + argNode: TAuraNode; + callLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + + callLabel := OwnerNode.AddLabel(OwnerNode, 'call '); + callLabel.Font.Style := callLabel.Font.Style + [TFontStyle.fsBold]; + + FCalleeNode := visu.CallAccept(FNode.Callee); + + if Length(FNode.Arguments) > 0 then + begin + OwnerNode.AddLabel(OwnerNode, '('); + for i := 0 to High(FNode.Arguments) do + begin + argNode := visu.CallAccept(FNode.Arguments[i]); + FArgumentNodes.Add(argNode); + if i < High(FNode.Arguments) then + OwnerNode.AddLabel(OwnerNode, ','); + end; + OwnerNode.AddLabel(OwnerNode, ')'); + end; + finally + OwnerNode.EndUpdate; + end; +end; + +function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + args: TArray; + i: Integer; +begin + SetLength(args, FArgumentNodes.Count); + for i := 0 to FArgumentNodes.Count - 1 do + args[i] := FArgumentNodes[i].CreateAst; + + Result := + TAst.FunctionCall( + FNode.Identity, + FCalleeNode.CreateAst, + args, + FNode.StaticType, + FNode.IsTailCall, + FNode.StaticTarget, + FNode.IsTargetPure + ); +end; + +{ TMacroExpansionNodeHandler } + +procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Expansion'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + FExpandedBodyNode := visu.CallAccept(FNode.ExpandedBody); + finally + OwnerNode.EndUpdate; + end; +end; + +function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.MacroExpansionNode(FNode.Identity, FNode.CallNode, FExpandedBodyNode.CreateAst.AsTypedNode); +end; + +{ TRecurNodeHandler } + +constructor TRecurNodeHandler.Create(const ANode: IRecurNode); +begin + inherited Create(ANode); + FArgumentNodes := TList.Create; +end; + +destructor TRecurNodeHandler.Destroy; +begin + FArgumentNodes.Free; + inherited; +end; + +procedure TRecurNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + i: Integer; + argNode: TAuraNode; + titleLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + + titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + + OwnerNode.AddLabel(OwnerNode, '('); + for i := 0 to High(FNode.Arguments) do + begin + argNode := visu.CallAccept(FNode.Arguments[i]); + FArgumentNodes.Add(argNode); + if i < High(FNode.Arguments) then + OwnerNode.AddLabel(OwnerNode, ','); + end; + OwnerNode.AddLabel(OwnerNode, ')'); + finally + OwnerNode.EndUpdate; + end; +end; + +function TRecurNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + args: TArray; + i: Integer; +begin + SetLength(args, FArgumentNodes.Count); + for i := 0 to FArgumentNodes.Count - 1 do + args[i] := FArgumentNodes[i].CreateAst; + Result := TAst.Recur(FNode.Identity, args, FNode.StaticType); +end; + +{ TVariableDeclarationNodeHandler } + +procedure TVariableDeclarationNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + varLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + + varLabel := OwnerNode.AddLabel(OwnerNode, 'var'); + + varLabel.Font.Style := varLabel.Font.Style + [TFontStyle.fsBold]; + FTargetNode := visu.CallAccept(FNode.Target); + + if Assigned(FNode.Initializer) then + begin + OwnerNode.AddLabel(OwnerNode, ':='); + FInitializerNode := visu.CallAccept(FNode.Initializer); + end + else + FInitializerNode := nil; + finally + OwnerNode.EndUpdate; + end; +end; + +function TVariableDeclarationNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + initAst: IAstNode; +begin + if Assigned(FInitializerNode) then + initAst := FInitializerNode.CreateAst + else + initAst := nil; + Result := TAst.VarDecl(FNode.Identity, FTargetNode.CreateAst, initAst, FNode.StaticType, FNode.IsBoxed); +end; + +{ TAssignmentNodeHandler } + +procedure TAssignmentNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FTargetNode := visu.CallAccept(FNode.Target); + OwnerNode.AddLabel(OwnerNode, ':='); + FValueNode := visu.CallAccept(FNode.Value); + finally + OwnerNode.EndUpdate; + end; +end; + +function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Assign(FNode.Identity, FTargetNode.CreateAst, FValueNode.CreateAst, FNode.StaticType); +end; + +{ TMacroDefinitionNodeHandler } + +procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleLabel: TLabel; + paramStr: string; + i: Integer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + + paramStr := ''; + for i := 0 to High(FNode.Parameters) do + begin + if i > 0 then + paramStr := paramStr + ', '; + paramStr := paramStr + FNode.Parameters[i].Name; + end; + + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Def: ' + FNode.Name.Name + ' (' + paramStr + ')'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + + FBodyNode := visu.CallAccept(FNode.Body); + finally + OwnerNode.EndUpdate; + end; +end; + +function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.MacroDef(FNode.Identity, FNode.Name, FNode.Parameters, FBodyNode.CreateAst); +end; + +{ TQuasiquoteNodeHandler } + +procedure TQuasiquoteNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + FExpressionNode := visu.CallAccept(FNode.Expression); + finally + OwnerNode.EndUpdate; + end; +end; + +function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Quasiquote(FNode.Identity, FExpressionNode.CreateAst); +end; + +{ TUnquoteNodeHandler } + +procedure TUnquoteNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + leftBracket, rightBracket: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + + leftBracket := OwnerNode.AddLabel(OwnerNode, '<'); + leftBracket.Padding.Right := 0; + leftBracket.Margins.Right := 0; + + FExpressionNode := visu.CallAccept(FNode.Expression); + + rightBracket := OwnerNode.AddLabel(OwnerNode, '>'); + rightBracket.Padding.Left := 0; + rightBracket.Margins.Left := 0; + finally + OwnerNode.EndUpdate; + end; +end; + +function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Unquote(FNode.Identity, FExpressionNode.CreateAst); +end; + +{ TUnquoteSplicingNodeHandler } + +procedure TUnquoteSplicingNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + FExpressionNode := visu.CallAccept(FNode.Expression); + finally + OwnerNode.EndUpdate; + end; +end; + +function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.UnquoteSplicing(FNode.Identity, FExpressionNode.CreateAst.AsQuasiquote); +end; + +{ TIndexerNodeHandler } + +procedure TIndexerNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FBaseNode := visu.CallAccept(FNode.Base); + OwnerNode.AddLabel(OwnerNode, '['); + FIndexNode := visu.CallAccept(FNode.Index); + OwnerNode.AddLabel(OwnerNode, ']'); + finally + OwnerNode.EndUpdate; + end; +end; + +function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.Indexer(FNode.Identity, FBaseNode.CreateAst, FIndexNode.CreateAst, FNode.StaticType); +end; + +{ TMemberAccessNodeHandler } + +procedure TMemberAccessNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FBaseNode := visu.CallAccept(FNode.Base); + OwnerNode.AddLabel(OwnerNode, '.'); + OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name); + finally + OwnerNode.EndUpdate; + end; +end; + +function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + // Reuse Identifier, Reuse Member Keyword (via TAst.Keyword with Identity) + Result := TAst.MemberAccess(FNode.Identity, FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Identity.AsKeyword), FNode.StaticType); +end; + +{ TRecordLiteralNodeHandler } + +constructor TRecordLiteralNodeHandler.Create(const ANode: IRecordLiteralNode); +begin + inherited Create(ANode); + FFieldNodes := TDictionary.Create; +end; + +destructor TRecordLiteralNodeHandler.Destroy; +begin + FFieldNodes.Free; + inherited; +end; + +procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + field: TRecordFieldLiteral; + fieldContainer: TAutoFitControl; + valueNode: TAuraNode; + keyLabel: TLabel; +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + + if Length(FNode.Fields) = 0 then + begin + OwnerNode.AddLabel(OwnerNode, '{}'); + end + else + begin + for field in FNode.Fields do + begin + fieldContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + keyLabel := OwnerNode.AddLabel(fieldContainer, ':' + field.Key.Value.Name); + keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold]; + keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor]; + keyLabel.FontColor := TAlphaColors.Mediumvioletred; + + valueNode := OwnerNode.Visualizer.Clone(fieldContainer, OwnerNode.Visualizer.ExprDepth + 1).CallAccept(field.Value); + FFieldNodes.Add(field.Key.Value, valueNode); + end; + end; + finally + OwnerNode.EndUpdate; + end; +end; + +function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + fields: TArray; + i: Integer; + valueNode: TAuraNode; + pair: TPair; +begin + SetLength(fields, FFieldNodes.Count); + i := 0; + for pair in FFieldNodes do + begin + valueNode := pair.Value; + fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst); + inc(i); + end; + Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType); +end; + +{ TCreateSeriesNodeHandler } + +procedure TCreateSeriesNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + titleLabel: TLabel; +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Create Series: ' + FNode.Definition); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + finally + OwnerNode.EndUpdate; + end; +end; + +function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.CreateSeries(FNode.Identity.AsDefinition, FNode.StaticType); +end; + +{ TAddSeriesItemNodeHandler } + +procedure TAddSeriesItemNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + visu: IAstVisualizer; + titleLabel: TLabel; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + + FValueNode := visu.CallAccept(FNode.Value); + if Assigned(FNode.Lookback) then + FLookbackNode := visu.CallAccept(FNode.Lookback) + else + FLookbackNode := nil; + finally + OwnerNode.EndUpdate; + end; +end; + +function TAddSeriesItemNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +var + lookbackAst: IAstNode; +begin + if Assigned(FLookbackNode) then + lookbackAst := FLookbackNode.CreateAst + else + lookbackAst := nil; + + Result := + TAst.AddSeriesItem( + FNode.Identity, + FNode.Series, // Reuse original Series Identifier Node + FValueNode.CreateAst, + lookbackAst, + FNode.StaticType + ); +end; + +{ TSeriesLengthNodeHandler } + +procedure TSeriesLengthNodeHandler.BuildUI(OwnerNode: TAuraNode); +var + titleLabel: TLabel; +begin + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + finally + OwnerNode.EndUpdate; + end; +end; + +function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAuraNode): IAstNode; +begin + Result := TAst.SeriesLength(FNode.Identity, FNode.Series, FNode.StaticType); +end; + +end. diff --git a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas new file mode 100644 index 0000000..e38decd --- /dev/null +++ b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas @@ -0,0 +1,249 @@ +unit Myc.Fmx.AstEditor.Visualizer; + +interface + +uses + System.SysUtils, + System.Classes, + FMX.Controls, + Myc.Data.Value, + Myc.Ast.Nodes, + Myc.Ast.Visitor, + Myc.Fmx.AstEditor.Workspace, + Myc.Fmx.AstEditor.Core, + Myc.Fmx.AstEditor.Handlers; + +type + // Inherits from the generic TAstVisitor + TAstVisualizer = class(TAstVisitor, IAstVisualizer) + private + FExprDepth: Integer; + FParentControl: TControl; + FWorkspace: TAuraWorkspace; + function CallAccept(const Node: IAstNode): TAuraNode; + function GetExprDepth: Integer; + function GetParentControl: TControl; + function GetWorkspace: TAuraWorkspace; + procedure SetExprDepth(const Value: Integer); + procedure SetParentControl(const Value: TControl); + protected + // Visitor implementations for each AST node type. + function VisitConstant(const Node: IConstantNode): TAuraNode; override; + function VisitIdentifier(const Node: IIdentifierNode): TAuraNode; override; + function VisitKeyword(const Node: IKeywordNode): TAuraNode; override; + function VisitIfExpression(const Node: IIfExpressionNode): TAuraNode; override; + function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAuraNode; override; + function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAuraNode; override; + function VisitFunctionCall(const Node: IFunctionCallNode): TAuraNode; override; + function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAuraNode; override; + function VisitBlockExpression(const Node: IBlockExpressionNode): TAuraNode; override; + function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAuraNode; override; + function VisitAssignment(const Node: IAssignmentNode): TAuraNode; override; + function VisitMacroDefinition(const Node: IMacroDefinitionNode): TAuraNode; override; + function VisitQuasiquote(const Node: IQuasiquoteNode): TAuraNode; override; + function VisitUnquote(const Node: IUnquoteNode): TAuraNode; override; + function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAuraNode; override; + function VisitIndexer(const Node: IIndexerNode): TAuraNode; override; + function VisitMemberAccess(const Node: IMemberAccessNode): TAuraNode; override; + function VisitRecordLiteral(const Node: IRecordLiteralNode): TAuraNode; override; + function VisitCreateSeries(const Node: ICreateSeriesNode): TAuraNode; override; + function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAuraNode; override; + function VisitSeriesLength(const Node: ISeriesLengthNode): TAuraNode; override; + function VisitRecurNode(const Node: IRecurNode): TAuraNode; override; + function VisitNop(const Node: INopNode): TAuraNode; override; + + public + constructor Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer); + destructor Destroy; override; + + function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; + + property ExprDepth: Integer read GetExprDepth write SetExprDepth; + property ParentControl: TControl read GetParentControl write SetParentControl; + property Workspace: TAuraWorkspace read GetWorkspace; + end; + +implementation + +{ TAstVisualizer } + +constructor TAstVisualizer.Create(AWorkspace: TAuraWorkspace; AParentControl: TControl; AExprDepth: Integer); +begin + inherited Create; + FWorkspace := AWorkspace; + FParentControl := AParentControl; + FExprDepth := AExprDepth; +end; + +destructor TAstVisualizer.Destroy; +begin + inherited; +end; + +function TAstVisualizer.CallAccept(const Node: IAstNode): TAuraNode; +var + dataValue: TDataValue; +begin + if not Assigned(Node) then + exit(nil); + + dataValue := Node.Accept(Self); + + if dataValue.Kind = TDataValueKind.vkGeneric then + begin + Result := dataValue.AsGeneric; + end + else + begin + Result := nil; + end; +end; + +function TAstVisualizer.Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; +begin + Result := TAstVisualizer.Create(FWorkspace, ParentControl, ExprDepth); +end; + +function TAstVisualizer.GetExprDepth: Integer; +begin + Result := FExprDepth; +end; + +function TAstVisualizer.GetParentControl: TControl; +begin + Result := FParentControl; +end; + +function TAstVisualizer.GetWorkspace: TAuraWorkspace; +begin + Result := FWorkspace; +end; + +procedure TAstVisualizer.SetExprDepth(const Value: Integer); +begin + FExprDepth := Value; +end; + +procedure TAstVisualizer.SetParentControl(const Value: TControl); +begin + FParentControl := Value; +end; + +// --- Visitor Implementations --- + +function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TConstantNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitIdentifier(const Node: IIdentifierNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TIdentifierNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitKeyword(const Node: IKeywordNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TKeywordNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TBlockExpressionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitIfExpression(const Node: IIfExpressionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TIfExpressionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TTernaryExpressionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TLambdaExpressionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitFunctionCall(const Node: IFunctionCallNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TFunctionCallNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TMacroExpansionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TVariableDeclarationNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitAssignment(const Node: IAssignmentNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TAssignmentNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TMacroDefinitionNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitQuasiquote(const Node: IQuasiquoteNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TQuasiquoteNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitUnquote(const Node: IUnquoteNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TUnquoteNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TUnquoteSplicingNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitIndexer(const Node: IIndexerNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TIndexerNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitMemberAccess(const Node: IMemberAccessNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TMemberAccessNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitRecordLiteral(const Node: IRecordLiteralNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TRecordLiteralNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitCreateSeries(const Node: ICreateSeriesNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TCreateSeriesNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TAddSeriesItemNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitSeriesLength(const Node: ISeriesLengthNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TSeriesLengthNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitRecurNode(const Node: IRecurNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TRecurNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitNop(const Node: INopNode): TAuraNode; +begin + Result := TAuraNode.Create(Self, TNopNodeHandler.Create(Node)); +end; + +end. diff --git a/ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas similarity index 90% rename from ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas rename to Src/AST/Myc.Fmx.AstEditor.Workspace.pas index 06a7290..1a9bec8 100644 --- a/ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas @@ -91,7 +91,8 @@ implementation uses System.Math, FMX.Platform, - Myc.Fmx.AstEditor.Node; + Myc.Fmx.AstEditor.Core, + Myc.Fmx.AstEditor.Visualizer; { TPinConnection } @@ -112,7 +113,10 @@ end; procedure TAuraWorkspace.Build(const RootNode: IAstNode; const Position: TPointF); begin var visu := TAstVisualizer.Create(Self, Self, 0) as IAstVisualizer; - visu.CallAccept(RootNode); + var node := visu.CallAccept(RootNode); + + if Assigned(node) then + node.Position.Point := Position; end; procedure TAuraWorkspace.DoDeleteChildren; @@ -125,7 +129,7 @@ function TAuraWorkspace.GetChildrenMatrix(var Matrix: TMatrix; var Simple: Boole begin Matrix := TMatrix.CreateScaling(FZoom, FZoom) * TMatrix.CreateTranslation(FPanning.cx, FPanning.cy); Simple := (FZoom = 1.0) and (FPanning.cx = 0) and (FPanning.cy = 0); - Result := true; + Result := True; end; procedure TAuraWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); @@ -225,15 +229,15 @@ end; function TAuraWorkspace.Zoom(Factor: Single): Boolean; var - MouseService: IFMXMouseService; + mouseService: IFMXMouseService; begin - Result := TPlatformServices.Current.SupportsPlatformService(IFMXMouseService, MouseService); + Result := TPlatformServices.Current.SupportsPlatformService(IFMXMouseService, mouseService); if Result then begin - var MousePos := ScreenToLocal(MouseService.GetMousePos); + var mousePos := ScreenToLocal(mouseService.GetMousePos); Factor := Max(0.2, Min(3.0, Factor)); - FPanning.cx := MousePos.X * (1 - Factor / FZoom) + FPanning.cx * (Factor / FZoom); - FPanning.cy := MousePos.Y * (1 - Factor / FZoom) + FPanning.cy * (Factor / FZoom); + FPanning.cx := mousePos.X * (1 - Factor / FZoom) + FPanning.cx * (Factor / FZoom); + FPanning.cy := mousePos.Y * (1 - Factor / FZoom) + FPanning.cy * (Factor / FZoom); FZoom := Factor; RecalcAbsolute; RecalcUpdateRect; diff --git a/Src/AST/Test.Myc.Ast.Compiler.Binder.pas b/Test/Test.Myc.Ast.Compiler.Binder.pas similarity index 100% rename from Src/AST/Test.Myc.Ast.Compiler.Binder.pas rename to Test/Test.Myc.Ast.Compiler.Binder.pas