Binding
This commit is contained in:
@@ -8,6 +8,7 @@ uses
|
||||
System.Generics.Collections,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast;
|
||||
|
||||
type
|
||||
@@ -80,7 +81,6 @@ uses
|
||||
System.TypInfo,
|
||||
Myc.Data.Decimal,
|
||||
Myc.Data.Series,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Printer,
|
||||
Myc.Data.Scalar.JSON;
|
||||
|
||||
@@ -92,13 +92,16 @@ type
|
||||
TClosureValue = class(TInterfacedObject, IEvaluatorClosure)
|
||||
private
|
||||
FBody: IExpressionNode;
|
||||
FParameters: TArray<IIdentifierNode>;
|
||||
FClosureScope: IExecutionScope;
|
||||
FLambdaNode: ILambdaExpressionNode;
|
||||
function GetBody: IExpressionNode;
|
||||
function GetParameters: TArray<IIdentifierNode>;
|
||||
function GetClosureScope: IExecutionScope;
|
||||
function GetLambdaNode: ILambdaExpressionNode;
|
||||
public
|
||||
constructor Create(ABody: IExpressionNode; const AParameters: TArray<IIdentifierNode>; const AClosureScope: IExecutionScope);
|
||||
constructor Create(const ALambdaNode: ILambdaExpressionNode; const AClosureScope: IExecutionScope);
|
||||
property ClosureScope: IExecutionScope read GetClosureScope;
|
||||
property LambdaNode: ILambdaExpressionNode read GetLambdaNode;
|
||||
end;
|
||||
|
||||
// Concrete implementation of IEvaluatorClosure for native Delphi functions.
|
||||
@@ -203,11 +206,11 @@ end;
|
||||
|
||||
{ TClosureValue }
|
||||
|
||||
constructor TClosureValue.Create(ABody: IExpressionNode; const AParameters: TArray<IIdentifierNode>; const AClosureScope: IExecutionScope);
|
||||
constructor TClosureValue.Create(const ALambdaNode: ILambdaExpressionNode; const AClosureScope: IExecutionScope);
|
||||
begin
|
||||
inherited Create;
|
||||
FBody := ABody;
|
||||
FParameters := AParameters;
|
||||
FLambdaNode := ALambdaNode;
|
||||
FBody := ALambdaNode.Body;
|
||||
FClosureScope := AClosureScope;
|
||||
end;
|
||||
|
||||
@@ -221,9 +224,14 @@ begin
|
||||
Result := FClosureScope;
|
||||
end;
|
||||
|
||||
function TClosureValue.GetLambdaNode: ILambdaExpressionNode;
|
||||
begin
|
||||
Result := FLambdaNode;
|
||||
end;
|
||||
|
||||
function TClosureValue.GetParameters: TArray<IIdentifierNode>;
|
||||
begin
|
||||
Result := FParameters;
|
||||
Result := FLambdaNode.Parameters;
|
||||
end;
|
||||
|
||||
{ TNativeClosure }
|
||||
@@ -284,14 +292,9 @@ function TEvaluatorVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): T
|
||||
var
|
||||
itemValue, lookbackValue, seriesVar: TAstValue;
|
||||
lookback: Int64;
|
||||
depth, index: Integer;
|
||||
begin
|
||||
// The target series must have been resolved by the binder.
|
||||
if not Node.Series.Resolve(depth, index) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Identifier could not be resolved: "%s". This should have been caught by the binder.', [Node.Series.Name]);
|
||||
|
||||
seriesVar := FScope.GetValue(depth, index);
|
||||
seriesVar := FScope.GetValue(Node.Series.Resolve);
|
||||
itemValue := Node.Value.Accept(Self);
|
||||
lookback := -1;
|
||||
|
||||
@@ -340,18 +343,9 @@ begin
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitAssignment(const Node: IAssignmentNode): TAstValue;
|
||||
var
|
||||
value: TAstValue;
|
||||
depth, index: Integer;
|
||||
begin
|
||||
value := Node.Value.Accept(Self);
|
||||
|
||||
if not Node.Identifier.Resolve(depth, index) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Identifier could not be resolved: "%s". This should have been caught by the binder.', [Node.Identifier.Name]);
|
||||
|
||||
FScope.AssignValue(depth, index, value);
|
||||
Result := value;
|
||||
Result := Node.Value.Accept(Self);
|
||||
FScope.AssignValue(Node.Identifier.Resolve, Result);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TAstValue;
|
||||
@@ -383,15 +377,8 @@ begin
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): TAstValue;
|
||||
var
|
||||
depth, index: Integer;
|
||||
begin
|
||||
if Node.Resolve(depth, index) then
|
||||
Result := FScope.GetValue(depth, index)
|
||||
else
|
||||
// This should not happen if the binder ran successfully.
|
||||
raise EArgumentException
|
||||
.CreateFmt('Identifier could not be resolved: "%s". This should have been caught by the binder.', [Node.Name]);
|
||||
Result := FScope.GetValue(Node.Resolve)
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIndexer(const Node: IIndexerNode): TAstValue;
|
||||
@@ -488,16 +475,14 @@ begin
|
||||
else
|
||||
value := TAstValue.Void;
|
||||
|
||||
FScope.Define(Node.Identifier.Name, value);
|
||||
FScope.AssignValue(Node.Identifier.Resolve, value);
|
||||
|
||||
Result := value;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
|
||||
var
|
||||
closureImpl: IEvaluatorClosure;
|
||||
begin
|
||||
closureImpl := TClosureValue.Create(Node.Body, Node.Parameters, FScope);
|
||||
Result := TAstValue.FromClosure(closureImpl);
|
||||
Result := TAstValue.FromClosure(TClosureValue.Create(Node, FScope));
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
|
||||
@@ -505,9 +490,9 @@ var
|
||||
calleeValue: TAstValue;
|
||||
closure: IEvaluatorClosure;
|
||||
i: Integer;
|
||||
argValues: TArray<TAstValue>;
|
||||
callScope: IExecutionScope;
|
||||
innerVisitor: IAstVisitor;
|
||||
descriptor: IScopeDescriptor;
|
||||
begin
|
||||
calleeValue := Node.Callee.Accept(Self);
|
||||
|
||||
@@ -518,11 +503,10 @@ begin
|
||||
|
||||
if closure is TNativeClosure then
|
||||
begin
|
||||
var argValues: TArray<TAstValue>;
|
||||
SetLength(argValues, Node.Arguments.Count);
|
||||
for i := 0 to Node.Arguments.Count - 1 do
|
||||
begin
|
||||
argValues[i] := Node.Arguments[i].Accept(Self);
|
||||
end;
|
||||
Result := (closure as TNativeClosure).Method(argValues);
|
||||
end
|
||||
else if closure is TClosureValue then
|
||||
@@ -531,20 +515,17 @@ begin
|
||||
raise EArgumentException
|
||||
.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(closure.Parameters), Node.Arguments.Count]);
|
||||
|
||||
callScope := TExecutionScope.Create(closure.ClosureScope);
|
||||
descriptor := (closure as TClosureValue).LambdaNode.ScopeDescriptor;
|
||||
if not Assigned(descriptor) then
|
||||
raise EParserError.Create('Lambda has no scope descriptor. Did the binder run?');
|
||||
|
||||
// The order of definitions must exactly match the binder's order.
|
||||
callScope := descriptor.Instantiate(closure.ClosureScope);
|
||||
callScope.SetValueByIndex(0, calleeValue);
|
||||
|
||||
// Define 'Self' first.
|
||||
callScope.Define('Self', calleeValue);
|
||||
|
||||
// 2. Then, define the parameters.
|
||||
for i := 0 to Node.Arguments.Count - 1 do
|
||||
begin
|
||||
var argValue := Node.Arguments[i].Accept(Self);
|
||||
callScope.Define(closure.Parameters[i].Name, argValue);
|
||||
end;
|
||||
callScope.SetValueByIndex(closure.Parameters[i].Resolve.SlotIndex, Node.Arguments[i].Accept(Self));
|
||||
|
||||
// 3. Führe den Körper der Funktion im neuen Scope aus.
|
||||
innerVisitor := Self.CreateVisitorForScope(callScope);
|
||||
Result := closure.Body.Accept(innerVisitor);
|
||||
end
|
||||
@@ -914,6 +895,7 @@ begin
|
||||
|
||||
AppendMultiline((pp as TPrettyPrintVisitor).GetResult);
|
||||
|
||||
ShowScope;
|
||||
Result := inherited VisitLambdaExpression(Node);
|
||||
finally
|
||||
Unindent;
|
||||
@@ -926,6 +908,7 @@ begin
|
||||
AppendLine('FunctionCall{');
|
||||
Indent;
|
||||
try
|
||||
ShowScope;
|
||||
Result := inherited VisitFunctionCall(Node);
|
||||
finally
|
||||
Unindent;
|
||||
@@ -938,8 +921,8 @@ begin
|
||||
AppendLine('Block{');
|
||||
Indent;
|
||||
try
|
||||
ShowScope;
|
||||
Result := inherited VisitBlockExpression(Node);
|
||||
ShowScope;
|
||||
finally
|
||||
Unindent;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user