From 851f56c63f5ef8a3d94e834a618925a17b3af2a1 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sat, 29 Nov 2025 18:59:16 +0100 Subject: [PATCH] Ast list nodes --- ASTPlayground/ASTPlayground.delphilsp.json | 2 +- ASTPlayground/UserLib.json | 63 ++- Src/AST/Myc.Ast.Analysis.Purity.pas | 69 ++- Src/AST/Myc.Ast.Compiler.Binder.Upvalues.pas | 2 +- Src/AST/Myc.Ast.Compiler.Binder.pas | 33 +- Src/AST/Myc.Ast.Compiler.Macros.pas | 80 ++- Src/AST/Myc.Ast.Compiler.Specializer.pas | 31 +- Src/AST/Myc.Ast.Compiler.TCO.pas | 74 ++- Src/AST/Myc.Ast.Compiler.TypeChecker.pas | 100 ++-- Src/AST/Myc.Ast.Debugger.pas | 1 + Src/AST/Myc.Ast.Dumper.pas | 67 ++- Src/AST/Myc.Ast.Evaluator.pas | 88 +++- Src/AST/Myc.Ast.Identities.pas | 84 ++- Src/AST/Myc.Ast.JSON.pas | 112 ++-- Src/AST/Myc.Ast.Nodes.pas | 434 ++++++++++++--- Src/AST/Myc.Ast.Script.pas | 171 +++--- Src/AST/Myc.Ast.Visitor.pas | 494 +++++++++++------- Src/AST/Myc.Ast.pas | 150 +++--- Src/AST/Myc.Fmx.AstEditor.Core.pas | 17 +- Src/AST/Myc.Fmx.AstEditor.Handlers.pas | 522 +++++++++++-------- Src/AST/Myc.Fmx.AstEditor.Visualizer.pas | 37 ++ Src/AST/Myc.Fmx.AstEditor.Workspace.pas | 31 +- Test/AST/Test.Myc.Ast.Script.pas | 17 +- Test/Test.Myc.Ast.Compiler.Binder.pas | 3 +- 24 files changed, 1819 insertions(+), 863 deletions(-) diff --git a/ASTPlayground/ASTPlayground.delphilsp.json b/ASTPlayground/ASTPlayground.delphilsp.json index 0459e48..c4a2d82 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.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Handlers", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Handlers.pas" }, { "name": "Myc.Fmx.AstEditor.Visualizer", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Controller", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Controller.pas" } ] , "includeDCUsInUsesCompletion": true, "enableKeyWordCompletion": false, "browsingPaths": [ "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/OCX/Servers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/VCL","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/RTL/SYS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win/winrt","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/ToolsAPI","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/IBX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Internet","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/PROPERTY%20EDITORS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/XML","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Core","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/System","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Protocols","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/fmx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/components","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/engine","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/graph","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ado","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/cloud","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dbx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dsnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/vclctrls","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/connectors","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/proxygen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DataExplorer","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/src","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/tests","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Experts","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/abstraction","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/implementation","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indyimpl","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Property%20Editors/Indy10","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap/wsdlimporter","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Visualizers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XMLReporting","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XPGen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/rest","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/firedac","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/tethering","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnitX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ems","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/net","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/FlatBox2D","file:///C%3A/Users/Public/Documents/Embarcadero/Studio/37.0/Dcp/%25PLATFORM%25","file:///%25TP%25/runtime/vcl","file:///S%3A/sc_famos_src/svn_vcl/cpxedits","file:///S%3A/sc_famos_src/svn_vcl/dzChart","file:///S%3A/sc_famos_src/svn_vcl/eaeditor","file:///S%3A/sc_famos_src/svn_vcl/FamosEvents","file:///S%3A/sc_famos_src/svn_vcl/HTML_Viewer/source","file:///S%3A/sc_famos_src/svn_vcl/Myc_ChartEdit","file:///S%3A/sc_famos_src/svn_vcl/Myc_HemiDrag","file:///S%3A/sc_famos_src/svn_vcl/Myc_SplitControl","file:///S%3A/sc_famos_src/svn_vcl/NiceChart","file:///S%3A/sc_famos_src/svn_vcl/plotter","file:///S%3A/sc_famos_src/svn_vcl/SimpleIPC","file:///S%3A/sc_famos_src/svn_vcl/SynEdit-master/Source","file:///S%3A/sc_famos_src/svn_vcl/ValEdits","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib/win32","file:///S%3A/sc_famos_src/svn_vcl/Virtual-TreeView/Source","file:///S%3A/sc_famos_src/svn_common/caHelpSys","file:///S%3A/sc_famos_src/svn_common/Misc","file:///S%3A/sc_famos_src/svn_common/Myc_VecMath","file:///S%3A/sc_famos_src/svn_common/PascalScript/source","file:///S%3A/sc_famos_src/svn_common/TreeBase","file:///S%3A/sc_famos_src/svn_common/TreeBase/Medien","file:///S%3A/3rdParty/spring4d/Source","file:///S%3A/3rdParty/spring4d/Source/Base","file:///S%3A/3rdParty/spring4d/Source/Base/Collections","file:///S%3A/3rdParty/spring4d/Source/Base/Logging","file:///S%3A/3rdParty/spring4d/Source/Base/Patches","file:///S%3A/3rdParty/spring4d/Source/Core/Container","file:///S%3A/3rdParty/spring4d/Source/Core/Interception","file:///S%3A/3rdParty/spring4d/Source/Core/Logging","file:///S%3A/3rdParty/spring4d/Source/Core/Mocking","file:///S%3A/3rdParty/spring4d/Source/Core/Services","file:///S%3A/3rdParty/spring4d/Source/Extensions/Cryptography","file:///S%3A/3rdParty/spring4d/Source/Extensions/Utils","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCommon%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressGDI%2B%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLibrary/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/XP%20Theme%20Manager/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLayout%20Control/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressPageControl/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressEditors%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDocking%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressBars/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressOfficeCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressMemData/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDataController/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressNavBar/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressSkins%20Library/Sources","file:///T%3A/Myc/Src","file:///T%3A/Myc/Src/Data","file:///T%3A/Myc/Src/AST" ] , "CommonAppData": "file:///C%3A/Users/Brummel/AppData/Roaming/Embarcadero/BDS/37.0/" , "Templates": "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/ObjRepos/" } } \ No newline at end of file +{ "settings": { "project": "file:///T%3A/Myc/ASTPlayground/ASTPlayground.dpr", "dllname": "dcc64370.dll", "dccOptions": "-$O- -$W+ --inline:off -$R+ -$Q+ --no-config -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG;;FRAMEWORK_FMX -E.\\Win64\\Debug -I\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -LEC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Bpl\\Win64 -LNC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NU.\\Win64\\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;System;Xml;Data;Datasnap;Web;Soap; -OT:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -R\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -U\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -V -VN -VR -NBC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NHC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\hpp\\Win64 -NO.\\Win64\\Debug -LU" , "projectFiles":[ { "name": "MainForm", "file": "file:///T%3A/Myc/ASTPlayground/MainForm.pas" }, { "name": "Myc.Ast.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Nodes.pas" }, { "name": "Myc.Ast.Scope", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Scope.pas" }, { "name": "Myc.Data.Value", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Data.Value.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Compiler.TCO", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TCO.pas" }, { "name": "Myc.Ast.Compiler.Binder", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Binder.pas" }, { "name": "Myc.Ast.Compiler.Lowering", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Lowering.pas" }, { "name": "Myc.Ast.Compiler.TypeChecker", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TypeChecker.pas" }, { "name": "Myc.Ast.Compiler.Macros", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Macros.pas" }, { "name": "Myc.Ast.Compiler.Specializer", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Specializer.pas" }, { "name": "Myc.Ast.Environment", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Environment.pas" }, { "name": "Myc.Ast.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Analysis.Purity", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Analysis.Purity.pas" }, { "name": "Myc.Ast.Identities", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Identities.pas" }, { "name": "Myc.Fmx.AstEditor.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Handlers", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Handlers.pas" }, { "name": "Myc.Fmx.AstEditor.Visualizer", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Controller", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Controller.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/UserLib.json b/ASTPlayground/UserLib.json index 2022c27..cad44f4 100644 --- a/ASTPlayground/UserLib.json +++ b/ASTPlayground/UserLib.json @@ -148,7 +148,8 @@ }, "ElseBranch": { "NodeType": "Block", - "Expressions": [] + "Expressions": [ + ] } } } @@ -1095,5 +1096,65 @@ } ] } + }, + "test2": { + "NodeType": "MacroDef", + "Name": { + "NodeType": "Identifier", + "Name": "test2" + }, + "Parameters": [ + { + "NodeType": "Identifier", + "Name": "body" + } + ], + "Body": { + "NodeType": "Quasiquote", + "Expression": { + "NodeType": "LambdaExpr", + "Parameters": [ + ], + "Body": { + "NodeType": "Unquote", + "Expression": { + "NodeType": "Identifier", + "Name": "body" + } + } + } + } + }, + "debug-mode": { + "NodeType": "Keyword", + "Name": "true" + }, + "test": { + "NodeType": "MacroDef", + "Name": { + "NodeType": "Identifier", + "Name": "test" + }, + "Parameters": [ + { + "NodeType": "Identifier", + "Name": "body" + } + ], + "Body": { + "NodeType": "Quasiquote", + "Expression": { + "NodeType": "LambdaExpr", + "Parameters": [ + ], + "Body": { + "NodeType": "Unquote", + "Expression": { + "NodeType": "Identifier", + "Name": "body" + } + } + } + } } } \ No newline at end of file diff --git a/Src/AST/Myc.Ast.Analysis.Purity.pas b/Src/AST/Myc.Ast.Analysis.Purity.pas index 41b12fe..ccfdaa6 100644 --- a/Src/AST/Myc.Ast.Analysis.Purity.pas +++ b/Src/AST/Myc.Ast.Analysis.Purity.pas @@ -29,6 +29,13 @@ type function VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; override; function VisitSeriesLength(const Node: ISeriesLengthNode): Boolean; override; + // --- List Visitors (New) --- + function VisitParameterList(const Node: IParameterList): Boolean; override; + function VisitArgumentList(const Node: IArgumentList): Boolean; override; + function VisitExpressionList(const Node: IExpressionList): Boolean; override; + function VisitRecordFieldList(const Node: IRecordFieldList): Boolean; override; + function VisitRecordField(const Node: IRecordFieldNode): Boolean; override; + // --- Critical Checks --- function VisitIdentifier(const Node: IIdentifierNode): Boolean; override; function VisitFunctionCall(const Node: IFunctionCallNode): Boolean; override; @@ -81,6 +88,44 @@ begin Result := Node.Accept(Self).AsGeneric; end; +// --- List Visitors --- + +function TPurityAnalyzer.VisitParameterList(const Node: IParameterList): Boolean; +begin + // Declarations are pure + Result := True; +end; + +function TPurityAnalyzer.VisitArgumentList(const Node: IArgumentList): Boolean; +begin + for var item in Node do + if not Accept(item) then + exit(False); + Result := True; +end; + +function TPurityAnalyzer.VisitExpressionList(const Node: IExpressionList): Boolean; +begin + for var item in Node do + if not Accept(item) then + exit(False); + Result := True; +end; + +function TPurityAnalyzer.VisitRecordFieldList(const Node: IRecordFieldList): Boolean; +begin + for var item in Node do + if not Accept(item) then + exit(False); + Result := True; +end; + +function TPurityAnalyzer.VisitRecordField(const Node: IRecordFieldNode): Boolean; +begin + // Key is usually pure (Keyword), check Value + Result := Accept(Node.Key) and Accept(Node.Value); +end; + // --- Safe Leaves --- function TPurityAnalyzer.VisitConstant(const Node: IConstantNode): Boolean; @@ -120,11 +165,8 @@ begin exit(False); // 2. All arguments must be pure expressions. - for var arg in Node.Arguments do - if not Accept(arg) then - exit(False); - - Result := True; + // Delegate to ArgumentList visitor + Result := Accept(Node.Arguments); end; // --- Recursion --- @@ -132,10 +174,7 @@ end; function TPurityAnalyzer.VisitRecurNode(const Node: IRecurNode): Boolean; begin // 'recur' is just control flow. It is pure if its arguments are pure. - for var arg in Node.Arguments do - if not Accept(arg) then - exit(False); - Result := True; + Result := Accept(Node.Arguments); end; // --- Structures: Recursive Checks --- @@ -152,10 +191,8 @@ end; function TPurityAnalyzer.VisitBlockExpression(const Node: IBlockExpressionNode): Boolean; begin - for var expr in Node.Expressions do - if not Accept(expr) then - exit(False); - Result := True; + // Delegate to ExpressionList + Result := Accept(Node.Expressions); end; function TPurityAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): Boolean; @@ -167,10 +204,8 @@ end; function TPurityAnalyzer.VisitRecordLiteral(const Node: IRecordLiteralNode): Boolean; begin - for var field in Node.Fields do - if not Accept(field.Value) then - exit(False); - Result := True; + // Delegate to RecordFieldList + Result := Accept(Node.Fields); end; function TPurityAnalyzer.VisitIndexer(const Node: IIndexerNode): Boolean; diff --git a/Src/AST/Myc.Ast.Compiler.Binder.Upvalues.pas b/Src/AST/Myc.Ast.Compiler.Binder.Upvalues.pas index 05e6d93..d986a3f 100644 --- a/Src/AST/Myc.Ast.Compiler.Binder.Upvalues.pas +++ b/Src/AST/Myc.Ast.Compiler.Binder.Upvalues.pas @@ -186,7 +186,7 @@ begin // 2. Register parameters (they mask outer variables) // We pass 'nil' as the node because we currently don't box parameters, // but we must ensure Resolve() finds them so we don't accidentally box a shadowed variable. - for i := 0 to High(Node.Parameters) do + for i := 0 to Node.Parameters.Count - 1 do begin FCurrentScope.Define(Node.Parameters[i].Name, nil); end; diff --git a/Src/AST/Myc.Ast.Compiler.Binder.pas b/Src/AST/Myc.Ast.Compiler.Binder.pas index 0455c95..6e789d8 100644 --- a/Src/AST/Myc.Ast.Compiler.Binder.pas +++ b/Src/AST/Myc.Ast.Compiler.Binder.pas @@ -342,6 +342,7 @@ var startCount: Integer; hasNested: Boolean; paramIdentity: INamedIdentity; + paramList: IParameterList; begin startCount := FLambdaCounter; Inc(FLambdaCounter); @@ -355,8 +356,10 @@ begin try FCurrentBuilder.Define(''); - SetLength(newParams, Length(Node.Parameters)); - for i := 0 to High(Node.Parameters) do + // Create Array to hold transformed parameters + SetLength(newParams, Node.Parameters.Count); + + for i := 0 to Node.Parameters.Count - 1 do begin var paramNode := Node.Parameters[i]; var paramName := paramNode.Name; @@ -414,11 +417,15 @@ begin hasNested := FLambdaCounter > (startCount + 1); + // Wrap the array in a List wrapper to satisfy the factory interface + // We reuse the identity of the old parameter list + paramList := TParameterList.Create(newParams, Node.Parameters.Identity); + // Rebuild Lambda using original identity Result := TAst.LambdaExpr( Node.Identity, - newParams, + paramList, newBody, finalLayout, nil, // Descriptor is created in TypeChecker @@ -433,11 +440,21 @@ begin if Node.Callee.Kind = akKeyword then begin // Transform keyword call (:key obj) into member access (.key obj) - // Note: The new MemberAccess node gets the identity of the original FunctionCall - // The member keyword retains its own identity. - var memberAccess := TAst.MemberAccess(Node.Identity, Accept(Node.Arguments[0]), Node.Callee.AsKeyword); - Result := memberAccess; - exit; + // Check argument count + if Node.Arguments.Count <> 1 then + begin + if Assigned(FLog) then + FLog.AddError(Format('Keyword access :%s requires exactly one argument.', [Node.Callee.AsKeyword.Value.Name]), Node); + // Fallthrough to standard visit/recreation to avoid crash + end + else + begin + // Note: The new MemberAccess node gets the identity of the original FunctionCall + // The member keyword retains its own identity. + var memberAccess := TAst.MemberAccess(Node.Identity, Accept(Node.Arguments[0]), Node.Callee.AsKeyword); + Result := memberAccess; + exit; + end; end; Result := inherited VisitFunctionCall(Node); end; diff --git a/Src/AST/Myc.Ast.Compiler.Macros.pas b/Src/AST/Myc.Ast.Compiler.Macros.pas index d04b94c..0aeedfa 100644 --- a/Src/AST/Myc.Ast.Compiler.Macros.pas +++ b/Src/AST/Myc.Ast.Compiler.Macros.pas @@ -34,15 +34,20 @@ type class var FGensymCounter: Int64; - function TransformAndSpliceNodes(const ANodes: TArray): TArray; + // Helper to handle unquote-splicing (~@) within lists. + // Takes a source list (e.g., Arguments) and returns a flattened array for the new node. + function TransformAndSpliceNodes(const ANodes: INodeList): TArray; function Gensym(const ABaseName: string): string; protected function VisitUnquote(const Node: IUnquoteNode): IAstNode; override; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override; + + // We override these container visits to handle Splicing manually, + // bypassing the standard 1:1 list visitor. function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override; function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override; - function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override; + function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; @@ -169,15 +174,16 @@ begin end; end; -function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: TArray): TArray; +function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: INodeList): TArray; var newList: TList; nodeToSplice: IAstNode; transformedNode: IAstNode; + node: IAstNode; begin newList := TList.Create; try - for var node in ANodes do + for node in ANodes do begin if node.Kind = akUnquoteSplicing then begin @@ -196,10 +202,30 @@ begin if (not evaluatedSpliceValue.IsVoid) and (evaluatedSpliceValue.Kind = vkInterface) then begin nodeToSplice := evaluatedSpliceValue.AsIntf; - if nodeToSplice.Kind = akBlockExpression then - newList.AddRange(nodeToSplice.AsBlockExpression.Expressions) + + // Splicing implies the value must be a list-like AST structure (Block or just a List Node) + // If the evaluated value is an IArgumentList, IExpressionList etc., we flatten it. + if nodeToSplice.Kind = akExpressionList then + begin + for var subItem in nodeToSplice.AsExpressionList do + newList.Add(subItem); + end + else if nodeToSplice.Kind = akArgumentList then + begin + for var subItem in nodeToSplice.AsArgumentList do + newList.Add(subItem); + end + else if nodeToSplice.Kind = akBlockExpression then + begin + // Splice content of block + for var subItem in nodeToSplice.AsBlockExpression.Expressions do + newList.Add(subItem); + end else + begin + // Treat as single item newList.Add(nodeToSplice); + end; end else if (not evaluatedSpliceValue.IsVoid) then begin @@ -261,19 +287,24 @@ var newBody: IAstNode; newName: string; i: Integer; + paramList: IParameterList; begin - SetLength(newParams, Length(Node.Parameters)); - for i := 0 to High(Node.Parameters) do + SetLength(newParams, Node.Parameters.Count); + for i := 0 to Node.Parameters.Count - 1 do begin - newName := Gensym(Node.Parameters[i].Name); + var param := Node.Parameters[i]; + newName := Gensym(param.Name); // Use location from original param - newParams[i] := TAst.Identifier(newName, Node.Parameters[i].Identity.Location); + newParams[i] := TAst.Identifier(newName, param.Identity.Location); end; newBody := Accept(Node.Body); - // Rebuild structural lambda - Result := TAst.LambdaExpr(Node.Identity, newParams, newBody); + // Rebuild: Wrap array in TParameterList with original Identity + paramList := TParameterList.Create(newParams, Node.Parameters.Identity); + + // Use transformation overload + Result := TAst.LambdaExpr(Node.Identity, paramList, newBody); end; function TExpansionVisitor.VisitUnquote(const Node: IUnquoteNode): IAstNode; @@ -284,6 +315,7 @@ var begin expr := Node.Expression; + // Optimization: If unquote refers to a local macro variable directly, try to get it. if expr.Kind = akIdentifier then begin addr := FMacroScope.Resolve(expr.AsIdentifier.Name); @@ -329,22 +361,36 @@ function TExpansionVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IAs var newArgs: TArray; transformedCallee: IAstNode; + argList: IArgumentList; begin transformedCallee := Self.Accept(Node.Callee); + + // Use splicing aware transformation for arguments (returns TArray) newArgs := TransformAndSpliceNodes(Node.Arguments); - Result := TAst.FunctionCall(Node.Identity, transformedCallee, newArgs); + + // Wrap in List container to use Transformation overload + argList := TArgumentList.Create(newArgs, Node.Arguments.Identity); + + Result := TAst.FunctionCall(Node.Identity, transformedCallee, argList); end; function TExpansionVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; var newExprs: TArray; + exprList: IExpressionList; begin + // Use splicing aware transformation for block expressions newExprs := TransformAndSpliceNodes(Node.Expressions); - Result := TAst.Block(Node.Identity, newExprs); + + // Wrap in List + exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity); + + Result := TAst.Block(Node.Identity, exprList); end; function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; begin + // For now, standard transformation for records (no splicing key-values yet) Result := inherited VisitRecordLiteral(Node); end; @@ -438,10 +484,10 @@ begin var expansionScope := TScope.CreateScope(FInitialScope, nil, nil); var params := macroDef.Parameters; - if Length(Node.Arguments) <> Length(params) then - raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, Length(params)]); + if Node.Arguments.Count <> params.Count then + raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, params.Count]); - for i := 0 to High(params) do + for i := 0 to params.Count - 1 do expansionScope.Define(params[i].Name, TDataValue.FromIntf(Node.Arguments[i])); var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator); diff --git a/Src/AST/Myc.Ast.Compiler.Specializer.pas b/Src/AST/Myc.Ast.Compiler.Specializer.pas index 620501c..48f0b98 100644 --- a/Src/AST/Myc.Ast.Compiler.Specializer.pas +++ b/Src/AST/Myc.Ast.Compiler.Specializer.pas @@ -122,7 +122,7 @@ end; function TStaticSpecializer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var newCallee: IAstNode; - newArgs: TArray; + newArgsList: IArgumentList; i: Integer; calleeIdent: IIdentifierNode; argTypes: TArray; @@ -134,15 +134,16 @@ var begin // 1. Specialize children first (bottom-up) newCallee := Accept(Node.Callee); - newArgs := AcceptNodes(Node.Arguments); + // Arguments are now visited as a List, returning an IArgumentList + newArgsList := Accept(Node.Arguments).AsArgumentList; // 2. Check if this call is a candidate for specialization if newCallee.Kind <> akIdentifier then begin - if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then + if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then Result := Node else - Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); + Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil); exit; end; @@ -151,10 +152,10 @@ begin // 3. Check if all argument types are statically known allTypesKnown := True; - SetLength(argTypes, Length(newArgs)); - for i := 0 to High(newArgs) do + SetLength(argTypes, newArgsList.Count); + for i := 0 to newArgsList.Count - 1 do begin - argTypes[i] := newArgs[i].AsTypedNode.StaticType; + argTypes[i] := newArgsList[i].AsTypedNode.StaticType; if argTypes[i].Kind = stUnknown then begin allTypesKnown := False; @@ -164,10 +165,10 @@ begin if not allTypesKnown then begin - if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then + if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then Result := Node else - Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); + Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil); exit; end; @@ -183,7 +184,7 @@ begin TAst.FunctionCall( Node.Identity, newCallee, - newArgs, + newArgsList, specializedMethod.ReturnType, Node.IsTailCall, specializedMethod.Target, @@ -203,7 +204,7 @@ begin TAst.FunctionCall( Node.Identity, newCallee, - newArgs, + newArgsList, specializedMethod.ReturnType, Node.IsTailCall, specializedMethod.Target, @@ -223,7 +224,7 @@ begin var lambdaDef := funcDef.AsLambdaExpression; if (Length(lambdaDef.Upvalues) > 0) or (lambdaDef.HasNestedLambdas) then begin - Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); + Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil); exit; end; end; @@ -244,15 +245,15 @@ begin FMonomorphCache.Add(key, specializedMethod); // 6c. Return the new node - Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, returnType, Node.IsTailCall, compiled.Func, compiled.IsPure); + Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, returnType, Node.IsTailCall, compiled.Func, compiled.IsPure); exit; end; // 7. Fallback: Not RTL, Not User-Code -> Dynamic - if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then + if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) then Result := Node else - Result := TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, nil); + Result := TAst.FunctionCall(Node.Identity, newCallee, newArgsList, Node.StaticType, Node.IsTailCall, nil); end; { TMonoCacheKey } diff --git a/Src/AST/Myc.Ast.Compiler.TCO.pas b/Src/AST/Myc.Ast.Compiler.TCO.pas index c5e938b..34b5162 100644 --- a/Src/AST/Myc.Ast.Compiler.TCO.pas +++ b/Src/AST/Myc.Ast.Compiler.TCO.pas @@ -99,26 +99,42 @@ function TAstTCO.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNod var isContextTail: Boolean; newExprs: TArray; + exprsList: IExpressionList; + i: Integer; + item, newItem: IAstNode; + hasChanged: Boolean; begin isContextTail := FIsTailStack.Peek; + exprsList := Node.Expressions; - var nTail := High(Node.Expressions); - newExprs := - AcceptNodes( - Node.Expressions, - function(idx: Integer; Node: IAstNode): IAstNode - begin - // Only the last expression in the block inherits the tail position status - FNextIsTail := isContextTail and (idx = nTail); - Result := Accept(Node); - end - ); + SetLength(newExprs, exprsList.Count); + hasChanged := False; - if newExprs = Node.Expressions then + var nTail := exprsList.Count - 1; + + for i := 0 to nTail do + begin + item := exprsList[i]; + + // Only the last expression in the block inherits the tail position status + FNextIsTail := isContextTail and (i = nTail); + + newItem := Accept(item); + newExprs[i] := newItem; + + if item <> newItem then + hasChanged := True; + end; + + if not hasChanged then Result := Node else + begin + // Wrap array in List container + var newList := TExpressionList.Create(newExprs, Node.Expressions.Identity); // CoW: Reuse Identity - Result := TAst.Block(Node.Identity, newExprs, Node.StaticType); + Result := TAst.Block(Node.Identity, newList, Node.StaticType); + end; end; function TAstTCO.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; @@ -169,12 +185,13 @@ end; function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; var - newParams: TArray; + newParams: IParameterList; newBody: IAstNode; begin // Parameters are not in tail position FNextIsTail := False; - newParams := AcceptParameters(Node.Parameters); + // Visit list node to handle potential transformations in children + newParams := Accept(Node.Parameters).AsParameterList; // The body of a lambda is *always* a tail position (relative to the lambda execution) FNextIsTail := True; @@ -185,8 +202,7 @@ begin else begin // Rebuild using factory. - // IMPORTANT: Pass Layout AND Descriptor (TCO runs after TypeChecker). - // CoW: Reuse Identity + // CoW: Reuse Identity. Factory expects IParameterList now. Result := TAst.LambdaExpr( Node.Identity, @@ -204,20 +220,21 @@ end; function TAstTCO.VisitRecurNode(const Node: IRecurNode): IAstNode; var - newArgs: TArray; + newArgsList: IArgumentList; begin if not FIsTailStack.Peek then raise EOptimizerException.Create('''recur'' can only be used in a tail position.'); // Arguments are not in tail position FNextIsTail := False; - newArgs := AcceptNodes(Node.Arguments); + // Visit the list node. Accept() ensures children are visited via TAstTransformer.VisitArgumentList + newArgsList := Accept(Node.Arguments).AsArgumentList; - if newArgs = Node.Arguments then + if newArgsList = Node.Arguments then Result := Node else - // CoW: Reuse Identity - Result := TAst.Recur(Node.Identity, newArgs, Node.StaticType); + // CoW: Reuse Identity. Factory expects IArgumentList. + Result := TAst.Recur(Node.Identity, newArgsList, Node.StaticType); end; function TAstTCO.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; @@ -239,29 +256,32 @@ function TAstTCO.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var isTailCall: Boolean; newCallee: IAstNode; - newArgs: TArray; + newArgsList: IArgumentList; begin isTailCall := FIsTailStack.Peek; // Callee/Arguments are not in tail position FNextIsTail := False; + newCallee := Accept(Node.Callee); - newArgs := AcceptNodes(Node.Arguments); + + // Visit the arguments list + newArgsList := Accept(Node.Arguments).AsArgumentList; // CoW check: Create a new node only if children changed OR IsTailCall needs update - if (newCallee = Node.Callee) and (newArgs = Node.Arguments) and (isTailCall = Node.IsTailCall) then + if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) and (isTailCall = Node.IsTailCall) then begin Result := Node; exit; end; // Use factory to create new node, passing the *new* TCO status - // CoW: Reuse Identity + // CoW: Reuse Identity. Factory expects IArgumentList. Result := TAst.FunctionCall( Node.Identity, newCallee, - newArgs, + newArgsList, Node.StaticType, isTailCall, Node.StaticTarget, // Preserve the static target from Specializer diff --git a/Src/AST/Myc.Ast.Compiler.TypeChecker.pas b/Src/AST/Myc.Ast.Compiler.TypeChecker.pas index 0745424..0b9a54f 100644 --- a/Src/AST/Myc.Ast.Compiler.TypeChecker.pas +++ b/Src/AST/Myc.Ast.Compiler.TypeChecker.pas @@ -12,7 +12,7 @@ uses Myc.Ast.Visitor, Myc.Ast.Scope, Myc.Ast.Types, - Myc.Ast.Identities, // Wichtig für Casts (AsNamed etc.) + Myc.Ast.Identities, Myc.Ast; type @@ -200,17 +200,15 @@ var identity: INamedIdentity; begin adr := Node.Address; - identity := Node.Identity.AsNamed; // Extract specific identity + identity := Node.Identity.AsNamed; if adr.Kind = akUnresolved then begin - // Propagate identity, set type to Unknown Result := TAst.Identifier(identity, adr, TTypes.Unknown); Exit; end; typ := FCurrentContext.LookupType(adr); - // CoW: Reuse Identity Result := TAst.Identifier(identity, adr, typ); end; @@ -219,12 +217,13 @@ var newArgs: TArray; i: Integer; begin - SetLength(newArgs, Length(Node.Arguments)); - for i := 0 to High(Node.Arguments) do + SetLength(newArgs, Node.Arguments.Count); + for i := 0 to Node.Arguments.Count - 1 do newArgs[i] := Accept(Node.Arguments[i]); - // CoW: Reuse Identity - Result := TAst.Recur(Node.Identity, newArgs, TTypes.Void); + // FIX: Wrap in List + var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity); + Result := TAst.Recur(Node.Identity, argList, TTypes.Void); end; function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; @@ -256,7 +255,7 @@ begin begin lambdaNode := Node.Initializer.AsLambdaExpression; var paramTypes: TArray; - SetLength(paramTypes, Length(lambdaNode.Parameters)); + SetLength(paramTypes, lambdaNode.Parameters.Count); for i := 0 to High(paramTypes) do paramTypes[i] := TTypes.Unknown; @@ -278,10 +277,8 @@ begin if initType.Kind <> stUnknown then FCurrentContext.SetType(adr.SlotIndex, initType); - // Reuse Identity for Identifier newIdent := TAst.Identifier(identIdentity, adr, initType); - // Reuse Identity for VarDecl Result := TAst.VarDecl(Node.Identity, newIdent, newInitializer, initType, Node.IsBoxed); end; @@ -296,11 +293,10 @@ var identNode: IIdentifierNode; identIdentity: INamedIdentity; begin - // Rebuild Identifier with potential type info updates identNode := Node.Target.AsIdentifier; identIdentity := identNode.Identity.AsNamed; - newIdent := Accept(Node.Target); // This visits identifier and might update type from context + newIdent := Accept(Node.Target); targetType := newIdent.AsTypedNode.StaticType; adr := identNode.Address; @@ -318,7 +314,7 @@ begin if (targetType.Kind <> stMethod) then begin var paramTypes: TArray; - SetLength(paramTypes, Length(lambdaNode.Parameters)); + SetLength(paramTypes, lambdaNode.Parameters.Count); for i := 0 to High(paramTypes) do paramTypes[i] := TTypes.Unknown; @@ -343,12 +339,10 @@ begin if ((targetType.Kind = stUnknown) or Assigned(placeholderType)) and (sourceType.Kind <> stUnknown) then begin FCurrentContext.SetType(adr.SlotIndex, sourceType); - // Recreate Identifier with new type and original identity newIdent := TAst.Identifier(identIdentity, adr, sourceType); targetType := sourceType; end; - // CoW: Reuse Assignment Identity Result := TAst.Assign(Node.Identity, newIdent, newValue, targetType); end; @@ -372,10 +366,10 @@ begin FCurrentContext := TTypeContext.Create(FCurrentContext, Node.Layout, upvalueTypes); try - SetLength(newParams, Length(Node.Parameters)); - SetLength(paramTypes, Length(Node.Parameters)); + SetLength(newParams, Node.Parameters.Count); + SetLength(paramTypes, Node.Parameters.Count); - for i := 0 to High(Node.Parameters) do + for i := 0 to Node.Parameters.Count - 1 do begin paramIdent := Node.Parameters[i]; paramIdentity := paramIdent.Identity.AsNamed; @@ -386,7 +380,6 @@ begin if paramAdr.Kind <> akUnresolved then FCurrentContext.SetType(paramAdr.SlotIndex, paramTypes[i]); - // CoW: Reuse Parameter Identity newParams[i] := TAst.Identifier(paramIdentity, paramAdr, paramTypes[i]); end; @@ -402,11 +395,13 @@ begin temp.Free; end; - // CoW: Reuse Lambda Identity + // FIX: Wrap in List + var paramList := TParameterList.Create(newParams, Node.Parameters.Identity); + Result := TAst.LambdaExpr( Node.Identity, - newParams, + paramList, newBody, Node.Layout, finalDescriptor, @@ -431,11 +426,11 @@ var argsStr: string; begin newCallee := Accept(Node.Callee); - SetLength(newArgs, Length(Node.Arguments)); - SetLength(argTypes, Length(Node.Arguments)); + SetLength(newArgs, Node.Arguments.Count); + SetLength(argTypes, Node.Arguments.Count); hasUnknownArgs := False; - for i := 0 to High(Node.Arguments) do + for i := 0 to Node.Arguments.Count - 1 do begin newArgs[i] := Accept(Node.Arguments[i]); argTypes[i] := newArgs[i].AsTypedNode.StaticType; @@ -498,17 +493,10 @@ begin retType := TTypes.Unknown; end; - // CoW: Reuse Call Identity - Result := - TAst.FunctionCall( - Node.Identity, - newCallee, - newArgs, - retType, - Node.IsTailCall, - nil, // StaticTarget set by Specializer - False // IsTargetPure set by Specializer - ); + // FIX: Wrap in List + var argList := TArgumentList.Create(newArgs, Node.Arguments.Identity); + + Result := TAst.FunctionCall(Node.Identity, newCallee, argList, retType, Node.IsTailCall, nil, False); end; function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; @@ -517,8 +505,8 @@ var newExprs: TArray; i: Integer; begin - SetLength(newExprs, Length(Node.Expressions)); - for i := 0 to High(Node.Expressions) do + SetLength(newExprs, Node.Expressions.Count); + for i := 0 to Node.Expressions.Count - 1 do newExprs[i] := Accept(Node.Expressions[i]); if Length(newExprs) > 0 then @@ -526,8 +514,9 @@ begin else blockType := TTypes.Void; - // CoW: Reuse Block Identity - Result := TAst.Block(Node.Identity, newExprs, blockType); + // FIX: Wrap in List + var exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity); + Result := TAst.Block(Node.Identity, exprList, blockType); end; function TTypeChecker.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; @@ -561,7 +550,6 @@ begin resultType := TTypes.Unknown; end; - // CoW: Reuse If Identity Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, resultType); end; @@ -594,7 +582,6 @@ begin resultType := TTypes.Unknown; end; - // CoW: Reuse Ternary Identity Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, resultType); end; @@ -648,7 +635,6 @@ begin end; end; - // CoW: Reuse MemberAccess Identity Result := TAst.MemberAccess(Node.Identity, newBase, newMember.AsKeyword, elemType); end; @@ -686,7 +672,6 @@ begin FLog.AddError(Format('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]), Node); end; - // CoW: Reuse Indexer Identity Result := TAst.Indexer(Node.Identity, newBase, newIndex, elemType); end; @@ -699,13 +684,19 @@ var valType: IStaticType; scalarKind: TScalar.TKind; allScalar: Boolean; - newFields: TArray; + newFields: TArray; begin - SetLength(newFields, Length(Node.Fields)); - for i := 0 to High(Node.Fields) do + SetLength(newFields, Node.Fields.Count); + for i := 0 to Node.Fields.Count - 1 do begin - newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword; - newFields[i].Value := Accept(Node.Fields[i].Value); + var field := Node.Fields[i]; + var newKey := Accept(field.Key).AsKeyword; + var newValue := Accept(field.Value); + + if (newKey = field.Key) and (newValue = field.Value) then + newFields[i] := field + else + newFields[i] := TAst.RecordField(field.Identity, newKey, newValue); end; SetLength(scalarDefFields, Length(newFields)); @@ -735,11 +726,14 @@ begin scalarDefFields[i] := TScalarRecordField.Create(newFields[i].Key.Value, scalarKind); end; + // FIX: Wrap in List + var fieldList := TRecordFieldList.Create(newFields, Node.Fields.Identity); + if allScalar then begin def := TScalarRecordRegistry.Intern(scalarDefFields); staticType := TTypes.CreateRecord(def); - Result := TAst.RecordLiteral(Node.Identity, newFields, def, nil, staticType); + Result := TAst.RecordLiteral(Node.Identity, fieldList, def, nil, staticType); end else begin @@ -750,7 +744,7 @@ begin var genDef := TGenericRecordRegistry.Intern(genDefFields); staticType := TTypes.CreateGenericRecord(genDef); - Result := TAst.RecordLiteral(Node.Identity, newFields, nil, genDef, staticType); + Result := TAst.RecordLiteral(Node.Identity, fieldList, nil, genDef, staticType); end; end; @@ -760,7 +754,6 @@ var defIdentity: IDefinitionIdentity; begin try - // Use definition from Identity to ensure SSOT defIdentity := Node.Identity.AsDefinition; elemType := TTypes.FromScalarKind(TScalar.StringToKind(defIdentity.Definition)); except @@ -772,7 +765,6 @@ begin end; end; - // CoW: Reuse Definition Identity Result := TAst.CreateSeries(defIdentity, TTypes.CreateSeries(elemType)); end; @@ -818,7 +810,6 @@ begin end; end; - // CoW: Reuse Add Identity Result := TAst.AddSeriesItem(Node.Identity, newSeries.AsIdentifier, newValue, newLookback, TTypes.Void); end; @@ -843,7 +834,6 @@ begin FLog.AddError(Format('"length" requires a series, but got %s', [seriesType.ToString]), Node); end; - // CoW: Reuse SeriesLength Identity Result := TAst.SeriesLength(Node.Identity, newSeries.AsIdentifier, TTypes.Ordinal); end; diff --git a/Src/AST/Myc.Ast.Debugger.pas b/Src/AST/Myc.Ast.Debugger.pas index 2289941..4bbab0a 100644 --- a/Src/AST/Myc.Ast.Debugger.pas +++ b/Src/AST/Myc.Ast.Debugger.pas @@ -267,6 +267,7 @@ begin AppendLine('Block {'); Indent; try + // Delegates to VisitExpressionList via inherited Result := inherited VisitBlockExpression(Node); // Scope might have changed after block execution if vars were defined ShowScope; diff --git a/Src/AST/Myc.Ast.Dumper.pas b/Src/AST/Myc.Ast.Dumper.pas index fdea334..b43ca44 100644 --- a/Src/AST/Myc.Ast.Dumper.pas +++ b/Src/AST/Myc.Ast.Dumper.pas @@ -30,7 +30,7 @@ type function FormatAddress(const Addr: TResolvedAddress): string; protected - // Override abstract PROCEDURES from TAstVisitor (not functions!) + // Override abstract PROCEDURES from TAstVisitor procedure VisitConstant(const Node: IConstantNode); override; procedure VisitIdentifier(const Node: IIdentifierNode); override; procedure VisitKeyword(const Node: IKeywordNode); override; @@ -55,6 +55,14 @@ type procedure VisitSeriesLength(const Node: ISeriesLengthNode); override; procedure VisitNop(const Node: INopNode); override; + // List Visitors are handled implicitly by parent node iteration in Dumper, + // but we implement them empty/default to satisfy the abstract base class if called directly. + procedure VisitParameterList(const Node: IParameterList); override; + procedure VisitArgumentList(const Node: IArgumentList); override; + procedure VisitExpressionList(const Node: IExpressionList); override; + procedure VisitRecordFieldList(const Node: IRecordFieldList); override; + procedure VisitRecordField(const Node: IRecordFieldNode); override; + public constructor Create(const AOutput: TStrings); class procedure Dump(const RootNode: IAstNode; const Output: TStrings); @@ -201,7 +209,6 @@ var slot: Integer; typ: IStaticType; begin - // (* UPDATED: Added IsPure output *) LogFmt( 'LambdaExpression (HasNested: %s, IsPure: %s)', [Node.HasNestedLambdas.ToString(TUseBoolStrs.True), BoolToStr(Node.IsPure, True)], @@ -236,6 +243,7 @@ begin // 3. Parameters Log('Parameters:'); Indent; + // Iterate over IParameterList for var param in Node.Parameters do param.Accept(Self); Unindent; @@ -266,11 +274,12 @@ var i: Integer; begin sigStr := ''; + // Note: Node.Arguments is IArgumentList now. if Assigned(Node.StaticTarget) then begin staticStatus := 'Assigned'; - SetLength(argTypes, Length(Node.Arguments)); - for i := 0 to High(Node.Arguments) do + SetLength(argTypes, Node.Arguments.Count); + for i := 0 to Node.Arguments.Count - 1 do begin if Node.Arguments[i].IsTyped then argTypes[i] := Node.Arguments[i].AsTypedNode.StaticType.ToString @@ -282,7 +291,6 @@ begin else staticStatus := 'nil'; - // (* UPDATED: Added IsTargetPure output *) LogFmt( 'FunctionCall (IsTailCall: %s, StaticTarget: %s%s, IsTargetPure: %s)', [Node.IsTailCall.ToString(TUseBoolStrs.True), staticStatus, sigStr, BoolToStr(Node.IsTargetPure, True)], @@ -292,8 +300,9 @@ begin Indent; Log('Callee:'); Node.Callee.Accept(Self); - LogFmt('Arguments (%d):', [Length(Node.Arguments)]); + LogFmt('Arguments (%d):', [Node.Arguments.Count]); Indent; + // Iterate over IArgumentList for arg in Node.Arguments do arg.Accept(Self); Unindent; @@ -311,7 +320,7 @@ begin Indent; Log('Callee:'); Node.CallNode.Callee.Accept(Self); - LogFmt('Arguments (%d):', [Length(Node.CallNode.Arguments)]); + LogFmt('Arguments (%d):', [Node.CallNode.Arguments.Count]); Indent; for arg in Node.CallNode.Arguments do arg.Accept(Self); @@ -332,7 +341,7 @@ var begin Log('Recur', Node); Indent; - LogFmt('Arguments (%d):', [Length(Node.Arguments)]); + LogFmt('Arguments (%d):', [Node.Arguments.Count]); Indent; for arg in Node.Arguments do arg.Accept(Self); @@ -446,10 +455,11 @@ end; procedure TAstDumper.VisitRecordLiteral(const Node: IRecordLiteralNode); var - field: TRecordFieldLiteral; + field: IRecordFieldNode; begin - LogFmt('RecordLiteral (%d fields)', [Length(Node.Fields)], Node); + LogFmt('RecordLiteral (%d fields)', [Node.Fields.Count], Node); Indent; + // Iterate over IRecordFieldList for field in Node.Fields do begin LogFmt('Field :%s', [field.Key.Value.Name]); @@ -495,4 +505,41 @@ begin Log('Nop', Node); end; +// --- List Visitors Implementation --- + +procedure TAstDumper.VisitParameterList(const Node: IParameterList); +begin + // Usually handled by Parent Node iteration (Lambda), + // but if visited directly: + for var item in Node do + item.Accept(Self); +end; + +procedure TAstDumper.VisitArgumentList(const Node: IArgumentList); +begin + for var item in Node do + item.Accept(Self); +end; + +procedure TAstDumper.VisitExpressionList(const Node: IExpressionList); +begin + for var item in Node do + item.Accept(Self); +end; + +procedure TAstDumper.VisitRecordFieldList(const Node: IRecordFieldList); +begin + for var item in Node do + item.Accept(Self); +end; + +procedure TAstDumper.VisitRecordField(const Node: IRecordFieldNode); +begin + // If visited directly (e.g. inside a list) + LogFmt('Field :%s', [Node.Key.Value.Name]); + Indent; + Node.Value.Accept(Self); + Unindent; +end; + end. diff --git a/Src/AST/Myc.Ast.Evaluator.pas b/Src/AST/Myc.Ast.Evaluator.pas index ec02abb..2e10e4a 100644 --- a/Src/AST/Myc.Ast.Evaluator.pas +++ b/Src/AST/Myc.Ast.Evaluator.pas @@ -25,6 +25,14 @@ type function VisitConstant(const Node: IConstantNode): TDataValue; virtual; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual; function VisitKeyword(const Node: IKeywordNode): TDataValue; virtual; + + // List Visitors + function VisitParameterList(const Node: IParameterList): TDataValue; virtual; + function VisitArgumentList(const Node: IArgumentList): TDataValue; virtual; + function VisitExpressionList(const Node: IExpressionList): TDataValue; virtual; + function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; virtual; + function VisitRecordField(const Node: IRecordFieldNode): TDataValue; virtual; + function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; virtual; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual; @@ -230,8 +238,8 @@ begin i: Integer; adr: TResolvedAddress; begin - if (Length(ArgValues) <> Length(params)) then - raise EEvaluatorException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(params), Length(ArgValues)]); + if (Length(ArgValues) <> params.Count) then + raise EEvaluatorException.CreateFmt('Argument count mismatch: expected %d, got %d', [params.Count, Length(ArgValues)]); // Create the new execution scope for this function call. lambdaScope := TScope.CreateScope(closureScope, descriptor, capturedCells); @@ -243,7 +251,7 @@ begin lambdaScope[adr] := TDataValue(closure); // Populate the scope with the actual parameters passed to the function. - for i := 0 to High(ArgValues) do + for i := 0 to params.Count - 1 do begin adr := params[i].Address; Assert(adr.ScopeDepth = 0); @@ -283,15 +291,15 @@ var calleeValue: TDataValue; argValues: TArray; i: Integer; - argNodes: TArray; + argList: IArgumentList; begin if Assigned(Node.StaticTarget) then begin // --- Static Path (Optimized) --- - argNodes := Node.Arguments; - SetLength(argValues, Length(argNodes)); - for i := 0 to High(argNodes) do - argValues[i] := argNodes[i].Accept(Self); + argList := Node.Arguments; + SetLength(argValues, argList.Count); + for i := 0 to argList.Count - 1 do + argValues[i] := argList[i].Accept(Self); // Call static target. Exceptions here are caught by Execute/HandleTCO. Result := Node.StaticTarget(argValues); @@ -304,10 +312,10 @@ begin if calleeValue.Kind <> vkMethod then raise EEvaluatorException.Create('Expression is not invokable in this context.'); - argNodes := Node.Arguments; - SetLength(argValues, Length(argNodes)); - for i := 0 to High(argNodes) do - argValues[i] := argNodes[i].Accept(Self); + argList := Node.Arguments; + SetLength(argValues, argList.Count); + for i := 0 to argList.Count - 1 do + argValues[i] := argList[i].Accept(Self); if Node.IsTailCall then begin @@ -333,8 +341,8 @@ var calleeValue: TDataValue; i: Integer; begin - SetLength(argValues, Length(Node.Arguments)); - for i := 0 to High(Node.Arguments) do + SetLength(argValues, Node.Arguments.Count); + for i := 0 to Node.Arguments.Count - 1 do argValues[i] := Node.Arguments[i].Accept(Self); calleeAddress.Kind := akLocalOrParent; @@ -517,11 +525,12 @@ begin if Assigned(Node.GenericDefinition) then begin var genFields: TArray>; - SetLength(genFields, Length(Node.Fields)); + SetLength(genFields, Node.Fields.Count); - for i := 0 to High(Node.Fields) do + for i := 0 to Node.Fields.Count - 1 do begin - genFields[i] := TPair.Create(Node.Fields[i].Key.Value, Node.Fields[i].Value.Accept(Self)); + var field := Node.Fields[i]; + genFields[i] := TPair.Create(field.Key.Value, field.Value.Accept(Self)); end; var dynRec := TDynamicRecord.Create(genFields); @@ -530,11 +539,12 @@ begin else if Assigned(Node.ScalarDefinition) then begin var values: TArray; - SetLength(values, Length(Node.Fields)); + SetLength(values, Node.Fields.Count); - for i := 0 to High(Node.Fields) do + for i := 0 to Node.Fields.Count - 1 do begin - var valData := Node.Fields[i].Value.Accept(Self); + var field := Node.Fields[i]; + var valData := field.Value.Accept(Self); values[i] := valData.AsScalar.Value; end; @@ -589,12 +599,18 @@ begin end; function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; +begin + // Delegate to ExpressionList visitor + Result := Node.Expressions.Accept(Self); +end; + +function TEvaluatorVisitor.VisitExpressionList(const Node: IExpressionList): TDataValue; var - expression: IAstNode; + i: Integer; begin Result := TDataValue.Void; - for expression in Node.Expressions do - Result := expression.Accept(Self); + for i := 0 to Node.Count - 1 do + Result := Node[i].Accept(Self); end; function TEvaluatorVisitor.VisitNop(const Node: INopNode): TDataValue; @@ -620,4 +636,30 @@ begin Result := TDataValue(TScalar.FromInt64(len)); end; +// --- List Visitor Stubs (Mostly Unused directly, but required by Interface) --- + +function TEvaluatorVisitor.VisitParameterList(const Node: IParameterList): TDataValue; +begin + Result := TDataValue.Void; +end; + +function TEvaluatorVisitor.VisitArgumentList(const Node: IArgumentList): TDataValue; +begin + // Could evaluate arguments here and return an array-wrapped TDataValue, + // but VisitFunctionCall handles iteration manually for efficiency. + Result := TDataValue.Void; +end; + +function TEvaluatorVisitor.VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; +begin + // Handled by VisitRecordLiteral + Result := TDataValue.Void; +end; + +function TEvaluatorVisitor.VisitRecordField(const Node: IRecordFieldNode): TDataValue; +begin + // Handled by manual iteration in VisitRecordLiteral + Result := TDataValue.Void; +end; + end. diff --git a/Src/AST/Myc.Ast.Identities.pas b/Src/AST/Myc.Ast.Identities.pas index 147d9aa..8175db6 100644 --- a/Src/AST/Myc.Ast.Identities.pas +++ b/Src/AST/Myc.Ast.Identities.pas @@ -13,6 +13,7 @@ type IConstantIdentity = interface; IKeywordIdentity = interface; IDefinitionIdentity = interface; + IListIdentity = interface; // Represents a position in the source code. ISourceLocation = interface @@ -29,7 +30,8 @@ type ikNamed, // Identifier, MacroDef (Name + Location) ikConstant, // Literals (Value + Location) ikKeyword, // Keywords (Keyword + Location) - ikDefinition // Complex definitions (DefString + Location) + ikDefinition, // Complex definitions (DefString + Location) + ikList // Lists (Open/Close Tokens + Separator + Location) ); // Base interface for the "Green Tree" nodes. @@ -47,6 +49,7 @@ type function AsConstant: IConstantIdentity; function AsKeyword: IKeywordIdentity; function AsDefinition: IDefinitionIdentity; + function AsList: IListIdentity; property Kind: TAstIdentityKind read GetKind; @@ -82,6 +85,18 @@ type property Definition: string read GetDefinition; end; + // Spezifische Identität für Listen + IListIdentity = interface(IAstIdentity) + {$region 'private'} + function GetOpenToken: string; + function GetCloseToken: string; + function GetSeparator: string; + {$endregion} + property OpenToken: string read GetOpenToken; + property CloseToken: string read GetCloseToken; + property Separator: string read GetSeparator; + end; + // Factory and static access. TIdentities = record public @@ -92,6 +107,8 @@ type class function Constant(const AValue: TDataValue; const ALoc: ISourceLocation = nil): IConstantIdentity; static; class function Keyword(const AValue: IKeyword; const ALoc: ISourceLocation = nil): IKeywordIdentity; static; class function Definition(const ADef: string; const ALoc: ISourceLocation = nil): IDefinitionIdentity; static; + + class function List(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation = nil): IListIdentity; static; end; implementation @@ -121,6 +138,7 @@ type function AsConstant: IConstantIdentity; virtual; function AsKeyword: IKeywordIdentity; virtual; function AsDefinition: IDefinitionIdentity; virtual; + function AsList: IListIdentity; virtual; end; TStructuralIdentity = class(TAbstractIdentity) @@ -176,6 +194,20 @@ type function AsDefinition: IDefinitionIdentity; override; end; + TListIdentity = class(TAbstractIdentity, IListIdentity) + private + FOpen, FClose, FSeparator: string; + function GetOpenToken: string; + function GetCloseToken: string; + function GetSeparator: string; + protected + function GetKind: TAstIdentityKind; override; + public + constructor Create(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation); + function ToString: string; override; + function AsList: IListIdentity; override; + end; + { TSourceLocation } constructor TSourceLocation.Create(ALine, ACol: Integer); @@ -241,6 +273,11 @@ begin raise EInvalidCast.Create('Identity is not a Definition Identity'); end; +function TAbstractIdentity.AsList: IListIdentity; +begin + raise EInvalidCast.Create('Identity is not a List Identity'); +end; + { TStructuralIdentity } function TStructuralIdentity.GetKind: TAstIdentityKind; @@ -360,6 +397,46 @@ begin Result := Format('Def: "%s" (%s)', [FDefinition, inherited ToString]); end; +{ TListIdentity } + +constructor TListIdentity.Create(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation); +begin + inherited Create(ALoc); + FOpen := AOpen; + FClose := AClose; + FSeparator := ASeparator; +end; + +function TListIdentity.GetKind: TAstIdentityKind; +begin + Result := ikList; +end; + +function TListIdentity.GetOpenToken: string; +begin + Result := FOpen; +end; + +function TListIdentity.GetCloseToken: string; +begin + Result := FClose; +end; + +function TListIdentity.GetSeparator: string; +begin + Result := FSeparator; +end; + +function TListIdentity.AsList: IListIdentity; +begin + Result := Self; +end; + +function TListIdentity.ToString: string; +begin + Result := Format('List: "%s...%s" (Sep: "%s") (%s)', [FOpen, FClose, FSeparator, inherited ToString]); +end; + { TIdentities } class function TIdentities.Location(ALine, ACol: Integer): ISourceLocation; @@ -392,4 +469,9 @@ begin Result := TDefinitionIdentity.Create(ADef, ALoc); end; +class function TIdentities.List(const AOpen, AClose, ASeparator: string; const ALoc: ISourceLocation): IListIdentity; +begin + Result := TListIdentity.Create(AOpen, AClose, ASeparator, ALoc); +end; + end. diff --git a/Src/AST/Myc.Ast.JSON.pas b/Src/AST/Myc.Ast.JSON.pas index d948494..8b5ea78 100644 --- a/Src/AST/Myc.Ast.JSON.pas +++ b/Src/AST/Myc.Ast.JSON.pas @@ -44,7 +44,7 @@ type function JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode; function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode; function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode; - function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode; + function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode; // <--- KORRIGIERT function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode; function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode; function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode; @@ -56,6 +56,14 @@ type function VisitConstant(const Node: IConstantNode): TJSONObject; override; function VisitIdentifier(const Node: IIdentifierNode): TJSONObject; override; function VisitKeyword(const Node: IKeywordNode): TJSONObject; override; + + // List Visitors (stubbed mostly, as parents handle array generation for JSON structure) + function VisitParameterList(const Node: IParameterList): TJSONObject; override; + function VisitArgumentList(const Node: IArgumentList): TJSONObject; override; + function VisitExpressionList(const Node: IExpressionList): TJSONObject; override; + function VisitRecordFieldList(const Node: IRecordFieldList): TJSONObject; override; + function VisitRecordField(const Node: IRecordFieldNode): TJSONObject; override; + function VisitIfExpression(const Node: IIfExpressionNode): TJSONObject; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TJSONObject; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TJSONObject; override; @@ -197,12 +205,13 @@ function TJsonAstConverter.VisitLambdaExpression(const Node: ILambdaExpressionNo var bodyObj: TJSONObject; paramsArray: TJSONArray; + i: Integer; begin bodyObj := Accept(Node.Body); paramsArray := TJSONArray.Create; - for var param in Node.Parameters do - paramsArray.Add(Accept(param)); + for i := 0 to Node.Parameters.Count - 1 do + paramsArray.Add(Accept(Node.Parameters[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('LambdaExpr')); @@ -214,13 +223,14 @@ function TJsonAstConverter.VisitMacroDefinition(const Node: IMacroDefinitionNode var nameObj, bodyObj: TJSONObject; paramsArray: TJSONArray; + i: Integer; begin nameObj := Accept(Node.Name); bodyObj := Accept(Node.Body); paramsArray := TJSONArray.Create; - for var param in Node.Parameters do - paramsArray.Add(Accept(param)); + for i := 0 to Node.Parameters.Count - 1 do + paramsArray.Add(Accept(Node.Parameters[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('MacroDef')); @@ -254,13 +264,13 @@ function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TJS var calleeObj: TJSONObject; argsArray: TJSONArray; - arg: IAstNode; + i: Integer; begin calleeObj := Accept(Node.Callee); argsArray := TJSONArray.Create; - for arg in Node.Arguments do - argsArray.Add(Accept(arg)); + for i := 0 to Node.Arguments.Count - 1 do + argsArray.Add(Accept(Node.Arguments[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('FunctionCall')); @@ -272,14 +282,14 @@ function TJsonAstConverter.VisitMacroExpansionNode(const Node: IMacroExpansionNo var calleeObj, bodyObj: TJSONObject; argsArray: TJSONArray; - arg: IAstNode; + i: Integer; begin calleeObj := Accept(Node.CallNode.Callee); bodyObj := Accept(Node.ExpandedBody); argsArray := TJSONArray.Create; - for arg in Node.CallNode.Arguments do - argsArray.Add(Accept(arg)); + for i := 0 to Node.CallNode.Arguments.Count - 1 do + argsArray.Add(Accept(Node.CallNode.Arguments[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('MacroExpansion')); @@ -291,11 +301,11 @@ end; function TJsonAstConverter.VisitRecurNode(const Node: IRecurNode): TJSONObject; var argsArray: TJSONArray; - arg: IAstNode; + i: Integer; begin argsArray := TJSONArray.Create; - for arg in Node.Arguments do - argsArray.Add(Accept(arg)); + for i := 0 to Node.Arguments.Count - 1 do + argsArray.Add(Accept(Node.Arguments[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Recur')); @@ -305,11 +315,11 @@ end; function TJsonAstConverter.VisitBlockExpression(const Node: IBlockExpressionNode): TJSONObject; var exprsArray: TJSONArray; - expr: IAstNode; + i: Integer; begin exprsArray := TJSONArray.Create; - for expr in Node.Expressions do - exprsArray.Add(Accept(expr)); + for i := 0 to Node.Expressions.Count - 1 do + exprsArray.Add(Accept(Node.Expressions[i])); Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Block')); @@ -375,24 +385,28 @@ end; function TJsonAstConverter.VisitRecordLiteral(const Node: IRecordLiteralNode): TJSONObject; var fieldsArray: TJSONArray; - field: TRecordFieldLiteral; - fieldObj: TJSONObject; + i: Integer; begin Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('RecordLiteral')); fieldsArray := TJSONArray.Create; - for field in Node.Fields do + for i := 0 to Node.Fields.Count - 1 do begin - fieldObj := TJSONObject.Create; - fieldObj.AddPair('Name', TJSONString.Create(field.Key.Value.Name)); - fieldObj.AddPair('Value', Accept(field.Value)); // Get TJSONObject - fieldsArray.Add(fieldObj); + // We visit the RecordFieldNode, which returns a JSON Object + fieldsArray.Add(Accept(Node.Fields[i])); end; Result.AddPair('Fields', fieldsArray); end; +function TJsonAstConverter.VisitRecordField(const Node: IRecordFieldNode): TJSONObject; +begin + Result := TJSONObject.Create; + Result.AddPair('Name', TJSONString.Create(Node.Key.Value.Name)); + Result.AddPair('Value', Accept(Node.Value)); +end; + function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TJSONObject; begin Result := TJSONObject.Create; @@ -436,7 +450,35 @@ begin Result.AddPair('NodeType', TJSONString.Create('Nop')); end; -{ TJsonAstConverter - Deserialization } +// --- List Visitors (Placeholder return) --- +// Since we iterate manually in parent nodes to form JSON Arrays, these are technically not used +// by the current logic, but required by the interface. +// Note: If we wanted strict visitor compliance, VisitFunctionCall would call Accept(List), +// which would return TJSONObject wrapping the array. We skip that level of nesting here. + +function TJsonAstConverter.VisitParameterList(const Node: IParameterList): TJSONObject; +begin + Result := nil; +end; + +function TJsonAstConverter.VisitArgumentList(const Node: IArgumentList): TJSONObject; +begin + Result := nil; +end; + +function TJsonAstConverter.VisitExpressionList(const Node: IExpressionList): TJSONObject; +begin + Result := nil; +end; + +function TJsonAstConverter.VisitRecordFieldList(const Node: IRecordFieldList): TJSONObject; +begin + Result := nil; +end; + +// ------------------------------------------------------------------------------------------------ +// Deserialization +// ------------------------------------------------------------------------------------------------ function TJsonAstConverter.JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue; var @@ -532,11 +574,10 @@ function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDe var name: IIdentifierNode; params: TArray; - body: IQuasiquoteNode; + body: IAstNode; paramArray: TJSONArray; i: Integer; begin - name := JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject); paramArray := AObj.GetValue('Parameters'); @@ -544,7 +585,7 @@ begin for i := 0 to paramArray.Count - 1 do params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); - body := IQuasiquoteNode(JsonToNode(AObj.GetValue('Body'), 'Quasiquote')); + body := JsonToNode(AObj.GetValue('Body'), 'Quasiquote'); Result := TAst.MacroDef(name, params, body); end; @@ -556,7 +597,6 @@ var i: Integer; tempCallNode: IFunctionCallNode; begin - // Recursively deserialize all parts of the macro expansion node callee := JsonToNode(AObj.GetValue('Callee')); expandedBody := JsonToNode(AObj.GetValue('ExpandedBody')); argsArray := AObj.GetValue('Arguments'); @@ -564,10 +604,7 @@ begin for i := 0 to argsArray.Count - 1 do args[i] := JsonToNode(argsArray.Items[i]); - // Create a temporary IFunctionCallNode to pass to the factory tempCallNode := TAst.FunctionCall(callee, args); - - // Use the new global factory function from the TAst record Result := TAst.MacroExpansionNode(tempCallNode, expandedBody); end; @@ -666,18 +703,25 @@ end; function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode; var - fields: TArray; + fields: TArray; fieldsArray: TJSONArray; fieldObj: TJSONObject; i: Integer; + keyNode: IKeywordNode; + valueNode: IAstNode; begin fieldsArray := AObj.GetValue('Fields'); SetLength(fields, fieldsArray.Count); + for i := 0 to fieldsArray.Count - 1 do begin fieldObj := fieldsArray.Items[i] as TJSONObject; - fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(fieldObj.GetValue('Name')), JsonToNode(fieldObj.GetValue('Value'))); + keyNode := TAst.Keyword(fieldObj.GetValue('Name')); + valueNode := JsonToNode(fieldObj.GetValue('Value')); + + fields[i] := TAst.RecordField(keyNode, valueNode); end; + Result := TAst.RecordLiteral(fields); end; diff --git a/Src/AST/Myc.Ast.Nodes.pas b/Src/AST/Myc.Ast.Nodes.pas index fea677f..91040f0 100644 --- a/Src/AST/Myc.Ast.Nodes.pas +++ b/Src/AST/Myc.Ast.Nodes.pas @@ -76,9 +76,20 @@ type IAstVisitor = interface; IAstTypedNode = interface; + + // Core Nodes IConstantNode = interface; IIdentifierNode = interface; IKeywordNode = interface; + + // Lists & Containers + IParameterList = interface; + IArgumentList = interface; + IExpressionList = interface; + IRecordFieldList = interface; + IRecordFieldNode = interface; + + // Control Flow & Structure IIfExpressionNode = interface; ITernaryExpressionNode = interface; ILambdaExpressionNode = interface; @@ -105,6 +116,12 @@ type akConstant, akIdentifier, akKeyword, + // Lists + akParameterList, + akArgumentList, + akExpressionList, + akRecordFieldList, + akRecordField, akIfExpression, akTernaryExpression, akLambdaExpression, @@ -148,6 +165,13 @@ type function AsConstant: IConstantNode; function AsIdentifier: IIdentifierNode; function AsKeyword: IKeywordNode; + + function AsParameterList: IParameterList; + function AsArgumentList: IArgumentList; + function AsExpressionList: IExpressionList; + function AsRecordFieldList: IRecordFieldList; + function AsRecordField: IRecordFieldNode; + function AsIfExpression: IIfExpressionNode; function AsTernaryExpression: ITernaryExpressionNode; function AsLambdaExpression: ILambdaExpressionNode; @@ -174,6 +198,17 @@ type property Identity: IAstIdentity read GetIdentity; end; + INodeList = interface(IAstNode) + {$region 'private'} + function GetCount: Integer; + function GetItem(Index: Integer): T; + {$endregion} + function GetEnumerator: TEnumerator; + function ToArray: TArray; + property Count: Integer read GetCount; + property Items[Index: Integer]: T read GetItem; default; + end; + IAstTypedNode = interface(IAstNode) {$region 'private'} function GetStaticType: IStaticType; @@ -181,17 +216,29 @@ type property StaticType: IStaticType read GetStaticType; end; + IRecordFieldNode = interface(IAstNode) + {$region 'private'} + function GetKey: IKeywordNode; + function GetValue: IAstNode; + {$endregion} + property Key: IKeywordNode read GetKey; + property Value: IAstNode read GetValue; + end; + + IRecordFieldList = interface(INodeList) + end; + // --- Node Interfaces (Definitions) --- // Function Definition (Lambda) IFunctionDefinition = interface(IAstTypedNode) {$region 'private'} function GetBody: IAstNode; - function GetParameters: TArray; + function GetParameters: IParameterList; function GetIsPure: Boolean; {$endregion} property Body: IAstNode read GetBody; - property Parameters: TArray read GetParameters; + property Parameters: IParameterList read GetParameters; property IsPure: Boolean read GetIsPure; end; @@ -259,13 +306,13 @@ type IFunctionCallNode = interface(IAstTypedNode) {$region 'private'} function GetCallee: IAstNode; - function GetArguments: TArray; + function GetArguments: IArgumentList; function GetIsTailCall: Boolean; function GetStaticTarget: TDataValue.TFunc; function GetIsTargetPure: Boolean; {$endregion} property Callee: IAstNode read GetCallee; - property Arguments: TArray read GetArguments; + property Arguments: IArgumentList read GetArguments; property IsTailCall: Boolean read GetIsTailCall; property StaticTarget: TDataValue.TFunc read GetStaticTarget; property IsTargetPure: Boolean read GetIsTargetPure; @@ -282,16 +329,16 @@ type IRecurNode = interface(IAstTypedNode) {$region 'private'} - function GetArguments: TArray; + function GetArguments: IArgumentList; {$endregion} - property Arguments: TArray read GetArguments; + property Arguments: IArgumentList read GetArguments; end; IBlockExpressionNode = interface(IAstTypedNode) {$region 'private'} - function GetExpressions: TArray; + function GetExpressions: IExpressionList; {$endregion} - property Expressions: TArray read GetExpressions; + property Expressions: IExpressionList read GetExpressions; end; IVariableDeclarationNode = interface(IAstTypedNode) @@ -317,11 +364,11 @@ type IMacroDefinitionNode = interface(IAstTypedNode) {$region 'private'} function GetName: IIdentifierNode; - function GetParameters: TArray; + function GetParameters: IParameterList; function GetBody: IAstNode; {$endregion} property Name: IIdentifierNode read GetName; - property Parameters: TArray read GetParameters; + property Parameters: IParameterList read GetParameters; property Body: IAstNode read GetBody; end; @@ -364,19 +411,13 @@ type property Member: IKeywordNode read GetMember; end; - TRecordFieldLiteral = record - Key: IKeywordNode; - Value: IAstNode; - constructor Create(const AKey: IKeywordNode; const AValue: IAstNode); - end; - IRecordLiteralNode = interface(IAstTypedNode) {$region 'private'} - function GetFields: TArray; + function GetFields: IRecordFieldList; function GetGenericDefinition: IGenericRecordDefinition; function GetScalarDefinition: IScalarRecordDefinition; {$endregion} - property Fields: TArray read GetFields; + property Fields: IRecordFieldList read GetFields; property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition; property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition; end; @@ -406,10 +447,25 @@ type property Series: IIdentifierNode read GetSeries; end; + IParameterList = interface(INodeList) + end; + IArgumentList = interface(INodeList) + end; + IExpressionList = interface(INodeList) + end; + IAstVisitor = interface function VisitConstant(const Node: IConstantNode): TDataValue; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; function VisitKeyword(const Node: IKeywordNode): TDataValue; + + // List Visits + function VisitParameterList(const Node: IParameterList): TDataValue; + function VisitArgumentList(const Node: IArgumentList): TDataValue; + function VisitExpressionList(const Node: IExpressionList): TDataValue; + function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; + function VisitRecordField(const Node: IRecordFieldNode): TDataValue; + function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; @@ -451,6 +507,13 @@ type function AsConstant: IConstantNode; virtual; function AsIdentifier: IIdentifierNode; virtual; function AsKeyword: IKeywordNode; virtual; + + function AsParameterList: IParameterList; virtual; + function AsArgumentList: IArgumentList; virtual; + function AsExpressionList: IExpressionList; virtual; + function AsRecordFieldList: IRecordFieldList; virtual; + function AsRecordField: IRecordFieldNode; virtual; + function AsIfExpression: IIfExpressionNode; virtual; function AsTernaryExpression: ITernaryExpressionNode; virtual; function AsLambdaExpression: ILambdaExpressionNode; virtual; @@ -490,6 +553,82 @@ type property StaticType: IStaticType read GetStaticType; end; + // --- List Implementation Bases --- + + TAstNodeList = class(TAstNode, INodeList) + type + TEnumerator = class(TEnumerator) + private + FArray: TArray; + FIndex: NativeInt; + function GetCurrent: T; inline; + protected + function DoGetCurrent: T; override; + function DoMoveNext: Boolean; override; + public + constructor Create(const AArray: TArray); + function MoveNext: Boolean; inline; + property Current: T read GetCurrent; + end; + private + FItems: TArray; + function GetCount: Integer; + function GetItem(Index: Integer): T; + public + constructor Create(const AItems: TArray; const AIdentity: IAstIdentity); + function GetEnumerator: TEnumerator; + function ToArray: TArray; + property Count: Integer read GetCount; + property Items[Index: Integer]: T read GetItem; default; + end; + + TParameterList = class(TAstNodeList, IParameterList) + protected + function GetKind: TAstNodeKind; override; + public + function Accept(const Visitor: IAstVisitor): TDataValue; override; + function AsParameterList: IParameterList; override; + end; + + TArgumentList = class(TAstNodeList, IArgumentList) + protected + function GetKind: TAstNodeKind; override; + public + function Accept(const Visitor: IAstVisitor): TDataValue; override; + function AsArgumentList: IArgumentList; override; + end; + + TExpressionList = class(TAstNodeList, IExpressionList) + protected + function GetKind: TAstNodeKind; override; + public + function Accept(const Visitor: IAstVisitor): TDataValue; override; + function AsExpressionList: IExpressionList; override; + end; + + TRecordFieldNode = class(TAstNode, IRecordFieldNode) + private + FKey: IKeywordNode; + FValue: IAstNode; + function GetKey: IKeywordNode; + function GetValue: IAstNode; + function GetKind: TAstNodeKind; override; + public + constructor Create(const AKey: IKeywordNode; const AValue: IAstNode; const AIdentity: IAstIdentity); + function Accept(const Visitor: IAstVisitor): TDataValue; override; + function AsRecordField: IRecordFieldNode; override; + end; + + TRecordFieldList = class(TAstNodeList, IRecordFieldList) + protected + function GetKind: TAstNodeKind; override; + public + function Accept(const Visitor: IAstVisitor): TDataValue; override; + function AsRecordFieldList: IRecordFieldList; override; + end; + + // --- Core Nodes Implementations --- + TConstantNode = class(TAstTypedNode, IConstantNode) private FConstIdentity: IConstantIdentity; // Typed reference for fast access @@ -574,13 +713,13 @@ type TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition) private - FParameters: TArray; + FParameters: IParameterList; FBody: IAstNode; FLayout: IScopeLayout; FDescriptor: IScopeDescriptor; FUpvalues: TArray; FHasNestedLambdas, FIsPure: Boolean; - function GetParameters: TArray; + function GetParameters: IParameterList; function GetBody: IAstNode; function GetLayout: IScopeLayout; function GetDescriptor: IScopeDescriptor; @@ -590,7 +729,7 @@ type function GetKind: TAstNodeKind; override; public constructor Create( - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const AStaticType: IStaticType; const ALayout: IScopeLayout; @@ -606,12 +745,12 @@ type TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode) private FCallee: IAstNode; - FArguments: TArray; + FArguments: IArgumentList; FIsTailCall: Boolean; FStaticTarget: TDataValue.TFunc; FIsTargetPure: Boolean; function GetCallee: IAstNode; - function GetArguments: TArray; + function GetArguments: IArgumentList; function GetIsTailCall: Boolean; function GetStaticTarget: TDataValue.TFunc; function GetIsTargetPure: Boolean; @@ -619,7 +758,7 @@ type public constructor Create( const ACallee: IAstNode; - const AArguments: TArray; + const AArguments: IArgumentList; const AStaticType: IStaticType; const AIsTailCall: Boolean; const AStaticTarget: TDataValue.TFunc; @@ -633,16 +772,16 @@ type TMacroDefinitionNode = class(TAstTypedNode, IMacroDefinitionNode) private FName: IIdentifierNode; - FParameters: TArray; + FParameters: IParameterList; FBody: IAstNode; function GetName: IIdentifierNode; - function GetParameters: TArray; + function GetParameters: IParameterList; function GetBody: IAstNode; function GetKind: TAstNodeKind; override; public constructor Create( const AName: IIdentifierNode; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const AIdentity: IAstIdentity ); @@ -698,22 +837,22 @@ type TRecurNode = class(TAstTypedNode, IRecurNode) private - FArguments: TArray; - function GetArguments: TArray; + FArguments: IArgumentList; + function GetArguments: IArgumentList; function GetKind: TAstNodeKind; override; public - constructor Create(const AArguments: TArray; const AStaticType: IStaticType; const AIdentity: IAstIdentity); + constructor Create(const AArguments: IArgumentList; const AStaticType: IStaticType; const AIdentity: IAstIdentity); function Accept(const Visitor: IAstVisitor): TDataValue; override; function AsRecur: IRecurNode; override; end; TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode) private - FExpressions: TArray; - function GetExpressions: TArray; + FExpressions: IExpressionList; + function GetExpressions: IExpressionList; function GetKind: TAstNodeKind; override; public - constructor Create(const AExpressions: array of IAstNode; const AStaticType: IStaticType; const AIdentity: IAstIdentity); + constructor Create(const AExpressions: IExpressionList; const AStaticType: IStaticType; const AIdentity: IAstIdentity); function Accept(const Visitor: IAstVisitor): TDataValue; override; function AsBlockExpression: IBlockExpressionNode; override; end; @@ -782,16 +921,16 @@ type TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode) private - FFields: TArray; + FFields: IRecordFieldList; FScalarDef: IScalarRecordDefinition; FGenericDef: IGenericRecordDefinition; - function GetFields: TArray; + function GetFields: IRecordFieldList; function GetGenericDefinition: IGenericRecordDefinition; function GetScalarDefinition: IScalarRecordDefinition; function GetKind: TAstNodeKind; override; public constructor Create( - const AFields: TArray; + const AFields: IRecordFieldList; const AScalarDef: IScalarRecordDefinition; const AGenericDef: IGenericRecordDefinition; const AStaticType: IStaticType; @@ -865,14 +1004,6 @@ begin Result := Result.Substring(2); end; -{ TRecordFieldLiteral } - -constructor TRecordFieldLiteral.Create(const AKey: IKeywordNode; const AValue: IAstNode); -begin - Key := AKey; - Value := AValue; -end; - { TCompilerError } constructor TCompilerError.Create(ALevel: TCompilerErrorLevel; const AMessage: string; const ANode: IAstNode); @@ -1017,6 +1148,28 @@ function TAstNode.AsKeyword: IKeywordNode; begin Result := nil; end; + +function TAstNode.AsParameterList: IParameterList; +begin + Result := nil; +end; +function TAstNode.AsArgumentList: IArgumentList; +begin + Result := nil; +end; +function TAstNode.AsExpressionList: IExpressionList; +begin + Result := nil; +end; +function TAstNode.AsRecordFieldList: IRecordFieldList; +begin + Result := nil; +end; +function TAstNode.AsRecordField: IRecordFieldNode; +begin + Result := nil; +end; + function TAstNode.AsIfExpression: IIfExpressionNode; begin Result := nil; @@ -1125,6 +1278,136 @@ begin Result := Self; end; +{ TAstNodeList } + +constructor TAstNodeList.Create(const AItems: TArray; const AIdentity: IAstIdentity); +begin + inherited Create(AIdentity); + FItems := AItems; +end; + +function TAstNodeList.GetCount: Integer; +begin + Result := Length(FItems); +end; + +function TAstNodeList.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(FItems); +end; + +function TAstNodeList.GetItem(Index: Integer): T; +begin + Result := FItems[Index]; +end; + +function TAstNodeList.ToArray: TArray; +begin + Result := FItems; +end; + +{ TParameterList } + +function TParameterList.Accept(const Visitor: IAstVisitor): TDataValue; +begin + Result := Visitor.VisitParameterList(Self); +end; + +function TParameterList.AsParameterList: IParameterList; +begin + Result := Self; +end; + +function TParameterList.GetKind: TAstNodeKind; +begin + Result := akParameterList; +end; + +{ TArgumentList } + +function TArgumentList.Accept(const Visitor: IAstVisitor): TDataValue; +begin + Result := Visitor.VisitArgumentList(Self); +end; + +function TArgumentList.AsArgumentList: IArgumentList; +begin + Result := Self; +end; + +function TArgumentList.GetKind: TAstNodeKind; +begin + Result := akArgumentList; +end; + +{ TExpressionList } + +function TExpressionList.Accept(const Visitor: IAstVisitor): TDataValue; +begin + Result := Visitor.VisitExpressionList(Self); +end; + +function TExpressionList.AsExpressionList: IExpressionList; +begin + Result := Self; +end; + +function TExpressionList.GetKind: TAstNodeKind; +begin + Result := akExpressionList; +end; + +{ TRecordFieldNode } + +constructor TRecordFieldNode.Create(const AKey: IKeywordNode; const AValue: IAstNode; const AIdentity: IAstIdentity); +begin + inherited Create(AIdentity); + FKey := AKey; + FValue := AValue; +end; + +function TRecordFieldNode.Accept(const Visitor: IAstVisitor): TDataValue; +begin + Result := Visitor.VisitRecordField(Self); +end; + +function TRecordFieldNode.AsRecordField: IRecordFieldNode; +begin + Result := Self; +end; + +function TRecordFieldNode.GetKey: IKeywordNode; +begin + Result := FKey; +end; + +function TRecordFieldNode.GetKind: TAstNodeKind; +begin + Result := akRecordField; +end; + +function TRecordFieldNode.GetValue: IAstNode; +begin + Result := FValue; +end; + +{ TRecordFieldList } + +function TRecordFieldList.Accept(const Visitor: IAstVisitor): TDataValue; +begin + Result := Visitor.VisitRecordFieldList(Self); +end; + +function TRecordFieldList.AsRecordFieldList: IRecordFieldList; +begin + Result := Self; +end; + +function TRecordFieldList.GetKind: TAstNodeKind; +begin + Result := akRecordFieldList; +end; + { TConstantNode } constructor TConstantNode.Create(const AIdentity: IConstantIdentity; const AStaticType: IStaticType); @@ -1328,7 +1611,7 @@ end; { TLambdaExpressionNode } constructor TLambdaExpressionNode.Create( - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const AStaticType: IStaticType; const ALayout: IScopeLayout; @@ -1362,7 +1645,7 @@ function TLambdaExpressionNode.GetBody: IAstNode; begin Result := FBody; end; -function TLambdaExpressionNode.GetParameters: TArray; +function TLambdaExpressionNode.GetParameters: IParameterList; begin Result := FParameters; end; @@ -1395,7 +1678,7 @@ end; constructor TFunctionCallNode.Create( const ACallee: IAstNode; - const AArguments: TArray; + const AArguments: IArgumentList; const AStaticType: IStaticType; const AIsTailCall: Boolean; const AStaticTarget: TDataValue.TFunc; @@ -1425,7 +1708,7 @@ function TFunctionCallNode.GetCallee: IAstNode; begin Result := FCallee; end; -function TFunctionCallNode.GetArguments: TArray; +function TFunctionCallNode.GetArguments: IArgumentList; begin Result := FArguments; end; @@ -1450,7 +1733,7 @@ end; constructor TMacroDefinitionNode.Create( const AName: IIdentifierNode; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const AIdentity: IAstIdentity ); @@ -1475,7 +1758,7 @@ function TMacroDefinitionNode.GetName: IIdentifierNode; begin Result := FName; end; -function TMacroDefinitionNode.GetParameters: TArray; +function TMacroDefinitionNode.GetParameters: IParameterList; begin Result := FParameters; end; @@ -1606,7 +1889,7 @@ end; { TRecurNode } -constructor TRecurNode.Create(const AArguments: TArray; const AStaticType: IStaticType; const AIdentity: IAstIdentity); +constructor TRecurNode.Create(const AArguments: IArgumentList; const AStaticType: IStaticType; const AIdentity: IAstIdentity); begin inherited Create(AStaticType, AIdentity); FArguments := AArguments; @@ -1622,7 +1905,7 @@ begin Result := Self; end; -function TRecurNode.GetArguments: TArray; +function TRecurNode.GetArguments: IArgumentList; begin Result := FArguments; end; @@ -1633,18 +1916,10 @@ end; { TBlockExpressionNode } -constructor TBlockExpressionNode.Create( - const AExpressions: array of IAstNode; - const AStaticType: IStaticType; - const AIdentity: IAstIdentity -); -var - i: Integer; +constructor TBlockExpressionNode.Create(const AExpressions: IExpressionList; const AStaticType: IStaticType; const AIdentity: IAstIdentity); begin inherited Create(AStaticType, AIdentity); - SetLength(FExpressions, Length(AExpressions)); - for i := 0 to High(AExpressions) do - FExpressions[i] := AExpressions[i]; + FExpressions := AExpressions; end; function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TDataValue; @@ -1657,7 +1932,7 @@ begin Result := Self; end; -function TBlockExpressionNode.GetExpressions: TArray; +function TBlockExpressionNode.GetExpressions: IExpressionList; begin Result := FExpressions; end; @@ -1813,7 +2088,7 @@ end; { TRecordLiteralNode } constructor TRecordLiteralNode.Create( - const AFields: TArray; + const AFields: IRecordFieldList; const AScalarDef: IScalarRecordDefinition; const AGenericDef: IGenericRecordDefinition; const AStaticType: IStaticType; @@ -1836,7 +2111,7 @@ begin Result := Self; end; -function TRecordLiteralNode.GetFields: TArray; +function TRecordLiteralNode.GetFields: IRecordFieldList; begin Result := FFields; end; @@ -1944,4 +2219,33 @@ begin Result := akNop; end; +constructor TAstNodeList.TEnumerator.Create(const AArray: TArray); +begin + inherited Create; + FArray := AArray; + FIndex := -1; +end; + +function TAstNodeList.TEnumerator.DoGetCurrent: T; +begin + Result := Current; +end; + +function TAstNodeList.TEnumerator.DoMoveNext: Boolean; +begin + Result := MoveNext; +end; + +function TAstNodeList.TEnumerator.GetCurrent: T; +begin + Result := FArray[FIndex]; +end; + +function TAstNodeList.TEnumerator.MoveNext: Boolean; +begin + Result := FIndex < High(FArray); + if Result then + Inc(FIndex); +end; + end. diff --git a/Src/AST/Myc.Ast.Script.pas b/Src/AST/Myc.Ast.Script.pas index cab5669..9535d3b 100644 --- a/Src/AST/Myc.Ast.Script.pas +++ b/Src/AST/Myc.Ast.Script.pas @@ -4,6 +4,7 @@ interface uses System.SysUtils, + Myc.Data.Value, Myc.Ast.Nodes, Myc.Ast.Visitor; @@ -35,7 +36,7 @@ var atom ::= number | string | identifier | keyword (* ---------------------------------------------------------------------- *) - (* ---- Reader-Macros (Syntactic Sugar) ---- *) + (* ---- Reader-Macros (Syntactic Sugar) ---- *) (* ---------------------------------------------------------------------- *) reader_macro ::= "'" expression (* (quote ...) *) | "`" expression (* (quasiquote ...) *) @@ -43,7 +44,7 @@ var | "~@" expression (* (unquote-splicing ...) *) (* ---------------------------------------------------------------------- *) - (* ---- Lists (S-Expressions) ---- *) + (* ---- Lists (S-Expressions) ---- *) (* ---------------------------------------------------------------------- *) list ::= "(" list_content ")" list_content ::= special_form | function_call @@ -62,13 +63,13 @@ var function_call ::= expression expression* (* ---------------------------------------------------------------------- *) - (* ---- Parameter Lists and Records ---- *) + (* ---- Parameter Lists and Records ---- *) (* ---------------------------------------------------------------------- *) parameter_list ::= "[" identifier* "]" record_literal ::= "{" (keyword expression)* "}" (* ---------------------------------------------------------------------- *) - (* ---- Terminals (Lexer Tokens) ---- *) + (* ---- Terminals (Lexer Tokens) ---- *) (* ---------------------------------------------------------------------- *) number ::= ["-"] digit+ ["." digit+] string ::= '"' ( ? any char except \ or " ? | '\' ( '"' | '\' | 'n' | 'r' | 't' ) )* '"' @@ -94,7 +95,6 @@ uses System.Character, System.Math, Myc.Data.Scalar, - Myc.Data.Value, Myc.Data.Keyword, Myc.Ast, Myc.Ast.Identities; @@ -197,6 +197,14 @@ type procedure VisitConstant(const Node: IConstantNode); override; procedure VisitIdentifier(const Node: IIdentifierNode); override; procedure VisitKeyword(const Node: IKeywordNode); override; + + // List Visitors + procedure VisitParameterList(const Node: IParameterList); override; + procedure VisitArgumentList(const Node: IArgumentList); override; + procedure VisitExpressionList(const Node: IExpressionList); override; + procedure VisitRecordFieldList(const Node: IRecordFieldList); override; + procedure VisitRecordField(const Node: IRecordFieldNode); override; + procedure VisitIfExpression(const Node: IIfExpressionNode); override; procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); override; procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); override; @@ -315,7 +323,6 @@ var startPos: Integer; begin startPos := FCurrentPos; - // Reader macro characters and comments are now also delimiters for identifiers. while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '{', '}', '''', '`', '~', ';']))) do Advance; Result := Copy(FSource, startPos, FCurrentPos - startPos); @@ -544,7 +551,6 @@ begin if FCurrentToken.Kind <> tkIdentifier then Error('Syntax Error: Expected identifier in parameter list.'); - // Pass Location to Factory params.Add(TAst.Identifier(FCurrentToken.Text, FCurrentToken.GetLocation)); NextToken; end; @@ -557,14 +563,15 @@ end; function TParser.ParseRecordLiteral: IAstNode; var - fields: TList; + fields: TList; fieldName: string; fieldValue: IAstNode; keyToken: TToken; + keyNode: IKeywordNode; begin var startLoc := FCurrentToken.GetLocation; Consume(tkLeftBrace); - fields := TList.Create; + fields := TList.Create; try while FCurrentToken.Kind <> tkRightBrace do begin @@ -576,13 +583,15 @@ begin keyToken := FCurrentToken; fieldName := FCurrentToken.Text; + keyNode := TAst.Keyword(fieldName, keyToken.GetLocation); NextToken; if FCurrentToken.Kind = tkRightBrace then Error('Syntax Error: Missing value for key ' + fieldName + ' in record literal.'); + fieldValue := ParseExpression.Node; - fields.Add(TRecordFieldLiteral.Create(TAst.Keyword(fieldName, keyToken.GetLocation), fieldValue)); + fields.Add(TAst.RecordField(keyNode, fieldValue, keyToken.GetLocation)); end; Result := TAst.RecordLiteral(fields.ToArray, startLoc); @@ -863,6 +872,63 @@ begin Append(':' + Node.Value.Name); end; +// --- List Visitors Implementation --- + +procedure TPrettyPrintVisitor.VisitParameterList(const Node: IParameterList); +begin + Append('['); + for var i := 0 to Node.Count - 1 do + begin + if i > 0 then + Append(' '); + Node[i].Accept(Self); + end; + Append(']'); +end; + +procedure TPrettyPrintVisitor.VisitArgumentList(const Node: IArgumentList); +begin + // Argument list does not have brackets of its own in Lisp call syntax + for var i := 0 to Node.Count - 1 do + begin + Append(' '); // Space before each argument + Node[i].Accept(Self); + end; +end; + +procedure TPrettyPrintVisitor.VisitExpressionList(const Node: IExpressionList); +begin + Indent; + for var item in Node do + begin + NewLine; + item.Accept(Self); + end; + Unindent; + NewLine; +end; + +procedure TPrettyPrintVisitor.VisitRecordFieldList(const Node: IRecordFieldList); +begin + Indent; + for var item in Node do + begin + NewLine; + item.Accept(Self); + end; + Unindent; + NewLine; +end; + +procedure TPrettyPrintVisitor.VisitRecordField(const Node: IRecordFieldNode); +begin + Node.Key.Accept(Self); + Append(' '); + Node.Value.Accept(Self); +end; + +// --- Node Visitors --- + procedure TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode); begin Append('(if '); @@ -895,21 +961,9 @@ begin end; procedure TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode); -var - sb: TStringBuilder; begin - sb := TStringBuilder.Create; - try - for var param in Node.Parameters do - sb.Append(param.Name + ' '); - if sb.Length > 0 then - sb.Remove(sb.Length - 1, 1); - - Append('(fn [' + sb.ToString + ']'); - finally - sb.Free; - end; - + Append('(fn '); + Node.Parameters.Accept(Self); Indent; NewLine; Node.Body.Accept(Self); @@ -919,21 +973,11 @@ begin end; procedure TPrettyPrintVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode); -var - sb: TStringBuilder; begin - sb := TStringBuilder.Create; - try - for var param in Node.Parameters do - sb.Append(param.Name + ' '); - if sb.Length > 0 then - sb.Remove(sb.Length - 1, 1); - - Append('(defmacro ' + Node.Name.Name + ' [' + sb.ToString + ']'); - finally - sb.Free; - end; - + Append('(defmacro '); + Node.Name.Accept(Self); + Append(' '); + Node.Parameters.Accept(Self); Indent; NewLine; Node.Body.Accept(Self); @@ -961,10 +1005,8 @@ begin end; procedure TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode); -var - arg: IAstNode; begin - if (Node.Callee.Kind = akIdentifier) and (Node.Callee.AsIdentifier.Name = 'quote') and (Length(Node.Arguments) = 1) then + if (Node.Callee.Kind = akIdentifier) and (Node.Callee.AsIdentifier.Name = 'quote') and (Node.Arguments.Count = 1) then begin Append(''''); Node.Arguments[0].Accept(Self); @@ -973,15 +1015,7 @@ begin Append('('); Node.Callee.Accept(Self); - - Indent; - for arg in Node.Arguments do - begin - Append(' '); - arg.Accept(Self); - end; - Unindent; - + Node.Arguments.Accept(Self); // Prints separated by space Append(')'); end; @@ -991,34 +1025,16 @@ begin end; procedure TPrettyPrintVisitor.VisitRecurNode(const Node: IRecurNode); -var - arg: IAstNode; begin Append('(recur'); - Indent; - for arg in Node.Arguments do - begin - Append(' '); - arg.Accept(Self); - end; - Unindent; - + Node.Arguments.Accept(Self); Append(')'); end; procedure TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode); -var - expr: IAstNode; begin Append('(do'); - Indent; - for expr in Node.Expressions do - begin - NewLine; - expr.Accept(Self); - end; - Unindent; - NewLine; + Node.Expressions.Accept(Self); Append(')'); end; @@ -1062,26 +1078,15 @@ begin end; procedure TPrettyPrintVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode); -var - field: TRecordFieldLiteral; begin - if Length(Node.Fields) = 0 then + if Node.Fields.Count = 0 then begin Append('{}'); exit; end; Append('{'); - Indent; - for field in Node.Fields do - begin - NewLine; - Append(':' + field.Key.Value.Name); - Append(' '); - field.Value.Accept(Self); - end; - Unindent; - NewLine; + Node.Fields.Accept(Self); Append('}'); end; diff --git a/Src/AST/Myc.Ast.Visitor.pas b/Src/AST/Myc.Ast.Visitor.pas index e18c8d5..4bf0c40 100644 --- a/Src/AST/Myc.Ast.Visitor.pas +++ b/Src/AST/Myc.Ast.Visitor.pas @@ -9,7 +9,7 @@ uses Myc.Ast, Myc.Ast.Types, Myc.Ast.Nodes, - Myc.Ast.Identities; // Needed for identity casting + Myc.Ast.Identities; type TAstVisitor = class abstract(TInterfacedObject, IAstVisitor) @@ -18,6 +18,13 @@ type function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitKeyword = DoVisitKeyword; + + function IAstVisitor.VisitParameterList = DoVisitParameterList; + function IAstVisitor.VisitArgumentList = DoVisitArgumentList; + function IAstVisitor.VisitExpressionList = DoVisitExpressionList; + function IAstVisitor.VisitRecordFieldList = DoVisitRecordFieldList; + function IAstVisitor.VisitRecordField = DoVisitRecordField; + function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; @@ -43,6 +50,13 @@ type function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue; + + function DoVisitParameterList(const Node: IParameterList): TDataValue; + function DoVisitArgumentList(const Node: IArgumentList): TDataValue; + function DoVisitExpressionList(const Node: IExpressionList): TDataValue; + function DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; + function DoVisitRecordField(const Node: IRecordFieldNode): TDataValue; + function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; @@ -71,6 +85,13 @@ type function VisitConstant(const Node: IConstantNode): T; virtual; abstract; function VisitIdentifier(const Node: IIdentifierNode): T; virtual; abstract; function VisitKeyword(const Node: IKeywordNode): T; virtual; abstract; + + function VisitParameterList(const Node: IParameterList): T; virtual; abstract; + function VisitArgumentList(const Node: IArgumentList): T; virtual; abstract; + function VisitExpressionList(const Node: IExpressionList): T; virtual; abstract; + function VisitRecordFieldList(const Node: IRecordFieldList): T; virtual; abstract; + function VisitRecordField(const Node: IRecordFieldNode): T; virtual; abstract; + function VisitIfExpression(const Node: IIfExpressionNode): T; virtual; abstract; function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual; abstract; function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual; abstract; @@ -95,12 +116,16 @@ type TAstTransformer = class abstract(TAstVisitor) protected - function AcceptParameters(const Nodes: TArray): TArray; - function AcceptNodes(const Nodes: TArray; const AcceptProc: TFunc = nil): TArray; - function VisitConstant(const Node: IConstantNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; function VisitKeyword(const Node: IKeywordNode): IAstNode; override; + + function VisitParameterList(const Node: IParameterList): IAstNode; override; + function VisitArgumentList(const Node: IArgumentList): IAstNode; override; + function VisitExpressionList(const Node: IExpressionList): IAstNode; override; + function VisitRecordFieldList(const Node: IRecordFieldList): IAstNode; override; + function VisitRecordField(const Node: IRecordFieldNode): IAstNode; override; + function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override; @@ -129,6 +154,11 @@ type function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitKeyword = DoVisitKeyword; + function IAstVisitor.VisitParameterList = DoVisitParameterList; + function IAstVisitor.VisitArgumentList = DoVisitArgumentList; + function IAstVisitor.VisitExpressionList = DoVisitExpressionList; + function IAstVisitor.VisitRecordFieldList = DoVisitRecordFieldList; + function IAstVisitor.VisitRecordField = DoVisitRecordField; function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; @@ -154,6 +184,11 @@ type function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue; + function DoVisitParameterList(const Node: IParameterList): TDataValue; + function DoVisitArgumentList(const Node: IArgumentList): TDataValue; + function DoVisitExpressionList(const Node: IExpressionList): TDataValue; + function DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; + function DoVisitRecordField(const Node: IRecordFieldNode): TDataValue; function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; @@ -183,6 +218,13 @@ type procedure VisitConstant(const Node: IConstantNode); virtual; procedure VisitIdentifier(const Node: IIdentifierNode); virtual; procedure VisitKeyword(const Node: IKeywordNode); virtual; + + procedure VisitParameterList(const Node: IParameterList); virtual; + procedure VisitArgumentList(const Node: IArgumentList); virtual; + procedure VisitExpressionList(const Node: IExpressionList); virtual; + procedure VisitRecordFieldList(const Node: IRecordFieldList); virtual; + procedure VisitRecordField(const Node: IRecordFieldNode); virtual; + procedure VisitIfExpression(const Node: IIfExpressionNode); virtual; procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); virtual; procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); virtual; @@ -207,7 +249,7 @@ type implementation -{ TAstVisitor } +{ TAstVisitor } function TAstVisitor.Accept(const Node: IAstNode): T; begin @@ -217,205 +259,122 @@ begin Result := Default(T); end; -{ TAstVisitor } - function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitConstant(Node)); end; - function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIdentifier(Node)); end; - function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitKeyword(Node)); end; +function TAstVisitor.DoVisitParameterList(const Node: IParameterList): TDataValue; +begin + Result := TDataValue.FromGeneric(VisitParameterList(Node)); +end; +function TAstVisitor.DoVisitArgumentList(const Node: IArgumentList): TDataValue; +begin + Result := TDataValue.FromGeneric(VisitArgumentList(Node)); +end; +function TAstVisitor.DoVisitExpressionList(const Node: IExpressionList): TDataValue; +begin + Result := TDataValue.FromGeneric(VisitExpressionList(Node)); +end; +function TAstVisitor.DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; +begin + Result := TDataValue.FromGeneric(VisitRecordFieldList(Node)); +end; +function TAstVisitor.DoVisitRecordField(const Node: IRecordFieldNode): TDataValue; +begin + Result := TDataValue.FromGeneric(VisitRecordField(Node)); +end; + function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIfExpression(Node)); end; - function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitTernaryExpression(Node)); end; - function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitLambdaExpression(Node)); end; - function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitFunctionCall(Node)); end; - function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMacroExpansionNode(Node)); end; - function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitBlockExpression(Node)); end; - function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitVariableDeclaration(Node)); end; - function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitAssignment(Node)); end; - function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMacroDefinition(Node)); end; - function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitQuasiquote(Node)); end; - function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitUnquote(Node)); end; - function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitUnquoteSplicing(Node)); end; - function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIndexer(Node)); end; - function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMemberAccess(Node)); end; - function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecordLiteral(Node)); end; - function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitCreateSeries(Node)); end; - function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitAddSeriesItem(Node)); end; - function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitSeriesLength(Node)); end; - function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecurNode(Node)); end; - function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitNop(Node)); end; -function TAstTransformer.AcceptParameters(const Nodes: TArray): TArray; -var - i: Integer; - hasChanged: Boolean; - newNode: IIdentifierNode; -begin - hasChanged := False; - SetLength(Result, Length(Nodes)); - - for i := 0 to High(Nodes) do - begin - newNode := Accept(Nodes[i]).AsIdentifier; - Result[i] := newNode; - if newNode <> Nodes[i] then - hasChanged := True; - end; - - if not hasChanged then - Result := Nodes; -end; - -function TAstTransformer.AcceptNodes( - const Nodes: TArray; - const AcceptProc: TFunc = nil -): TArray; -var - i: Integer; - newNode: IAstNode; - newList: TList; - hasChanged: Boolean; -begin - hasChanged := False; - newList := nil; - - for i := 0 to High(Nodes) do - begin - if Assigned(AcceptProc) then - newNode := AcceptProc(i, Nodes[i]) - else - newNode := Accept(Nodes[i]); - - if not Assigned(newNode) then - begin - hasChanged := True; - if newList = nil then - begin - newList := TList.Create; - for var j := 0 to i - 1 do - newList.Add(Nodes[j]); - end; - end - else - begin - if newNode <> Nodes[i] then - begin - hasChanged := True; - if newList = nil then - begin - newList := TList.Create; - for var j := 0 to i - 1 do - newList.Add(Nodes[j]); - end; - newList.Add(newNode); - end - else - begin - if newList <> nil then - newList.Add(Nodes[i]); - end; - end; - end; - - if not hasChanged then - Result := Nodes - else if newList <> nil then - begin - Result := newList.ToArray; - newList.Free; - end - else - Result := []; -end; +{ TAstTransformer } // --- Base Virtual Implementations --- @@ -423,21 +382,138 @@ function TAstTransformer.VisitConstant(const Node: IConstantNode): IAstNode; begin Result := Node; end; - function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): IAstNode; begin Result := Node; end; - function TAstTransformer.VisitKeyword(const Node: IKeywordNode): IAstNode; begin Result := Node; end; - function TAstTransformer.VisitNop(const Node: INopNode): IAstNode; begin Result := Node; end; +function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode; +begin + Result := Node; +end; + +// --- List Transformations --- + +function TAstTransformer.VisitParameterList(const Node: IParameterList): IAstNode; +var + hasChanged: Boolean; + newItems: TArray; + item, newItem: IIdentifierNode; + i: Integer; +begin + hasChanged := False; + SetLength(newItems, Node.Count); + for i := 0 to Node.Count - 1 do + begin + item := Node[i]; + newItem := Accept(item).AsIdentifier; + newItems[i] := newItem; + if item <> newItem then + hasChanged := True; + end; + + if not hasChanged then + Result := Node + else + // Manually reconstruct using concrete class to verify transformation + Result := TParameterList.Create(newItems, Node.Identity); +end; + +function TAstTransformer.VisitArgumentList(const Node: IArgumentList): IAstNode; +var + hasChanged: Boolean; + newItems: TArray; + item, newItem: IAstNode; + i: Integer; +begin + hasChanged := False; + SetLength(newItems, Node.Count); + for i := 0 to Node.Count - 1 do + begin + item := Node[i]; + newItem := Accept(item); + newItems[i] := newItem; + if item <> newItem then + hasChanged := True; + end; + + if not hasChanged then + Result := Node + else + Result := TArgumentList.Create(newItems, Node.Identity); +end; + +function TAstTransformer.VisitExpressionList(const Node: IExpressionList): IAstNode; +var + hasChanged: Boolean; + newItems: TArray; + item, newItem: IAstNode; + i: Integer; +begin + hasChanged := False; + SetLength(newItems, Node.Count); + for i := 0 to Node.Count - 1 do + begin + item := Node[i]; + newItem := Accept(item); + newItems[i] := newItem; + if item <> newItem then + hasChanged := True; + end; + + if not hasChanged then + Result := Node + else + Result := TExpressionList.Create(newItems, Node.Identity); +end; + +function TAstTransformer.VisitRecordFieldList(const Node: IRecordFieldList): IAstNode; +var + hasChanged: Boolean; + newItems: TArray; + item, newItem: IRecordFieldNode; + i: Integer; +begin + hasChanged := False; + SetLength(newItems, Node.Count); + for i := 0 to Node.Count - 1 do + begin + item := Node[i]; + // Ensure we transform the field node itself via Accept to trigger VisitRecordField + newItem := Accept(item).AsRecordField; + newItems[i] := newItem; + if item <> newItem then + hasChanged := True; + end; + + if not hasChanged then + Result := Node + else + Result := TRecordFieldList.Create(newItems, Node.Identity); +end; + +function TAstTransformer.VisitRecordField(const Node: IRecordFieldNode): IAstNode; +var + newKey: IKeywordNode; + newValue: IAstNode; +begin + newKey := Accept(Node.Key).AsKeyword; + newValue := Accept(Node.Value); + + if (newKey = Node.Key) and (newValue = Node.Value) then + Result := Node + else + Result := TAst.RecordField(newKey, newValue, Node.Identity.Location); +end; + +// --- Node Transformations --- function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; var @@ -469,27 +545,29 @@ end; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; var - newParams: TArray; + newParams: IParameterList; newBody: IAstNode; begin - newParams := AcceptParameters(Node.Parameters); + newParams := Accept(Node.Parameters).AsParameterList; newBody := Accept(Node.Body); if (newParams = Node.Parameters) and (newBody = Node.Body) then Result := Node else begin + // Rebuild Lambda via concrete constructor to keep Layout/Descriptor info + // TAst factory would reset layout info. Result := - TAst.LambdaExpr( - Node.Identity, + TLambdaExpressionNode.Create( newParams, newBody, + Node.StaticType, Node.Layout, Node.Descriptor, Node.Upvalues, Node.HasNestedLambdas, Node.IsPure, - Node.StaticType + Node.Identity ); end; end; @@ -497,17 +575,18 @@ end; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var newCallee: IAstNode; - newArgs: TArray; + newArgs: IArgumentList; begin newCallee := Accept(Node.Callee); - newArgs := AcceptNodes(Node.Arguments); + newArgs := Accept(Node.Arguments).AsArgumentList; if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then Result := Node else begin Result := - TAst.FunctionCall(Node.Identity, newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget, Node.IsTargetPure); + TFunctionCallNode + .Create(newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget, Node.IsTargetPure, Node.Identity); end; end; @@ -519,20 +598,22 @@ begin if newBody = Node.ExpandedBody then exit(Node); - // Macro Expansion Nodes are structural, reuse identity + // Macro Expansion Nodes are structural, reuse identity. + // Note: We don't visit the CallNode as it is the "source" which doesn't change during this transformation typically Result := TAst.MacroExpansionNode(Node.Identity, Node.CallNode, newBody); end; function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; var - newExprs: TArray; + newExprs: IExpressionList; begin - newExprs := AcceptNodes(Node.Expressions); + newExprs := Accept(Node.Expressions).AsExpressionList; if newExprs = Node.Expressions then Result := Node else - Result := TAst.Block(Node.Identity, newExprs, Node.StaticType); + // Rebuild manually to preserve type + Result := TBlockExpressionNode.Create(newExprs, Node.StaticType, Node.Identity); end; function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; @@ -598,15 +679,11 @@ function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): var newExpr: IAstNode; begin - // Note: Accept expects IAstNode, IQuasiquoteNode inherits from it. newExpr := Accept(Node.Expression); if (newExpr = Node.Expression) then Result := Node else - // We need to ensure the transformed expression is still a Quasiquote, - // or we have to assume the transformer knows what it's doing. - // For safety, we cast back. If transformation changed type, this will fail fast. Result := TAst.UnquoteSplicing(Node.Identity, newExpr.AsQuasiquote); end; @@ -639,35 +716,18 @@ end; function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; var - i: Integer; - newFields: TArray; - hasChanged: Boolean; + newFields: IRecordFieldList; begin - SetLength(newFields, Length(Node.Fields)); - hasChanged := False; + newFields := Accept(Node.Fields).AsRecordFieldList; - for i := 0 to High(Node.Fields) do - begin - // Keys are typically static, but we visit them anyway - newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword; - newFields[i].Value := Accept(Node.Fields[i].Value); - if (newFields[i].Key <> Node.Fields[i].Key) or (newFields[i].Value <> Node.Fields[i].Value) then - hasChanged := True; - end; - - if not hasChanged then + if newFields = Node.Fields then Result := Node else begin - Result := TAst.RecordLiteral(Node.Identity, newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType); + Result := TRecordLiteralNode.Create(newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType, Node.Identity); end; end; -function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode; -begin - Result := Node; -end; - function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode; var newSeries: IIdentifierNode; @@ -697,14 +757,14 @@ end; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode; var - newArgs: TArray; + newArgs: IArgumentList; begin - newArgs := AcceptNodes(Node.Arguments); + newArgs := Accept(Node.Arguments).AsArgumentList; if newArgs = Node.Arguments then Result := Node else - Result := TAst.Recur(Node.Identity, newArgs, Node.StaticType); + Result := TRecurNode.Create(newArgs, Node.StaticType, Node.Identity); end; { TAstVisitor } @@ -717,17 +777,49 @@ end; procedure TAstVisitor.VisitConstant(const Node: IConstantNode); begin - // Leaf node end; - procedure TAstVisitor.VisitIdentifier(const Node: IIdentifierNode); begin - // Leaf node end; - procedure TAstVisitor.VisitKeyword(const Node: IKeywordNode); begin - // Leaf node +end; +procedure TAstVisitor.VisitNop(const Node: INopNode); +begin +end; +procedure TAstVisitor.VisitCreateSeries(const Node: ICreateSeriesNode); +begin +end; + +// List visitors iterate children by default +procedure TAstVisitor.VisitParameterList(const Node: IParameterList); +begin + for var item in Node do + Accept(item); +end; + +procedure TAstVisitor.VisitArgumentList(const Node: IArgumentList); +begin + for var item in Node do + Accept(item); +end; + +procedure TAstVisitor.VisitExpressionList(const Node: IExpressionList); +begin + for var item in Node do + Accept(item); +end; + +procedure TAstVisitor.VisitRecordFieldList(const Node: IRecordFieldList); +begin + for var item in Node do + Accept(item); +end; + +procedure TAstVisitor.VisitRecordField(const Node: IRecordFieldNode); +begin + Accept(Node.Key); + Accept(Node.Value); end; procedure TAstVisitor.VisitIfExpression(const Node: IIfExpressionNode); @@ -746,16 +838,14 @@ end; procedure TAstVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode); begin - for var param in Node.Parameters do - Accept(param); + Accept(Node.Parameters); Accept(Node.Body); end; procedure TAstVisitor.VisitFunctionCall(const Node: IFunctionCallNode); begin Accept(Node.Callee); - for var arg in Node.Arguments do - Accept(arg); + Accept(Node.Arguments); end; procedure TAstVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode); @@ -766,8 +856,7 @@ end; procedure TAstVisitor.VisitBlockExpression(const Node: IBlockExpressionNode); begin - for var expr in Node.Expressions do - Accept(expr); + Accept(Node.Expressions); end; procedure TAstVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode); @@ -785,8 +874,7 @@ end; procedure TAstVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode); begin Accept(Node.Name); - for var param in Node.Parameters do - Accept(param); + Accept(Node.Parameters); Accept(Node.Body); end; @@ -819,16 +907,7 @@ end; procedure TAstVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode); begin - for var field in Node.Fields do - begin - Accept(field.Key); - Accept(field.Value); - end; -end; - -procedure TAstVisitor.VisitCreateSeries(const Node: ICreateSeriesNode); -begin - // Leaf node + Accept(Node.Fields); end; procedure TAstVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode); @@ -845,130 +924,177 @@ end; procedure TAstVisitor.VisitRecurNode(const Node: IRecurNode); begin - for var arg in Node.Arguments do - Accept(arg); + Accept(Node.Arguments); end; -procedure TAstVisitor.VisitNop(const Node: INopNode); -begin - // Leaf node -end; - -// ... [Private Bridge Methods implementation remains unchanged] ... +// --- TAstVisitor (Non-Generic) Bridge Implementations --- function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue; begin VisitConstant(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; begin VisitIdentifier(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue; begin VisitKeyword(Node); + Result := TDataValue.Void; +end; + +function TAstVisitor.DoVisitParameterList(const Node: IParameterList): TDataValue; +begin + VisitParameterList(Node); + Result := TDataValue.Void; +end; + +function TAstVisitor.DoVisitArgumentList(const Node: IArgumentList): TDataValue; +begin + VisitArgumentList(Node); + Result := TDataValue.Void; +end; + +function TAstVisitor.DoVisitExpressionList(const Node: IExpressionList): TDataValue; +begin + VisitExpressionList(Node); + Result := TDataValue.Void; +end; + +function TAstVisitor.DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; +begin + VisitRecordFieldList(Node); + Result := TDataValue.Void; +end; + +function TAstVisitor.DoVisitRecordField(const Node: IRecordFieldNode): TDataValue; +begin + VisitRecordField(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; begin VisitIfExpression(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; begin VisitTernaryExpression(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; begin VisitLambdaExpression(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; begin VisitFunctionCall(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; begin VisitMacroExpansionNode(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; begin VisitBlockExpression(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; begin VisitVariableDeclaration(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; begin VisitAssignment(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; begin VisitMacroDefinition(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; begin VisitQuasiquote(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; begin VisitUnquote(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; begin VisitUnquoteSplicing(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue; begin VisitIndexer(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; begin VisitMemberAccess(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; begin VisitRecordLiteral(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; begin VisitCreateSeries(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; begin VisitAddSeriesItem(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; begin VisitSeriesLength(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue; begin VisitRecurNode(Node); + Result := TDataValue.Void; end; function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue; begin VisitNop(Node); + Result := TDataValue.Void; end; end. diff --git a/Src/AST/Myc.Ast.pas b/Src/AST/Myc.Ast.pas index c3441dc..8be07db 100644 --- a/Src/AST/Myc.Ast.pas +++ b/Src/AST/Myc.Ast.pas @@ -124,7 +124,7 @@ type class function LambdaExpr( const Identity: IAstIdentity; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const ALayout: IScopeLayout = nil; const ADescriptor: IScopeDescriptor = nil; @@ -145,7 +145,7 @@ type class function MacroDef( const Identity: IAstIdentity; const AName: IIdentifierNode; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode ): IMacroDefinitionNode; overload; static; @@ -175,7 +175,7 @@ type class function FunctionCall( const Identity: IAstIdentity; const ACallee: IAstNode; - const AArguments: TArray; + const AArguments: IArgumentList; const AStaticType: IStaticType = nil; const AIsTailCall: Boolean = False; const AStaticTarget: TDataValue.TFunc = nil; @@ -183,7 +183,6 @@ type ): IFunctionCallNode; overload; static; // --- MACRO EXPANSION --- - // Note: MacroExpansion is usually created during transformation, but conceptually it's a new node wrapping the original call. class function MacroExpansionNode( const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode; @@ -201,7 +200,7 @@ type class function Recur( const Identity: IAstIdentity; - const AArguments: TArray; + const AArguments: IArgumentList; const AStaticType: IStaticType = nil ): IRecurNode; overload; static; @@ -213,7 +212,7 @@ type class function Block( const Identity: IAstIdentity; - const AExpressions: TArray; + const AExpressions: IExpressionList; const AStaticType: IStaticType = nil ): IBlockExpressionNode; overload; static; @@ -241,10 +240,6 @@ type const AStaticType: IStaticType = nil ): IAssignmentNode; overload; static; - // --- ASSIGN RESULT (Helper) --- - // Special case: Creates implicit nodes. No explicit "Transformation" overload needed as it maps to Assign. - class function AssignResult(const AValue: IAstNode; const Loc: ISourceLocation = nil): IAssignmentNode; static; deprecated; - // --- INDEXER --- class function Indexer( const ABase: IAstNode; @@ -273,15 +268,28 @@ type const AStaticType: IStaticType = nil ): IMemberAccessNode; overload; static; - // --- RECORD LITERAL --- + // --- RECORD FIELD & LITERAL --- + class function RecordField( + const AKey: IKeywordNode; + const AValue: IAstNode; + const Loc: ISourceLocation = nil + ): IRecordFieldNode; overload; static; + + // Neuer Overload für Identitäts-Erhalt + class function RecordField( + const Identity: IAstIdentity; + const AKey: IKeywordNode; + const AValue: IAstNode + ): IRecordFieldNode; overload; static; + class function RecordLiteral( - const AFields: TArray; + const AFields: TArray; const Loc: ISourceLocation = nil ): IRecordLiteralNode; overload; static; class function RecordLiteral( const Identity: IAstIdentity; - const AFields: TArray; + const AFields: IRecordFieldList; const AScalarDefinition: IScalarRecordDefinition = nil; const AGenericDefinition: IGenericRecordDefinition = nil; const AStaticType: IStaticType = nil @@ -355,11 +363,9 @@ begin end; // ============================================================================= -// IMPLEMENTATION: DATA NODES +// DATA NODES // ============================================================================= -// --- Identifier --- - class function TAst.Identifier(const AName: string; const Loc: ISourceLocation): IIdentifierNode; begin var id := TIdentities.Identifier(AName, Loc); @@ -381,8 +387,6 @@ begin ); end; -// --- Constant --- - class function TAst.Constant(const AValue: TDataValue; const Loc: ISourceLocation): IConstantNode; begin var constType: IStaticType; @@ -413,8 +417,6 @@ begin ); end; -// --- Keyword --- - class function TAst.Keyword(const AName: string; const Loc: ISourceLocation): IKeywordNode; begin var val := TKeywordRegistry.Intern(AName); @@ -427,8 +429,6 @@ begin Result := TKeywordNode.Create(Identity); end; -// --- CreateSeries --- - class function TAst.CreateSeries(const ADefinition: String; const Loc: ISourceLocation): ICreateSeriesNode; begin var id := TIdentities.Definition(ADefinition, Loc); @@ -446,11 +446,9 @@ begin end; // ============================================================================= -// IMPLEMENTATION: STRUCTURAL NODES +// STRUCTURAL NODES // ============================================================================= -// --- NOP --- - class function TAst.Nop(const Loc: ISourceLocation): IAstNode; begin var id := TIdentities.Structural(Loc); @@ -467,8 +465,6 @@ begin ); end; -// --- IfExpr --- - class function TAst.IfExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): IIfExpressionNode; begin var id := TIdentities.Structural(Loc); @@ -492,8 +488,6 @@ begin ); end; -// --- TernaryExpr --- - class function TAst.TernaryExpr(const ACondition, AThenBranch, AElseBranch: IAstNode; const Loc: ISourceLocation): ITernaryExpressionNode; begin var id := TIdentities.Structural(Loc); @@ -517,21 +511,22 @@ begin ); end; -// --- LambdaExpr --- - class function TAst.LambdaExpr( const AParameters: TArray; const ABody: IAstNode; const Loc: ISourceLocation ): ILambdaExpressionNode; begin + var listId := TIdentities.List('[', ']', ' ', Loc); + var paramList := TParameterList.Create(AParameters, listId); + var id := TIdentities.Structural(Loc); - Result := TLambdaExpressionNode.Create(AParameters, ABody, TTypes.Unknown, nil, nil, nil, False, False, id); + Result := TLambdaExpressionNode.Create(paramList, ABody, TTypes.Unknown, nil, nil, nil, False, False, id); end; class function TAst.LambdaExpr( const Identity: IAstIdentity; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode; const ALayout: IScopeLayout; const ADescriptor: IScopeDescriptor; @@ -555,8 +550,6 @@ begin ); end; -// --- MacroDef --- - class function TAst.MacroDef( const AName: IIdentifierNode; const AParameters: TArray; @@ -564,22 +557,23 @@ class function TAst.MacroDef( const Loc: ISourceLocation ): IMacroDefinitionNode; begin + var listId := TIdentities.List('[', ']', ' ', Loc); + var paramList := TParameterList.Create(AParameters, listId); + var id := TIdentities.Structural(Loc); - Result := TMacroDefinitionNode.Create(AName, AParameters, ABody, id); + Result := TMacroDefinitionNode.Create(AName, paramList, ABody, id); end; class function TAst.MacroDef( const Identity: IAstIdentity; const AName: IIdentifierNode; - const AParameters: TArray; + const AParameters: IParameterList; const ABody: IAstNode ): IMacroDefinitionNode; begin Result := TMacroDefinitionNode.Create(AName, AParameters, ABody, Identity); end; -// --- Quotes --- - class function TAst.Quasiquote(const AExpression: IAstNode; const Loc: ISourceLocation): IQuasiquoteNode; begin var id := TIdentities.Structural(Loc); @@ -613,22 +607,23 @@ begin Result := TUnquoteSplicingNode.Create(AExpression, Identity); end; -// --- FunctionCall --- - class function TAst.FunctionCall( const ACallee: IAstNode; const AArguments: TArray; const Loc: ISourceLocation ): IFunctionCallNode; begin + var listId := TIdentities.List('', '', ' ', Loc); + var argList := TArgumentList.Create(AArguments, listId); + var id := TIdentities.Structural(Loc); - Result := TFunctionCallNode.Create(ACallee, AArguments, TTypes.Unknown, False, nil, False, id); + Result := TFunctionCallNode.Create(ACallee, argList, TTypes.Unknown, False, nil, False, id); end; class function TAst.FunctionCall( const Identity: IAstIdentity; const ACallee: IAstNode; - const AArguments: TArray; + const AArguments: IArgumentList; const AStaticType: IStaticType; const AIsTailCall: Boolean; const AStaticTarget: TDataValue.TFunc; @@ -648,8 +643,6 @@ begin ); end; -// --- MacroExpansion --- - class function TAst.MacroExpansionNode( const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode; @@ -669,8 +662,6 @@ begin Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody, Identity); end; -// --- Recur --- - class function TAst.Recur(const AArguments: array of IAstNode; const Loc: ISourceLocation): IRecurNode; var args: TArray; @@ -679,11 +670,15 @@ begin SetLength(args, Length(AArguments)); for i := 0 to High(AArguments) do args[i] := AArguments[i]; + + var listId := TIdentities.List('', '', ' ', Loc); + var argList := TArgumentList.Create(args, listId); + var id := TIdentities.Structural(Loc); - Result := TRecurNode.Create(args, TTypes.Void, id); + Result := TRecurNode.Create(argList, TTypes.Void, id); end; -class function TAst.Recur(const Identity: IAstIdentity; const AArguments: TArray; const AStaticType: IStaticType): IRecurNode; +class function TAst.Recur(const Identity: IAstIdentity; const AArguments: IArgumentList; const AStaticType: IStaticType): IRecurNode; begin Result := TRecurNode.Create( @@ -694,8 +689,6 @@ begin ); end; -// --- Block --- - class function TAst.Block(const AExpressions: array of IAstNode; const Loc: ISourceLocation): IBlockExpressionNode; var exprs: TArray; @@ -704,13 +697,17 @@ begin SetLength(exprs, Length(AExpressions)); for i := 0 to High(AExpressions) do exprs[i] := AExpressions[i]; + + var listId := TIdentities.List('', '', ' ', Loc); + var exprList := TExpressionList.Create(exprs, listId); + var id := TIdentities.Structural(Loc); - Result := TBlockExpressionNode.Create(exprs, TTypes.Unknown, id); + Result := TBlockExpressionNode.Create(exprList, TTypes.Unknown, id); end; class function TAst.Block( const Identity: IAstIdentity; - const AExpressions: TArray; + const AExpressions: IExpressionList; const AStaticType: IStaticType ): IBlockExpressionNode; begin @@ -723,8 +720,6 @@ begin ); end; -// --- VarDecl --- - class function TAst.VarDecl(const AIdentifier: IAstNode; AInitializer: IAstNode; const Loc: ISourceLocation): IVariableDeclarationNode; begin var id := TIdentities.Structural(Loc); @@ -750,8 +745,6 @@ begin ); end; -// --- Assign --- - class function TAst.Assign(const ATarget, AValue: IAstNode; const Loc: ISourceLocation): IAssignmentNode; begin var id := TIdentities.Structural(Loc); @@ -770,15 +763,6 @@ begin ); end; -class function TAst.AssignResult(const AValue: IAstNode; const Loc: ISourceLocation): IAssignmentNode; -begin - // Helper: Creates an implicit Identifier "Result" with new Identity - var resultId := TAst.Identifier('Result', Loc); - Result := TAst.Assign(resultId, AValue, Loc); -end; - -// --- Indexer --- - class function TAst.Indexer(const ABase, AIndex: IAstNode; const Loc: ISourceLocation): IIndexerNode; begin var id := TIdentities.Structural(Loc); @@ -797,8 +781,6 @@ begin ); end; -// --- MemberAccess --- - class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode; const Loc: ISourceLocation): IMemberAccessNode; begin var id := TIdentities.Structural(Loc); @@ -822,17 +804,29 @@ begin ); end; -// --- RecordLiteral --- - -class function TAst.RecordLiteral(const AFields: TArray; const Loc: ISourceLocation): IRecordLiteralNode; +class function TAst.RecordField(const AKey: IKeywordNode; const AValue: IAstNode; const Loc: ISourceLocation): IRecordFieldNode; begin var id := TIdentities.Structural(Loc); - Result := TRecordLiteralNode.Create(AFields, nil, nil, TTypes.Unknown, id); + Result := TRecordFieldNode.Create(AKey, AValue, id); +end; + +class function TAst.RecordField(const Identity: IAstIdentity; const AKey: IKeywordNode; const AValue: IAstNode): IRecordFieldNode; +begin + Result := TRecordFieldNode.Create(AKey, AValue, Identity); +end; + +class function TAst.RecordLiteral(const AFields: TArray; const Loc: ISourceLocation): IRecordLiteralNode; +begin + var listId := TIdentities.List('{', '}', ' ', Loc); + var fieldList := TRecordFieldList.Create(AFields, listId); + + var id := TIdentities.Structural(Loc); + Result := TRecordLiteralNode.Create(fieldList, nil, nil, TTypes.Unknown, id); end; class function TAst.RecordLiteral( const Identity: IAstIdentity; - const AFields: TArray; + const AFields: IRecordFieldList; const AScalarDefinition: IScalarRecordDefinition; const AGenericDefinition: IGenericRecordDefinition; const AStaticType: IStaticType @@ -849,11 +843,10 @@ begin ); end; -// --- AddSeriesItem --- - class function TAst.AddSeriesItem( const ASeries: IIdentifierNode; - const AValue, ALookback: IAstNode; + const AValue: IAstNode; + const ALookback: IAstNode; const Loc: ISourceLocation ): IAddSeriesItemNode; begin @@ -864,7 +857,8 @@ end; class function TAst.AddSeriesItem( const Identity: IAstIdentity; const ASeries: IIdentifierNode; - const AValue, ALookback: IAstNode; + const AValue: IAstNode; + const ALookback: IAstNode; const AStaticType: IStaticType ): IAddSeriesItemNode; begin @@ -879,8 +873,6 @@ begin ); end; -// --- SeriesLength --- - class function TAst.SeriesLength(const ASeries: IIdentifierNode; const Loc: ISourceLocation): ISeriesLengthNode; begin var id := TIdentities.Structural(Loc); diff --git a/Src/AST/Myc.Fmx.AstEditor.Core.pas b/Src/AST/Myc.Fmx.AstEditor.Core.pas index 73ccac7..263197a 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Core.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Core.pas @@ -577,15 +577,22 @@ var effBorderWidth: Single; effDash: TStrokeDash; isHovering: Boolean; - isBlock: Boolean; + shouldIgnoreHover: Boolean; begin inherited; - // Check if this is a block node (blocks should not highlight on hover) - isBlock := Assigned(Node) and (Node.Kind = TAstNodeKind.akBlockExpression); + shouldIgnoreHover := False; + if Assigned(Node) then + begin + case Node.Kind of + // Lists and Blocks should generally not be highlighted as a whole on hover + // because they are containers for other selectable items. + akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: shouldIgnoreHover := True; + end; + end; - // Determine hover state: active only if mouse is over AND it is not a block - isHovering := IsMouseOver and (not isBlock); + // Determine hover state: active only if mouse is over AND it is not a container type + isHovering := IsMouseOver and (not shouldIgnoreHover); // 1. Set base values if FFrameless then diff --git a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas index c85bcbc..2e5cde9 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas @@ -20,7 +20,62 @@ uses Myc.Fmx.AstEditor.Core; type - // --- Basic Handlers --- + // --- Abstract List Base --- + // Handles layout, brackets (from Identity), and child iteration + TNodeListHandler = class(TBaseNodeHandler>) + protected + FChildNodes: TList; + function GetOrientation: TLayoutOrientation; virtual; abstract; + function GetAlignment: TLayoutAlignment; virtual; + public + constructor Create(const ANode: INodeList); + destructor Destroy; override; + procedure BuildUI(OwnerNode: TAstViewNode); override; + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; abstract; + end; + + // --- Concrete List Handlers --- + + TParameterListHandler = class(TNodeListHandler) + protected + function GetOrientation: TLayoutOrientation; override; + public + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; + end; + + TArgumentListHandler = class(TNodeListHandler) + protected + function GetOrientation: TLayoutOrientation; override; + public + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; + end; + + TExpressionListHandler = class(TNodeListHandler) + protected + function GetOrientation: TLayoutOrientation; override; + function GetAlignment: TLayoutAlignment; override; + public + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; + end; + + TRecordFieldListHandler = class(TNodeListHandler) + protected + function GetOrientation: TLayoutOrientation; override; + function GetAlignment: TLayoutAlignment; override; + public + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; + end; + + // --- Node Handlers --- + + TRecordFieldHandler = class(TBaseNodeHandler) + private + FKeyLabel: TLabel; + FValueNode: TAstViewNode; + public + procedure BuildUI(OwnerNode: TAstViewNode); override; + function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; + end; TConstantNodeHandler = class(TBaseNodeHandler) public @@ -50,10 +105,8 @@ type TBlockExpressionNodeHandler = class(TBaseNodeHandler) private - FChildNodes: TList; + FExpressionsNode: TAstViewNode; public - constructor Create(const ANode: IBlockExpressionNode); - destructor Destroy; override; procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; @@ -82,11 +135,9 @@ type TLambdaExpressionNodeHandler = class(TBaseNodeHandler) private + FParamsNode: TAstViewNode; FBodyNode: TAstViewNode; - FParamLabels: TList; public - constructor Create(const ANode: ILambdaExpressionNode); - destructor Destroy; override; procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; @@ -94,10 +145,8 @@ type TFunctionCallNodeHandler = class(TBaseNodeHandler) private FCalleeNode: TAstViewNode; - FArgumentNodes: TList; + FArgumentsNode: TAstViewNode; public - constructor Create(const ANode: IFunctionCallNode); - destructor Destroy; override; procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; @@ -112,10 +161,8 @@ type TRecurNodeHandler = class(TBaseNodeHandler) private - FArgumentNodes: TList; + FArgumentsNode: TAstViewNode; public - constructor Create(const ANode: IRecurNode); - destructor Destroy; override; procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; @@ -142,6 +189,7 @@ type TMacroDefinitionNodeHandler = class(TBaseNodeHandler) private + FParamsNode: TAstViewNode; FBodyNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; @@ -195,10 +243,8 @@ type TRecordLiteralNodeHandler = class(TBaseNodeHandler) private - FFieldNodes: TDictionary; + FFieldsNode: TAstViewNode; public - constructor Create(const ANode: IRecordLiteralNode); - destructor Destroy; override; procedure BuildUI(OwnerNode: TAstViewNode); override; function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; end; @@ -228,6 +274,200 @@ type implementation +{ TNodeListHandler } + +constructor TNodeListHandler.Create(const ANode: INodeList); +begin + inherited Create(ANode); + FChildNodes := TList.Create; +end; + +destructor TNodeListHandler.Destroy; +begin + FChildNodes.Free; + inherited; +end; + +function TNodeListHandler.GetAlignment: TLayoutAlignment; +begin + Result := TLayoutAlignment.laCenter; +end; + +procedure TNodeListHandler.BuildUI(OwnerNode: TAstViewNode); +var + visu: IAstVisualizer; + i: Integer; + childView: TAstViewNode; + openTok, closeTok, sep: string; + listId: IListIdentity; +begin + if (FNode.Identity <> nil) and (FNode.Identity.Kind = ikList) then + begin + listId := FNode.Identity.AsList; + openTok := listId.OpenToken; + closeTok := listId.CloseToken; + sep := listId.Separator; + end + else + begin + openTok := ''; + closeTok := ''; + sep := ' '; + end; + + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth); + + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := GetOrientation; + OwnerNode.Alignment := GetAlignment; + + if openTok <> '' then + OwnerNode.AddLabel(OwnerNode, openTok); + + for i := 0 to FNode.Count - 1 do + begin + childView := visu.CallAccept(FNode[i]); + FChildNodes.Add(childView); + + if (i < FNode.Count - 1) and (sep <> '') and (sep <> ' ') then + OwnerNode.AddLabel(OwnerNode, sep); + end; + + if closeTok <> '' then + OwnerNode.AddLabel(OwnerNode, closeTok); + + if FNode.Count = 0 then + begin + if (openTok = '') and (closeTok = '') then + begin + var lbl := OwnerNode.AddLabel(OwnerNode, 'ø'); + lbl.Opacity := 0.5; + end; + end; + + finally + OwnerNode.EndUpdate; + end; +end; + +{ TParameterListHandler } + +function TParameterListHandler.GetOrientation: TLayoutOrientation; +begin + Result := loHorizontal; +end; + +function TParameterListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; +var + arr: TArray; + i: Integer; +begin + SetLength(arr, FChildNodes.Count); + for i := 0 to FChildNodes.Count - 1 do + arr[i] := FChildNodes[i].CreateAst.AsIdentifier; + + Result := TParameterList.Create(arr, FNode.Identity); +end; + +{ TArgumentListHandler } + +function TArgumentListHandler.GetOrientation: TLayoutOrientation; +begin + Result := loHorizontal; +end; + +function TArgumentListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; +var + arr: TArray; + i: Integer; +begin + SetLength(arr, FChildNodes.Count); + for i := 0 to FChildNodes.Count - 1 do + arr[i] := FChildNodes[i].CreateAst; + + Result := TArgumentList.Create(arr, FNode.Identity); +end; + +{ TExpressionListHandler } + +function TExpressionListHandler.GetOrientation: TLayoutOrientation; +begin + Result := loVertical; +end; + +function TExpressionListHandler.GetAlignment: TLayoutAlignment; +begin + Result := laFlush; +end; + +function TExpressionListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; +var + arr: TArray; + i: Integer; +begin + SetLength(arr, FChildNodes.Count); + for i := 0 to FChildNodes.Count - 1 do + arr[i] := FChildNodes[i].CreateAst; + + Result := TExpressionList.Create(arr, FNode.Identity); +end; + +{ TRecordFieldListHandler } + +function TRecordFieldListHandler.GetOrientation: TLayoutOrientation; +begin + Result := loVertical; +end; + +function TRecordFieldListHandler.GetAlignment: TLayoutAlignment; +begin + Result := laFlush; +end; + +function TRecordFieldListHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; +var + arr: TArray; + i: Integer; +begin + SetLength(arr, FChildNodes.Count); + for i := 0 to FChildNodes.Count - 1 do + arr[i] := FChildNodes[i].CreateAst.AsRecordField; + + Result := TRecordFieldList.Create(arr, FNode.Identity); +end; + +{ TRecordFieldHandler } + +procedure TRecordFieldHandler.BuildUI(OwnerNode: TAstViewNode); +var + visu: IAstVisualizer; +begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth); + OwnerNode.BeginUpdate; + try + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + OwnerNode.Alignment := laCenter; + + FKeyLabel := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Key.Value.Name); + FKeyLabel.Font.Style := FKeyLabel.Font.Style + [TFontStyle.fsBold]; + FKeyLabel.StyledSettings := FKeyLabel.StyledSettings - [TStyledSetting.FontColor]; + FKeyLabel.FontColor := TAlphaColors.Mediumvioletred; + + FValueNode := visu.CallAccept(FNode.Value); + finally + OwnerNode.EndUpdate; + end; +end; + +function TRecordFieldHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; +begin + // Updated to use new Factory Overload to preserve Identity + Result := TAst.RecordField(FNode.Identity, FNode.Key, FValueNode.CreateAst); +end; + { TConstantNodeHandler } procedure TConstantNodeHandler.BuildUI(OwnerNode: TAstViewNode); @@ -335,76 +575,31 @@ end; { TBlockExpressionNodeHandler } -constructor TBlockExpressionNodeHandler.Create(const ANode: IBlockExpressionNode); -begin - inherited Create(ANode); - FChildNodes := TList.Create; -end; - -destructor TBlockExpressionNodeHandler.Destroy; -begin - FChildNodes.Free; - inherited; -end; - procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - childNode: TAstViewNode; - expr: IAstNode; titleLabel: TLabel; - i: Integer; - returnContainer: TAutoFitControl; - visuReturn: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); OwnerNode.BeginUpdate; try - OwnerNode.Frameless := True; + OwnerNode.Frameless := False; OwnerNode.Orientation := loVertical; OwnerNode.Alignment := laFlush; - for i := 0 to High(FNode.Expressions) do - begin - expr := FNode.Expressions[i]; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'do'); + titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - if i = High(FNode.Expressions) then - begin - returnContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - titleLabel := OwnerNode.AddLabel(returnContainer, 'return'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - visuReturn := OwnerNode.Visualizer.Clone(returnContainer, OwnerNode.Visualizer.ExprDepth + 1); - childNode := visuReturn.CallAccept(expr); - FChildNodes.Add(childNode); - end - else - begin - childNode := visu.CallAccept(expr); - FChildNodes.Add(childNode); - end; - end; + FExpressionsNode := visu.CallAccept(FNode.Expressions); + FExpressionsNode.Frameless := True; finally OwnerNode.EndUpdate; end; end; function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; -var - exprs: TArray; - childNode: TAstViewNode; - i: Integer; begin - SetLength(exprs, FChildNodes.Count); - for i := 0 to FChildNodes.Count - 1 do - begin - childNode := FChildNodes[i]; - if Assigned(childNode) then - exprs[i] := childNode.CreateAst - else - exprs[i] := TAst.Nop; - end; - - Result := TAst.Block(FNode.Identity, exprs, FNode.StaticType); + Result := TAst.Block(FNode.Identity, FExpressionsNode.CreateAst.AsExpressionList, FNode.StaticType); end; { TIfExpressionNodeHandler } @@ -466,24 +661,11 @@ end; { TLambdaExpressionNodeHandler } -constructor TLambdaExpressionNodeHandler.Create(const ANode: ILambdaExpressionNode); -begin - inherited Create(ANode); - FParamLabels := TList.Create; -end; - -destructor TLambdaExpressionNodeHandler.Destroy; -begin - FParamLabels.Free; - inherited; -end; - procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; titleContainer: TAutoFitControl; - paramLabel: TLabel; - i: Integer; + lbl: TLabel; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, 0); OwnerNode.BeginUpdate; @@ -494,32 +676,16 @@ begin OwnerNode.BackgroundColor := $090000ff; titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + lbl := OwnerNode.AddLabel(titleContainer, 'fn'); + lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; - paramLabel := OwnerNode.AddLabel(titleContainer, 'fn'); - paramLabel.Font.Style := paramLabel.Font.Style + [TFontStyle.fsBold]; - FParamLabels.Add(paramLabel); - - paramLabel := OwnerNode.AddLabel(titleContainer, '('); - FParamLabels.Add(paramLabel); - - for i := 0 to High(FNode.Parameters) do - begin - paramLabel := OwnerNode.AddLabel(titleContainer, FNode.Parameters[i].Name); - FParamLabels.Add(paramLabel); - - if i < High(FNode.Parameters) then - begin - paramLabel := OwnerNode.AddLabel(titleContainer, ','); - FParamLabels.Add(paramLabel); - end; - end; - - paramLabel := OwnerNode.AddLabel(titleContainer, ')'); - FParamLabels.Add(paramLabel); + // Parameters: Delegate to List Handler + var paramVisu := visu.Clone(titleContainer, 0); + FParamsNode := paramVisu.CallAccept(FNode.Parameters); + // Body FBodyNode := visu.CallAccept(FNode.Body); FBodyNode.Frameless := False; - finally OwnerNode.EndUpdate; end; @@ -530,7 +696,7 @@ begin Result := TAst.LambdaExpr( FNode.Identity, - FNode.Parameters, + FParamsNode.CreateAst.AsParameterList, FBodyNode.CreateAst, FNode.Layout, FNode.Descriptor, @@ -543,23 +709,9 @@ end; { TFunctionCallNodeHandler } -constructor TFunctionCallNodeHandler.Create(const ANode: IFunctionCallNode); -begin - inherited Create(ANode); - FArgumentNodes := TList.Create; -end; - -destructor TFunctionCallNodeHandler.Destroy; -begin - FArgumentNodes.Free; - inherited; -end; - procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - i: Integer; - argNode: TAstViewNode; callLabel: TLabel; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); @@ -573,37 +725,19 @@ begin FCalleeNode := visu.CallAccept(FNode.Callee); - if Length(FNode.Arguments) > 0 then - begin - OwnerNode.AddLabel(OwnerNode, '('); - for i := 0 to High(FNode.Arguments) do - begin - argNode := visu.CallAccept(FNode.Arguments[i]); - FArgumentNodes.Add(argNode); - if i < High(FNode.Arguments) then - OwnerNode.AddLabel(OwnerNode, ','); - end; - OwnerNode.AddLabel(OwnerNode, ')'); - end; + FArgumentsNode := visu.CallAccept(FNode.Arguments); finally OwnerNode.EndUpdate; end; end; function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; -var - args: TArray; - i: Integer; begin - SetLength(args, FArgumentNodes.Count); - for i := 0 to FArgumentNodes.Count - 1 do - args[i] := FArgumentNodes[i].CreateAst; - Result := TAst.FunctionCall( FNode.Identity, FCalleeNode.CreateAst, - args, + FArgumentsNode.CreateAst.AsArgumentList, FNode.StaticType, FNode.IsTailCall, FNode.StaticTarget, @@ -638,23 +772,9 @@ end; { TRecurNodeHandler } -constructor TRecurNodeHandler.Create(const ANode: IRecurNode); -begin - inherited Create(ANode); - FArgumentNodes := TList.Create; -end; - -destructor TRecurNodeHandler.Destroy; -begin - FArgumentNodes.Free; - inherited; -end; - procedure TRecurNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - i: Integer; - argNode: TAstViewNode; titleLabel: TLabel; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); @@ -666,29 +786,15 @@ begin titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - OwnerNode.AddLabel(OwnerNode, '('); - for i := 0 to High(FNode.Arguments) do - begin - argNode := visu.CallAccept(FNode.Arguments[i]); - FArgumentNodes.Add(argNode); - if i < High(FNode.Arguments) then - OwnerNode.AddLabel(OwnerNode, ','); - end; - OwnerNode.AddLabel(OwnerNode, ')'); + FArgumentsNode := visu.CallAccept(FNode.Arguments); finally OwnerNode.EndUpdate; end; end; function TRecurNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; -var - args: TArray; - i: Integer; begin - SetLength(args, FArgumentNodes.Count); - for i := 0 to FArgumentNodes.Count - 1 do - args[i] := FArgumentNodes[i].CreateAst; - Result := TAst.Recur(FNode.Identity, args, FNode.StaticType); + Result := TAst.Recur(FNode.Identity, FArgumentsNode.CreateAst.AsArgumentList, FNode.StaticType); end; { TVariableDeclarationNodeHandler } @@ -762,8 +868,7 @@ procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; titleLabel: TLabel; - paramStr: string; - i: Integer; + titleContainer: TAutoFitControl; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); OwnerNode.BeginUpdate; @@ -771,17 +876,14 @@ begin OwnerNode.Frameless := False; OwnerNode.Orientation := loVertical; - paramStr := ''; - for i := 0 to High(FNode.Parameters) do - begin - if i > 0 then - paramStr := paramStr + ', '; - paramStr := paramStr + FNode.Parameters[i].Name; - end; - - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Def: ' + FNode.Name.Name + ' (' + paramStr + ')'); + titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + titleLabel := OwnerNode.AddLabel(titleContainer, 'Macro Def: ' + FNode.Name.Name); titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + // Parameters List + var paramVisu := visu.Clone(titleContainer, visu.ExprDepth); + FParamsNode := paramVisu.CallAccept(FNode.Parameters); + FBodyNode := visu.CallAccept(FNode.Body); finally OwnerNode.EndUpdate; @@ -790,7 +892,7 @@ end; function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; begin - Result := TAst.MacroDef(FNode.Identity, FNode.Name, FNode.Parameters, FBodyNode.CreateAst); + Result := TAst.MacroDef(FNode.Identity, FNode.Name, FParamsNode.CreateAst.AsParameterList, FBodyNode.CreateAst); end; { TQuasiquoteNodeHandler } @@ -927,70 +1029,34 @@ end; { TRecordLiteralNodeHandler } -constructor TRecordLiteralNodeHandler.Create(const ANode: IRecordLiteralNode); -begin - inherited Create(ANode); - FFieldNodes := TDictionary.Create; -end; - -destructor TRecordLiteralNodeHandler.Destroy; -begin - FFieldNodes.Free; - inherited; -end; - procedure TRecordLiteralNodeHandler.BuildUI(OwnerNode: TAstViewNode); var - field: TRecordFieldLiteral; - fieldContainer: TAutoFitControl; - valueNode: TAstViewNode; - keyLabel: TLabel; + visu: IAstVisualizer; begin + visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); OwnerNode.BeginUpdate; try OwnerNode.Frameless := False; OwnerNode.Orientation := loVertical; OwnerNode.Alignment := laFlush; - if Length(FNode.Fields) = 0 then - begin - OwnerNode.AddLabel(OwnerNode, '{}'); - end - else - begin - for field in FNode.Fields do - begin - fieldContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - keyLabel := OwnerNode.AddLabel(fieldContainer, ':' + field.Key.Value.Name); - keyLabel.Font.Style := keyLabel.Font.Style + [TFontStyle.fsBold]; - keyLabel.StyledSettings := keyLabel.StyledSettings - [TStyledSetting.FontColor]; - keyLabel.FontColor := TAlphaColors.Mediumvioletred; - - valueNode := OwnerNode.Visualizer.Clone(fieldContainer, OwnerNode.Visualizer.ExprDepth + 1).CallAccept(field.Value); - FFieldNodes.Add(field.Key.Value, valueNode); - end; - end; + // Delegate to RecordFieldList + FFieldsNode := visu.CallAccept(FNode.Fields); finally OwnerNode.EndUpdate; end; end; function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; -var - fields: TArray; - i: Integer; - valueNode: TAstViewNode; - pair: TPair; begin - SetLength(fields, FFieldNodes.Count); - i := 0; - for pair in FFieldNodes do - begin - valueNode := pair.Value; - fields[i] := TRecordFieldLiteral.Create(TAst.Keyword(pair.Key.Name), valueNode.CreateAst); - inc(i); - end; - Result := TAst.RecordLiteral(FNode.Identity, fields, FNode.ScalarDefinition, FNode.GenericDefinition, FNode.StaticType); + Result := + TAst.RecordLiteral( + FNode.Identity, + FFieldsNode.CreateAst.AsRecordFieldList, + FNode.ScalarDefinition, + FNode.GenericDefinition, + FNode.StaticType + ); end; { TCreateSeriesNodeHandler } diff --git a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas index 2e95d1f..57e879f 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas @@ -31,6 +31,14 @@ type function VisitConstant(const Node: IConstantNode): TAstViewNode; override; function VisitIdentifier(const Node: IIdentifierNode): TAstViewNode; override; function VisitKeyword(const Node: IKeywordNode): TAstViewNode; override; + + // --- List Visitors (NEW) --- + function VisitParameterList(const Node: IParameterList): TAstViewNode; override; + function VisitArgumentList(const Node: IArgumentList): TAstViewNode; override; + function VisitExpressionList(const Node: IExpressionList): TAstViewNode; override; + function VisitRecordFieldList(const Node: IRecordFieldList): TAstViewNode; override; + function VisitRecordField(const Node: IRecordFieldNode): TAstViewNode; override; + function VisitIfExpression(const Node: IIfExpressionNode): TAstViewNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; override; @@ -146,6 +154,35 @@ begin Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node)); end; +// --- List Visitors --- + +function TAstVisualizer.VisitParameterList(const Node: IParameterList): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TParameterListHandler.Create(Node)); +end; + +function TAstVisualizer.VisitArgumentList(const Node: IArgumentList): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TArgumentListHandler.Create(Node)); +end; + +function TAstVisualizer.VisitExpressionList(const Node: IExpressionList): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TExpressionListHandler.Create(Node)); +end; + +function TAstVisualizer.VisitRecordFieldList(const Node: IRecordFieldList): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TRecordFieldListHandler.Create(Node)); +end; + +function TAstVisualizer.VisitRecordField(const Node: IRecordFieldNode): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TRecordFieldHandler.Create(Node)); +end; + +// --- Node Visitors --- + function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TBlockExpressionNodeHandler.Create(Node)); diff --git a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas index 85b54fb..d29ce50 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas @@ -110,6 +110,9 @@ constructor TAstWorkspace.Create(AOwner: TComponent); begin inherited; FZoom := 1.0; + // Standard-Eigenschaften für einen Arbeitsbereich + ClipChildren := True; + HitTest := True; end; procedure TAstWorkspace.Build(const RootNode: IAstNode; const Position: TPointF); @@ -117,10 +120,20 @@ var visu: IAstVisualizer; node: TAstViewNode; begin + // Löscht alle bestehenden visuellen Knoten + DeleteChildren; + FConnections := nil; + + if not Assigned(RootNode) then + Exit; + + // Erstellt den Visualizer mit dem Workspace als Kontext visu := TAstVisualizer.Create(Self, Self, 0); node := visu.CallAccept(RootNode); if Assigned(node) then + begin node.Position.Point := Position; + end; end; procedure TAstWorkspace.DoDeleteChildren; @@ -204,7 +217,12 @@ end; procedure TAstWorkspace.DblClick; begin inherited; - Zoom(1.0); + // Reset Zoom/Pan on double click + FZoom := 1.0; + FPanning := TSizeF.Create(0, 0); + RecalcAbsolute; + RecalcUpdateRect; + Repaint; end; procedure TAstWorkspace.Paint; @@ -224,6 +242,13 @@ begin for connection in FConnections do begin + // Safety check if pins are still valid/visible + if (connection.OutputPin = nil) + or (connection.InputPin = nil) + or (connection.OutputPin.Root <> Self.Root) + or (connection.InputPin.Root <> Self.Root) then + continue; + pinCenter := TPointF.Create(connection.OutputPin.Width / 2, connection.OutputPin.Height / 2); absoluteStart := connection.OutputPin.LocalToAbsolute(pinCenter); @@ -263,9 +288,13 @@ begin begin mousePos := ScreenToLocal(mouseService.GetMousePos); Factor := Max(0.2, Min(3.0, Factor)); + + // Adjust panning to zoom towards mouse position FPanning.cx := mousePos.X * (1 - Factor / FZoom) + FPanning.cx * (Factor / FZoom); FPanning.cy := mousePos.Y * (1 - Factor / FZoom) + FPanning.cy * (Factor / FZoom); + FZoom := Factor; + RecalcAbsolute; RecalcUpdateRect; Repaint; diff --git a/Test/AST/Test.Myc.Ast.Script.pas b/Test/AST/Test.Myc.Ast.Script.pas index a2af179..3e1043a 100644 --- a/Test/AST/Test.Myc.Ast.Script.pas +++ b/Test/AST/Test.Myc.Ast.Script.pas @@ -209,7 +209,8 @@ begin call := node.AsFunctionCall; Assert.AreEqual('add', call.Callee.AsIdentifier.Name); - Assert.AreEqual(2, Length(call.Arguments)); + // Use Count instead of Length + Assert.AreEqual(2, call.Arguments.Count); Assert.AreEqual(1, call.Arguments[0].AsConstant.Value.AsScalar.Value.AsInt64); Assert.AreEqual(2, call.Arguments[1].AsConstant.Value.AsScalar.Value.AsInt64); @@ -225,7 +226,9 @@ begin Assert.AreEqual(TAstNodeKind.akRecordLiteral, node.Kind); rec := node.AsRecordLiteral; - Assert.AreEqual(2, Length(rec.Fields)); + Assert.AreEqual(2, rec.Fields.Count); + + // Accessing fields via IRecordFieldNode Assert.AreEqual('a', rec.Fields[0].Key.Value.Name); Assert.AreEqual(1, rec.Fields[0].Value.AsConstant.Value.AsScalar.Value.AsInt64); @@ -239,7 +242,7 @@ var begin node := Parse('{}'); Assert.AreEqual(TAstNodeKind.akRecordLiteral, node.Kind); - Assert.AreEqual(0, Length(node.AsRecordLiteral.Fields)); + Assert.AreEqual(0, node.AsRecordLiteral.Fields.Count); end; // --- Special Forms --- @@ -268,7 +271,7 @@ begin Assert.AreEqual(TAstNodeKind.akLambdaExpression, node.Kind); lam := node.AsLambdaExpression; - Assert.AreEqual(2, Length(lam.Parameters)); + Assert.AreEqual(2, lam.Parameters.Count); Assert.AreEqual('a', lam.Parameters[0].Name); Assert.AreEqual('b', lam.Parameters[1].Name); @@ -317,7 +320,7 @@ begin call := node.AsFunctionCall; Assert.AreEqual('quote', call.Callee.AsIdentifier.Name); - Assert.AreEqual(1, Length(call.Arguments)); + Assert.AreEqual(1, call.Arguments.Count); Assert.AreEqual('foo', call.Arguments[0].AsIdentifier.Name); end; @@ -343,8 +346,8 @@ procedure TTestMycAstScript.Parser_UnquoteSplicing_CreatesNode; var node: IAstNode; begin - // ~@x - // There's something off here - we'll fix this later + // Note: Parser requires backtick after ~@ currently due to cast in Myc.Ast.Script: + // Result.Node := TAst.UnquoteSplicing(expr.Node.AsQuasiquote, startLoc); node := Parse('~@`x'); Assert.AreEqual(TAstNodeKind.akUnquoteSplicing, node.Kind); diff --git a/Test/Test.Myc.Ast.Compiler.Binder.pas b/Test/Test.Myc.Ast.Compiler.Binder.pas index 5300846..c020ccb 100644 --- a/Test/Test.Myc.Ast.Compiler.Binder.pas +++ b/Test/Test.Myc.Ast.Compiler.Binder.pas @@ -104,7 +104,7 @@ end; function TTestAstBinder.Unwrap(const Node: IAstNode): IAstNode; begin - if (Node.Kind = akBlockExpression) and (Length(Node.AsBlockExpression.Expressions) = 1) then + if (Node.Kind = akBlockExpression) and (Node.AsBlockExpression.Expressions.Count = 1) then Result := Node.AsBlockExpression.Expressions[0] else Result := Node; @@ -236,6 +236,7 @@ begin Assert.IsFalse(log.HasErrors); lambda := bound.AsLambdaExpression; + // Access parameter list via index Assert.AreEqual(1, lambda.Parameters[0].Address.SlotIndex); // Slot 0 is reserved for end;