Macro expander integrated in binder

This commit is contained in:
Michael Schimmel
2025-10-04 19:05:50 +02:00
parent d9219474e0
commit 7c48e9e203
16 changed files with 487 additions and 522 deletions
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,6 +1,7 @@
program ASTPlayground;
uses
FastMM5,
System.StartUpCopy,
FMX.Forms,
MainForm in 'MainForm.pas' {Form1},
@@ -19,8 +20,7 @@ uses
Myc.Fmx.AstEditor.Workspace in 'Myc.Fmx.AstEditor.Workspace.pas',
Myc.Fmx.AstEditor.Text in 'Myc.Fmx.AstEditor.Text.pas',
Myc.Utils in '..\Src\Myc.Utils.pas',
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas',
Myc.Ast.MacroExpander in '..\Src\AST\Myc.Ast.MacroExpander.pas';
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas';
{$R *.res}
-2
View File
@@ -134,7 +134,6 @@
</DelphiCompile>
<DCCReference Include="MainForm.pas">
<Form>Form1</Form>
<FormType>fmx</FormType>
</DCCReference>
<DCCReference Include="..\Src\AST\Myc.Ast.Evaluator.pas"/>
<DCCReference Include="..\Src\AST\Myc.Ast.Nodes.pas"/>
@@ -152,7 +151,6 @@
<DCCReference Include="Myc.Fmx.AstEditor.Text.pas"/>
<DCCReference Include="..\Src\Myc.Utils.pas"/>
<DCCReference Include="..\Src\AST\Myc.Ast.Script.pas"/>
<DCCReference Include="..\Src\AST\Myc.Ast.MacroExpander.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
-20
View File
@@ -20,7 +20,6 @@ object Form1: TForm1
Position.Y = 32.000000000000000000
TabOrder = 1
Text = 'Test 1'
TextSettings.Trimming = None
OnClick = Test1ButtonClick
end
object Test2Button: TButton
@@ -28,7 +27,6 @@ object Form1: TForm1
Position.Y = 62.000000000000000000
TabOrder = 2
Text = 'Test 2'
TextSettings.Trimming = None
OnClick = Test2ButtonClick
end
object PrettyPrintButton: TButton
@@ -36,7 +34,6 @@ object Form1: TForm1
Position.Y = 479.000000000000000000
TabOrder = 3
Text = 'Print'
TextSettings.Trimming = None
OnClick = PrettyPrintButtonClick
end
object RecursionButton: TButton
@@ -47,7 +44,6 @@ object Form1: TForm1
Size.PlatformDefault = False
TabOrder = 4
Text = 'Recursion'
TextSettings.Trimming = None
OnClick = RecursionButtonClick
end
object ShowScopeBox: TCheckBox
@@ -61,7 +57,6 @@ object Form1: TForm1
Position.Y = 122.000000000000000000
TabOrder = 7
Text = 'Fibonacci'
TextSettings.Trimming = None
OnClick = FibonacciButtonClick
end
object CrerateTriggerExampleButton: TButton
@@ -69,7 +64,6 @@ object Form1: TForm1
Position.Y = 168.000000000000000000
TabOrder = 8
Text = 'TriggerTest'
TextSettings.Trimming = None
OnClick = CreateTriggerExampleButtonClick
end
object DoTriggerButton: TButton
@@ -77,13 +71,11 @@ object Form1: TForm1
Position.Y = 198.000000000000000000
TabOrder = 9
Text = 'Trigger!'
TextSettings.Trimming = None
OnClick = DoTriggerButtonClick
object DoTrigger2Button: TButton
Position.Y = 30.000000000000000000
TabOrder = 5
Text = 'Trigger2'
TextSettings.Trimming = None
OnClick = DoTrigger2ButtonClick
end
end
@@ -95,7 +87,6 @@ object Form1: TForm1
Size.PlatformDefault = False
TabOrder = 10
Text = 'Clear'
TextSettings.Trimming = None
OnClick = ClearButtonClick
end
object FlowOnlyBox: TCheckBox
@@ -113,7 +104,6 @@ object Form1: TForm1
Size.PlatformDefault = False
TabOrder = 13
Text = 'Series'
TextSettings.Trimming = None
OnClick = SeriesTestButtonClick
end
object OHLCButton: TButton
@@ -121,7 +111,6 @@ object Form1: TForm1
Position.Y = 288.000000000000000000
TabOrder = 14
Text = 'OHLC'
TextSettings.Trimming = None
OnClick = OHLCButtonClick
end
object DebugBox: TCheckBox
@@ -135,7 +124,6 @@ object Form1: TForm1
Position.Y = 602.000000000000000000
TabOrder = 16
Text = 'From JSON'
TextSettings.Trimming = None
OnClick = FromJSONButtonClick
end
object ToJSONButton: TButton
@@ -143,7 +131,6 @@ object Form1: TForm1
Position.Y = 632.000000000000000000
TabOrder = 17
Text = 'To JSON'
TextSettings.Trimming = None
OnClick = ToJSONButtonClick
end
object ExternalFuncButton: TButton
@@ -151,7 +138,6 @@ object Form1: TForm1
Position.Y = 318.000000000000000000
TabOrder = 18
Text = 'External Func'
TextSettings.Trimming = None
OnClick = ExternalFuncButtonClick
end
object InnerLambdaButton: TButton
@@ -159,7 +145,6 @@ object Form1: TForm1
Position.Y = 348.000000000000000000
TabOrder = 19
Text = 'Inner Lambda'
TextSettings.Trimming = None
OnClick = InnerLambdaButtonClick
end
object DumpButton: TButton
@@ -167,7 +152,6 @@ object Form1: TForm1
Position.Y = 509.000000000000000000
TabOrder = 20
Text = 'Dump'
TextSettings.Trimming = None
OnClick = DumpButtonClick
end
object FailingUpvalueButton: TButton
@@ -175,7 +159,6 @@ object Form1: TForm1
Position.Y = 378.000000000000000000
TabOrder = 22
Text = 'Upvalue'
TextSettings.Trimming = None
OnClick = FailingUpvalueButtonClick
end
object TailCallButten: TButton
@@ -183,7 +166,6 @@ object Form1: TForm1
Position.Y = 406.000000000000000000
TabOrder = 23
Text = 'Tail calls'
TextSettings.Trimming = None
OnClick = TailCallButtenClick
end
object SaveUserLibButton: TButton
@@ -191,7 +173,6 @@ object Form1: TForm1
Position.Y = 680.000000000000000000
TabOrder = 24
Text = 'Save Lib'
TextSettings.Trimming = None
OnClick = SaveUserLibButtonClick
end
object LoadUserLibButton: TButton
@@ -199,7 +180,6 @@ object Form1: TForm1
Position.Y = 710.000000000000000000
TabOrder = 25
Text = 'LoadLib'
TextSettings.Trimming = None
OnClick = LoadUserLibButtonClick
end
end
+23 -29
View File
@@ -33,7 +33,6 @@ uses
Myc.Ast.Binding,
Myc.Ast.RTL,
Myc.Ast.Script,
Myc.Ast.MacroExpander,
FMX.Layouts,
FMX.Objects,
Myc.Ast.Debugger,
@@ -114,7 +113,7 @@ type
FTriggerScope: IExecutionScope;
FScriptUpdate: Boolean;
procedure WorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
function CreateEvaluator(Scope: IExecutionScope): IEvaluatorVisitor;
function CreateEvaluator(const Scope: IExecutionScope): IEvaluatorVisitor;
// Helper function to encapsulate the Bind -> Evaluate pattern
function ExecuteAst(const ANode: IAstNode; const AParentScope: IExecutionScope): TDataValue;
procedure UpdateScript;
@@ -212,31 +211,26 @@ end;
function TForm1.ExecuteAst(const ANode: IAstNode; const AParentScope: IExecutionScope): TDataValue;
var
binder: IAstBinder;
scriptScope: IExecutionScope;
boundAst: IAstNode;
descriptor: IScopeDescriptor;
evalScope: IExecutionScope;
visitor: IEvaluatorVisitor;
begin
var macroExpander :=
TMacroExpander.Create(
function(const ANode: IAstNode): TDataValue
begin
var binder := TAstBinder.Create(AParentScope) as IAstBinder;
// The new, streamlined pipeline: The binder handles macro expansion internally.
var descriptor: IScopeDescriptor;
var boundAst := binder.Execute(ANode, descriptor);
// Step 1: Create a binder, passing the evaluator factory for compile-time evaluations.
binder := TAstBinder.Create(AParentScope, CreateEvaluator);
var evalScope := descriptor.CreateScope(AParentScope);
var evaluator := CreateEvaluator(evalScope);
boundAst := binder.Execute(ANode, descriptor);
Result := evaluator.Execute(boundAst);
end)
as IMacroExpander;
// Store the final bound AST for visualization and debugging.
FCurrAst := ANode;
FCurrDesc := descriptor;
binder := TAstBinder.Create(AParentScope);
FCurrAst := binder.Execute(macroExpander.Execute(ANode), FCurrDesc);
scriptScope := FCurrDesc.CreateScope(AParentScope);
visitor := CreateEvaluator(scriptScope);
Result := visitor.Execute(FCurrAst);
// Step 2: Create the final scope and evaluator for runtime execution.
evalScope := descriptor.CreateScope(AParentScope);
visitor := CreateEvaluator(evalScope);
Result := visitor.Execute(boundAst);
end;
procedure TForm1.FormCreate(Sender: TObject);
@@ -307,7 +301,7 @@ begin
)
);
binder := TAstBinder.Create(Scope);
binder := TAstBinder.Create(Scope, CreateEvaluator);
boundSmaAst := binder.Execute(smaAst, smaDescriptor);
smaScope := smaDescriptor.CreateScope(Scope);
@@ -496,7 +490,7 @@ begin
raise EJSONParseException.Create('Invalid JSON format.');
try
var binder := TAstBinder.Create(FGScope);
var binder := TAstBinder.Create(FGScope, CreateEvaluator);
var unboundAst := converter.Deserialize(jsonObj);
FCurrAst := binder.Execute(unboundAst, FCurrDesc);
Memo1.Lines.Add('AST deserialized successfully from JSON.');
@@ -566,7 +560,7 @@ begin
end;
// Re-bind the current AST against the global scope to ensure up-to-date binding info for the dump.
binder := TAstBinder.Create(FGScope);
binder := TAstBinder.Create(FGScope, CreateEvaluator);
boundNode := binder.Execute(FCurrAst, FCurrDesc);
TAstDumper.Dump(boundNode, Memo1.Lines);
end;
@@ -608,7 +602,7 @@ begin
]
);
binder := TAstBinder.Create(FGScope);
binder := TAstBinder.Create(FGScope, CreateEvaluator);
var desc: IScopeDescriptor;
boundFibAst := binder.Execute(fibAst, desc);
fibScope := desc.CreateScope(FGScope);
@@ -902,7 +896,7 @@ begin
);
// 1. Bind and execute the setup script.
binder := TAstBinder.Create(FGScope);
binder := TAstBinder.Create(FGScope, CreateEvaluator);
boundSetupAst := binder.Execute(setupAst, setupDescriptor);
scope := setupDescriptor.CreateScope(FGScope);
@@ -915,7 +909,7 @@ begin
callAst := TAst.FunctionCall(TAst.Identifier('maCrossStrategy'), [currentSeriesIdent]);
// 3. Re-bind the call AST within the now-populated scope to resolve the new variable.
binder := TAstBinder.Create(scope);
binder := TAstBinder.Create(scope, CreateEvaluator);
boundCallAst := binder.Execute(callAst, callDescriptor);
// 4. Get the address of 'current_series' from the new descriptor.
@@ -1041,7 +1035,7 @@ begin
]
);
binder := TAstBinder.Create(FGScope);
binder := TAstBinder.Create(FGScope, CreateEvaluator);
FCurrAst := binder.Execute(blk, FCurrDesc);
FTriggerScope := FCurrDesc.CreateScope(FGScope);
@@ -1053,7 +1047,7 @@ begin
UpdateScript;
end;
function TForm1.CreateEvaluator(Scope: IExecutionScope): IEvaluatorVisitor;
function TForm1.CreateEvaluator(const Scope: IExecutionScope): IEvaluatorVisitor;
begin
if DebugBox.IsChecked then
Result := TDebugEvaluatorVisitor.Create(Scope, Memo1.Lines, ShowScopeBox.IsChecked)