Binder refactoring - extracted macro expander
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -22,7 +22,8 @@ uses
|
||||
Myc.Ast.Script in '..\Src\AST\Myc.Ast.Script.pas',
|
||||
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.Binding.Nodes in '..\Src\AST\Myc.Ast.Binding.Nodes.pas',
|
||||
Myc.Ast.MacroExpander in '..\Src\AST\Myc.Ast.MacroExpander.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Types.pas"/>
|
||||
<DCCReference Include="..\Src\Data\Myc.Data.Keyword.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.Binding.Nodes.pas"/>
|
||||
<DCCReference Include="..\Src\AST\Myc.Ast.MacroExpander.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
|
||||
+55
-30
@@ -38,11 +38,12 @@ uses
|
||||
Myc.Ast.Debugger,
|
||||
Myc.Fmx.AstEditor.Node,
|
||||
Myc.Fmx.AstEditor.Workspace,
|
||||
Myc.Ast.MacroExpander,
|
||||
FMX.DialogService,
|
||||
FMX.ListView.Types,
|
||||
FMX.ListView.Appearances,
|
||||
FMX.ListView.Adapters.Base,
|
||||
FMX.ListView; // Added for platform-independent dialogs
|
||||
FMX.ListView;
|
||||
|
||||
type
|
||||
// A test record
|
||||
@@ -208,25 +209,31 @@ end;
|
||||
|
||||
function TForm1.ExecuteAst(const ANode: IAstNode; const AParentScope: IExecutionScope): TDataValue;
|
||||
var
|
||||
binder: IAstBinder;
|
||||
boundAst: IAstNode;
|
||||
descriptor: IScopeDescriptor;
|
||||
descriptor: IScopeDescriptor; // This is the final (binder) descriptor
|
||||
evalScope: IExecutionScope;
|
||||
visitor: IEvaluatorVisitor;
|
||||
macroDescriptor: IScopeDescriptor; // This is the macro-pass descriptor
|
||||
expandedAst: IAstNode;
|
||||
begin
|
||||
// The new, streamlined pipeline: The binder handles macro expansion internally.
|
||||
FCurrUnboundAst := ANode;
|
||||
|
||||
// Step 1: Create a binder, passing the evaluator factory for compile-time evaluations.
|
||||
binder := TAstBinder.Create(AParentScope, CreateEvaluator);
|
||||
// Step 1: Expand macros (Phase 1)
|
||||
// The expander uses the parent scope to find macros and the factory to eval unquotes.
|
||||
expandedAst := TMacroExpander.ExpandMacros(AParentScope, ANode, macroDescriptor, CreateEvaluator);
|
||||
|
||||
boundAst := binder.Execute(ANode, descriptor);
|
||||
// Step 2: Bind names and types (Phase 2)
|
||||
// The binder runs on the *expanded* AST. It uses the same parent scope.
|
||||
// It no longer needs the factory.
|
||||
boundAst := TAstBinder.Bind(AParentScope, expandedAst, descriptor);
|
||||
|
||||
// Store the final bound AST for visualization and debugging.
|
||||
FCurrAst := boundAst;
|
||||
FCurrDesc := descriptor;
|
||||
|
||||
// Step 2: Create the final scope and evaluator for runtime execution.
|
||||
// Step 3: Create the final scope and evaluator for runtime execution.
|
||||
// The runtime scope is created from the *binder's* descriptor, using the parent scope.
|
||||
evalScope := descriptor.CreateScope(AParentScope);
|
||||
visitor := CreateEvaluator(evalScope);
|
||||
Result := visitor.Execute(boundAst);
|
||||
@@ -243,9 +250,10 @@ begin
|
||||
TAst.RegisterLibrary(
|
||||
procedure(const Scope: IExecutionScope)
|
||||
var
|
||||
smaAst, boundSmaAst: IAstNode;
|
||||
binder: IAstBinder;
|
||||
smaAst, boundSmaAst, expandedAst: IAstNode;
|
||||
// binder: IAstBinder; // <-- REMOVED
|
||||
smaDescriptor: IScopeDescriptor;
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
smaScope: IExecutionScope;
|
||||
smaVisitor: IEvaluatorVisitor;
|
||||
begin
|
||||
@@ -300,8 +308,10 @@ begin
|
||||
)
|
||||
);
|
||||
|
||||
binder := TAstBinder.Create(Scope, CreateEvaluator);
|
||||
boundSmaAst := binder.Execute(smaAst, smaDescriptor);
|
||||
// Phase 1: Expand
|
||||
expandedAst := TMacroExpander.ExpandMacros(Scope, smaAst, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2: Bind
|
||||
boundSmaAst := TAstBinder.Bind(Scope, expandedAst, smaDescriptor);
|
||||
|
||||
smaScope := smaDescriptor.CreateScope(Scope);
|
||||
smaVisitor := CreateEvaluator(smaScope);
|
||||
@@ -310,8 +320,10 @@ begin
|
||||
'print',
|
||||
TDataValue(
|
||||
function(const Args: TArray<TDataValue>): TDataValue
|
||||
var
|
||||
str: TStringBuilder;
|
||||
begin
|
||||
var str := TStringBuilder.Create;
|
||||
str := TStringBuilder.Create;
|
||||
try
|
||||
for var i := 0 to High(Args) do
|
||||
begin
|
||||
@@ -531,6 +543,8 @@ var
|
||||
jsonString: string;
|
||||
jsonObj: TJSONObject;
|
||||
converter: IJsonAstConverter;
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
expandedAst: IAstNode;
|
||||
begin
|
||||
Memo1.Lines.BeginUpdate;
|
||||
try
|
||||
@@ -550,9 +564,13 @@ begin
|
||||
raise EJSONParseException.Create('Invalid JSON format.');
|
||||
|
||||
try
|
||||
var binder := TAstBinder.Create(FGScope, CreateEvaluator);
|
||||
var unboundAst := converter.Deserialize(jsonObj);
|
||||
FCurrAst := binder.Execute(unboundAst, FCurrDesc);
|
||||
|
||||
// Phase 1: Expand
|
||||
expandedAst := TMacroExpander.ExpandMacros(FGScope, unboundAst, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2: Bind
|
||||
FCurrAst := TAstBinder.Bind(FGScope, expandedAst, FCurrDesc);
|
||||
|
||||
Memo1.Lines.Add('AST deserialized successfully from JSON.');
|
||||
Memo1.Lines.Add('You can now visualize it (Middle Mouse Click) or pretty-print it.');
|
||||
finally
|
||||
@@ -607,8 +625,8 @@ end;
|
||||
|
||||
procedure TForm1.DumpButtonClick(Sender: TObject);
|
||||
var
|
||||
binder: IAstBinder;
|
||||
boundNode: IAstNode;
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- AST Dump ---');
|
||||
@@ -619,9 +637,9 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Re-bind the current AST against the global scope to ensure up-to-date binding info for the dump.
|
||||
binder := TAstBinder.Create(FGScope, CreateEvaluator);
|
||||
boundNode := binder.Execute(FCurrAst, FCurrDesc);
|
||||
// Re-expand and re-bind the *unbound* AST (FCurrUnboundAst)
|
||||
var expandedAst := TMacroExpander.ExpandMacros(FGScope, FCurrUnboundAst, macroDescriptor, CreateEvaluator);
|
||||
boundNode := TAstBinder.Bind(FGScope, expandedAst, FCurrDesc);
|
||||
TAstDumper.Dump(boundNode, Memo1.Lines);
|
||||
end;
|
||||
|
||||
@@ -632,7 +650,7 @@ var
|
||||
sw: TStopwatch;
|
||||
fibScope: IExecutionScope;
|
||||
visitor: IEvaluatorVisitor;
|
||||
binder: IAstBinder;
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
fibAst :=
|
||||
TAst.Block(
|
||||
@@ -662,9 +680,11 @@ begin
|
||||
]
|
||||
);
|
||||
|
||||
binder := TAstBinder.Create(FGScope, CreateEvaluator);
|
||||
// Phase 1: Expand
|
||||
var expandedAst := TMacroExpander.ExpandMacros(FGScope, fibAst, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2: Bind
|
||||
var desc: IScopeDescriptor;
|
||||
boundFibAst := binder.Execute(fibAst, desc);
|
||||
boundFibAst := TAstBinder.Bind(FGScope, expandedAst, desc);
|
||||
fibScope := desc.CreateScope(FGScope);
|
||||
|
||||
visitor := CreateEvaluator(fibScope);
|
||||
@@ -900,9 +920,8 @@ var
|
||||
scope: IExecutionScope;
|
||||
values: TArray<TScalar.TValue>;
|
||||
recordValue: TScalarRecord;
|
||||
binder: IAstBinder;
|
||||
setupAst, boundSetupAst, callAst, boundCallAst: IAstNode;
|
||||
setupDescriptor, callDescriptor: IScopeDescriptor;
|
||||
setupDescriptor, callDescriptor, macroDescriptor: IScopeDescriptor;
|
||||
seriesAddress: TResolvedSymbol; // Use TResolvedSymbol
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
@@ -958,8 +977,10 @@ begin
|
||||
);
|
||||
|
||||
// 1. Bind and execute the setup script.
|
||||
binder := TAstBinder.Create(FGScope, CreateEvaluator);
|
||||
boundSetupAst := binder.Execute(setupAst, setupDescriptor);
|
||||
// Phase 1
|
||||
var expandedAst := TMacroExpander.ExpandMacros(FGScope, setupAst, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2
|
||||
boundSetupAst := TAstBinder.Bind(FGScope, expandedAst, setupDescriptor);
|
||||
|
||||
scope := setupDescriptor.CreateScope(FGScope);
|
||||
var setupVisitor := CreateEvaluator(scope);
|
||||
@@ -971,8 +992,10 @@ 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, CreateEvaluator);
|
||||
boundCallAst := binder.Execute(callAst, callDescriptor);
|
||||
// Phase 1
|
||||
var expandedAst2 := TMacroExpander.ExpandMacros(scope, callAst, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2
|
||||
boundCallAst := TAstBinder.Bind(scope, expandedAst2, callDescriptor);
|
||||
|
||||
// 4. Get the address of 'current_series' from the new descriptor.
|
||||
seriesAddress := callDescriptor.FindSymbol('current_series');
|
||||
@@ -1077,8 +1100,8 @@ end;
|
||||
procedure TForm1.CreateTriggerExampleButtonClick(Sender: TObject);
|
||||
var
|
||||
blk: IAstNode;
|
||||
binder: IAstBinder;
|
||||
visitor: IEvaluatorVisitor;
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
Memo1.Lines.Clear;
|
||||
Memo1.Lines.Add('--- Creating Trigger Blueprint ---');
|
||||
@@ -1099,8 +1122,10 @@ begin
|
||||
]
|
||||
);
|
||||
|
||||
binder := TAstBinder.Create(FGScope, CreateEvaluator);
|
||||
FCurrAst := binder.Execute(blk, FCurrDesc);
|
||||
// Phase 1
|
||||
var expandedAst := TMacroExpander.ExpandMacros(FGScope, blk, macroDescriptor, CreateEvaluator);
|
||||
// Phase 2
|
||||
FCurrAst := TAstBinder.Bind(FGScope, expandedAst, FCurrDesc);
|
||||
FTriggerScope := FCurrDesc.CreateScope(FGScope);
|
||||
|
||||
visitor := CreateEvaluator(FTriggerScope);
|
||||
|
||||
Reference in New Issue
Block a user