diff --git a/ASTPlayground/ASTPlayground.delphilsp.json b/ASTPlayground/ASTPlayground.delphilsp.json
index 37b65e5..af95420 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.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.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" }, { "name": "Myc.Fmx.AstEditor.Controller", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Controller.pas" }, { "name": "Myc.Fmx.AstEditor", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.pas" }, { "name": "Myc.Fmx.AstEditor.Layout", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Layout.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.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" }, { "name": "Myc.Fmx.AstEditor.Layout", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Layout.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.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 73bb958..81dc4df 100644
--- a/ASTPlayground/ASTPlayground.dpr
+++ b/ASTPlayground/ASTPlayground.dpr
@@ -29,9 +29,9 @@ uses
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',
- Myc.Fmx.AstEditor.Controller in '..\Src\AST\Myc.Fmx.AstEditor.Controller.pas',
- Myc.Fmx.AstEditor in '..\Src\AST\Myc.Fmx.AstEditor.pas',
- Myc.Fmx.AstEditor.Layout in '..\Src\AST\Myc.Fmx.AstEditor.Layout.pas';
+ Myc.Fmx.AstEditor.Layout in '..\Src\AST\Myc.Fmx.AstEditor.Layout.pas',
+ Myc.Fmx.AstEditor.Node in '..\Src\AST\Myc.Fmx.AstEditor.Node.pas',
+ Myc.Fmx.AstEditor in '..\Src\AST\Myc.Fmx.AstEditor.pas';
{$R *.res}
diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj
index 2a24462..75a07ad 100644
--- a/ASTPlayground/ASTPlayground.dproj
+++ b/ASTPlayground/ASTPlayground.dproj
@@ -159,9 +159,9 @@
-
-
+
+
Base
diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas
index ef802ec..bfaff17 100644
--- a/ASTPlayground/MainForm.pas
+++ b/ASTPlayground/MainForm.pas
@@ -44,9 +44,7 @@ uses
Myc.Ast.RTL,
Myc.Ast.Compiler.Macros,
// Editor Units
- Myc.Fmx.AstEditor,
- Myc.Fmx.AstEditor.Workspace,
- Myc.Fmx.AstEditor.Controller; // Controller integration
+ Myc.Fmx.AstEditor; // Die neue Komponente (ersetzt Controller und Workspace-Access)
type
// A test record
@@ -93,7 +91,6 @@ type
procedure ClearButtonClick(Sender: TObject);
procedure CompilerStageBoxChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
procedure CreateTriggerExampleButtonClick(Sender: TObject);
procedure DebugBoxChange(Sender: TObject);
procedure DoTrigger2ButtonClick(Sender: TObject);
@@ -119,17 +116,16 @@ type
FCurrUnboundAst: IAstNode;
FCurrExec: TCompiledFunction;
FEnvironment: TAstEnvironment;
- FWorkspace: TWorkspace; // Changed to TWorkspace
- FController: TAstEditorController; // The UI Controller
+ FAstEditor: TAstEditor; // Die Komponente (Facade)
FScriptUpdate: Boolean;
FTriggerTest: TAstEnvironment;
- procedure WorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+ procedure AstEditorMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
// Helper function to encapsulate the Compile -> Evaluate pattern
function ExecuteAst(const ANode: IAstNode): TDataValue;
procedure UpdateScript;
- procedure ShowVizualization(X, Y: Single);
+ procedure ShowVizualization;
procedure PrintScript(const Node: IAstNode);
public
{ Public declarations }
@@ -158,19 +154,20 @@ begin
// 1. Initialize Environment
FEnvironment := TAstEnvironment.Construct(TAst.CreateScope(nil));
- // 2. Initialize Workspace
- // TWorkspace is now a simple viewport control
- FWorkspace := TWorkspace.Create(Panel2);
- FWorkspace.Parent := Panel2;
- FWorkspace.Align := TAlignLayout.Client;
- FWorkspace.ClipChildren := true;
- FWorkspace.OnMouseDown := WorkspaceMouseDown;
+ // 2. Initialize AST Editor Component
+ // This replaces the manual Workspace + Controller setup.
+ // The Editor encapsulates logic for Navigation, Zoom, Drag&Drop, Undo/Redo.
+ FAstEditor := TAstEditor.Create(Self);
+ FAstEditor.Parent := Panel2;
+ FAstEditor.Align := TAlignLayout.Client;
- // 3. Initialize Controller (connects Env and Workspace)
- // The Controller will manage the nodes inside FWorkspace.World
- FController := TAstEditorController.Create(FEnvironment, FWorkspace);
+ // Wire up events exposed by the component
+ FAstEditor.OnMouseDown := AstEditorMouseDown;
- // 4. Register the SMA factory into the environment
+ // Initialize the logic backend of the editor
+ FAstEditor.Init(FEnvironment);
+
+ // 3. Register the SMA factory into the environment
var RegFunc :=
procedure(const Scope: IExecutionScope)
var
@@ -286,19 +283,13 @@ begin
ClearButtonClick(Self);
end;
-procedure TForm1.FormDestroy(Sender: TObject);
-begin
- FController.Free;
-end;
-
-procedure TForm1.ShowVizualization(X, Y: Single);
+procedure TForm1.ShowVizualization;
begin
if FCurrUnboundAst = nil then
exit;
- // Use the Controller to build, validate and show the UI
- // The controller internally clears FWorkspace.World and adds nodes there.
- FController.SetRoot(FCurrUnboundAst);
+ // Use the Editor Component to build, validate and show the UI
+ FAstEditor.SetRoot(FCurrUnboundAst);
end;
// Simplified ExecuteAst using TEnvironment and handling errors gracefully
@@ -422,14 +413,13 @@ end;
procedure TForm1.ClearButtonClick(Sender: TObject);
begin
- // Clear content of world (not workspace itself, as it has the root layer)
- FWorkspace.World.DeleteChildren;
- FWorkspace.World.Repaint;
+ // Clear content of component
+ FAstEditor.SetRoot(nil);
end;
procedure TForm1.CompilerStageBoxChange(Sender: TObject);
begin
- ShowVizualization(14, 14);
+ ShowVizualization;
end;
procedure TForm1.CreateTriggerExampleButtonClick(Sender: TObject);
@@ -731,8 +721,8 @@ begin
var result := ExecuteAst(FCurrUnboundAst);
Memo1.Lines.Add(Format('Script executed. Final result: %s', [result.ToString]));
finally
- // Trigger visualization update via Controller (inside ShowVizualization)
- ShowVizualization(14, 14);
+ // Trigger visualization update via Component
+ ShowVizualization;
end;
except
on E: Exception do
@@ -890,15 +880,15 @@ procedure TForm1.UpdateScript;
begin
PrintScript(FCurrUnboundAst);
- // Clear and redraw via Controller
- FController.SetRoot(FCurrUnboundAst);
+ // Clear and redraw via Component
+ FAstEditor.SetRoot(FCurrUnboundAst);
end;
-procedure TForm1.WorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+procedure TForm1.AstEditorMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
- if Button <> TMouseButton.mbMiddle then
- exit;
- ShowVizualization(X, Y);
+ // Nur zur Demo: Wir könnten hier klicken, um etwas im Memo zu loggen
+ if Button = TMouseButton.mbMiddle then
+ ShowVizualization;
end;
procedure TForm1.SaveUserLibButtonClick(Sender: TObject);
diff --git a/Src/AST/Myc.Fmx.AstEditor.Controller.pas b/Src/AST/Myc.Fmx.AstEditor.Controller.pas
deleted file mode 100644
index 7a9a4db..0000000
--- a/Src/AST/Myc.Fmx.AstEditor.Controller.pas
+++ /dev/null
@@ -1,432 +0,0 @@
-unit Myc.Fmx.AstEditor.Controller;
-
-interface
-
-uses
- System.SysUtils,
- System.Classes,
- System.Types,
- System.Math.Vectors,
- System.Generics.Collections,
- FMX.Types,
- FMX.Controls,
- Myc.Ast,
- Myc.Ast.Nodes,
- Myc.Ast.Identities,
- Myc.Ast.Types,
- Myc.Ast.Visitor,
- Myc.Ast.Scope,
- Myc.Ast.Environment,
- Myc.Fmx.AstEditor,
- Myc.Fmx.AstEditor.Workspace;
-
-type
- TAstEditorController = class
- private
- type
- TNodeMap = TDictionary;
- TUndoStack = TStack;
-
- TTypePropagator = class(TAstVisitor)
- private
- FMap: TNodeMap;
- procedure ApplyType(const Node: IAstNode);
- protected
- procedure Accept(const Node: IAstNode); override;
- public
- constructor Create(AMap: TNodeMap);
- end;
-
- private
- FEnv: TAstEnvironment;
- FWorkspace: TWorkspace;
- FNodeMap: TNodeMap;
- FRootViewNode: TAstViewNode;
-
- // State Tracking
- FCurrentAst: IAstNode;
-
- // Undo/Redo Stacks
- FUndoStack: TUndoStack;
- FRedoStack: TUndoStack;
- FIsUndoing: Boolean;
-
- procedure CollectNodes(Parent: TControl);
- procedure ClearVisuals;
- procedure ApplyErrors(const Log: ICompilerLog);
- procedure ApplyTypes(const TypedAst: IAstNode);
- procedure RootResized(Sender: TObject);
-
- procedure HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer);
-
- procedure CommitSnapshot;
-
- public
- constructor Create(const AEnv: TAstEnvironment; AWorkspace: TWorkspace);
- destructor Destroy; override;
-
- procedure ValidateAndShow;
- procedure SetRoot(const AstNode: IAstNode);
-
- procedure Undo;
- procedure Redo;
- function CanUndo: Boolean;
- function CanRedo: Boolean;
-
- // Expose current AST for external use (saving etc.)
- property CurrentAst: IAstNode read FCurrentAst;
- end;
-
-implementation
-
-uses
- Myc.Data.Value,
- Myc.Fmx.AstEditor.Visualizer;
-
-{ TAstEditorController }
-
-constructor TAstEditorController.Create(const AEnv: TAstEnvironment; AWorkspace: TWorkspace);
-begin
- inherited Create;
- FEnv := AEnv;
- FWorkspace := AWorkspace;
- FWorkspace.OnNodeDragDrop := HandleNodeDragDrop;
- FNodeMap := TNodeMap.Create;
-
- FUndoStack := TUndoStack.Create;
- FRedoStack := TUndoStack.Create;
- FIsUndoing := False;
- FCurrentAst := nil;
-end;
-
-destructor TAstEditorController.Destroy;
-begin
- // Cleaning up FCurrentAst is done by ARC automatically
- SetRoot(nil);
- FNodeMap.Free;
- FUndoStack.Free;
- FRedoStack.Free;
- inherited;
-end;
-
-procedure TAstEditorController.CommitSnapshot;
-begin
- // Optimization: Push the already known AST instead of recreating it from UI.
- // Since AST nodes are immutable interfaces, storing the reference is safe.
- if Assigned(FCurrentAst) and (not FIsUndoing) then
- begin
- FUndoStack.Push(FCurrentAst);
- FRedoStack.Clear;
- end;
-end;
-
-procedure TAstEditorController.Undo;
-var
- prevAst: IAstNode;
-begin
- if FUndoStack.Count = 0 then
- exit;
-
- FIsUndoing := True;
- try
- // Capture current state for Redo
- if Assigned(FCurrentAst) then
- FRedoStack.Push(FCurrentAst);
-
- // Restore previous state
- prevAst := FUndoStack.Pop;
- SetRoot(prevAst);
- finally
- FIsUndoing := False;
- end;
-end;
-
-procedure TAstEditorController.Redo;
-var
- nextAst: IAstNode;
-begin
- if FRedoStack.Count = 0 then
- exit;
-
- FIsUndoing := True;
- try
- // Capture current state for Undo
- if Assigned(FCurrentAst) then
- FUndoStack.Push(FCurrentAst);
-
- // Restore next state
- nextAst := FRedoStack.Pop;
- SetRoot(nextAst);
- finally
- FIsUndoing := False;
- end;
-end;
-
-function TAstEditorController.CanUndo: Boolean;
-begin
- Result := FUndoStack.Count > 0;
-end;
-
-function TAstEditorController.CanRedo: Boolean;
-begin
- Result := FRedoStack.Count > 0;
-end;
-
-procedure TAstEditorController.HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer);
-var
- SourceParent: TControl;
- ContainerOwner: TAstViewNode;
- Reorderable: IReorderable;
- SourceIdx, TargetIdx: Integer;
- NewAst: IAstNode;
-begin
- if (ASource = nil) or (AIndex < 0) then
- exit;
- if not (ASource is TAstViewNode) then
- exit;
-
- if not (ASource.Parent is TControl) then
- exit;
- SourceParent := TControl(ASource.Parent);
-
- ContainerOwner := nil;
-
- // Logic to find the Reorderable container (same as before)
- if (SourceParent is TAstViewNode) then
- begin
- ContainerOwner := TAstViewNode(SourceParent);
- if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then
- ContainerOwner := nil;
- end;
-
- if (ContainerOwner = nil) and (SourceParent.Parent is TAstViewNode) then
- begin
- ContainerOwner := TAstViewNode(SourceParent.Parent);
- if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then
- ContainerOwner := nil;
- end;
-
- if (ContainerOwner <> nil) and (Reorderable <> nil) then
- begin
- if Reorderable.CanDrag(ASource) then
- begin
- SourceIdx := ASource.Index;
- TargetIdx := AIndex;
-
- if SourceIdx <> TargetIdx then
- begin
- // 1. Commit the CURRENT (clean) AST before visual changes
- CommitSnapshot;
-
- // 2. Perform Visual Change (Dirty State)
- Reorderable.MoveChild(SourceIdx, TargetIdx);
-
- // 3. Generate NEW AST from the modified visual tree
- NewAst := FRootViewNode.CreateAst;
-
- // 4. Update the system with the new AST (Updates FCurrentAst)
- SetRoot(NewAst);
- end;
- end;
- end;
-end;
-
-procedure TAstEditorController.SetRoot(const AstNode: IAstNode);
-var
- Visualizer: IAstVisualizer;
-begin
- // Update the "Truth"
- FCurrentAst := AstNode;
-
- if not FIsUndoing then
- begin
- FUndoStack.Clear;
- FRedoStack.Clear;
- end;
-
- FWorkspace.World.DeleteChildren;
- if Assigned(FRootViewNode) then
- FRootViewNode.OnResized := nil;
- FRootViewNode := nil;
-
- if not Assigned(AstNode) then
- exit;
-
- Visualizer := TAstVisualizer.Create(FWorkspace, FWorkspace.World, 0);
- FRootViewNode := Visualizer.CallAccept(AstNode);
-
- if Assigned(FRootViewNode) then
- begin
- FWorkspace.World.Size := FRootViewNode.Size;
- FRootViewNode.OnResized := RootResized;
- FRootViewNode.Position.Point := TPointF.Create(50, 50);
- end;
-
- if Assigned(FRootViewNode) then
- ValidateAndShow;
-end;
-
-// ... (Rest: CollectNodes, ClearVisuals, ApplyErrors, ApplyTypes, RootResized, TTypePropagator bleiben gleich)
-
-procedure TAstEditorController.CollectNodes(Parent: TControl);
-var
- i: Integer;
- child: TControl;
- viewNode: TAstViewNode;
-begin
- for i := 0 to Parent.ChildrenCount - 1 do
- begin
- if Parent.Children[i] is TControl then
- begin
- child := TControl(Parent.Children[i]);
-
- if child is TAstViewNode then
- begin
- viewNode := TAstViewNode(child);
- if Assigned(viewNode.Node) and Assigned(viewNode.Node.Identity) then
- begin
- FNodeMap.AddOrSetValue(viewNode.Node.Identity, viewNode);
- end;
- end;
-
- if child.ChildrenCount > 0 then
- CollectNodes(child);
- end;
- end;
-end;
-
-procedure TAstEditorController.ClearVisuals;
-begin
- for var viewNode in FNodeMap.Values do
- begin
- viewNode.ErrorMessage := '';
- viewNode.TypeInfoText := '';
- end;
-end;
-
-procedure TAstEditorController.ApplyErrors(const Log: ICompilerLog);
-var
- entry: TCompilerError;
- viewNode: TAstViewNode;
-begin
- for entry in Log.GetEntries do
- begin
- if (entry.Level = elError) and Assigned(entry.Node) and Assigned(entry.Node.Identity) then
- begin
- if FNodeMap.TryGetValue(entry.Node.Identity, viewNode) then
- begin
- if viewNode.ErrorMessage = '' then
- viewNode.ErrorMessage := entry.Message
- else
- viewNode.ErrorMessage := viewNode.ErrorMessage + sLineBreak + entry.Message;
- end;
- end;
- end;
-end;
-
-procedure TAstEditorController.ApplyTypes(const TypedAst: IAstNode);
-var
- propagator: TTypePropagator;
-begin
- if not Assigned(TypedAst) then
- exit;
-
- propagator := TTypePropagator.Create(FNodeMap);
- try
- propagator.Accept(TypedAst);
- finally
- propagator.Free;
- end;
-end;
-
-procedure TAstEditorController.RootResized(Sender: TObject);
-begin
- FWorkspace.World.Size := FRootViewNode.Size;
-end;
-
-procedure TAstEditorController.ValidateAndShow;
-var
- logicalAst: IAstNode;
-begin
- if not Assigned(FRootViewNode) then
- exit;
-
- // Note: We use FCurrentAst here if we trust it, or recreate for safety.
- // Since SetRoot sets FCurrentAst, and any UI manipulation (DragDrop) calls SetRoot afterwards,
- // FCurrentAst should be in sync.
- // However, strictly speaking, ValidateAndShow operates on the VISUAL tree to find Mapping.
- // But since we have FCurrentAst, we can use it directly for binding.
-
- // BUT: ValidateAndShow is responsible for mapping NodeMap.
- logicalAst := FRootViewNode.CreateAst;
- // ^ This is still needed to rebuild the Mapping if we haven't tracked ViewNodes perfectly.
- // Or we rely on FCurrentAst being the source of truth and we assume ViewNodes match.
- // For now, let's keep CreateAst here to be 100% sure the mapping corresponds to what is on screen.
- // The performance hit here is acceptable as it's part of the validation cycle, not the drag-start.
-
- FNodeMap.Clear;
- CollectNodes(FWorkspace.World);
-
- ClearVisuals;
-
- try
- var log := TCompilerLog.Create as ICompilerLog;
-
- var expanded := FEnv.ExpandMacros(logicalAst);
- var typedAst := FEnv.Bind(expanded, [], log);
- var specAst := FEnv.Specialize(typedAst);
-
- ApplyTypes(specAst);
-
- if specAst.Kind = akLambdaExpression then
- var compiled := FEnv.Link(specAst.AsLambdaExpression, log);
-
- ApplyErrors(log);
- except
- on E: ECompilationFailed do
- begin
- var tempLog := TCompilerLog.Create as ICompilerLog;
- for var err in E.Errors do
- tempLog.Add(err.Level, err.Message, err.Node);
- ApplyErrors(tempLog);
- end;
- end;
-
- FWorkspace.World.Repaint;
-end;
-
-{ TAstEditorController.TTypePropagator }
-
-constructor TAstEditorController.TTypePropagator.Create(AMap: TNodeMap);
-begin
- inherited Create;
- FMap := AMap;
-end;
-
-procedure TAstEditorController.TTypePropagator.ApplyType(const Node: IAstNode);
-var
- viewNode: TAstViewNode;
-begin
- if Assigned(Node) and Assigned(Node.Identity) then
- begin
- if FMap.TryGetValue(Node.Identity, viewNode) then
- begin
- if Node.IsTyped then
- begin
- var st := Node.AsTypedNode.StaticType;
- if Assigned(st) then
- viewNode.TypeInfoText := st.ToString;
- end;
- end;
- end;
-end;
-
-procedure TAstEditorController.TTypePropagator.Accept(const Node: IAstNode);
-begin
- if Node = nil then
- exit;
- ApplyType(Node);
- Node.Accept(Self);
-end;
-
-end.
diff --git a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas
index edfcafb..270374e 100644
--- a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas
+++ b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas
@@ -18,7 +18,7 @@ uses
Myc.Ast.Nodes,
Myc.Ast.Identities,
Myc.Fmx.AstEditor.Layout,
- Myc.Fmx.AstEditor;
+ Myc.Fmx.AstEditor.Node;
type
// --- Abstract List Base ---
diff --git a/Src/AST/Myc.Fmx.AstEditor.Node.pas b/Src/AST/Myc.Fmx.AstEditor.Node.pas
new file mode 100644
index 0000000..5306f91
--- /dev/null
+++ b/Src/AST/Myc.Fmx.AstEditor.Node.pas
@@ -0,0 +1,542 @@
+unit Myc.Fmx.AstEditor.Node;
+
+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,
+ Myc.Fmx.AstEditor.Layout;
+
+const
+ cNodePadding = 10;
+ cTitleTopPadding = 2;
+ cTitleBottomPadding = 4;
+ cMinNodeWidth = 10;
+ cMinNodeHeight = 10;
+ cDragGutterWidth = 20; // Width of the trigger zone for dragging
+
+type
+ TAstViewNode = class;
+
+ IAstViewNodeHandler = interface
+ function GetAstNode: IAstNode;
+ procedure BuildUI(OwnerNode: TAstViewNode);
+ function ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
+ property Node: IAstNode read GetAstNode;
+ end;
+
+ IReorderable = interface
+ ['{9FA7C504-D327-4E00-A5FE-DD2876886212}']
+ function CanDrag(Child: TControl): Boolean;
+ procedure MoveChild(SourceIndex, TargetIndex: Integer);
+ end;
+
+ IAstVisualizer = interface
+ {$region 'private'}
+ function GetExprDepth: Integer;
+ function GetParentControl: TControl;
+ function GetWorkspace: TWorkspace;
+ {$endregion}
+
+ function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer;
+ function CallAccept(const Node: IAstNode): TAstViewNode;
+
+ property ExprDepth: Integer read GetExprDepth;
+ property ParentControl: TControl read GetParentControl;
+ property Workspace: TWorkspace read GetWorkspace;
+ end;
+
+ TAstViewNode = class(TAutoFitControl)
+ private
+ FBackgroundColor: TAlphaColor;
+ FBorderColor: TAlphaColor;
+ FBorderWidth: Single;
+ FBorderRadius: Single;
+ FFrameless: Boolean;
+ FVisualizer: IAstVisualizer;
+ FHandler: IAstViewNodeHandler;
+
+ FErrorMessage: string;
+ FTypeInfoText: string;
+
+ FIsFocused: Boolean;
+
+ 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;
+
+ procedure SetErrorMessage(const Value: string);
+ procedure SetTypeInfoText(const Value: string);
+ procedure UpdateVisualState;
+ procedure SetIsFocused(const Value: Boolean);
+
+ protected
+ procedure Paint; override;
+ procedure SetupNode;
+
+ procedure DoMouseEnter; override;
+ procedure DoMouseLeave; 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;
+
+ public
+ constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); 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): TAstViewNode;
+
+ function CreateAst: IAstNode;
+
+ property Visualizer: IAstVisualizer read FVisualizer;
+ property Node: IAstNode read GetNode;
+ property Handler: IAstViewNodeHandler read FHandler;
+
+ property ErrorMessage: string read FErrorMessage write SetErrorMessage;
+ property TypeInfoText: string read FTypeInfoText write SetTypeInfoText;
+ property IsFocused: Boolean read FIsFocused write SetIsFocused;
+
+ 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;
+
+ TBaseNodeHandler = class(TInterfacedObject, IAstViewNodeHandler)
+ protected
+ FNode: T;
+ function GetAstNode: IAstNode;
+ public
+ constructor Create(const ANode: T);
+ procedure BuildUI(OwnerNode: TAstViewNode); virtual; abstract;
+ function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; virtual; abstract;
+ end;
+
+implementation
+
+uses
+ Myc.Ast;
+
+{ TAstViewNode }
+
+constructor TAstViewNode.Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler);
+begin
+ inherited Create(AVisualizer.Workspace);
+
+ Parent := AVisualizer.ParentControl;
+
+ FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth);
+ FHandler := AHandler;
+
+ FBorderColor := TAlphaColors.Gray;
+ FBorderWidth := 1;
+ FBorderRadius := 9;
+ FBackgroundColor := $080a0a0a;
+
+ FFrameless := False;
+ FIsFocused := 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 TAstViewNode.Destroy;
+begin
+ FHandler := nil;
+ inherited;
+end;
+
+procedure TAstViewNode.DoMouseEnter;
+begin
+ inherited;
+ Repaint;
+end;
+
+procedure TAstViewNode.DoMouseLeave;
+begin
+ inherited;
+ Repaint;
+end;
+
+procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+const
+ cHeaderHeight = 30; // Defined height for header drag area
+begin
+ // Check for Drag Start.
+ // Condition: Left Click AND we are part of a container (list)
+ if (Button = TMouseButton.mbLeft) and (Parent is TAutoFitControl) then
+ begin
+ // Hit-Test: Either Gutter (Left) OR Header area (Top)
+ if (X < cDragGutterWidth) or (Y < cHeaderHeight) then
+ begin
+ if Assigned(FVisualizer.Workspace) then
+ begin
+ FVisualizer.Workspace.BeginDragNode(Self);
+ Exit;
+ end;
+ end;
+ end;
+
+ inherited;
+end;
+
+procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single);
+const
+ cHeaderHeight = 30;
+begin
+ // Cursor Logic (Hover Feedback)
+ if (Parent is TAutoFitControl) and ((X < cDragGutterWidth) or (Y < cHeaderHeight)) then
+ Cursor := crSizeAll
+ else
+ Cursor := crDefault;
+
+ inherited;
+end;
+
+procedure TAstViewNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+begin
+ inherited;
+end;
+
+function TAstViewNode.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 TAstViewNode.AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAstViewNode;
+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 TAstViewNode.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 TAstViewNode.AfterConstruction;
+begin
+ inherited;
+ SetupNode;
+end;
+
+function TAstViewNode.CreateAst: IAstNode;
+begin
+ if Assigned(FHandler) then
+ Result := FHandler.ReconstructAst(Self)
+ else
+ Result := TAst.Nop;
+end;
+
+function TAstViewNode.GetNode: IAstNode;
+begin
+ if Assigned(FHandler) then
+ Result := FHandler.Node
+ else
+ Result := nil;
+end;
+
+procedure TAstViewNode.SetErrorMessage(const Value: string);
+begin
+ if FErrorMessage <> Value then
+ begin
+ FErrorMessage := Value;
+ UpdateVisualState;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.SetTypeInfoText(const Value: string);
+begin
+ if FTypeInfoText <> Value then
+ begin
+ FTypeInfoText := Value;
+ UpdateVisualState;
+ end;
+end;
+
+procedure TAstViewNode.SetIsFocused(const Value: Boolean);
+begin
+ if FIsFocused <> Value then
+ begin
+ FIsFocused := Value;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.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 TAstViewNode.Paint;
+var
+ rect: TRectF;
+ effBorderColor: TAlphaColor;
+ effBorderWidth: Single;
+ effDash: TStrokeDash;
+ isHovering: Boolean;
+ shouldIgnoreHover: Boolean;
+begin
+ inherited;
+
+ shouldIgnoreHover := False;
+ if Assigned(Node) then
+ begin
+ case Node.Kind of
+ akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: shouldIgnoreHover := True;
+ end;
+ end;
+
+ isHovering := IsMouseOver and (not shouldIgnoreHover);
+
+ // 1. Determine Base Style
+ if FFrameless then
+ begin
+ effBorderColor := FBorderColor;
+ effBorderWidth := FBorderWidth;
+ effDash := TStrokeDash.Dot;
+ end
+ else
+ begin
+ effBorderColor := FBorderColor;
+ effBorderWidth := FBorderWidth;
+ effDash := TStrokeDash.Solid;
+ end;
+
+ // 2. Hover Overlay
+ if isHovering then
+ begin
+ effBorderColor := TAlphaColors.White;
+ effBorderWidth := Max(2.0, FBorderWidth + 1.0);
+ effDash := TStrokeDash.Solid;
+ end;
+
+ // 3. Error Overlay (High Priority for Color)
+ if FErrorMessage <> '' then
+ begin
+ effBorderColor := TAlphaColors.Red;
+ effBorderWidth := 2.0;
+ effDash := TStrokeDash.Solid;
+ end;
+
+ // 4. Focus Overlay (Highest Priority for Visibility/Color)
+ // Note: If Error is present, Focus will override color to Blue to indicate "Active Cursor".
+ // Error text is available in Hint.
+ if FIsFocused then
+ begin
+ effBorderColor := TAlphaColors.Dodgerblue;
+ effBorderWidth := 2.0;
+ effDash := TStrokeDash.Solid;
+ end;
+
+ Canvas.Fill.Kind := TBrushKind.Solid;
+ Canvas.Fill.Color := FBackgroundColor;
+
+ if FFrameless and (FErrorMessage = '') and (not isHovering) and (not FIsFocused) then
+ begin
+ Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
+
+ if FBorderWidth > 0 then
+ begin
+ 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;
+ end
+ else
+ begin
+ 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);
+
+ if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then
+ begin
+ 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;
+
+ if isHovering and (Parent is TAutoFitControl) then
+ begin
+ Canvas.Fill.Color := TAlphaColors.DimGray;
+ Canvas.FillEllipse(TRectF.Create(4, 6, 8, 10), 1.0);
+ Canvas.FillEllipse(TRectF.Create(4, 12, 8, 16), 1.0);
+ Canvas.FillEllipse(TRectF.Create(4, 18, 8, 22), 1.0);
+ end;
+end;
+
+procedure TAstViewNode.SetBorderColor(const Value: TAlphaColor);
+begin
+ if FBorderColor <> Value then
+ begin
+ FBorderColor := Value;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.SetBorderRadius(const Value: Single);
+begin
+ if FBorderRadius <> Value then
+ begin
+ FBorderRadius := Value;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.SetBorderWidth(const Value: Single);
+begin
+ if FBorderWidth <> Value then
+ begin
+ FBorderWidth := Value;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.SetFrameless(const Value: Boolean);
+begin
+ if FFrameless <> Value then
+ begin
+ FFrameless := Value;
+ Repaint;
+ end;
+end;
+
+procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor);
+begin
+ FBackgroundColor := Value;
+ Repaint;
+end;
+
+procedure TAstViewNode.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.Visualizer.pas b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas
index 6f3388c..fae9a98 100644
--- a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas
+++ b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas
@@ -10,7 +10,7 @@ uses
Myc.Ast.Nodes,
Myc.Ast.Visitor,
Myc.Fmx.AstEditor.Workspace,
- Myc.Fmx.AstEditor,
+ Myc.Fmx.AstEditor.Node,
Myc.Fmx.AstEditor.Handlers;
type
diff --git a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas
index d9b20a4..d8c1595 100644
--- a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas
+++ b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas
@@ -18,7 +18,6 @@ uses
type
TOnPaintConnectionsEvent = procedure(ASender: TObject; ACanvas: TCanvas) of object;
-
TOnDragDropEvent = procedure(ASource, ATarget: TControl; AIndex: Integer) of object;
TAstWorld = class(TControl)
@@ -29,7 +28,7 @@ type
FDropP1, FDropP2: TPointF;
protected
procedure Paint; override;
- procedure AfterPaint; override; // <--- HIER: Für Zeichnen ÜBER den Kindern
+ procedure AfterPaint; override;
public
constructor Create(AOwner: TComponent); override;
procedure InvalidateConnections;
@@ -163,6 +162,8 @@ begin
inherited Create(AOwner);
ClipChildren := True;
HitTest := True;
+ CanFocus := True; // Enable Keyboard Input
+ AutoCapture := True;
FRootLayer := TAstWorld.Create(Self);
FRootLayer.Parent := Self;
@@ -369,6 +370,10 @@ end;
procedure TWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
inherited;
+ // Capture Keyboard Focus
+ if CanFocus then
+ SetFocus;
+
if not FIsDraggingNode and (Button in [TMouseButton.mbLeft, TMouseButton.mbMiddle]) then
begin
FIsPanning := True;
diff --git a/Src/AST/Myc.Fmx.AstEditor.pas b/Src/AST/Myc.Fmx.AstEditor.pas
index 13fb963..d29bacd 100644
--- a/Src/AST/Myc.Fmx.AstEditor.pas
+++ b/Src/AST/Myc.Fmx.AstEditor.pas
@@ -5,511 +5,1007 @@ interface
uses
System.SysUtils,
System.Classes,
- System.UITypes,
System.Types,
+ System.UITypes,
System.Math,
System.Math.Vectors,
- System.Generics.Defaults,
System.Generics.Collections,
FMX.Types,
FMX.Controls,
- FMX.Objects,
FMX.Graphics,
- FMX.StdCtrls,
+ Myc.Ast,
Myc.Ast.Nodes,
- Myc.Fmx.AstEditor.Workspace,
- Myc.Fmx.AstEditor.Layout;
-
-const
- cNodePadding = 10;
- cTitleTopPadding = 2;
- cTitleBottomPadding = 4;
- cMinNodeWidth = 10;
- cMinNodeHeight = 10;
- cDragGutterWidth = 20; // Width of the trigger zone for dragging
+ Myc.Ast.Identities,
+ Myc.Ast.Types,
+ Myc.Ast.Visitor,
+ Myc.Ast.Scope,
+ Myc.Ast.Environment,
+ Myc.Fmx.AstEditor.Node,
+ Myc.Fmx.AstEditor.Layout,
+ Myc.Fmx.AstEditor.Workspace;
type
- TAstViewNode = class;
-
- IAstViewNodeHandler = interface
- function GetAstNode: IAstNode;
- procedure BuildUI(OwnerNode: TAstViewNode);
- function ReconstructAst(OwnerNode: TAstViewNode): IAstNode;
- property Node: IAstNode read GetAstNode;
- end;
-
- IReorderable = interface
- ['{9FA7C504-D327-4E00-A5FE-DD2876886212}']
- function CanDrag(Child: TControl): Boolean;
- procedure MoveChild(SourceIndex, TargetIndex: Integer);
- end;
-
- IAstVisualizer = interface
- {$region 'private'}
- function GetExprDepth: Integer;
- function GetParentControl: TControl;
- function GetWorkspace: TWorkspace;
- {$endregion}
-
- function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer;
- function CallAccept(const Node: IAstNode): TAstViewNode;
-
- property ExprDepth: Integer read GetExprDepth;
- property ParentControl: TControl read GetParentControl;
- property Workspace: TWorkspace read GetWorkspace;
- end;
-
- TAstViewNode = class(TAutoFitControl)
+ TAstEditor = class(TControl)
private
- FBackgroundColor: TAlphaColor;
- FBorderColor: TAlphaColor;
- FBorderWidth: Single;
- FBorderRadius: Single;
- FFrameless: Boolean;
- FVisualizer: IAstVisualizer;
- FHandler: IAstViewNodeHandler;
+ type
+ TNodeMap = TDictionary;
+ TUndoStack = TStack;
- FErrorMessage: string;
- FTypeInfoText: string;
+ TTypePropagator = class(TAstVisitor)
+ private
+ FMap: TNodeMap;
+ procedure ApplyType(const Node: IAstNode);
+ protected
+ procedure Accept(const Node: IAstNode); override;
+ public
+ constructor Create(AMap: TNodeMap);
+ end;
- 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;
+ private
+ FEnv: TAstEnvironment;
+ FWorkspace: TWorkspace;
+ FNodeMap: TNodeMap;
+ FRootViewNode: TAstViewNode;
+ FFocusedNode: TAstViewNode;
- procedure SetErrorMessage(const Value: string);
- procedure SetTypeInfoText(const Value: string);
- procedure UpdateVisualState;
+ // State Tracking
+ FCurrentAst: IAstNode;
+
+ // Undo/Redo Stacks
+ FUndoStack: TUndoStack;
+ FRedoStack: TUndoStack;
+ FIsUndoing: Boolean;
+
+ // Events
+ FOnPaintConnections: TOnPaintConnectionsEvent;
+ FOnWorkspaceMouseDown: TMouseEvent;
+
+ procedure CollectNodes(Parent: TControl);
+ procedure ClearVisuals;
+ procedure ApplyErrors(const Log: ICompilerLog);
+ procedure ApplyTypes(const TypedAst: IAstNode);
+ procedure RootResized(Sender: TObject);
+
+ // Internal Event Wiring
+ procedure HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer);
+ procedure HandleKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
+ procedure HandleWorkspacePaintConnections(ASender: TObject; ACanvas: TCanvas);
+ procedure HandleWorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+
+ // NEU: Handler für Klicks auf die Nodes selbst
+ procedure HandleNodeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+
+ procedure CommitSnapshot;
+
+ // --- Navigation Helper ---
+ procedure EnsureVisible(Node: TAstViewNode);
+ function GetParentNode(StartNode: TAstViewNode): TAstViewNode;
+ function GetFirstChild(StartNode: TAstViewNode): TAstViewNode;
+ function GetNextVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode;
+ function GetPrevVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode;
+ function GetNextLinearNode(StartNode: TAstViewNode): TAstViewNode;
+ function GetPrevLinearNode(StartNode: TAstViewNode): TAstViewNode;
+
+ procedure SetOnPaintConnections(const Value: TOnPaintConnectionsEvent);
protected
- procedure Paint; override;
- procedure SetupNode;
-
- procedure DoMouseEnter; override;
- procedure DoMouseLeave; 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 Paint; override; // For design-time border
public
- constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); reintroduce;
+ constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
- procedure AfterConstruction; override;
+ // Must be called after creation to link the AST Environment
+ procedure Init(const AEnv: TAstEnvironment);
- 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): TAstViewNode;
+ procedure ValidateAndShow;
+ procedure SetRoot(const AstNode: IAstNode);
- function CreateAst: IAstNode;
+ procedure Undo;
+ procedure Redo;
+ function CanUndo: Boolean;
+ function CanRedo: Boolean;
- property Visualizer: IAstVisualizer read FVisualizer;
- property Node: IAstNode read GetNode;
- property Handler: IAstViewNodeHandler read FHandler;
+ procedure SetFocusedNode(Node: TAstViewNode);
+ procedure Navigate(Key: Word; Shift: TShiftState);
- property ErrorMessage: string read FErrorMessage write SetErrorMessage;
- property TypeInfoText: string read FTypeInfoText write SetTypeInfoText;
+ property CurrentAst: IAstNode read FCurrentAst;
+ property FocusedNode: TAstViewNode read FFocusedNode;
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;
+ property Height;
+ property Visible;
+ property Enabled;
+ property Opacity;
- TBaseNodeHandler = class(TInterfacedObject, IAstViewNodeHandler)
- protected
- FNode: T;
- function GetAstNode: IAstNode;
- public
- constructor Create(const ANode: T);
- procedure BuildUI(OwnerNode: TAstViewNode); virtual; abstract;
- function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; virtual; abstract;
+ // Expose events relevant to the outside world
+ property OnPaintConnections: TOnPaintConnectionsEvent read FOnPaintConnections write SetOnPaintConnections;
+ property OnMouseDown: TMouseEvent read FOnWorkspaceMouseDown write FOnWorkspaceMouseDown;
end;
implementation
uses
- Myc.Ast;
+ Myc.Data.Value,
+ Myc.Fmx.AstEditor.Visualizer;
-{ TAstViewNode }
+{ TAstEditor }
-constructor TAstViewNode.Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler);
+constructor TAstEditor.Create(AOwner: TComponent);
begin
- inherited Create(AVisualizer.Workspace);
-
- Parent := AVisualizer.ParentControl;
-
- FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth);
- FHandler := AHandler;
-
- FBorderColor := TAlphaColors.Gray;
- FBorderWidth := 1;
- FBorderRadius := 9;
- FBackgroundColor := $080a0a0a;
-
- FFrameless := False;
-
- Width := cMinNodeWidth;
- Height := cMinNodeHeight;
-
- HitTest := True;
+ inherited Create(AOwner);
+ Width := 400;
+ Height := 300;
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;
+ // Create Internal Workspace
+ FWorkspace := TWorkspace.Create(Self);
+ FWorkspace.Parent := Self;
+ FWorkspace.Align := TAlignLayout.Client;
+ FWorkspace.Stored := False;
+ FWorkspace.Locked := True;
- var cn: Cardinal := $ea - (7 * FVisualizer.ExprDepth);
- var c: Cardinal := $ff000000 or (cn shl 16) or (cn shl 8) or cn;
- BackgroundColor := c;
+ // Wire Internal Events
+ FWorkspace.OnNodeDragDrop := HandleNodeDragDrop;
+ FWorkspace.OnKeyDown := HandleKeyDown;
+ FWorkspace.OnPaintConnections := HandleWorkspacePaintConnections;
+ FWorkspace.OnMouseDown := HandleWorkspaceMouseDown;
+
+ FNodeMap := TNodeMap.Create;
+ FUndoStack := TUndoStack.Create;
+ FRedoStack := TUndoStack.Create;
+ FIsUndoing := False;
+ FCurrentAst := nil;
end;
-destructor TAstViewNode.Destroy;
+destructor TAstEditor.Destroy;
begin
- FHandler := nil;
+ SetRoot(nil);
+ FNodeMap.Free;
+ FUndoStack.Free;
+ FRedoStack.Free;
inherited;
end;
-procedure TAstViewNode.DoMouseEnter;
+procedure TAstEditor.Init(const AEnv: TAstEnvironment);
begin
- inherited;
- Repaint;
+ FEnv := AEnv;
end;
-procedure TAstViewNode.DoMouseLeave;
+procedure TAstEditor.Paint;
begin
inherited;
- Repaint;
-end;
-
-procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
-const
- cHeaderHeight = 30; // Defined height for header drag area
-begin
- // Check for Drag Start.
- // Condition: Left Click AND we are part of a container (list)
- if (Button = TMouseButton.mbLeft) and (Parent is TAutoFitControl) then
+ if (csDesigning in ComponentState) then
begin
- // Hit-Test: Either Gutter (Left) OR Header area (Top)
- if (X < cDragGutterWidth) or (Y < cHeaderHeight) then
+ Canvas.Stroke.Kind := TBrushKind.Solid;
+ Canvas.Stroke.Color := TAlphaColors.Gray;
+ Canvas.Stroke.Dash := TStrokeDash.Dash;
+ Canvas.DrawRect(LocalRect, 0, 0, AllCorners, 1.0);
+ end;
+end;
+
+procedure TAstEditor.SetOnPaintConnections(const Value: TOnPaintConnectionsEvent);
+begin
+ FOnPaintConnections := Value;
+end;
+
+procedure TAstEditor.HandleWorkspacePaintConnections(ASender: TObject; ACanvas: TCanvas);
+begin
+ if Assigned(FOnPaintConnections) then
+ FOnPaintConnections(Self, ACanvas);
+end;
+
+procedure TAstEditor.HandleWorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+begin
+ // Wenn wir in den leeren Bereich klicken:
+ // 1. Tastaturfokus sicherstellen (wichtig!)
+ if FWorkspace.CanFocus then
+ FWorkspace.SetFocus;
+
+ // Optional: Fokus löschen, wenn man ins Leere klickt?
+ // SetFocusedNode(nil); // Geschmackssache. Viele Editoren behalten den Fokus.
+
+ if Assigned(FOnWorkspaceMouseDown) then
+ FOnWorkspaceMouseDown(Self, Button, Shift, X, Y);
+end;
+
+procedure TAstEditor.HandleNodeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
+begin
+ // 1. Fokus für Navigation sicherstellen (Keyboard Events gehen an Workspace)
+ if FWorkspace.CanFocus then
+ FWorkspace.SetFocus;
+
+ // 2. Visuellen/Logischen Node-Fokus setzen
+ if (Button = TMouseButton.mbLeft) and (Sender is TAstViewNode) then
+ begin
+ SetFocusedNode(TAstViewNode(Sender));
+
+ // Stoppt die Event-Propagation nach oben zum Workspace, damit wir nicht
+ // sofort wieder deselektieren (falls wir das im WorkspaceMouseDown implementiert hätten).
+ // TControl.MouseDown hat kein 'Handled', aber wir sind hier im Event-Handler.
+ end;
+end;
+
+procedure TAstEditor.CommitSnapshot;
+begin
+ if Assigned(FCurrentAst) and (not FIsUndoing) then
+ begin
+ FUndoStack.Push(FCurrentAst);
+ FRedoStack.Clear;
+ end;
+end;
+
+procedure TAstEditor.Undo;
+var
+ prevAst: IAstNode;
+begin
+ if FUndoStack.Count = 0 then
+ exit;
+
+ FIsUndoing := True;
+ try
+ if Assigned(FCurrentAst) then
+ FRedoStack.Push(FCurrentAst);
+
+ prevAst := FUndoStack.Pop;
+ SetRoot(prevAst);
+ finally
+ FIsUndoing := False;
+ end;
+end;
+
+procedure TAstEditor.Redo;
+var
+ nextAst: IAstNode;
+begin
+ if FRedoStack.Count = 0 then
+ exit;
+
+ FIsUndoing := True;
+ try
+ if Assigned(FCurrentAst) then
+ FUndoStack.Push(FCurrentAst);
+
+ nextAst := FRedoStack.Pop;
+ SetRoot(nextAst);
+ finally
+ FIsUndoing := False;
+ end;
+end;
+
+function TAstEditor.CanUndo: Boolean;
+begin
+ Result := FUndoStack.Count > 0;
+end;
+
+function TAstEditor.CanRedo: Boolean;
+begin
+ Result := FRedoStack.Count > 0;
+end;
+
+procedure TAstEditor.HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer);
+var
+ SourceParent: TControl;
+ ContainerOwner: TAstViewNode;
+ Reorderable: IReorderable;
+ SourceIdx, TargetIdx: Integer;
+ NewAst: IAstNode;
+begin
+ if (ASource = nil) or (AIndex < 0) then
+ exit;
+ if not (ASource is TAstViewNode) then
+ exit;
+
+ if not (ASource.Parent is TControl) then
+ exit;
+ SourceParent := TControl(ASource.Parent);
+
+ ContainerOwner := nil;
+
+ if (SourceParent is TAstViewNode) then
+ begin
+ ContainerOwner := TAstViewNode(SourceParent);
+ if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then
+ ContainerOwner := nil;
+ end;
+
+ if (ContainerOwner = nil) and (SourceParent.Parent is TAstViewNode) then
+ begin
+ ContainerOwner := TAstViewNode(SourceParent.Parent);
+ if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then
+ ContainerOwner := nil;
+ end;
+
+ if (ContainerOwner <> nil) and (Reorderable <> nil) then
+ begin
+ if Reorderable.CanDrag(ASource) then
begin
- if Assigned(FVisualizer.Workspace) then
+ SourceIdx := ASource.Index;
+ TargetIdx := AIndex;
+
+ if SourceIdx <> TargetIdx then
begin
- FVisualizer.Workspace.BeginDragNode(Self);
- Exit;
+ CommitSnapshot;
+ Reorderable.MoveChild(SourceIdx, TargetIdx);
+ NewAst := FRootViewNode.CreateAst;
+ SetRoot(NewAst);
+
+ // Optional: Fokus auf den verschobenen Node wiederherstellen
+ // Da der Node neu erzeugt wurde, müssten wir ihn über die Identity suchen.
end;
end;
end;
-
- inherited;
end;
-procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single);
-const
- cHeaderHeight = 30;
+procedure TAstEditor.HandleKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
begin
- // Cursor Logic (Hover Feedback)
- if (Parent is TAutoFitControl) and ((X < cDragGutterWidth) or (Y < cHeaderHeight)) then
- Cursor := crSizeAll
- else
- Cursor := crDefault;
-
- inherited;
-end;
-
-procedure TAstViewNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
-begin
- inherited;
-end;
-
-function TAstViewNode.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 TAstViewNode.AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAstViewNode;
-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 TAstViewNode.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 TAstViewNode.AfterConstruction;
-begin
- inherited;
- SetupNode;
-end;
-
-function TAstViewNode.CreateAst: IAstNode;
-begin
- if Assigned(FHandler) then
- Result := FHandler.ReconstructAst(Self)
- else
- Result := TAst.Nop;
-end;
-
-function TAstViewNode.GetNode: IAstNode;
-begin
- if Assigned(FHandler) then
- Result := FHandler.Node
- else
- Result := nil;
-end;
-
-procedure TAstViewNode.SetErrorMessage(const Value: string);
-begin
- if FErrorMessage <> Value then
+ if Key in [vkLeft, vkRight, vkUp, vkDown, vkTab, vkEscape] then
begin
- FErrorMessage := Value;
- UpdateVisualState;
- Repaint;
+ Navigate(Key, Shift);
+ Key := 0;
end;
end;
-procedure TAstViewNode.SetTypeInfoText(const Value: string);
-begin
- if FTypeInfoText <> Value then
- begin
- FTypeInfoText := Value;
- UpdateVisualState;
- end;
-end;
-
-procedure TAstViewNode.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 TAstViewNode.Paint;
+procedure TAstEditor.SetRoot(const AstNode: IAstNode);
var
- rect: TRectF;
- effBorderColor: TAlphaColor;
- effBorderWidth: Single;
- effDash: TStrokeDash;
- isHovering: Boolean;
- shouldIgnoreHover: Boolean;
+ Visualizer: IAstVisualizer;
begin
- inherited;
+ FCurrentAst := AstNode;
- shouldIgnoreHover := False;
- if Assigned(Node) then
+ if not FIsUndoing then
begin
- case Node.Kind of
- akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: shouldIgnoreHover := True;
- end;
+ FUndoStack.Clear;
+ FRedoStack.Clear;
end;
- isHovering := IsMouseOver and (not shouldIgnoreHover);
+ FFocusedNode := nil;
- if FFrameless then
+ FWorkspace.World.DeleteChildren;
+ if Assigned(FRootViewNode) then
+ FRootViewNode.OnResized := nil;
+ FRootViewNode := nil;
+
+ if not Assigned(AstNode) then
+ exit;
+
+ Visualizer := TAstVisualizer.Create(FWorkspace, FWorkspace.World, 0);
+ FRootViewNode := Visualizer.CallAccept(AstNode);
+
+ if Assigned(FRootViewNode) then
begin
- effBorderColor := FBorderColor;
- effBorderWidth := FBorderWidth;
- effDash := TStrokeDash.Dot;
- end
- else
- begin
- effBorderColor := FBorderColor;
- effBorderWidth := FBorderWidth;
- effDash := TStrokeDash.Solid;
+ FWorkspace.World.Size := FRootViewNode.Size;
+ FRootViewNode.OnResized := RootResized;
+ FRootViewNode.Position.Point := TPointF.Create(50, 50);
end;
- if isHovering then
+ if Assigned(FRootViewNode) then
+ ValidateAndShow;
+end;
+
+procedure TAstEditor.CollectNodes(Parent: TControl);
+var
+ i: Integer;
+ child: TControl;
+ viewNode: TAstViewNode;
+begin
+ for i := 0 to Parent.ChildrenCount - 1 do
begin
- effBorderColor := TAlphaColors.White;
- effBorderWidth := Max(2.0, FBorderWidth + 1.0);
- effDash := TStrokeDash.Solid;
- end;
-
- if FErrorMessage <> '' then
- begin
- effBorderColor := TAlphaColors.Red;
- effBorderWidth := 2.0;
- effDash := TStrokeDash.Solid;
- end;
-
- Canvas.Fill.Kind := TBrushKind.Solid;
- Canvas.Fill.Color := FBackgroundColor;
-
- if FFrameless and (FErrorMessage = '') and (not isHovering) then
- begin
- Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0);
-
- if FBorderWidth > 0 then
+ if Parent.Children[i] is TControl then
begin
- 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);
+ child := TControl(Parent.Children[i]);
+
+ if child is TAstViewNode then
+ begin
+ viewNode := TAstViewNode(child);
+
+ // HIER: Das Click-Event wiring
+ viewNode.OnMouseDown := HandleNodeMouseDown;
+
+ if Assigned(viewNode.Node) and Assigned(viewNode.Node.Identity) then
+ begin
+ FNodeMap.AddOrSetValue(viewNode.Node.Identity, viewNode);
+ end;
+ end;
+
+ if child.ChildrenCount > 0 then
+ CollectNodes(child);
end;
- end
- else
+ end;
+end;
+
+procedure TAstEditor.ClearVisuals;
+begin
+ for var viewNode in FNodeMap.Values do
begin
- rect := TRectF.Create(0, 0, Width, Height);
- if (effBorderWidth > 0) then
- rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2);
+ viewNode.ErrorMessage := '';
+ viewNode.TypeInfoText := '';
+ end;
+end;
- Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round);
-
- if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then
+procedure TAstEditor.ApplyErrors(const Log: ICompilerLog);
+var
+ entry: TCompilerError;
+ viewNode: TAstViewNode;
+begin
+ for entry in Log.GetEntries do
+ begin
+ if (entry.Level = elError) and Assigned(entry.Node) and Assigned(entry.Node.Identity) then
begin
- 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);
+ if FNodeMap.TryGetValue(entry.Node.Identity, viewNode) then
+ begin
+ if viewNode.ErrorMessage = '' then
+ viewNode.ErrorMessage := entry.Message
+ else
+ viewNode.ErrorMessage := viewNode.ErrorMessage + sLineBreak + entry.Message;
+ end;
+ end;
+ end;
+end;
+
+procedure TAstEditor.ApplyTypes(const TypedAst: IAstNode);
+var
+ propagator: TTypePropagator;
+begin
+ if not Assigned(TypedAst) then
+ exit;
+
+ propagator := TTypePropagator.Create(FNodeMap);
+ try
+ propagator.Accept(TypedAst);
+ finally
+ propagator.Free;
+ end;
+end;
+
+procedure TAstEditor.RootResized(Sender: TObject);
+begin
+ FWorkspace.World.Size := FRootViewNode.Size;
+end;
+
+procedure TAstEditor.ValidateAndShow;
+var
+ logicalAst: IAstNode;
+begin
+ if not Assigned(FRootViewNode) then
+ exit;
+
+ logicalAst := FRootViewNode.CreateAst;
+
+ FNodeMap.Clear;
+ CollectNodes(FWorkspace.World);
+
+ ClearVisuals;
+
+ try
+ var log := TCompilerLog.Create as ICompilerLog;
+
+ var expanded := FEnv.ExpandMacros(logicalAst);
+ var typedAst := FEnv.Bind(expanded, [], log);
+ var specAst := FEnv.Specialize(typedAst);
+
+ ApplyTypes(specAst);
+
+ if specAst.Kind = akLambdaExpression then
+ var compiled := FEnv.Link(specAst.AsLambdaExpression, log);
+
+ ApplyErrors(log);
+ except
+ on E: ECompilationFailed do
+ begin
+ var tempLog := TCompilerLog.Create as ICompilerLog;
+ for var err in E.Errors do
+ tempLog.Add(err.Level, err.Message, err.Node);
+ ApplyErrors(tempLog);
end;
end;
- if isHovering and (Parent is TAutoFitControl) then
+ FWorkspace.World.Repaint;
+end;
+
+// =================================================================================================
+// == NAVIGATION IMPLEMENTATION
+// =================================================================================================
+
+procedure TAstEditor.SetFocusedNode(Node: TAstViewNode);
+begin
+ if FFocusedNode = Node then
+ Exit;
+
+ if Assigned(FFocusedNode) then
+ FFocusedNode.IsFocused := False;
+
+ FFocusedNode := Node;
+
+ if Assigned(FFocusedNode) then
begin
- Canvas.Fill.Color := TAlphaColors.DimGray;
- Canvas.FillEllipse(TRectF.Create(4, 6, 8, 10), 1.0);
- Canvas.FillEllipse(TRectF.Create(4, 12, 8, 16), 1.0);
- Canvas.FillEllipse(TRectF.Create(4, 18, 8, 22), 1.0);
+ FFocusedNode.IsFocused := True;
+ EnsureVisible(FFocusedNode);
end;
end;
-procedure TAstViewNode.SetBorderColor(const Value: TAlphaColor);
+procedure TAstEditor.EnsureVisible(Node: TAstViewNode);
+const
+ cMargin = 40; // Abstand zum Rand in Pixeln
+var
+ NodeRect, ViewRect: TRectF;
+ Delta: TPointF;
begin
- if FBorderColor <> Value then
+ if (Node = nil) or (FWorkspace = nil) then
+ Exit;
+
+ // 1. Hole absolute Koordinaten
+ NodeRect := Node.AbsoluteRect;
+ ViewRect := FWorkspace.AbsoluteRect;
+
+ // 2. Definiere den "sicheren" Bereich (Viewport minus Rand)
+ ViewRect.Inflate(-cMargin, -cMargin);
+
+ Delta := TPointF.Zero;
+
+ // 3. Horizontal prüfen
+ if NodeRect.Width > ViewRect.Width then
begin
- FBorderColor := Value;
- Repaint;
+ // Node ist breiter als der Screen -> Zentrieren
+ Delta.X := ViewRect.CenterPoint.X - NodeRect.CenterPoint.X;
+ end
+ else if NodeRect.Left < ViewRect.Left then
+ begin
+ // Node ragt links raus -> nach rechts schieben
+ Delta.X := ViewRect.Left - NodeRect.Left;
+ end
+ else if NodeRect.Right > ViewRect.Right then
+ begin
+ // Node ragt rechts raus -> nach links schieben
+ Delta.X := ViewRect.Right - NodeRect.Right;
+ end;
+
+ // 4. Vertikal prüfen
+ if NodeRect.Height > ViewRect.Height then
+ begin
+ // Node ist höher als der Screen -> Zentrieren
+ Delta.Y := ViewRect.CenterPoint.Y - NodeRect.CenterPoint.Y;
+ end
+ else if NodeRect.Top < ViewRect.Top then
+ begin
+ // Node ragt oben raus -> nach unten schieben
+ Delta.Y := ViewRect.Top - NodeRect.Top;
+ end
+ else if NodeRect.Bottom > ViewRect.Bottom then
+ begin
+ // Node ragt unten raus -> nach oben schieben
+ Delta.Y := ViewRect.Bottom - NodeRect.Bottom;
+ end;
+
+ // 5. Nur anwenden, wenn eine Verschiebung nötig ist
+ if not (SameValue(Delta.X, 0, TEpsilon.Position) and SameValue(Delta.Y, 0, TEpsilon.Position)) then
+ begin
+ FWorkspace.ContentOffset := FWorkspace.ContentOffset + Delta;
end;
end;
-procedure TAstViewNode.SetBorderRadius(const Value: Single);
+function TAstEditor.GetParentNode(StartNode: TAstViewNode): TAstViewNode;
+var
+ curr: TControl;
begin
- if FBorderRadius <> Value then
+ Result := nil;
+ if StartNode = nil then
+ Exit;
+
+ curr := StartNode.ParentControl;
+ while (curr <> nil) and (curr <> FWorkspace.World) do
begin
- FBorderRadius := Value;
- Repaint;
+ if curr is TAstViewNode then
+ Exit(TAstViewNode(curr));
+ curr := curr.ParentControl;
end;
end;
-procedure TAstViewNode.SetBorderWidth(const Value: Single);
-begin
- if FBorderWidth <> Value then
+function TAstEditor.GetFirstChild(StartNode: TAstViewNode): TAstViewNode;
+ function FindFirst(Parent: TControl): TAstViewNode;
+ var
+ i: Integer;
begin
- FBorderWidth := Value;
- Repaint;
+ Result := nil;
+ for i := 0 to Parent.ChildrenCount - 1 do
+ begin
+ if Parent.Children[i] is TAstViewNode then
+ Exit(TAstViewNode(Parent.Children[i]))
+ else if (Parent.Children[i] is TControl) and (TControl(Parent.Children[i]).ChildrenCount > 0) then
+ begin
+ Result := FindFirst(TControl(Parent.Children[i]));
+ if Result <> nil then
+ Exit;
+ end;
+ end;
+ end;
+begin
+ Result := FindFirst(StartNode);
+end;
+
+function FindFirstViewNode(Container: TControl): TAstViewNode;
+var
+ i: Integer;
+ Child: TControl;
+begin
+ Result := nil;
+ if Container is TAstViewNode then
+ Exit(TAstViewNode(Container));
+
+ for i := 0 to Container.ChildrenCount - 1 do
+ begin
+ if Container.Children[i] is TControl then
+ begin
+ Child := TControl(Container.Children[i]);
+ if Child.Visible then
+ begin
+ Result := FindFirstViewNode(Child);
+ if Result <> nil then
+ Exit;
+ end;
+ end;
end;
end;
-procedure TAstViewNode.SetFrameless(const Value: Boolean);
+function FindLastViewNode(Container: TControl): TAstViewNode;
+var
+ i: Integer;
+ Child: TControl;
begin
- if FFrameless <> Value then
+ Result := nil;
+ if Container is TAstViewNode then
+ exit(TAstViewNode(Container));
+
+ for i := Container.ChildrenCount - 1 downto 0 do
begin
- FFrameless := Value;
- Repaint;
+ if Container.Children[i] is TControl then
+ begin
+ Child := TControl(Container.Children[i]);
+ if Child.Visible then
+ begin
+ var Found := FindLastViewNode(Child);
+ if Found <> nil then
+ Exit(Found);
+ end;
+ end;
end;
end;
-procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor);
+// Helper um den nächsten ViewNode in einer Liste von Controls zu finden
+
+function FindNextSiblingInList(Parent: TControl; AfterControl: TControl): TAstViewNode;
+var
+ i, StartIndex: Integer;
+ Candidate: TControl;
begin
- FBackgroundColor := Value;
- Repaint;
+ Result := nil;
+ StartIndex := -1;
+ for i := 0 to Parent.ChildrenCount - 1 do
+ if Parent.Children[i] = AfterControl then
+ begin
+ StartIndex := i;
+ Break;
+ end;
+
+ if StartIndex >= 0 then
+ begin
+ for i := StartIndex + 1 to Parent.ChildrenCount - 1 do
+ begin
+ if Parent.Children[i] is TControl then
+ begin
+ Candidate := TControl(Parent.Children[i]);
+ if Candidate.Visible then
+ begin
+ Result := FindFirstViewNode(Candidate);
+ if Result <> nil then
+ Exit;
+ end;
+ end;
+ end;
+ end;
end;
-procedure TAstViewNode.SetupNode;
+function FindPrevSiblingInList(Parent: TControl; BeforeControl: TControl): TAstViewNode;
+var
+ i, StartIndex: Integer;
+ Candidate: TControl;
begin
- if Assigned(FHandler) then
- FHandler.BuildUI(Self);
+ Result := nil;
+ StartIndex := -1;
+ for i := 0 to Parent.ChildrenCount - 1 do
+ if Parent.Children[i] = BeforeControl then
+ begin
+ StartIndex := i;
+ Break;
+ end;
+
+ if StartIndex >= 0 then
+ begin
+ for i := StartIndex - 1 downto 0 do
+ begin
+ if Parent.Children[i] is TControl then
+ begin
+ Candidate := TControl(Parent.Children[i]);
+ if Candidate.Visible then
+ begin
+ Result := FindLastViewNode(Candidate);
+ if Result <> nil then
+ Exit;
+ end;
+ end;
+ end;
+ end;
end;
-{ TBaseNodeHandler }
+// --- Vertical Axis Navigation (Skip Row) ---
-constructor TBaseNodeHandler.Create(const ANode: T);
+function TAstEditor.GetNextVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode;
+var
+ Current, Parent: TControl;
+begin
+ Result := nil;
+ Current := StartNode;
+
+ while (Current <> nil) and (Current <> FWorkspace.World) do
+ begin
+ Parent := Current.ParentControl;
+ if Parent = nil then
+ Break;
+
+ // Wenn der Parent vertikal ist, suchen wir hier den Nachbarn.
+ if (Parent is TAutoFitControl) and (TAutoFitControl(Parent).Orientation = TLayoutOrientation.loVertical) then
+ begin
+ Result := FindNextSiblingInList(Parent, Current);
+ if Result <> nil then
+ Exit;
+ end;
+
+ Current := Parent;
+ end;
+
+ if Result = nil then
+ Result := GetNextLinearNode(StartNode)
+end;
+
+function TAstEditor.GetPrevVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode;
+var
+ Current, Parent: TControl;
+begin
+ Result := nil;
+ Current := StartNode;
+
+ while (Current <> nil) and (Current <> FWorkspace.World) do
+ begin
+ Parent := Current.ParentControl;
+ if Parent = nil then
+ Break;
+
+ if (Parent is TAutoFitControl) and (TAutoFitControl(Parent).Orientation = TLayoutOrientation.loVertical) then
+ begin
+ Result := FindPrevSiblingInList(Parent, Current);
+ if Result <> nil then
+ Exit;
+ end;
+
+ Current := Parent;
+ end;
+
+ if Result = nil then
+ Result := GetPrevLinearNode(StartNode)
+end;
+
+function TAstEditor.GetNextLinearNode(StartNode: TAstViewNode): TAstViewNode;
+var
+ CurrentControl, ParentControl: TControl;
+ i, StartIndex: Integer;
+ Candidate: TControl;
+begin
+ // 1. Try Child (Drill Down)
+ Result := GetFirstChild(StartNode);
+ if Result <> nil then
+ Exit;
+
+ // 2. Walk up visually and check for next siblings at every layout level
+ CurrentControl := StartNode;
+ while (CurrentControl <> nil) and (CurrentControl <> FWorkspace.World) do
+ begin
+ ParentControl := CurrentControl.ParentControl;
+ if ParentControl = nil then
+ Break;
+
+ // Find index of current control
+ StartIndex := -1;
+ for i := 0 to ParentControl.ChildrenCount - 1 do
+ if ParentControl.Children[i] = CurrentControl then
+ begin
+ StartIndex := i;
+ Break;
+ end;
+
+ // Scan forward from next index
+ if StartIndex >= 0 then
+ begin
+ for i := StartIndex + 1 to ParentControl.ChildrenCount - 1 do
+ begin
+ if ParentControl.Children[i] is TControl then
+ begin
+ Candidate := TControl(ParentControl.Children[i]);
+ if Candidate.Visible then
+ begin
+ // Check if this candidate IS a node or CONTAINS a node
+ Result := FindFirstViewNode(Candidate);
+ if Result <> nil then
+ Exit;
+ end;
+ end;
+ end;
+ end;
+
+ // Move up one physical level (e.g. from ParameterList to TitleContainer)
+ CurrentControl := ParentControl;
+ end;
+
+ Result := nil;
+end;
+
+function TAstEditor.GetPrevLinearNode(StartNode: TAstViewNode): TAstViewNode;
+var
+ CurrentControl, ParentControl: TControl;
+ i, StartIndex: Integer;
+ Candidate: TControl;
+begin
+ // No simple "Drill Down" here, because Prev means "Left of me".
+ // If I have children, "Left of me" is OUTSIDE of me (Parent or Sibling).
+ // Wait: Standard Tab behavior:
+ // Tab: Current -> Child -> Next Sibling
+ // Shift-Tab: Current -> Prev Sibling (Deepest Child) -> Parent
+
+ CurrentControl := StartNode;
+ while (CurrentControl <> nil) and (CurrentControl <> FWorkspace.World) do
+ begin
+ ParentControl := CurrentControl.ParentControl;
+ if ParentControl = nil then
+ Break;
+
+ // Find index
+ StartIndex := -1;
+ for i := 0 to ParentControl.ChildrenCount - 1 do
+ if ParentControl.Children[i] = CurrentControl then
+ begin
+ StartIndex := i;
+ Break;
+ end;
+
+ // Scan backward
+ if StartIndex >= 0 then
+ begin
+ for i := StartIndex - 1 downto 0 do
+ begin
+ if ParentControl.Children[i] is TControl then
+ begin
+ Candidate := TControl(ParentControl.Children[i]);
+ if Candidate.Visible then
+ begin
+ // Find the deepest last node inside this sibling
+ Result := FindLastViewNode(Candidate);
+ if Result <> nil then
+ Exit;
+ end;
+ end;
+ end;
+ end;
+
+ // If no sibling found to the left, the Parent is the previous logical node
+ if ParentControl is TAstViewNode then
+ Exit(TAstViewNode(ParentControl));
+
+ // If Parent is just a Layout Container, keep walking up
+ CurrentControl := ParentControl;
+ end;
+
+ Result := nil;
+end;
+
+// --- Main Navigate Method ---
+
+procedure TAstEditor.Navigate(Key: Word; Shift: TShiftState);
+var
+ Current: TAstViewNode;
+ Target: TAstViewNode;
+begin
+ if FFocusedNode = nil then
+ begin
+ SetFocusedNode(FRootViewNode);
+ Exit;
+ end;
+
+ Current := FFocusedNode;
+ Target := nil;
+
+ // 1. Linear Navigation (Tab) - Bleibt wie gehabt
+ if Key = vkTab then
+ begin
+ if ssShift in Shift then
+ Target := GetPrevLinearNode(Current)
+ else
+ Target := GetNextLinearNode(Current);
+
+ if Target <> nil then
+ SetFocusedNode(Target);
+ Exit;
+ end;
+
+ // 2. Escape - Bleibt "Notausgang" zum Parent
+ if Key = vkEscape then
+ begin
+ Target := GetParentNode(Current);
+ if Target <> nil then
+ SetFocusedNode(Target);
+ Exit;
+ end;
+
+ // 3. Axis Analysis
+ case Key of
+ vkLeft:
+ begin
+ Target := GetPrevLinearNode(Current);
+ end;
+
+ vkRight:
+ begin
+ Target := GetNextLinearNode(Current);
+ end;
+
+ vkUp:
+ begin
+ Target := GetPrevVerticalNeighbor(Current)
+ end;
+
+ vkDown:
+ begin
+ Target := GetNextVerticalNeighbor(Current)
+ end;
+ end;
+
+ if Target <> nil then
+ SetFocusedNode(Target);
+end;
+
+{ TAstEditor.TTypePropagator }
+
+constructor TAstEditor.TTypePropagator.Create(AMap: TNodeMap);
begin
inherited Create;
- FNode := ANode;
+ FMap := AMap;
end;
-function TBaseNodeHandler.GetAstNode: IAstNode;
+procedure TAstEditor.TTypePropagator.ApplyType(const Node: IAstNode);
+var
+ viewNode: TAstViewNode;
begin
- Result := FNode;
+ if Assigned(Node) and Assigned(Node.Identity) then
+ begin
+ if FMap.TryGetValue(Node.Identity, viewNode) then
+ begin
+ if Node.IsTyped then
+ begin
+ var st := Node.AsTypedNode.StaticType;
+ if Assigned(st) then
+ viewNode.TypeInfoText := st.ToString;
+ end;
+ end;
+ end;
+end;
+
+procedure TAstEditor.TTypePropagator.Accept(const Node: IAstNode);
+begin
+ if Node = nil then
+ exit;
+ ApplyType(Node);
+ Node.Accept(Self);
end;
end.