Scope cells refactoring

This commit is contained in:
Michael Schimmel
2025-09-05 12:46:24 +02:00
parent edf8329b28
commit 100646c7d8
5 changed files with 61 additions and 117 deletions
+3 -3
View File
@@ -394,7 +394,7 @@ end;
procedure TForm1.OHLCButtonClick(Sender: TObject);
const
numRecs = 100;
numRecs = 1000;
lookback = 50;
smaSlowLength = 20;
smaFastLength = 10;
@@ -561,12 +561,12 @@ begin
if series.AsRecordSeries.Value.TotalCount >= smaSlowLength then
begin
// Update the 'current_series' value in the scope using the FAST index-based assignment
scope[seriesAddress] := series;
scope[seriesAddress].Value := series;
// Execute the PRE-BOUND call AST
var resultValue := callAst.Accept(visitor);
if i < smaSlowLength + 50 then
if i mod 50 = 0 then
begin
Memo1.Lines.Add(Format('Tick %d/%d: Close = %.2f, Signal = %s', [i, numRecs, ohlcvRec.Close, resultValue.ToString]));
Application.ProcessMessages;
+6 -6
View File
@@ -309,7 +309,7 @@ var
lookback: Int64;
begin
// The target series must have been resolved by the binder.
seriesVar := FScope[Node.Series.Address];
seriesVar := FScope[Node.Series.Address].Value;
itemValue := Node.Value.Accept(Self);
lookback := -1;
@@ -360,7 +360,7 @@ end;
function TEvaluatorVisitor.VisitAssignment(const Node: IAssignmentNode): TAstValue;
begin
Result := Node.Value.Accept(Self);
FScope[Node.Identifier.Address] := Result;
FScope[Node.Identifier.Address].Value := Result;
end;
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TAstValue;
@@ -393,7 +393,7 @@ end;
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): TAstValue;
begin
Result := FScope[Node.Address];
Result := FScope[Node.Address].Value;
end;
function TEvaluatorVisitor.VisitIndexer(const Node: IIndexerNode): TAstValue;
@@ -490,7 +490,7 @@ begin
else
value := TAstValue.Void;
FScope[Node.Identifier.Address] := value;
FScope[Node.Identifier.Address].Value := value;
Result := value;
end;
@@ -559,12 +559,12 @@ begin
// Slot 0 is 'Self'.
adr.SlotIndex := 0;
callScope.Values[adr] := calleeValue;
callScope[adr].Value := calleeValue;
for i := 0 to Node.Arguments.Count - 1 do
begin
adr.SlotIndex := closure.Parameters[i].Address.SlotIndex;
callScope.Values[adr] := Node.Arguments[i].Accept(Self);
callScope[adr].Value := Node.Arguments[i].Accept(Self);
end;
Result := closure.Body.Accept(CreateVisitorForScope(callScope));
+22 -4
View File
@@ -116,13 +116,14 @@ type
Kind: TAddressKind;
ScopeDepth: Integer;
SlotIndex: Integer;
Name: String;
constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer; const AName: String);
class operator Initialize(out Dest: TResolvedAddress);
end;
IExecutionScope = interface
{$region 'private'}
function GetParent: IExecutionScope;
function GetValues(const Address: TResolvedAddress): TAstValue;
procedure SetValues(const Address: TResolvedAddress; const Value: TAstValue);
function GetCell(const Address: TResolvedAddress): IValueCell;
{$endregion}
@@ -130,8 +131,7 @@ type
function Dump: string;
procedure Clear;
property Cell[const Address: TResolvedAddress]: IValueCell read GetCell;
property Values[const Address: TResolvedAddress]: TAstValue read GetValues write SetValues; default;
property Cell[const Address: TResolvedAddress]: IValueCell read GetCell; default;
property Parent: IExecutionScope read GetParent;
end;
@@ -484,6 +484,24 @@ begin
Result := Default(TAstValue);
end;
{ TResolvedAddress }
constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer; const AName: String);
begin
Kind := AKind;
ScopeDepth := AScopeDepth;
SlotIndex := ASlotIndex;
Name := AName;
end;
class operator TResolvedAddress.Initialize(out Dest: TResolvedAddress);
begin
Dest.Kind := akUnresolved;
Dest.ScopeDepth := -1;
Dest.SlotIndex := -1;
Dest.Name := 'unresolved';
end;
{ TBinaryOperatorHelper }
function TBinaryOperatorHelper.ToString: string;
+26 -88
View File
@@ -17,8 +17,6 @@ type
FCapturedUpvalues: TArray<IValueCell>;
FNameToIndex: TDictionary<string, Integer>;
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
function GetValues(const Address: TResolvedAddress): TAstValue;
procedure SetValues(const Address: TResolvedAddress; const Value: TAstValue);
function GetParent: IExecutionScope;
function GetCell(const Address: TResolvedAddress): IValueCell;
public
@@ -63,8 +61,6 @@ end;
{ TExecutionScope }
{ TExecutionScope }
constructor TExecutionScope.Create(
AParent: IExecutionScope;
const ADescriptor: IScopeDescriptor;
@@ -99,23 +95,34 @@ begin
end;
function TExecutionScope.GetCell(const Address: TResolvedAddress): IValueCell;
var
targetScope: TExecutionScope;
i: Integer;
begin
// Cells can only be retrieved from local/parent scopes.
if Address.Kind <> akLocalOrParent then
raise EInvalidOpException.Create('Cannot get a cell for a non-local address.');
targetScope := Self;
for i := 1 to Address.ScopeDepth do
begin
targetScope := targetScope.Parent as TExecutionScope;
Assert(Assigned(targetScope), 'Invalid scope depth during cell retrieval.');
case Address.Kind of
akUpvalue:
begin
Assert(Assigned(FCapturedUpvalues), 'Attempt to access an upvalue in a scope with no closure context.');
Assert(
(Address.SlotIndex >= 0) and (Address.SlotIndex < Length(FCapturedUpvalues)),
'Invalid upvalue index during value retrieval.'
);
Result := FCapturedUpvalues[Address.SlotIndex];
end;
akLocalOrParent:
begin
var targetScope := Self;
for var i := 1 to Address.ScopeDepth do
begin
targetScope := targetScope.Parent as TExecutionScope;
Assert(Assigned(targetScope), 'Invalid scope depth during value retrieval.');
end;
Assert(
(Address.SlotIndex >= 0) and (Address.SlotIndex < Length(targetScope.Values)),
'Invalid scope index during value retrieval.'
);
Result := targetScope.Values[Address.SlotIndex];
end;
else
raise EInvalidOpException.Create('Cannot get value for an unresolved address.');
end;
Assert((Address.SlotIndex >= 0) and (Address.SlotIndex < Length(targetScope.FValues)), 'Invalid scope index during cell retrieval.');
Result := targetScope.FValues[Address.SlotIndex];
end;
function TExecutionScope.GetParent: IExecutionScope;
@@ -189,73 +196,4 @@ begin
end;
end;
function TExecutionScope.GetValues(const Address: TResolvedAddress): TAstValue;
var
targetScope: TExecutionScope;
i: Integer;
begin
case Address.Kind of
akUpvalue:
begin
Assert(Assigned(FCapturedUpvalues), 'Attempt to access an upvalue in a scope with no closure context.');
Assert(
(Address.SlotIndex >= 0) and (Address.SlotIndex < Length(FCapturedUpvalues)),
'Invalid upvalue index during value retrieval.'
);
Result := FCapturedUpvalues[Address.SlotIndex].Value;
end;
akLocalOrParent:
begin
targetScope := Self;
for i := 1 to Address.ScopeDepth do
begin
targetScope := targetScope.Parent as TExecutionScope;
Assert(Assigned(targetScope), 'Invalid scope depth during value retrieval.');
end;
Assert(
(Address.SlotIndex >= 0) and (Address.SlotIndex < Length(targetScope.Values)),
'Invalid scope index during value retrieval.'
);
Result := targetScope.Values[Address.SlotIndex].Value;
end;
else
raise EInvalidOpException.Create('Cannot get value for an unresolved address.');
end;
end;
procedure TExecutionScope.SetValues(const Address: TResolvedAddress; const Value: TAstValue);
var
targetScope: IExecutionScope;
i: Integer;
begin
case Address.Kind of
akUpvalue:
begin
Assert(Assigned(FCapturedUpvalues), 'Attempt to access an upvalue in a scope with no closure context.');
Assert(
(Address.SlotIndex >= 0) and (Address.SlotIndex < Length(FCapturedUpvalues)),
'Invalid upvalue index during value assignment.'
);
FCapturedUpvalues[Address.SlotIndex].Value := Value;
end;
akLocalOrParent:
begin
targetScope := Self;
for i := 0 to Address.ScopeDepth - 1 do
begin
if Assigned(targetScope) then
targetScope := targetScope.Parent
else
raise EInvalidOpException.Create('Invalid scope depth during assignment.');
end;
if Address.SlotIndex >= Length((targetScope as TExecutionScope).Values) then
raise EInvalidOpException.Create('Invalid scope index during assignment.');
(targetScope as TExecutionScope).Values[Address.SlotIndex].Value := Value;
end;
else
raise EInvalidOpException.Create('Cannot set value for an unresolved address.');
end;
end;
end.
+4 -16
View File
@@ -436,10 +436,6 @@ constructor TIdentifierNode.Create(AName: string);
begin
inherited Create;
FName := AName;
// Default to unresolved.
FResolvedAddress.Kind := akUnresolved;
FResolvedAddress.ScopeDepth := -1;
FResolvedAddress.SlotIndex := -1;
end;
function TIdentifierNode.Accept(const Visitor: IAstVisitor): TAstValue;
@@ -904,9 +900,7 @@ begin
upvalueMap := FUpvalueMapStack.Peek;
upvalueNodes := FUpvalueNodesStack.Peek;
originalAddress.Kind := akLocalOrParent;
originalAddress.ScopeDepth := originalDepth;
originalAddress.SlotIndex := originalIndex;
originalAddress.Create(akLocalOrParent, originalDepth, originalIndex, identNode.Name);
if not upvalueMap.TryGetValue(originalAddress, upvalueIndex) then
begin
@@ -915,15 +909,11 @@ begin
upvalueNodes.Add(identNode);
end;
identNode.FResolvedAddress.Kind := akUpvalue;
identNode.FResolvedAddress.SlotIndex := upvalueIndex;
identNode.FResolvedAddress.ScopeDepth := 0;
identNode.FResolvedAddress.Create(akUpvalue, 0, upvalueIndex, identNode.Name);
end
else
begin
identNode.FResolvedAddress.Kind := akLocalOrParent;
identNode.FResolvedAddress.ScopeDepth := originalDepth;
identNode.FResolvedAddress.SlotIndex := originalIndex;
identNode.FResolvedAddress.Create(akLocalOrParent, originalDepth, originalIndex, identNode.Name);
end;
end
else
@@ -989,9 +979,7 @@ begin
Node.Initializer.Accept(Self);
slotIndex := (FCurrentDescriptor as TScopeDescriptor).Define(Node.Identifier.Name);
identNode.FResolvedAddress.Kind := akLocalOrParent;
identNode.FResolvedAddress.ScopeDepth := 0;
identNode.FResolvedAddress.SlotIndex := slotIndex;
identNode.FResolvedAddress.Create(akLocalOrParent, 0, slotIndex, Node.Identifier.Name);
end;
{ TAst }