From 6826b75c19bbd137844a2e0bda355dbbaa75df10 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sat, 1 Nov 2025 14:04:45 +0100 Subject: [PATCH] Binder refactoring - extracted type checking --- ASTPlayground/ASTPlayground.delphilsp.json | 2 +- ASTPlayground/ASTPlayground.dpr | 3 +- ASTPlayground/ASTPlayground.dproj | 1 + Src/AST/Myc.Ast.Binding.Nodes.pas | 4 +- Src/AST/Myc.Ast.Binding.pas | 527 ++++++-------------- Src/AST/Myc.Ast.TypeChecker.pas | 528 +++++++++++++++++++++ 6 files changed, 671 insertions(+), 394 deletions(-) create mode 100644 Src/AST/Myc.Ast.TypeChecker.pas diff --git a/ASTPlayground/ASTPlayground.delphilsp.json b/ASTPlayground/ASTPlayground.delphilsp.json index d088b85..d95af88 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.Evaluator", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Evaluator.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.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.Binding", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Binding.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Text", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Text.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Binding.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Binding.Nodes.pas" }, { "name": "Unit1", "file": "file:///T%3A/Myc/ASTPlayground/Unit1.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.Evaluator", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Evaluator.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.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.Binding", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Binding.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Text", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Fmx.AstEditor.Text.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Binding.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Binding.Nodes.pas" }, { "name": "Myc.Ast.MacroExpander", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.MacroExpander.pas" }, { "name": "Unit1", "file": "file:///T%3A/Myc/ASTPlayground/Unit1.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 diff --git a/ASTPlayground/ASTPlayground.dpr b/ASTPlayground/ASTPlayground.dpr index 90021e7..9a09187 100644 --- a/ASTPlayground/ASTPlayground.dpr +++ b/ASTPlayground/ASTPlayground.dpr @@ -23,7 +23,8 @@ uses Myc.Ast.Types in '..\Src\AST\Myc.Ast.Types.pas', Myc.Data.Keyword in '..\Src\Data\Myc.Data.Keyword.pas', Myc.Ast.Binding.Nodes in '..\Src\AST\Myc.Ast.Binding.Nodes.pas', - Myc.Ast.MacroExpander in '..\Src\AST\Myc.Ast.MacroExpander.pas'; + Myc.Ast.MacroExpander in '..\Src\AST\Myc.Ast.MacroExpander.pas', + Myc.Ast.TypeChecker in '..\Src\AST\Myc.Ast.TypeChecker.pas'; {$R *.res} diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj index 52cbde6..4f30dba 100644 --- a/ASTPlayground/ASTPlayground.dproj +++ b/ASTPlayground/ASTPlayground.dproj @@ -154,6 +154,7 @@ + Base diff --git a/Src/AST/Myc.Ast.Binding.Nodes.pas b/Src/AST/Myc.Ast.Binding.Nodes.pas index 9fb33dc..c594b9e 100644 --- a/Src/AST/Myc.Ast.Binding.Nodes.pas +++ b/Src/AST/Myc.Ast.Binding.Nodes.pas @@ -68,7 +68,7 @@ type FDefinition: IScalarRecordDefinition; public constructor Create(const AFields: TArray; const ADef: IScalarRecordDefinition); - property Definition: IScalarRecordDefinition read FDefinition; + property Definition: IScalarRecordDefinition read FDefinition write FDefinition; end; // Represents a bound record literal that maps to a generic (non-scalar) record @@ -77,7 +77,7 @@ type FDefinition: IGenericRecordDefinition; public constructor Create(const AFields: TArray; const ADef: IGenericRecordDefinition); - property Definition: IGenericRecordDefinition read FDefinition; + property Definition: IGenericRecordDefinition read FDefinition write FDefinition; end; implementation diff --git a/Src/AST/Myc.Ast.Binding.pas b/Src/AST/Myc.Ast.Binding.pas index 7b82417..8a30fca 100644 --- a/Src/AST/Myc.Ast.Binding.pas +++ b/Src/AST/Myc.Ast.Binding.pas @@ -39,9 +39,6 @@ type FIsTailStack: TStack; FNextIsTail: Boolean; FBoxedDeclarations: THashSet; - // Operator folding maps - FBinaryOperators: TDictionary; - FUnaryOperators: TDictionary; procedure EnterScope; procedure ExitScope; @@ -73,7 +70,7 @@ type function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; public - constructor Create(const AInitialScope: IExecutionScope); + constructor Create(const AInitialScope: IExecutionScope); // Signature changed destructor Destroy; override; function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode; @@ -129,8 +126,6 @@ end; { TAstBinder } constructor TAstBinder.Create(const AInitialScope: IExecutionScope); -var - op: TScalar.TBinaryOp; begin inherited Create; Assert(Assigned(AInitialScope)); @@ -142,21 +137,10 @@ begin FIsTailStack := TStack.Create; FNextIsTail := True; FBoxedDeclarations := nil; - - // Initialize operator folding maps - FBinaryOperators := TDictionary.Create; - for op := Low(TScalar.TBinaryOp) to High(TScalar.TBinaryOp) do - FBinaryOperators.Add(op.ToString, op); - - FUnaryOperators := TDictionary.Create; - FUnaryOperators.Add('not', TScalar.TUnaryOp.Not); - // Note: '-' is handled as a special case in VisitFunctionCall end; destructor TAstBinder.Destroy; begin - FUnaryOperators.Free; - FBinaryOperators.Free; FIsTailStack.Free; FUpvalueStack.Free; FBoxedDeclarations.Free; @@ -194,173 +178,6 @@ begin FCurrentDescriptor := TScope.CreateDescriptor(FCurrentDescriptor); end; -function TAstBinder.Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode; -var - rootType: IStaticType; -begin - FBoxedDeclarations := TUpvalueAnalyzer.Analyze(RootNode, FCurrentDescriptor.Parent); - try - EnterScope; - try - var transformedValue := Accept(RootNode); - if transformedValue.IsVoid then - begin - Result := TAst.Block([]); - rootType := TTypes.Void; - end - else - begin - Result := transformedValue.AsIntf; - rootType := (Result as TAstNode).StaticType; - end; - - // Set the type for the root node (which is often a block) - (Result as TAstNode).StaticType := rootType; - Descriptor := FCurrentDescriptor; - finally - ExitScope; - end; - finally - // The binder now owns the hash set, which will be freed in the destructor. - end; -end; - -function TAstBinder.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; -begin - FCurrentDescriptor.DefineMacro(Node.Name.Name, Node); - Result := TDataValue.Void; - // Macros have no type at runtime - (Node as TAstNode).StaticType := TTypes.Void; -end; - -function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; -var - calleeIdentifier: TIdentifierNode; - binaryOp: TScalar.TBinaryOp; - unaryOp: TScalar.TUnaryOp; - left, right: IAstNode; - leftType, rightType, resultType: IStaticType; - boundCall: TBoundFunctionCallNode; - callee: IAstNode; - calleeType: IStaticType; - args: TArray; - i: Integer; -begin - // --- Transformation: Keyword-as-Function --- - // Check if the callee is a keyword literal - if (Node.Callee is TKeywordNode) then - begin - var keywordNode := (Node.Callee as TKeywordNode); - var keywordName := keywordNode.Value.Name; - - // 1. Validate argument count - if Length(Node.Arguments) <> 1 then - raise ETypeException - .CreateFmt('Keyword :%s expects exactly one argument (the record/map), but got %d', [keywordName, Length(Node.Arguments)]); - - // 2. Bind the base (the record/map) - FNextIsTail := False; // Accessing a member is not a tail call - var baseNode := Accept(Node.Arguments[0]).AsIntf; - - // 3. Create a synthetic IMemberAccessNode - var memberAccessNode := TAst.MemberAccess(baseNode, TAst.Keyword(keywordName)); - - // 4. Re-bind the synthetic node by calling Accept (which dispatches to VisitMemberAccess) - // This ensures type checking and type inference for member access is centralized. - Result := Accept(memberAccessNode); - exit; - end; - - if (Node.Callee is TIdentifierNode) then - begin - calleeIdentifier := Node.Callee as TIdentifierNode; - - // --- Optimization: Operator Folding --- - - // Try to fold binary operators - if Length(Node.Arguments) = 2 then - begin - if FBinaryOperators.TryGetValue(calleeIdentifier.Name, binaryOp) then - begin - FNextIsTail := False; - left := Accept(Node.Arguments[0]).AsIntf; - right := Accept(Node.Arguments[1]).AsIntf; - leftType := (left as TAstNode).StaticType; - rightType := (right as TAstNode).StaticType; - resultType := TTypeRules.ResolveBinaryOp(binaryOp, leftType, rightType); - var binExpr := TAst.BinaryExpr(left, binaryOp, right); - (binExpr as TAstNode).StaticType := resultType; - Result := TDataValue.FromIntf(binExpr); - exit; - end; - end; - - // Try to fold unary operators - if Length(Node.Arguments) = 1 then - begin - if FUnaryOperators.TryGetValue(calleeIdentifier.Name, unaryOp) then - begin - FNextIsTail := False; - right := Accept(Node.Arguments[0]).AsIntf; - rightType := (right as TAstNode).StaticType; - resultType := TTypeRules.ResolveUnaryOp(unaryOp, rightType); - var unExpr := TAst.UnaryExpr(unaryOp, right); - (unExpr as TAstNode).StaticType := resultType; - Result := TDataValue.FromIntf(unExpr); - exit; - end; - - // Special case for negation '-' - if (calleeIdentifier.Name = '-') then - begin - FNextIsTail := False; - right := Accept(Node.Arguments[0]).AsIntf; - rightType := (right as TAstNode).StaticType; - resultType := TTypeRules.ResolveUnaryOp(TScalar.TUnaryOp.Negate, rightType); - var unExpr := TAst.UnaryExpr(TScalar.TUnaryOp.Negate, right); - (unExpr as TAstNode).StaticType := resultType; - Result := TDataValue.FromIntf(unExpr); - exit; - end; - end; - end; - - // --- Default: Bind as a standard function call --- - var isTailCall := FIsTailStack.Peek; - FNextIsTail := False; - callee := Accept(Node.Callee).AsIntf; - args := AcceptNodes(Node.Arguments); - - var retType: IStaticType := TTypes.Unknown; - calleeType := (callee as TAstNode).StaticType; - if calleeType.Kind = TStaticTypeKind.stMethod then - begin - var signature := calleeType.Signature; - if Length(args) <> Length(signature.ParamTypes) then - raise ETypeException.CreateFmt('Function expects %d arguments, but got %d', [Length(signature.ParamTypes), Length(args)]); - retType := signature.ReturnType; - - // Check argument types - for i := 0 to High(args) do - begin - var argType := (args[i] as TAstNode).StaticType; - var paramType := signature.ParamTypes[i]; - if not TTypeRules.CanAssign(paramType, argType) then - raise ETypeException - .CreateFmt('Cannot assign argument %d (type %s) to parameter (type %s)', [i, argType.ToString, paramType.ToString]); - end; - end; - - boundCall := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall); - Result := SetType(TDataValue.FromIntf(boundCall), retType); -end; - -function TAstBinder.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; -begin - // Macro expansion nodes should not exist by this stage. - raise Exception.Create('MacroExpansionNode is not expected in the binding pass.'); -end; - procedure TAstBinder.ExitScope; begin FCurrentDescriptor := FCurrentDescriptor.Parent; @@ -383,40 +200,107 @@ begin Result := True; end; +function TAstBinder.Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode; +begin + // Pre-pass: Find all variables that need boxing. + FBoxedDeclarations := TUpvalueAnalyzer.Analyze(RootNode, FCurrentDescriptor.Parent); + try + EnterScope; + try + var transformedValue := Accept(RootNode); + if transformedValue.IsVoid then + Result := TAst.Block([]) + else + Result := transformedValue.AsIntf; + + // The binder no longer knows the root type. + // It sets Unknown, and the TypeChecker will find the true type. + (Result as TAstNode).StaticType := TTypes.Unknown; + Descriptor := FCurrentDescriptor; + finally + ExitScope; + end; + finally + // The binder owns the hash set, which will be freed in the destructor. + end; +end; + +function TAstBinder.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; +begin + // This node should have been consumed by the MacroExpander. + raise Exception.Create('TMyAstBinder: MacroDefinition node encountered.'); +end; + +function TAstBinder.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; +begin + // This node is just a wrapper for debugging/tracing. + // We bind its contents (the expanded body). + Result := Accept(Node.ExpandedBody); +end; + +function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; +var + boundCall: TBoundFunctionCallNode; + callee: IAstNode; + args: TArray; +begin + // --- Transformation: Keyword-as-Function --- + if (Node.Callee is TKeywordNode) then + begin + var keywordNode := (Node.Callee as TKeywordNode); + if Length(Node.Arguments) <> 1 then + raise ETypeException.CreateFmt( + 'Keyword :%s expects exactly one argument (the record/map), but got %d', + [keywordNode.Value.Name, Length(Node.Arguments)]); + + FNextIsTail := False; + var baseNode := Accept(Node.Arguments[0]).AsIntf; + var memberAccessNode := TAst.MemberAccess(baseNode, keywordNode); + + // Re-bind the synthetic node by calling Accept (which dispatches to VisitMemberAccess) + Result := Accept(memberAccessNode); + exit; + end; + + // --- Default: Bind as a standard function call --- + var isTailCall := FIsTailStack.Peek; + FNextIsTail := False; + callee := Accept(Node.Callee).AsIntf; + args := AcceptNodes(Node.Arguments); + + boundCall := TBoundFunctionCallNode.Create(Node, callee, args, isTailCall); + + // Set type to Unknown. The TypeChecker will infer it. + Result := SetType(TDataValue.FromIntf(boundCall), TTypes.Unknown); +end; + function TAstBinder.VisitAssignment(const Node: IAssignmentNode): TDataValue; var boundIdentifier, boundValue: IAstNode; - targetType, sourceType: IStaticType; boundNode: IAssignmentNode; begin FNextIsTail := False; + // Bind children boundIdentifier := Accept(Node.Identifier).AsIntf; boundValue := Accept(Node.Value).AsIntf; - targetType := (boundIdentifier as TAstNode).StaticType; - sourceType := (boundValue as TAstNode).StaticType; - - if not TTypeRules.CanAssign(targetType, sourceType) then - raise ETypeException.CreateFmt('Cannot assign type %s to %s', [sourceType.ToString, targetType.ToString]); - boundNode := TAst.Assign(boundIdentifier as TBoundIdentifierNode, boundValue); - Result := SetType(TDataValue.FromIntf(boundNode), targetType); + + // Set type to Unknown. The TypeChecker will infer it from the identifier. + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; var left, right: IAstNode; - leftType, rightType, resultType: IStaticType; boundNode: IBinaryExpressionNode; begin FNextIsTail := False; left := Accept(Node.Left).AsIntf; right := Accept(Node.Right).AsIntf; - leftType := (left as TAstNode).StaticType; - rightType := (right as TAstNode).StaticType; - resultType := TTypeRules.ResolveBinaryOp(Node.Operator, leftType, rightType); + boundNode := TAst.BinaryExpr(left, Node.Operator, right); - Result := SetType(TDataValue.FromIntf(boundNode), resultType); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; @@ -426,7 +310,6 @@ var isContextTail: Boolean; transformedValue: TDataValue; exprList: TList; - blockType: IStaticType; boundNode: IBlockExpressionNode; begin isContextTail := FIsTailStack.Peek; @@ -444,6 +327,7 @@ begin exprList.Free; end; + // Check if the node was modified (e.g. by macro removal) if (Length(exprs) = Length(Node.Expressions)) then begin var same := True; @@ -454,41 +338,33 @@ begin break; end; if same then - begin - boundNode := Node; // Use original node - end + boundNode := Node // Use original node else boundNode := TAst.Block(exprs); // Create new node end else boundNode := TAst.Block(exprs); // Create new node - // Type of the block is the type of the last expression - if Length(exprs) > 0 then - blockType := (exprs[High(exprs)] as TAstNode).StaticType - else - blockType := TTypes.Void; - - Result := SetType(TDataValue.FromIntf(boundNode), blockType); + // Type of the block is Unknown; TypeChecker will set it. + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitConstant(const Node: IConstantNode): TDataValue; begin + // Binder can set the literal type case Node.Value.Kind of TDataValueKind.vkScalar: Result := SetType(TDataValue.FromIntf(Node), TTypes.FromScalarKind(Node.Value.AsScalar.Kind)); TDataValueKind.vkText: Result := SetType(TDataValue.FromIntf(Node), TTypes.Text); TDataValueKind.vkVoid: Result := SetType(TDataValue.FromIntf(Node), TTypes.Void); else - // Handle other constant types if they become supported Result := SetType(TDataValue.FromIntf(Node), TTypes.Unknown); end; end; function TAstBinder.VisitKeyword(const Node: IKeywordNode): TDataValue; begin - // Keywords are literals. Their type is set in TKeywordNode.Create. - // We also set the static type on the node itself during binding. + // Binder can set the literal type Result := SetType(TDataValue.FromIntf(Node), TTypes.Keyword); end; @@ -496,11 +372,13 @@ function TAstBinder.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue var elemType: IStaticType; begin + // Binder can set the literal type try elemType := TTypes.FromScalarKind(TScalar.StringToKind(Node.Definition)); except on E: Exception do - raise ETypeException.CreateFmt('Invalid series type definition: "%s". %s', [Node.Definition, E.Message]); + // Error, but set to Unknown for now. TypeChecker can re-validate. + elemType := TTypes.Unknown; end; Result := SetType(TDataValue.FromIntf(Node), TTypes.CreateSeries(elemType)); end; @@ -508,7 +386,6 @@ end; function TAstBinder.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; var seriesNode, valueNode, lookbackNode: IAstNode; - seriesType, valueType: IStaticType; begin seriesNode := Accept(Node.Series).AsIntf; valueNode := Accept(Node.Value).AsIntf; @@ -517,32 +394,13 @@ begin else lookbackNode := nil; - seriesType := (seriesNode as TAstNode).StaticType; - valueType := (valueNode as TAstNode).StaticType; - - if seriesType.Kind <> TStaticTypeKind.stSeries then - raise ETypeException.CreateFmt('"add" requires a series as its first argument, but got %s', [seriesType.ToString]); - - if not TTypeRules.CanAssign(seriesType.ElementType, valueType) then - raise ETypeException - .CreateFmt('Cannot add item of type %s to series of type %s', [valueType.ToString, seriesType.ElementType.ToString]); - - if (lookbackNode <> nil) and not ((lookbackNode as TAstNode).StaticType.Kind = TStaticTypeKind.stOrdinal) then - raise ETypeException.Create('Lookback parameter for "add" must be an ordinal value.'); - var boundNode := TAst.AddSeriesItem(seriesNode as TIdentifierNode, valueNode, lookbackNode); Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Void); end; function TAstBinder.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; -var - seriesNode: IAstNode; - seriesType: IStaticType; begin - seriesNode := Accept(Node.Series).AsIntf; - seriesType := (seriesNode as TAstNode).StaticType; - if (seriesType.Kind <> TStaticTypeKind.stSeries) and (seriesType.Kind <> TStaticTypeKind.stRecordSeries) then - raise ETypeException.CreateFmt('"length" requires a series, but got %s', [seriesType.ToString]); + Accept(Node.Series); Result := SetType(TDataValue.FromIntf(Node), TTypes.Ordinal); end; @@ -550,174 +408,85 @@ function TAstBinder.VisitIfExpression(const Node: IIfExpressionNode): TDataValue var isContextTail: Boolean; condition, thenBranch, elseBranch: IAstNode; - conditionType, thenType, elseType, resultType: IStaticType; boundNode: IIfExpressionNode; begin isContextTail := FIsTailStack.Peek; FNextIsTail := False; condition := Accept(Node.Condition).AsIntf; - FNextIsTail := isContextTail; + FNextIsTail := isContextTail; // Propagate tail position thenBranch := Accept(Node.ThenBranch).AsIntf; if Assigned(Node.ElseBranch) then - elseBranch := Accept(Node.ElseBranch).AsIntf; - - conditionType := (condition as TAstNode).StaticType; - if not TTypeRules.CanAssign(TTypes.Ordinal, conditionType) then - raise ETypeException.CreateFmt('If condition must be Ordinal, but got %s', [conditionType.ToString]); - - thenType := (thenBranch as TAstNode).StaticType; - elseType := - if elseBranch <> nil then (elseBranch as TAstNode).StaticType - else TTypes.Void; - resultType := TTypeRules.Promote(thenType, elseType); + elseBranch := Accept(Node.ElseBranch).AsIntf + else + elseBranch := nil; if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then boundNode := TAst.IfExpr(condition, thenBranch, elseBranch) else boundNode := Node; - Result := SetType(TDataValue.FromIntf(boundNode), resultType); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitIndexer(const Node: IIndexerNode): TDataValue; var baseNode, indexNode: IAstNode; - baseType, indexType, elemType: IStaticType; + boundNode: IIndexerNode; begin baseNode := Accept(Node.Base).AsIntf; indexNode := Accept(Node.Index).AsIntf; - baseType := (baseNode as TAstNode).StaticType; - indexType := (indexNode as TAstNode).StaticType; - elemType := TTypes.Unknown; - if (baseType.Kind <> TStaticTypeKind.stUnknown) then - begin - if (baseType.Kind <> TStaticTypeKind.stSeries) and (baseType.Kind <> TStaticTypeKind.stRecordSeries) then - raise ETypeException.CreateFmt('Indexer `[]` can only be applied to series types, but got %s', [baseType.ToString]); - - if not TTypeRules.CanAssign(TTypes.Ordinal, indexType) then - raise ETypeException.CreateFmt('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]); - - if baseType.Kind = TStaticTypeKind.stSeries then - elemType := baseType.ElementType - else // stRecordSeries - elemType := TTypes.CreateRecord(baseType.Definition); - end; - - var boundNode := TAst.Indexer(baseNode, indexNode); - Result := SetType(TDataValue.FromIntf(boundNode), elemType); + boundNode := TAst.Indexer(baseNode, indexNode); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; var baseNode: IAstNode; - baseType, elemType: IStaticType; - fieldIndex: Integer; + boundNode: IMemberAccessNode; begin baseNode := Accept(Node.Base).AsIntf; - baseType := (baseNode as TAstNode).StaticType; - elemType := TTypes.Unknown; - if (baseType.Kind <> TStaticTypeKind.stUnknown) then - begin - if (baseType.Kind = TStaticTypeKind.stRecord) or (baseType.Kind = TStaticTypeKind.stRecordSeries) then - begin - // --- SALAR PATH --- - fieldIndex := baseType.Definition.IndexOf(Node.Member.Value); - if fieldIndex < 0 then - raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]); - - var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Value); - - if baseType.Kind = TStaticTypeKind.stRecord then - elemType := fieldType - else // stRecordSeries - elemType := TTypes.CreateSeries(fieldType); - end - else if (baseType.Kind = TStaticTypeKind.stGenericRecord) then - begin - // --- GENERIC PATH --- - var genDef := baseType.GenericDefinition; - fieldIndex := genDef.IndexOf(Node.Member.Value); - if fieldIndex < 0 then - raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]); - - // Type is stored directly in the generic definition - elemType := genDef.Fields[fieldIndex].Value; - end - else - begin - raise ETypeException.CreateFmt('Member access requires a record type, but got %s', [baseType.ToString]); - end; - end; - - var boundNode := TAst.MemberAccess(baseNode, Node.Member); - Result := SetType(TDataValue.FromIntf(boundNode), elemType); + boundNode := TAst.MemberAccess(baseNode, Node.Member); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; var i: Integer; boundFields: TArray; - scalarDefFields: TArray; // Renamed - def: IScalarRecordDefinition; - staticType: IStaticType; valNode: IAstNode; valType: IStaticType; - scalarKind: TScalar.TKind; allScalar: Boolean; begin FNextIsTail := False; SetLength(boundFields, Length(Node.Fields)); - SetLength(scalarDefFields, Length(Node.Fields)); // Renamed allScalar := True; for i := 0 to High(Node.Fields) do begin valNode := Accept(Node.Fields[i].Value).AsIntf; + // We peek at the *literal* type. If it's not a scalar literal, + // we *assume* it *could* be generic. The TypeChecker will verify. valType := (valNode as TAstNode).StaticType; - // Check if this field fits the scalar path - if (valType.Kind = stOrdinal) then - scalarKind := TScalar.TKind.Ordinal - else if (valType.Kind = stFloat) then - scalarKind := TScalar.TKind.Float - else if (valType.Kind = stKeyword) then - scalarKind := TScalar.TKind.Keyword - else - begin - allScalar := False; // It's a generic record - scalarKind := TScalar.TKind.Ordinal; // Dummy value, won't be used - end; + if not (valType.Kind in [stOrdinal, stFloat, stKeyword, stUnknown]) then + allScalar := False; boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Key, valNode); - - // Conditionally fill the scalar definition array - if allScalar then - scalarDefFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind); end; - // Now, create the correct bound node based on the flag + // Create the appropriate bound node, but without the definition. + // The TypeChecker will populate the definition. if allScalar then begin - // --- EXISTING SCALAR PATH --- - def := TScalarRecordRegistry.Intern(scalarDefFields); - staticType := TTypes.CreateRecord(def); - var boundNode := TBoundRecordLiteralNode.Create(boundFields, def); // Old bound node - Result := SetType(TDataValue.FromIntf(boundNode), staticType); + var boundNode := TBoundRecordLiteralNode.Create(boundFields, nil); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end else begin - // --- NEW GENERIC PATH --- - var genDefFields: TArray>; - SetLength(genDefFields, Length(boundFields)); - for i := 0 to High(boundFields) do - genDefFields[i] := TPair.Create(boundFields[i].Key.Value, (boundFields[i].Value as TAstNode).StaticType); - - var genDef := TGenericRecordRegistry.Intern(genDefFields); - staticType := TTypes.CreateGenericRecord(genDef); - var genBoundNode := TBoundGenericRecordLiteralNode.Create(boundFields, genDef); - Result := SetType(TDataValue.FromIntf(genBoundNode), staticType); + var genBoundNode := TBoundGenericRecordLiteralNode.Create(boundFields, nil); + Result := SetType(TDataValue.FromIntf(genBoundNode), TTypes.Unknown); end; end; @@ -731,48 +500,34 @@ var hasNestedLambdas: Boolean; lastNestedLambdaCount: Integer; boundLambda: ILambdaExpressionNode; - bodyType, methodType: IStaticType; - paramTypes: TArray; - selfSlot: Integer; begin FUpvalueStack.Push(TUpvalueMapping.Create); try EnterScope; try - // Define placeholder for (rekursion) - selfSlot := FCurrentDescriptor.Define('', TTypes.Unknown); + // Define placeholder for + FCurrentDescriptor.Define('', TTypes.Unknown); SetLength(boundParams, Length(Node.Parameters)); - SetLength(paramTypes, Length(Node.Parameters)); for i := 0 to High(Node.Parameters) do begin var paramNode := Node.Parameters[i]; - // Parameters are not typed yet, use Unknown - var paramType := TTypes.Unknown; - var slotIndex := FCurrentDescriptor.Define(paramNode.Name, paramType); + var slotIndex := FCurrentDescriptor.Define(paramNode.Name, TTypes.Unknown); var address := TResolvedAddress.Create(akLocalOrParent, 0, slotIndex); boundParams[i] := TBoundIdentifierNode.Create(paramNode, address); - (boundParams[i] as TAstNode).StaticType := paramType; - paramTypes[i] := paramType; + (boundParams[i] as TAstNode).StaticType := TTypes.Unknown; end; lastNestedLambdaCount := FNestedLambdaCount; - FNextIsTail := True; + FNextIsTail := True; // The body of a lambda is a tail position boundBody := Accept(Node.Body).AsIntf; hasNestedLambdas := FNestedLambdaCount > lastNestedLambdaCount; lambdaScope := FCurrentDescriptor; - - // Now that body is bound, infer return type - bodyType := (boundBody as TAstNode).StaticType; - methodType := TTypes.CreateMethod(paramTypes, bodyType); - - // Update the type for - FCurrentDescriptor.UpdateType(selfSlot, methodType); - finally ExitScope; end; + // Upvalue mapping extraction remains the same var upvalueMapping := FUpvalueStack.Peek; var sortedPairs := upvalueMapping.Map.ToArray; TArray.Sort>( @@ -790,7 +545,9 @@ begin inc(FNestedLambdaCount); boundLambda := TBoundLambdaExpressionNode.Create(Node, boundBody, boundParams, lambdaScope, upvalues, hasNestedLambdas); - Result := SetType(TDataValue.FromIntf(boundLambda), methodType); + + // Set type to Unknown. The TypeChecker will infer it. + Result := SetType(TDataValue.FromIntf(boundLambda), TTypes.Unknown); end; function TAstBinder.VisitRecurNode(const Node: IRecurNode): TDataValue; @@ -798,10 +555,7 @@ begin if not FIsTailStack.Peek then raise Exception.Create('''recur'' can only be used in a tail position.'); FNextIsTail := False; - // TODO: Check argument count and types against current lambda signature - // 'recur' itself doesn't evaluate to a value, it jumps. - // We set its type to Void. var boundNode := TAst.Recur(AcceptNodes(Node.Arguments)); Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Void); end; @@ -810,44 +564,33 @@ function TAstBinder.VisitTernaryExpression(const Node: ITernaryExpressionNode): var isContextTail: Boolean; condition, thenBranch, elseBranch: IAstNode; - conditionType, thenType, elseType, resultType: IStaticType; boundNode: ITernaryExpressionNode; begin isContextTail := FIsTailStack.Peek; FNextIsTail := False; condition := Accept(Node.Condition).AsIntf; - FNextIsTail := isContextTail; + FNextIsTail := isContextTail; // Propagate tail position thenBranch := Accept(Node.ThenBranch).AsIntf; elseBranch := Accept(Node.ElseBranch).AsIntf; - conditionType := (condition as TAstNode).StaticType; - if not TTypeRules.CanAssign(TTypes.Ordinal, conditionType) then - raise ETypeException.CreateFmt('Ternary condition must be Ordinal, but got %s', [conditionType.ToString]); - - thenType := (thenBranch as TAstNode).StaticType; - elseType := (elseBranch as TAstNode).StaticType; - resultType := TTypeRules.Promote(thenType, elseType); - if (condition <> Node.Condition) or (thenBranch <> Node.ThenBranch) or (elseBranch <> Node.ElseBranch) then boundNode := TAst.TernaryExpr(condition, thenBranch, elseBranch) else boundNode := Node; - Result := SetType(TDataValue.FromIntf(boundNode), resultType); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; var right: IAstNode; - rightType, resultType: IStaticType; boundNode: IUnaryExpressionNode; begin FNextIsTail := False; right := Accept(Node.Right).AsIntf; - rightType := (right as TAstNode).StaticType; - resultType := TTypeRules.ResolveUnaryOp(Node.Operator, rightType); + boundNode := TAst.UnaryExpr(Node.Operator, right); - Result := SetType(TDataValue.FromIntf(boundNode), resultType); + Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Unknown); end; function TAstBinder.VisitIdentifier(const Node: IIdentifierNode): TDataValue; @@ -863,6 +606,7 @@ begin begin if (adr.ScopeDepth > 0) and (FUpvalueStack.Count > 0) then begin + // Handle Upvalue var upvalue := FUpvalueStack.Peek; dec(adr.ScopeDepth); // Adjust address to be relative to the lambda's parent var upvalueIndex: Integer; @@ -874,8 +618,11 @@ begin boundNode := TBoundIdentifierNode.Create(Node, TResolvedAddress.Create(akUpvalue, 0, upvalueIndex)); end else + // Handle LocalOrParent boundNode := TBoundIdentifierNode.Create(Node, adr); + // Set the type *known at this stage*. The TypeChecker will update it + // for definitions (e.g. in VarDecl). Result := SetType(TDataValue.FromIntf(boundNode), symbol.StaticType); end else @@ -890,7 +637,6 @@ var boundIdentifier: IIdentifierNode; isBoxed: Boolean; boundDecl: IVariableDeclarationNode; - initType: IStaticType; begin if not IsValidIdentifier(Node.Identifier.Name) then raise Exception.CreateFmt('Invalid identifier name: "%s".', [Node.Identifier.Name]); @@ -900,19 +646,20 @@ begin if Node.Initializer <> nil then begin initializer := Accept(Node.Initializer).AsIntf; - initType := (initializer as TAstNode).StaticType; - end - else - initType := TTypes.Void; // Default type if no initializer + end; - slotIndex := FCurrentDescriptor.Define(Node.Identifier.Name, initType); + // Define the variable with TTypes.Unknown. + // The TypeChecker will update this in its pass. + slotIndex := FCurrentDescriptor.Define(Node.Identifier.Name, TTypes.Unknown); address := TResolvedAddress.Create(akLocalOrParent, 0, slotIndex); boundIdentifier := TBoundIdentifierNode.Create(Node.Identifier, address); - (boundIdentifier as TAstNode).StaticType := initType; + (boundIdentifier as TAstNode).StaticType := TTypes.Unknown; isBoxed := (FBoxedDeclarations <> nil) and FBoxedDeclarations.Contains(Node); boundDecl := TBoundVariableDeclarationNode.Create(boundIdentifier, initializer, isBoxed); - Result := SetType(TDataValue.FromIntf(boundDecl), initType); + + // The declaration itself has the type of its initializer (which is currently Unknown) + Result := SetType(TDataValue.FromIntf(boundDecl), TTypes.Unknown); end; end. diff --git a/Src/AST/Myc.Ast.TypeChecker.pas b/Src/AST/Myc.Ast.TypeChecker.pas new file mode 100644 index 0000000..3489ef1 --- /dev/null +++ b/Src/AST/Myc.Ast.TypeChecker.pas @@ -0,0 +1,528 @@ +unit Myc.Ast.TypeChecker; + +interface + +uses + System.SysUtils, + System.Classes, + System.Generics.Collections, + Myc.Data.Scalar, + Myc.Data.Value, + Myc.Ast.Nodes, + Myc.Ast.Visitor, + Myc.Ast.Scope, + Myc.Ast.Types, + Myc.Ast, + Myc.Ast.Binding.Nodes; + +type + IAstTypeChecker = interface(IAstVisitor) + function Execute(const RootNode: IAstNode; const ADecriptor: IScopeDescriptor): IAstNode; + end; + + // This transformer runs *after* the TAstBinder. + // It takes the "Bound AST" (which has addresses but mostly TTypes.Unknown) + // and traverses it bottom-up to infer and check all static types. + // It modifies the node.StaticType property and updates the IScopeDescriptor. + TTypeChecker = class(TAstTransformer, IAstTypeChecker) + private + FCurrentDescriptor: IScopeDescriptor; + function SetType(const NodeData: TDataValue; const AType: IStaticType): TDataValue; overload; + protected + // Override all visit methods to perform type checking + function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override; + function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override; + function VisitAssignment(const Node: IAssignmentNode): TDataValue; override; + function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override; + function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override; + function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override; + function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override; + function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override; + function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override; + function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override; + function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override; + function VisitIndexer(const Node: IIndexerNode): TDataValue; override; + function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override; + function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override; + function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override; + function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; + function VisitRecurNode(const Node: IRecurNode): TDataValue; override; + + // Base cases (types are already known from binder) + function VisitConstant(const Node: IConstantNode): TDataValue; override; + function VisitKeyword(const Node: IKeywordNode): TDataValue; override; + // Compile-time nodes (should not be present) + function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; override; + function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override; + public + constructor Create(const ADescriptor: IScopeDescriptor); + function Execute(const RootNode: IAstNode; const ADescriptor: IScopeDescriptor): IAstNode; + + class function CheckTypes(const RootNode: IAstNode; const ADescriptor: IScopeDescriptor): IAstNode; static; + end; + +implementation + +uses + System.Generics.Defaults, + Myc.Data.Keyword; + +{ TTypeChecker } + +constructor TTypeChecker.Create(const ADescriptor: IScopeDescriptor); +begin + inherited Create; + Assert(Assigned(ADescriptor)); + FCurrentDescriptor := ADescriptor; +end; + +class function TTypeChecker.CheckTypes(const RootNode: IAstNode; const ADescriptor: IScopeDescriptor): IAstNode; +begin + var checker := TTypeChecker.Create(ADescriptor) as IAstTypeChecker; + Result := checker.Execute(RootNode, ADescriptor); +end; + +function TTypeChecker.Execute(const RootNode: IAstNode; const ADescriptor: IScopeDescriptor): IAstNode; +begin + FCurrentDescriptor := ADescriptor; + var transformedValue := Accept(RootNode); + if transformedValue.IsVoid then + Result := TAst.Block([]) + else + Result := transformedValue.AsIntf; + (Result as TAstNode).StaticType := (Result as TAstNode).StaticType; +end; + +function TTypeChecker.SetType(const NodeData: TDataValue; const AType: IStaticType): TDataValue; +begin + if (not NodeData.IsVoid) and (NodeData.Kind = vkInterface) then + (NodeData.AsIntf as TAstNode).StaticType := AType; + Result := NodeData; +end; + +function TTypeChecker.VisitConstant(const Node: IConstantNode): TDataValue; +begin + // Type was set by Binder, just propagate it up. + Result := TDataValue.FromIntf(Node); +end; + +function TTypeChecker.VisitKeyword(const Node: IKeywordNode): TDataValue; +begin + // Type was set by Binder, just propagate it up. + Result := TDataValue.FromIntf(Node); +end; + +function TTypeChecker.VisitIdentifier(const Node: IIdentifierNode): TDataValue; +begin + // Type was set by Binder (read from scope), just propagate it up. + Result := TDataValue.FromIntf(Node); +end; + +function TTypeChecker.VisitRecurNode(const Node: IRecurNode): TDataValue; +begin + // Type was set by Binder (TTypes.Void), just propagate it up. + Result := TDataValue.FromIntf(Node); +end; + +function TTypeChecker.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; +begin + raise Exception.Create('TTypeChecker: MacroDefinition node encountered.'); +end; + +function TTypeChecker.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; +begin + raise Exception.Create('TTypeChecker: MacroExpansionNode node encountered.'); +end; + +function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; +var + initNode: IAstNode; + initType: IStaticType; + boundIdent: TBoundIdentifierNode; + adr: TResolvedAddress; +begin + // 1. Visit the initializer (if it exists) to get its (now-inferred) type. + if Assigned(Node.Initializer) then + begin + initNode := Accept(Node.Initializer).AsIntf; + initType := (initNode as TAstNode).StaticType; + end + else + initType := TTypes.Void; + + // 2. Get the address from the bound identifier. + boundIdent := (Node.Identifier as TBoundIdentifierNode); + adr := boundIdent.Address; + + // 3. Update the type in the scope descriptor (which was set to Unknown by the binder). + FCurrentDescriptor.UpdateType(adr.SlotIndex, initType); + + // 4. Update the static types of the nodes themselves. + (boundIdent as TAstNode).StaticType := initType; + Result := SetType(TDataValue.FromIntf(Node), initType); +end; + +function TTypeChecker.VisitAssignment(const Node: IAssignmentNode): TDataValue; +var + boundIdentifier, boundValue: IAstNode; + targetType, sourceType: IStaticType; +begin + boundIdentifier := Accept(Node.Identifier).AsIntf; + boundValue := Accept(Node.Value).AsIntf; + + targetType := (boundIdentifier as TAstNode).StaticType; + sourceType := (boundValue as TAstNode).StaticType; + + if not TTypeRules.CanAssign(targetType, sourceType) then + raise ETypeException.CreateFmt('Cannot assign type %s to %s', [sourceType.ToString, targetType.ToString]); + + Result := SetType(TDataValue.FromIntf(Node), targetType); +end; + +function TTypeChecker.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; +var + boundNode: TBoundLambdaExpressionNode; + boundBody: IAstNode; + bodyType, methodType: IStaticType; + paramTypes: TArray; + i: Integer; +begin + boundNode := (Node as TBoundLambdaExpressionNode); + + // 1. Enter the lambda's scope + FCurrentDescriptor := boundNode.ScopeDescriptor; + try + // 2. Set parameter types (currently Unknown, but required for signature) + SetLength(paramTypes, Length(boundNode.Parameters)); + for i := 0 to High(boundNode.Parameters) do + paramTypes[i] := (boundNode.Parameters[i] as TAstNode).StaticType; // Propagates Unknown + + // 3. Visit the body to infer its return type + boundBody := Accept(boundNode.Body).AsIntf; + bodyType := (boundBody as TAstNode).StaticType; + + // 4. Create the final method type + methodType := TTypes.CreateMethod(paramTypes, bodyType); + + // 5. Update the type for (Slot 0) in the descriptor + FCurrentDescriptor.UpdateType(0, methodType); + + finally + // 6. Restore parent descriptor + FCurrentDescriptor := FCurrentDescriptor.Parent; + end; + + // 7. Set the type of the lambda node itself + Result := SetType(TDataValue.FromIntf(boundNode), methodType); +end; + +function TTypeChecker.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; +var + callee: IAstNode; + args: TArray; + calleeType, retType: IStaticType; + i: Integer; +begin + // 1. Visit children first (bottom-up) + callee := Accept(Node.Callee).AsIntf; + args := AcceptNodes(Node.Arguments); + + // 2. Get callee type (now inferred) + calleeType := (callee as TAstNode).StaticType; + retType := TTypes.Unknown; // Default if not a method + + // 3. Perform type checking + if calleeType.Kind = TStaticTypeKind.stMethod then + begin + var signature := calleeType.Signature; + if Length(args) <> Length(signature.ParamTypes) then + raise ETypeException.CreateFmt('Function expects %d arguments, but got %d', [Length(signature.ParamTypes), Length(args)]); + + retType := signature.ReturnType; + + // Check argument types + for i := 0 to High(args) do + begin + var argType := (args[i] as TAstNode).StaticType; + var paramType := signature.ParamTypes[i]; + if not TTypeRules.CanAssign(paramType, argType) then + raise ETypeException + .CreateFmt('Cannot assign argument %d (type %s) to parameter (type %s)', [i, argType.ToString, paramType.ToString]); + end; + end + else if calleeType.Kind <> TStaticTypeKind.stUnknown then + raise ETypeException.CreateFmt('Cannot invoke type %s as a function.', [calleeType.ToString]); + + // 4. Set the type for this call node + Result := SetType(TDataValue.FromIntf(Node), retType); +end; + +function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; +var + blockType: IStaticType; + exprs: TArray; +begin + exprs := AcceptNodes(Node.Expressions); + + if Length(exprs) > 0 then + blockType := (exprs[High(exprs)] as TAstNode).StaticType + else + blockType := TTypes.Void; + + Result := SetType(TDataValue.FromIntf(Node), blockType); +end; + +function TTypeChecker.VisitIfExpression(const Node: IIfExpressionNode): TDataValue; +var + condition, thenBranch, elseBranch: IAstNode; + conditionType, thenType, elseType, resultType: IStaticType; +begin + condition := Accept(Node.Condition).AsIntf; + thenBranch := Accept(Node.ThenBranch).AsIntf; + elseBranch := Accept(Node.ElseBranch).AsIntf; // Accept(nil) returns void + + conditionType := (condition as TAstNode).StaticType; + if (conditionType.Kind <> stUnknown) and not TTypeRules.CanAssign(TTypes.Ordinal, conditionType) then + raise ETypeException.CreateFmt('If condition must be Ordinal, but got %s', [conditionType.ToString]); + + thenType := (thenBranch as TAstNode).StaticType; + elseType := + if elseBranch <> nil then (elseBranch as TAstNode).StaticType + else TTypes.Void; + + resultType := TTypeRules.Promote(thenType, elseType); + Result := SetType(TDataValue.FromIntf(Node), resultType); +end; + +function TTypeChecker.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; +var + condition, thenBranch, elseBranch: IAstNode; + conditionType, thenType, elseType, resultType: IStaticType; +begin + condition := Accept(Node.Condition).AsIntf; + thenBranch := Accept(Node.ThenBranch).AsIntf; + elseBranch := Accept(Node.ElseBranch).AsIntf; + + conditionType := (condition as TAstNode).StaticType; + if (conditionType.Kind <> stUnknown) and not TTypeRules.CanAssign(TTypes.Ordinal, conditionType) then + raise ETypeException.CreateFmt('Ternary condition must be Ordinal, but got %s', [conditionType.ToString]); + + thenType := (thenBranch as TAstNode).StaticType; + elseType := (elseBranch as TAstNode).StaticType; + resultType := TTypeRules.Promote(thenType, elseType); + Result := SetType(TDataValue.FromIntf(Node), resultType); +end; + +function TTypeChecker.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; +var + left, right: IAstNode; + leftType, rightType, resultType: IStaticType; +begin + left := Accept(Node.Left).AsIntf; + right := Accept(Node.Right).AsIntf; + leftType := (left as TAstNode).StaticType; + rightType := (right as TAstNode).StaticType; + resultType := TTypeRules.ResolveBinaryOp(Node.Operator, leftType, rightType); + Result := SetType(TDataValue.FromIntf(Node), resultType); +end; + +function TTypeChecker.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; +var + right: IAstNode; + rightType, resultType: IStaticType; +begin + right := Accept(Node.Right).AsIntf; + rightType := (right as TAstNode).StaticType; + resultType := TTypeRules.ResolveUnaryOp(Node.Operator, rightType); + Result := SetType(TDataValue.FromIntf(Node), resultType); +end; + +function TTypeChecker.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; +var + baseNode: IAstNode; + baseType, elemType: IStaticType; + fieldIndex: Integer; +begin + baseNode := Accept(Node.Base).AsIntf; + baseType := (baseNode as TAstNode).StaticType; + + elemType := TTypes.Unknown; + if (baseType.Kind <> TStaticTypeKind.stUnknown) then + begin + if (baseType.Kind = TStaticTypeKind.stRecord) or (baseType.Kind = TStaticTypeKind.stRecordSeries) then + begin + fieldIndex := baseType.Definition.IndexOf(Node.Member.Value); + if fieldIndex < 0 then + raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]); + + var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Value); + + if baseType.Kind = TStaticTypeKind.stRecord then + elemType := fieldType + else // stRecordSeries + elemType := TTypes.CreateSeries(fieldType); + end + else if (baseType.Kind = TStaticTypeKind.stGenericRecord) then + begin + var genDef := baseType.GenericDefinition; + fieldIndex := genDef.IndexOf(Node.Member.Value); + if fieldIndex < 0 then + raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]); + elemType := genDef.Fields[fieldIndex].Value; + end + else + begin + raise ETypeException.CreateFmt('Member access requires a record type, but got %s', [baseType.ToString]); + end; + end; + + Result := SetType(TDataValue.FromIntf(Node), elemType); +end; + +function TTypeChecker.VisitIndexer(const Node: IIndexerNode): TDataValue; +var + baseNode, indexNode: IAstNode; + baseType, indexType, elemType: IStaticType; +begin + baseNode := Accept(Node.Base).AsIntf; + indexNode := Accept(Node.Index).AsIntf; + baseType := (baseNode as TAstNode).StaticType; + indexType := (indexNode as TAstNode).StaticType; + + elemType := TTypes.Unknown; + if (baseType.Kind <> TStaticTypeKind.stUnknown) then + begin + if (baseType.Kind <> TStaticTypeKind.stSeries) and (baseType.Kind <> TStaticTypeKind.stRecordSeries) then + raise ETypeException.CreateFmt('Indexer `[]` can only be applied to series types, but got %s', [baseType.ToString]); + + if (indexType.Kind <> stUnknown) and not TTypeRules.CanAssign(TTypes.Ordinal, indexType) then + raise ETypeException.CreateFmt('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]); + + if baseType.Kind = TStaticTypeKind.stSeries then + elemType := baseType.ElementType + else // stRecordSeries + elemType := TTypes.CreateRecord(baseType.Definition); + end; + + Result := SetType(TDataValue.FromIntf(Node), elemType); +end; + +function TTypeChecker.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; +var + i: Integer; + boundFields: TArray; + scalarDefFields: TArray; + def: IScalarRecordDefinition; + staticType: IStaticType; + valNode: IAstNode; + valType: IStaticType; + scalarKind: TScalar.TKind; + allScalar: Boolean; +begin + SetLength(boundFields, Length(Node.Fields)); + SetLength(scalarDefFields, Length(Node.Fields)); + allScalar := True; + + // 1. Visit all child nodes first to infer their types + for i := 0 to High(Node.Fields) do + begin + valNode := Accept(Node.Fields[i].Value).AsIntf; + valType := (valNode as TAstNode).StaticType; + boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Key, valNode); + + // 2. Check if this field fits the scalar path + if (valType.Kind = stOrdinal) then + scalarKind := TScalar.TKind.Ordinal + else if (valType.Kind = stFloat) then + scalarKind := TScalar.TKind.Float + else if (valType.Kind = stKeyword) then + scalarKind := TScalar.TKind.Keyword + else + begin + allScalar := False; + scalarKind := TScalar.TKind.Ordinal; // Dummy + end; + + if allScalar then + scalarDefFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind); + end; + + // 3. Create the appropriate record type (Scalar or Generic) + if allScalar then + begin + def := TScalarRecordRegistry.Intern(scalarDefFields); + staticType := TTypes.CreateRecord(def); + // We can re-use the TBoundRecordLiteralNode from the binder + (Node as TBoundRecordLiteralNode).Definition := def; + end + else + begin + var genDefFields: TArray>; + SetLength(genDefFields, Length(boundFields)); + for i := 0 to High(boundFields) do + genDefFields[i] := TPair.Create(boundFields[i].Key.Value, (boundFields[i].Value as TAstNode).StaticType); + + var genDef := TGenericRecordRegistry.Intern(genDefFields); + staticType := TTypes.CreateGenericRecord(genDef); + // Re-use the TBoundGenericRecordLiteralNode from the binder + (Node as TBoundGenericRecordLiteralNode).Definition := genDef; + end; + + Result := SetType(TDataValue.FromIntf(Node), staticType); +end; + +function TTypeChecker.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; +begin + // Type was set by Binder, just propagate it up. + Result := TDataValue.FromIntf(Node); +end; + +function TTypeChecker.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; +var + seriesNode, valueNode, lookbackNode: IAstNode; + seriesType, valueType: IStaticType; +begin + seriesNode := Accept(Node.Series).AsIntf; + valueNode := Accept(Node.Value).AsIntf; + lookbackNode := Accept(Node.Lookback).AsIntf; + + seriesType := (seriesNode as TAstNode).StaticType; + valueType := (valueNode as TAstNode).StaticType; + + if (seriesType.Kind <> stUnknown) then + begin + if (seriesType.Kind <> TStaticTypeKind.stSeries) then + raise ETypeException.CreateFmt('"add" requires a series as its first argument, but got %s', [seriesType.ToString]); + + if not TTypeRules.CanAssign(seriesType.ElementType, valueType) then + raise ETypeException + .CreateFmt('Cannot add item of type %s to series of type %s', [valueType.ToString, seriesType.ElementType.ToString]); + end; + + if (lookbackNode <> nil) then + begin + var lookbackType := (lookbackNode as TAstNode).StaticType; + if (lookbackType.Kind <> stUnknown) and not (lookbackType.Kind = TStaticTypeKind.stOrdinal) then + raise ETypeException.Create('Lookback parameter for "add" must be an ordinal value.'); + end; + + Result := SetType(TDataValue.FromIntf(Node), TTypes.Void); +end; + +function TTypeChecker.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; +var + seriesNode: IAstNode; + seriesType: IStaticType; +begin + seriesNode := Accept(Node.Series).AsIntf; + seriesType := (seriesNode as TAstNode).StaticType; + + if (seriesType.Kind <> stUnknown) + and (seriesType.Kind <> TStaticTypeKind.stSeries) + and (seriesType.Kind <> TStaticTypeKind.stRecordSeries) then + raise ETypeException.CreateFmt('"length" requires a series, but got %s', [seriesType.ToString]); + + Result := SetType(TDataValue.FromIntf(Node), TTypes.Ordinal); +end; + +end.