Ast environment refactoring
This commit is contained in:
+31
-45
@@ -109,7 +109,7 @@ type
|
|||||||
procedure RTLListViewChange(Sender: TObject);
|
procedure RTLListViewChange(Sender: TObject);
|
||||||
private
|
private
|
||||||
FCurrUnboundAst: IAstNode;
|
FCurrUnboundAst: IAstNode;
|
||||||
FCurrExec: IExecutable; // Replaced FCurrAst and FCurrDesc
|
FCurrExec: TDataValue.TFunc;
|
||||||
FEnvironment: TAstEnvironment;
|
FEnvironment: TAstEnvironment;
|
||||||
FWorkspace: TAuraWorkspace;
|
FWorkspace: TAuraWorkspace;
|
||||||
FScriptUpdate: Boolean;
|
FScriptUpdate: Boolean;
|
||||||
@@ -226,12 +226,8 @@ begin
|
|||||||
FEnvironment.SetStandardMode;
|
FEnvironment.SetStandardMode;
|
||||||
|
|
||||||
try
|
try
|
||||||
// 2. Compile (Pipeline is inside Environment)
|
|
||||||
// We store the executable artifact in the form
|
|
||||||
FCurrExec := FEnvironment.Compile(ANode);
|
FCurrExec := FEnvironment.Compile(ANode);
|
||||||
|
Result := FCurrExec([]);
|
||||||
// 3. Execute
|
|
||||||
Result := FEnvironment.Execute(FCurrExec);
|
|
||||||
|
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
@@ -260,7 +256,6 @@ begin
|
|||||||
procedure(const Scope: IExecutionScope)
|
procedure(const Scope: IExecutionScope)
|
||||||
var
|
var
|
||||||
smaAst: IAstNode;
|
smaAst: IAstNode;
|
||||||
smaExec: IExecutable;
|
|
||||||
begin
|
begin
|
||||||
smaAst :=
|
smaAst :=
|
||||||
TAst.LambdaExpr(
|
TAst.LambdaExpr(
|
||||||
@@ -313,13 +308,7 @@ begin
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Compile the SMA factory using the environment itself
|
var smaFactory := FEnvironment.Run(smaAst);
|
||||||
// Note: We pass FEnvironment.RootScope as the parent scope
|
|
||||||
smaExec := FEnvironment.Compile(smaAst);
|
|
||||||
|
|
||||||
// Execute the compiled AST to define the 'CreateSMA' function in the target scope
|
|
||||||
// We must use the *target* scope (Scope) as the parent for execution.
|
|
||||||
var smaFactory := FEnvironment.Execute(smaExec);
|
|
||||||
|
|
||||||
Scope.Define('CreateSMA', smaFactory); // Define the factory
|
Scope.Define('CreateSMA', smaFactory); // Define the factory
|
||||||
|
|
||||||
@@ -641,7 +630,7 @@ begin
|
|||||||
|
|
||||||
try
|
try
|
||||||
converter := TJsonAstConverter.Create;
|
converter := TJsonAstConverter.Create;
|
||||||
jsonObj := converter.Serialize(FCurrExec.CompiledAst);
|
jsonObj := converter.Serialize(FCurrUnboundAst);
|
||||||
try
|
try
|
||||||
Memo1.Lines.Text := jsonObj.Format(4);
|
Memo1.Lines.Text := jsonObj.Format(4);
|
||||||
finally
|
finally
|
||||||
@@ -668,7 +657,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Dump the compiled AST from the executable
|
// Dump the compiled AST from the executable
|
||||||
TAstDumper.Dump(FCurrExec.CompiledAst, Memo1.Lines);
|
TAstDumper.Dump(FCurrUnboundAst, Memo1.Lines);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.FibonacciButtonClick(Sender: TObject);
|
procedure TForm1.FibonacciButtonClick(Sender: TObject);
|
||||||
@@ -703,7 +692,7 @@ begin
|
|||||||
var fibExec := TestEnv.Compile(TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(25)]));
|
var fibExec := TestEnv.Compile(TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(25)]));
|
||||||
|
|
||||||
sw := TStopwatch.StartNew;
|
sw := TStopwatch.StartNew;
|
||||||
result := TestEnv.Execute(fibExec);
|
result := fibExec([]);
|
||||||
sw.Stop;
|
sw.Stop;
|
||||||
Memo1.Lines.Add(Format('Result: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
Memo1.Lines.Add(Format('Result: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
||||||
|
|
||||||
@@ -718,11 +707,11 @@ begin
|
|||||||
var memoizeExec := memoizeTest.Compile(TAstScript.Parse('(fib 25)'));
|
var memoizeExec := memoizeTest.Compile(TAstScript.Parse('(fib 25)'));
|
||||||
|
|
||||||
sw := TStopwatch.StartNew;
|
sw := TStopwatch.StartNew;
|
||||||
result := memoizeTest.Execute(memoizeExec);
|
result := memoizeExec([]);
|
||||||
sw.Stop;
|
sw.Stop;
|
||||||
Memo1.Lines.Add(Format('Result 1st call: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
Memo1.Lines.Add(Format('Result 1st call: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
||||||
sw := TStopwatch.StartNew;
|
sw := TStopwatch.StartNew;
|
||||||
result := memoizeTest.Execute(memoizeExec);
|
result := memoizeExec([]);
|
||||||
sw.Stop;
|
sw.Stop;
|
||||||
Memo1.Lines.Add(Format('Result 2nd call: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
Memo1.Lines.Add(Format('Result 2nd call: fib(25) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
|
||||||
|
|
||||||
@@ -741,7 +730,7 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Memo1.Lines.Add(TAstScript.Print(FCurrExec.CompiledAst));
|
Memo1.Lines.Add(TAstScript.Print(FCurrUnboundAst));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.RecursionButtonClick(Sender: TObject);
|
procedure TForm1.RecursionButtonClick(Sender: TObject);
|
||||||
@@ -797,7 +786,7 @@ end;
|
|||||||
|
|
||||||
procedure TForm1.SeriesTestButtonClick(Sender: TObject);
|
procedure TForm1.SeriesTestButtonClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
ast, callAst: IAstNode;
|
ast: IAstNode;
|
||||||
resultValue: TDataValue;
|
resultValue: TDataValue;
|
||||||
series: TScalarRecordSeries;
|
series: TScalarRecordSeries;
|
||||||
recordDef: IScalarRecordDefinition;
|
recordDef: IScalarRecordDefinition;
|
||||||
@@ -840,9 +829,9 @@ begin
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
callAst := TAst.FunctionCall(ast, []);
|
var callAst := TAst.FunctionCall(ast, []);
|
||||||
|
|
||||||
resultValue := testEnv.CompileAndExecute(callAst);
|
resultValue := testEnv.Run(callAst);
|
||||||
|
|
||||||
Memo1.Lines.Add(Format('Result of script: %s', [resultValue.ToString]));
|
Memo1.Lines.Add(Format('Result of script: %s', [resultValue.ToString]));
|
||||||
UpdateScript;
|
UpdateScript;
|
||||||
@@ -851,24 +840,20 @@ end;
|
|||||||
procedure TForm1.Test1ButtonClick(Sender: TObject);
|
procedure TForm1.Test1ButtonClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
FCurrUnboundAst :=
|
FCurrUnboundAst :=
|
||||||
TAst.Block(
|
TAstScript.Parse(
|
||||||
[
|
'''
|
||||||
TAst.LambdaExpr(
|
(do
|
||||||
[],
|
(print txt)
|
||||||
TAst.Block(
|
)
|
||||||
[
|
'''
|
||||||
TAst.VarDecl(TAst.Identifier('a'), TAst.Nop),
|
|
||||||
TAst.VarDecl(
|
|
||||||
TAst.Identifier('b'),
|
|
||||||
TAst.BinaryExpr(TAst.Identifier('a'), TScalar.TBinaryOp.Multiply, TAst.Constant(2))
|
|
||||||
),
|
|
||||||
TAst.BinaryExpr(TAst.Identifier('a'), TScalar.TBinaryOp.Add, TAst.Identifier('b'))
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var fn := FEnvironment.Compile(FCurrUnboundAst, [TAst.Identifier('txt')]);
|
||||||
|
|
||||||
|
fn(['Hello World']);
|
||||||
|
|
||||||
|
FEnvironment.RootScope.Define('fn', fn);
|
||||||
|
|
||||||
UpdateScript;
|
UpdateScript;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -879,12 +864,14 @@ var
|
|||||||
sw: TStopwatch;
|
sw: TStopwatch;
|
||||||
begin
|
begin
|
||||||
Memo1.Lines.Clear;
|
Memo1.Lines.Clear;
|
||||||
|
|
||||||
Memo1.Lines.Add('--- Factory Pattern Demo ---');
|
Memo1.Lines.Add('--- Factory Pattern Demo ---');
|
||||||
sw := TStopwatch.StartNew;
|
sw := TStopwatch.StartNew;
|
||||||
|
|
||||||
root :=
|
root :=
|
||||||
TAst.Block(
|
TAst.Block(
|
||||||
[
|
[
|
||||||
|
TAst.FunctionCall(TAst.Identifier('fn'), [TAst.Constant('xyz')]),
|
||||||
TAst.VarDecl(
|
TAst.VarDecl(
|
||||||
TAst.Identifier('createStrategyInstance'),
|
TAst.Identifier('createStrategyInstance'),
|
||||||
TAst.LambdaExpr(
|
TAst.LambdaExpr(
|
||||||
@@ -926,7 +913,6 @@ var
|
|||||||
values: TArray<TScalar.TValue>;
|
values: TArray<TScalar.TValue>;
|
||||||
recordValue: TScalarRecord;
|
recordValue: TScalarRecord;
|
||||||
setupAst: IAstNode;
|
setupAst: IAstNode;
|
||||||
callExec: IExecutable;
|
|
||||||
begin
|
begin
|
||||||
Memo1.Lines.Clear;
|
Memo1.Lines.Clear;
|
||||||
Memo1.Lines.Add(Format('--- Simulating O(1) SMA Crossover Strategy for %d ticks ---', [numRecs]));
|
Memo1.Lines.Add(Format('--- Simulating O(1) SMA Crossover Strategy for %d ticks ---', [numRecs]));
|
||||||
@@ -960,7 +946,7 @@ begin
|
|||||||
|
|
||||||
var seriesAddress := env.RootScope.Define('current_series', TDataValue.Void);
|
var seriesAddress := env.RootScope.Define('current_series', TDataValue.Void);
|
||||||
|
|
||||||
callExec := env.Compile(TAst.FunctionCall(TAst.Identifier('maCrossStrategy'), [TAst.Identifier('current_series')]));
|
var callExec := env.Compile(TAst.FunctionCall(TAst.Identifier('maCrossStrategy'), [TAst.Identifier('current_series')]));
|
||||||
|
|
||||||
// Simulation Loop
|
// Simulation Loop
|
||||||
Memo1.Lines.Clear;
|
Memo1.Lines.Clear;
|
||||||
@@ -998,7 +984,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
env.RootScope[seriesAddress] := series;
|
env.RootScope[seriesAddress] := series;
|
||||||
|
|
||||||
var resultValue := env.Execute(callExec);
|
var resultValue := callExec([]);
|
||||||
|
|
||||||
if i mod 50 = 0 then
|
if i mod 50 = 0 then
|
||||||
begin
|
begin
|
||||||
@@ -1078,7 +1064,7 @@ begin
|
|||||||
|
|
||||||
FTriggerTest := FEnvironment.CreateEnvironment;
|
FTriggerTest := FEnvironment.CreateEnvironment;
|
||||||
|
|
||||||
FTriggerTest.Define('X', TAst.VarDecl(TAst.Identifier('X'), TAst.Constant(0)));
|
FTriggerTest.Define('X', TAst.Constant(0));
|
||||||
FTriggerTest.Define(
|
FTriggerTest.Define(
|
||||||
'tickHandler',
|
'tickHandler',
|
||||||
TAst.LambdaExpr(
|
TAst.LambdaExpr(
|
||||||
@@ -1106,7 +1092,7 @@ var
|
|||||||
begin
|
begin
|
||||||
callAst := TAst.FunctionCall(TAst.Identifier('tickHandler'), [TAst.Constant(1)]);
|
callAst := TAst.FunctionCall(TAst.Identifier('tickHandler'), [TAst.Constant(1)]);
|
||||||
|
|
||||||
var X := FTriggerTest.CompileAndExecute(callAst);
|
var X := FTriggerTest.Run(callAst);
|
||||||
|
|
||||||
Memo1.Lines.Add(Format('Tick(1)! New value of X: %s', [X.ToString]));
|
Memo1.Lines.Add(Format('Tick(1)! New value of X: %s', [X.ToString]));
|
||||||
UpdateScript;
|
UpdateScript;
|
||||||
@@ -1118,7 +1104,7 @@ var
|
|||||||
begin
|
begin
|
||||||
callAst := TAst.FunctionCall(TAst.Identifier('tickHandler'), [TAst.Constant(2)]);
|
callAst := TAst.FunctionCall(TAst.Identifier('tickHandler'), [TAst.Constant(2)]);
|
||||||
|
|
||||||
var X := FTriggerTest.CompileAndExecute(callAst);
|
var X := FTriggerTest.Run(callAst);
|
||||||
|
|
||||||
Memo1.Lines.Add(Format('Tick(2)! New value of X: %s', [X.ToString]));
|
Memo1.Lines.Add(Format('Tick(2)! New value of X: %s', [X.ToString]));
|
||||||
UpdateScript;
|
UpdateScript;
|
||||||
|
|||||||
@@ -48,19 +48,27 @@ uses
|
|||||||
constructor TAstLowerer.Create;
|
constructor TAstLowerer.Create;
|
||||||
var
|
var
|
||||||
op: TScalar.TBinaryOp;
|
op: TScalar.TBinaryOp;
|
||||||
uOp: TScalar.TUnaryOp; // Added for unary
|
uOp: TScalar.TUnaryOp;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
|
||||||
// Operator folding maps
|
// Operator folding maps
|
||||||
FBinaryOperators := TDictionary<string, TScalar.TBinaryOp>.Create;
|
FBinaryOperators := TDictionary<string, TScalar.TBinaryOp>.Create;
|
||||||
for op := Low(TScalar.TBinaryOp) to High(TScalar.TBinaryOp) do
|
|
||||||
FBinaryOperators.Add(op.ToString, op);
|
FBinaryOperators.Add('+', TScalar.TBinaryOp.Add);
|
||||||
|
FBinaryOperators.Add('-', TScalar.TBinaryOp.Subtract);
|
||||||
|
FBinaryOperators.Add('*', TScalar.TBinaryOp.Multiply);
|
||||||
|
FBinaryOperators.Add('/', TScalar.TBinaryOp.Divide);
|
||||||
|
FBinaryOperators.Add('=', TScalar.TBinaryOp.Equal);
|
||||||
|
FBinaryOperators.Add('<>', TScalar.TBinaryOp.NotEqual);
|
||||||
|
FBinaryOperators.Add('<', TScalar.TBinaryOp.Less);
|
||||||
|
FBinaryOperators.Add('<=', TScalar.TBinaryOp.LessOrEqual);
|
||||||
|
FBinaryOperators.Add('>', TScalar.TBinaryOp.Greater);
|
||||||
|
FBinaryOperators.Add('>=', TScalar.TBinaryOp.GreaterOrEqual);
|
||||||
|
|
||||||
FUnaryOperators := TDictionary<string, TScalar.TUnaryOp>.Create;
|
FUnaryOperators := TDictionary<string, TScalar.TUnaryOp>.Create;
|
||||||
for uOp := Low(TScalar.TUnaryOp) to High(TScalar.TUnaryOp) do // Changed
|
|
||||||
FUnaryOperators.Add(uOp.ToString, uOp);
|
FUnaryOperators.Add('not', TScalar.TUnaryOp.Not);
|
||||||
// Note: '-' is handled as a special case in VisitFunctionCall
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TAstLowerer.Destroy;
|
destructor TAstLowerer.Destroy;
|
||||||
@@ -95,7 +103,7 @@ begin
|
|||||||
if Node.Callee.Kind = akIdentifier then
|
if Node.Callee.Kind = akIdentifier then
|
||||||
begin
|
begin
|
||||||
calleeIdentifier := Node.Callee.AsIdentifier;
|
calleeIdentifier := Node.Callee.AsIdentifier;
|
||||||
nodeType := Node.StaticType;
|
nodeType := Node.StaticType; // Get type from (un-lowered) node
|
||||||
|
|
||||||
if (Length(Node.Arguments) = 2) then
|
if (Length(Node.Arguments) = 2) then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -371,7 +371,6 @@ begin
|
|||||||
boundSubAst: IAstNode;
|
boundSubAst: IAstNode;
|
||||||
begin
|
begin
|
||||||
// This is the compile-time evaluation (Binder + Evaluator)
|
// This is the compile-time evaluation (Binder + Evaluator)
|
||||||
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthaelt
|
|
||||||
boundSubAst := TAstBinder.Bind(expansionScope.CreateDescriptor, ANodeToEvaluate, subDescriptor);
|
boundSubAst := TAstBinder.Bind(expansionScope.CreateDescriptor, ANodeToEvaluate, subDescriptor);
|
||||||
|
|
||||||
// Create eval scope from the new descriptor, parented to the expansion scope
|
// Create eval scope from the new descriptor, parented to the expansion scope
|
||||||
|
|||||||
+61
-111
@@ -15,7 +15,6 @@ type
|
|||||||
IMacroRegistry = interface; // Forward
|
IMacroRegistry = interface; // Forward
|
||||||
IEnvironment = interface; // Forward
|
IEnvironment = interface; // Forward
|
||||||
IExecutionStrategy = interface; // Forward
|
IExecutionStrategy = interface; // Forward
|
||||||
IExecutable = interface; // Forward
|
|
||||||
|
|
||||||
// Defines the Strategy for creating an Evaluator.
|
// Defines the Strategy for creating an Evaluator.
|
||||||
IExecutionStrategy = interface
|
IExecutionStrategy = interface
|
||||||
@@ -34,20 +33,6 @@ type
|
|||||||
property Parent: IMacroRegistry read GetParent;
|
property Parent: IMacroRegistry read GetParent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Represents a compiled, ready-to-run script.
|
|
||||||
// This encapsulates the compiled AST and its internal layout (Descriptor).
|
|
||||||
IExecutable = interface
|
|
||||||
{$region 'private'}
|
|
||||||
function GetCompiledAst: IAstNode;
|
|
||||||
function GetDescriptor: IScopeDescriptor;
|
|
||||||
{$endregion}
|
|
||||||
|
|
||||||
// The final, compiled AST (for debugging, serialization, etc.)
|
|
||||||
property CompiledAst: IAstNode read GetCompiledAst;
|
|
||||||
// The internal layout (hidden from TForm1, used by IEnvironment.Execute)
|
|
||||||
property Descriptor: IScopeDescriptor read GetDescriptor;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Defines the central environment for compilation and execution.
|
// Defines the central environment for compilation and execution.
|
||||||
IEnvironment = interface
|
IEnvironment = interface
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -57,11 +42,7 @@ type
|
|||||||
|
|
||||||
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||||
|
|
||||||
// Compiles source AST into a runnable script.
|
function Compile(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []): TDataValue.TFunc;
|
||||||
function Compile(const ANode: IAstNode): IExecutable; // Changed return type
|
|
||||||
|
|
||||||
// Executes a previously compiled script.
|
|
||||||
function Execute(const AScript: IExecutable): TDataValue;
|
|
||||||
|
|
||||||
function CreateEnvironment: IEnvironment;
|
function CreateEnvironment: IEnvironment;
|
||||||
|
|
||||||
@@ -87,10 +68,8 @@ type
|
|||||||
procedure SetStandardMode;
|
procedure SetStandardMode;
|
||||||
procedure SetDebugMode(ALog: TStrings; AShowScope: Boolean);
|
procedure SetDebugMode(ALog: TStrings; AShowScope: Boolean);
|
||||||
|
|
||||||
function Compile(const ANode: IAstNode): IExecutable;
|
function Run(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []; const Args: TArray<TDataValue> = []): TDataValue;
|
||||||
function Execute(const AScript: IExecutable): TDataValue;
|
function Compile(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []): TDataValue.TFunc;
|
||||||
|
|
||||||
function CompileAndExecute(const AScript: IAstNode): TDataValue;
|
|
||||||
|
|
||||||
procedure Define(const Name: String; const AScript: IAstNode);
|
procedure Define(const Name: String; const AScript: IAstNode);
|
||||||
|
|
||||||
@@ -141,17 +120,6 @@ type
|
|||||||
function CreateChildRegistry: IMacroRegistry;
|
function CreateChildRegistry: IMacroRegistry;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TExecutable }
|
|
||||||
TExecutable = class(TInterfacedObject, IExecutable)
|
|
||||||
private
|
|
||||||
FCompiledAst: IAstNode;
|
|
||||||
FDescriptor: IScopeDescriptor;
|
|
||||||
function GetCompiledAst: IAstNode;
|
|
||||||
function GetDescriptor: IScopeDescriptor;
|
|
||||||
public
|
|
||||||
constructor Create(ACompiledAst: IAstNode; ADescriptor: IScopeDescriptor);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TEnvironment }
|
{ TEnvironment }
|
||||||
TEnvironment = class(TInterfacedObject, IEnvironment)
|
TEnvironment = class(TInterfacedObject, IEnvironment)
|
||||||
private
|
private
|
||||||
@@ -172,8 +140,8 @@ type
|
|||||||
|
|
||||||
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
procedure SetExecutionStrategy(const AStrategy: IExecutionStrategy);
|
||||||
|
|
||||||
function Compile(const ANode: IAstNode): IExecutable;
|
function Compile(const ANode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode; overload;
|
||||||
function Execute(const AScript: IExecutable): TDataValue;
|
function Compile(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []): TDataValue.TFunc; overload;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// --- Factory Implementations ---
|
// --- Factory Implementations ---
|
||||||
@@ -211,14 +179,9 @@ begin
|
|||||||
Result := A.FEnvironment;
|
Result := A.FEnvironment;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstEnvironment.Compile(const ANode: IAstNode): IExecutable;
|
function TAstEnvironment.Compile(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []): TDataValue.TFunc;
|
||||||
begin
|
begin
|
||||||
Result := FEnvironment.Compile(ANode);
|
Result := FEnvironment.Compile(ANode, Params);
|
||||||
end;
|
|
||||||
|
|
||||||
function TAstEnvironment.CompileAndExecute(const AScript: IAstNode): TDataValue;
|
|
||||||
begin
|
|
||||||
Result := Execute(Compile(AScript));
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstEnvironment.CreateEnvironment: TAstEnvironment;
|
function TAstEnvironment.CreateEnvironment: TAstEnvironment;
|
||||||
@@ -228,12 +191,8 @@ end;
|
|||||||
|
|
||||||
procedure TAstEnvironment.Define(const Name: String; const AScript: IAstNode);
|
procedure TAstEnvironment.Define(const Name: String; const AScript: IAstNode);
|
||||||
begin
|
begin
|
||||||
RootScope.Define(Name, CompileAndExecute(AScript));
|
var exec := Compile(AScript);
|
||||||
end;
|
RootScope.Define(Name, exec([]));
|
||||||
|
|
||||||
function TAstEnvironment.Execute(const AScript: IExecutable): TDataValue;
|
|
||||||
begin
|
|
||||||
Result := FEnvironment.Execute(AScript);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstEnvironment.GetRootScope: IExecutionScope;
|
function TAstEnvironment.GetRootScope: IExecutionScope;
|
||||||
@@ -246,6 +205,16 @@ begin
|
|||||||
Result := FEnvironment.GetMacroRegistry;
|
Result := FEnvironment.GetMacroRegistry;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstEnvironment.Run(
|
||||||
|
const ANode: IAstNode;
|
||||||
|
const Params: TArray<IIdentifierNode> = [];
|
||||||
|
const Args: TArray<TDataValue> = []
|
||||||
|
): TDataValue;
|
||||||
|
begin
|
||||||
|
var exec := Compile(ANode, Params);
|
||||||
|
Result := exec(Args);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TStandardExecutionStrategy }
|
{ TStandardExecutionStrategy }
|
||||||
|
|
||||||
function TStandardExecutionStrategy.CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
function TStandardExecutionStrategy.CreateVisitor(const AScope: IExecutionScope): IEvaluatorVisitor;
|
||||||
@@ -311,25 +280,6 @@ begin
|
|||||||
Result := TMacroRegistryImpl.Create(Self);
|
Result := TMacroRegistryImpl.Create(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TExecutable }
|
|
||||||
|
|
||||||
constructor TExecutable.Create(ACompiledAst: IAstNode; ADescriptor: IScopeDescriptor);
|
|
||||||
begin
|
|
||||||
inherited Create;
|
|
||||||
FCompiledAst := ACompiledAst;
|
|
||||||
FDescriptor := ADescriptor;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TExecutable.GetCompiledAst: IAstNode;
|
|
||||||
begin
|
|
||||||
Result := FCompiledAst;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TExecutable.GetDescriptor: IScopeDescriptor;
|
|
||||||
begin
|
|
||||||
Result := FDescriptor;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TEnvironment }
|
{ TEnvironment }
|
||||||
|
|
||||||
constructor TEnvironment.Create(
|
constructor TEnvironment.Create(
|
||||||
@@ -364,56 +314,56 @@ begin
|
|||||||
FExecutionStrategy := AStrategy;
|
FExecutionStrategy := AStrategy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEnvironment.Compile(const ANode: IAstNode): IExecutable;
|
|
||||||
var
|
|
||||||
expandedAst, boundAst, typedAst, loweredAst: IAstNode;
|
|
||||||
descriptor: IScopeDescriptor;
|
|
||||||
begin
|
|
||||||
// Step 1: Expand macros
|
|
||||||
expandedAst :=
|
|
||||||
TMacroExpander.ExpandMacros(
|
|
||||||
FMacroRegistry,
|
|
||||||
FRootScope,
|
|
||||||
ANode,
|
|
||||||
function(const Scope: IExecutionScope): IEvaluatorVisitor begin Result := FExecutionStrategy.CreateVisitor(Scope); end
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 2: Bind names
|
|
||||||
boundAst := TAstBinder.Bind(FRootScope.CreateDescriptor, expandedAst, descriptor);
|
|
||||||
|
|
||||||
// Step 3: Check types
|
|
||||||
typedAst := TTypeChecker.CheckTypes(boundAst, descriptor);
|
|
||||||
|
|
||||||
// Step 4: Lowering
|
|
||||||
loweredAst := TAstLowerer.Lower(typedAst);
|
|
||||||
|
|
||||||
// Step 5: TCO
|
|
||||||
var compiledAst := TAstTCO.Optimize(loweredAst);
|
|
||||||
|
|
||||||
// Step 6: Create the executable package
|
|
||||||
Result := TExecutable.Create(compiledAst, descriptor);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TEnvironment.CreateEnvironment: IEnvironment;
|
function TEnvironment.CreateEnvironment: IEnvironment;
|
||||||
begin
|
begin
|
||||||
Result := TEnvironment.Create(TScope.CreateScope(FRootScope, nil, nil), TMacroRegistryImpl.Create(FMacroRegistry), FExecutionStrategy);
|
Result := TEnvironment.Create(TScope.CreateScope(FRootScope, nil, nil), TMacroRegistryImpl.Create(FMacroRegistry), FExecutionStrategy);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TEnvironment.Execute(const AScript: IExecutable): TDataValue;
|
function TEnvironment.Compile(const ANode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||||
var
|
|
||||||
evalScope: IExecutionScope;
|
|
||||||
visitor: IEvaluatorVisitor;
|
|
||||||
begin
|
begin
|
||||||
// 1. Create the runtime scope *directly from the descriptor*.
|
// Step 1: Expand macros
|
||||||
// This creates the raw scope with the correct slot count for local variables,
|
var cExecutionStrategy := FExecutionStrategy;
|
||||||
// parented to FRootScope.
|
var expandedAst :=
|
||||||
evalScope := AScript.Descriptor.CreateScope(FRootScope);
|
TMacroExpander.ExpandMacros(
|
||||||
|
FMacroRegistry,
|
||||||
|
FRootScope,
|
||||||
|
ANode,
|
||||||
|
function(const Scope: IExecutionScope): IEvaluatorVisitor begin Result := cExecutionStrategy.CreateVisitor(Scope); end
|
||||||
|
);
|
||||||
|
|
||||||
// 2. Use the strategy to create the final evaluator
|
// Step 2: Bind names
|
||||||
visitor := FExecutionStrategy.CreateVisitor(evalScope);
|
var boundAst := TAstBinder.Bind(FRootScope.CreateDescriptor, expandedAst, Descriptor);
|
||||||
|
|
||||||
// 3. Execute the compiled AST
|
// Step 3: Check types
|
||||||
Result := visitor.Execute(AScript.CompiledAst);
|
var typedAst := TTypeChecker.CheckTypes(boundAst, Descriptor);
|
||||||
|
|
||||||
|
// Step 4: Lowering
|
||||||
|
var loweredAst := TAstLowerer.Lower(typedAst);
|
||||||
|
|
||||||
|
// Step 5: TCO
|
||||||
|
var compiledAst := TAstTCO.Optimize(loweredAst);
|
||||||
|
|
||||||
|
Result := compiledAst;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TEnvironment.Compile(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []): TDataValue.TFunc;
|
||||||
|
var
|
||||||
|
desc: IScopeDescriptor;
|
||||||
|
begin
|
||||||
|
var prg := TAst.LambdaExpr(Params, ANode);
|
||||||
|
|
||||||
|
var compiled := Compile(prg, desc);
|
||||||
|
|
||||||
|
var visitor := FExecutionStrategy.CreateVisitor(desc.CreateScope(FRootScope));
|
||||||
|
|
||||||
|
var func := compiled.Accept(visitor).AsMethod;
|
||||||
|
|
||||||
|
Result :=
|
||||||
|
function(const Args: TArray<TDataValue>): TDataValue
|
||||||
|
begin
|
||||||
|
Result := func(Args);
|
||||||
|
TEvaluatorVisitor.HandleTCO(Result);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ type
|
|||||||
private
|
private
|
||||||
FScope: IExecutionScope;
|
FScope: IExecutionScope;
|
||||||
class var
|
class var
|
||||||
procedure HandleTCO(var ResultValue: TDataValue);
|
|
||||||
|
|
||||||
protected
|
protected
|
||||||
// IAstVisitor methods made virtual for TDebugEvaluatorVisitor to override
|
// IAstVisitor methods made virtual for TDebugEvaluatorVisitor to override
|
||||||
@@ -60,6 +59,7 @@ type
|
|||||||
|
|
||||||
// Executes an AST with proper TCO handling. This is the main entry point.
|
// Executes an AST with proper TCO handling. This is the main entry point.
|
||||||
function Execute(const RootNode: IAstNode): TDataValue;
|
function Execute(const RootNode: IAstNode): TDataValue;
|
||||||
|
class procedure HandleTCO(var ResultValue: TDataValue); static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -149,7 +149,7 @@ begin
|
|||||||
Result := function(const AScope: IExecutionScope): IEvaluatorVisitor begin Result := TEvaluatorVisitor.Create(AScope); end;
|
Result := function(const AScope: IExecutionScope): IEvaluatorVisitor begin Result := TEvaluatorVisitor.Create(AScope); end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TEvaluatorVisitor.HandleTCO(var ResultValue: TDataValue);
|
class procedure TEvaluatorVisitor.HandleTCO(var ResultValue: TDataValue);
|
||||||
begin
|
begin
|
||||||
// This is the central trampoline loop for Tail Call Optimization.
|
// This is the central trampoline loop for Tail Call Optimization.
|
||||||
// It runs as long as the evaluation returns a thunk.
|
// It runs as long as the evaluation returns a thunk.
|
||||||
|
|||||||
Reference in New Issue
Block a user