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
+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)