Refactoring + Panning in Workspace

This commit is contained in:
Michael Schimmel
2025-09-05 21:00:07 +02:00
parent f2357a543e
commit 6b77391e91
6 changed files with 253 additions and 145 deletions
+37 -104
View File
@@ -122,61 +122,6 @@ type
property Method: TNativeFunction read FMethod;
end;
// --- Helper Functions ---
function ScalarKindToString(AKind: TScalarKind): string;
begin
case AKind of
skInteger: Result := 'integer';
skInt64: Result := 'int64';
skUInt64: Result := 'uint64';
skSingle: Result := 'single';
skDouble: Result := 'double';
skDateTime: Result := 'datetime';
skTimestamp: Result := 'timestamp';
skBoolean: Result := 'boolean';
skChar: Result := 'char';
skPChar: Result := 'pchar';
skString: Result := 'string';
skBytes: Result := 'bytes';
skDecimal: Result := 'decimal';
else
Result := 'unknown';
end;
end;
function StringToScalarKind(const AName: string): TScalarKind;
begin
if SameText(AName, 'integer') then
Result := skInteger
else if SameText(AName, 'int64') then
Result := skInt64
else if SameText(AName, 'uint64') then
Result := skUInt64
else if SameText(AName, 'single') then
Result := skSingle
else if SameText(AName, 'double') then
Result := skDouble
else if SameText(AName, 'datetime') then
Result := skDateTime
else if SameText(AName, 'timestamp') then
Result := skTimestamp
else if SameText(AName, 'boolean') then
Result := skBoolean
else if SameText(AName, 'char') then
Result := skChar
else if SameText(AName, 'pchar') then
Result := skPChar
else if SameText(AName, 'string') then
Result := skString
else if SameText(AName, 'bytes') then
Result := skBytes
else if SameText(AName, 'decimal') then
Result := skDecimal
else
raise EArgumentException.CreateFmt('Unknown scalar type name: "%s"', [AName]);
end;
// --- Native Functions Implementation ---
function NativeCreateRecordSeries(const Args: TArray<TAstValue>): TAstValue;
@@ -201,13 +146,10 @@ end;
// --- Registration Procedure ---
procedure RegisterNativeFunctions(const AScope: IExecutionScope);
var
closure: TAstValue.IClosure;
begin
// Use 'Define' to clearly state that we are adding a new variable
// to the global scope before the binder runs.
closure := TNativeClosure.Create(NativeCreateRecordSeries);
AScope.Define('CreateRecordSeries', TAstValue.FromClosure(closure));
AScope.Define('CreateRecordSeries', TNativeClosure.Create(NativeCreateRecordSeries));
end;
{ TClosureValue }
@@ -335,9 +277,8 @@ begin
with seriesVar.AsSeries.Value do
begin
if (itemValue.AsScalar.Kind <> Kind) then
raise EArgumentException.CreateFmt(
'Type mismatch: Cannot add %s to a series of %s.',
[ScalarKindToString(itemValue.AsScalar.Kind), ScalarKindToString(Kind)]);
raise EArgumentException
.CreateFmt('Type mismatch: Cannot add %s to a series of %s.', [itemValue.AsScalar.Kind.ToString, Kind.ToString]);
Items.Add(itemValue.AsScalar.Value, lookback);
end;
@@ -365,7 +306,7 @@ end;
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TAstValue;
begin
Result := TAstValue.FromScalar(Node.Value);
Result := Node.Value;
end;
function TEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TAstValue;
@@ -385,7 +326,7 @@ begin
end
else
begin
var scalarKind := StringToScalarKind(def);
var scalarKind := TScalar.StringToKind(def);
var scalarSeries := TScalarSeries.Create(scalarKind, Default(TSeries<TScalarValue>));
Result := TAstValue.FromSeries(scalarSeries);
end;
@@ -424,7 +365,7 @@ begin
if (index < 0) or (index >= Items.TotalCount) then
raise EArgumentException.CreateFmt('Index %d is out of bounds for series with %d elements.', [index, Items.TotalCount]);
Result := TAstValue.FromScalar(TScalar.Create(Kind, Items[Integer(index)]));
Result := TScalar.Create(Kind, Items[Integer(index)]);
end;
end;
avkRecordSeries:
@@ -443,8 +384,7 @@ begin
raise EArgumentException
.CreateFmt('Index %d is out of bounds for member series with %d elements.', [index, memberSeries.Count]);
var scalarValue := memberSeries.Items[Integer(index)];
Result := TAstValue.FromScalar(scalarValue);
Result := memberSeries.Items[Integer(index)];
end;
else
raise EArgumentException.Create('Indexer `[]` is not supported for this value type.');
@@ -465,17 +405,17 @@ begin
with baseValue.AsSeries.Value do
begin
if SameText(memberName, 'Count') then
Result := TAstValue.FromScalar(TScalar.FromInt64(Items.Count))
Result := TScalar.FromInt64(Items.Count)
else if SameText(memberName, 'TotalCount') then
Result := TAstValue.FromScalar(TScalar.FromInt64(Items.TotalCount))
Result := TScalar.FromInt64(Items.TotalCount)
else if SameText(memberName, 'Kind') then
Result := TAstValue.FromText(ScalarKindToString(Kind))
Result := Kind.ToString
else
raise EArgumentException.CreateFmt('Member "%s" not found on TScalarSeries.', [memberName]);
end;
end;
avkRecordSeries: Result := TAstValue.FromMemberSeries(baseValue.AsRecordSeries.Value.CreateMemberSeries(memberName));
avkRecord: Result := TAstValue.FromScalar(baseValue.AsRecord.Items[memberName]);
avkRecord: Result := baseValue.AsRecord.Items[memberName];
else
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
end;
@@ -507,16 +447,9 @@ begin
sourceAddresses := Node.Upvalues;
SetLength(capturedCells, Length(sourceAddresses));
for i := 0 to High(sourceAddresses) do
begin
sourceAddr := sourceAddresses[i];
// The binder gives the depth relative to the lambda's
// inner scope. The evaluator is in the outer scope, so we adjust the
// depth by -1 to find the cell in the current context.
dec(sourceAddr.ScopeDepth);
capturedCells[i] := FScope.GetCell(sourceAddr);
end;
capturedCells[i] := FScope.GetCell(sourceAddresses[i]);
Result := TAstValue.FromClosure(TClosureValue.Create(Node, FScope, capturedCells));
Result := TClosureValue.Create(Node, FScope, capturedCells);
end;
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
@@ -610,16 +543,16 @@ begin
var leftVal := leftScalar.Value.AsInt64;
var rightVal := rightScalar.Value.AsInt64;
case Node.Operator of
boAdd: Result := TAstValue.FromScalar(TScalar.FromInt64(leftVal + rightVal));
boSubtract: Result := TAstValue.FromScalar(TScalar.FromInt64(leftVal - rightVal));
boMultiply: Result := TAstValue.FromScalar(TScalar.FromInt64(leftVal * rightVal));
boDivide: Result := TAstValue.FromScalar(TScalar.FromInt64(leftVal div rightVal));
boEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal = rightVal));
boNotEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal <> rightVal));
boLess: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal < rightVal));
boGreater: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal > rightVal));
boLessOrEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal <= rightVal));
boGreaterOrEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal >= rightVal));
boAdd: Result := TScalar.FromInt64(leftVal + rightVal);
boSubtract: Result := TScalar.FromInt64(leftVal - rightVal);
boMultiply: Result := TScalar.FromInt64(leftVal * rightVal);
boDivide: Result := TScalar.FromInt64(leftVal div rightVal);
boEqual: Result := TScalar.FromBoolean(leftVal = rightVal);
boNotEqual: Result := TScalar.FromBoolean(leftVal <> rightVal);
boLess: Result := TScalar.FromBoolean(leftVal < rightVal);
boGreater: Result := TScalar.FromBoolean(leftVal > rightVal);
boLessOrEqual: Result := TScalar.FromBoolean(leftVal <= rightVal);
boGreaterOrEqual: Result := TScalar.FromBoolean(leftVal >= rightVal);
else
raise ENotSupportedException.Create('Operator not supported for Int64.');
end;
@@ -629,16 +562,16 @@ begin
var leftVal := leftScalar.Value.AsDouble;
var rightVal := rightScalar.Value.AsDouble;
case Node.Operator of
boAdd: Result := TAstValue.FromScalar(TScalar.FromDouble(leftVal + rightVal));
boSubtract: Result := TAstValue.FromScalar(TScalar.FromDouble(leftVal - rightVal));
boMultiply: Result := TAstValue.FromScalar(TScalar.FromDouble(leftVal * rightVal));
boDivide: Result := TAstValue.FromScalar(TScalar.FromDouble(leftVal / rightVal));
boEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal = rightVal));
boNotEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal <> rightVal));
boLess: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal < rightVal));
boGreater: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal > rightVal));
boLessOrEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal <= rightVal));
boGreaterOrEqual: Result := TAstValue.FromScalar(TScalar.FromBoolean(leftVal >= rightVal));
boAdd: Result := TScalar.FromDouble(leftVal + rightVal);
boSubtract: Result := TScalar.FromDouble(leftVal - rightVal);
boMultiply: Result := TScalar.FromDouble(leftVal * rightVal);
boDivide: Result := TScalar.FromDouble(leftVal / rightVal);
boEqual: Result := TScalar.FromBoolean(leftVal = rightVal);
boNotEqual: Result := TScalar.FromBoolean(leftVal <> rightVal);
boLess: Result := TScalar.FromBoolean(leftVal < rightVal);
boGreater: Result := TScalar.FromBoolean(leftVal > rightVal);
boLessOrEqual: Result := TScalar.FromBoolean(leftVal <= rightVal);
boGreaterOrEqual: Result := TScalar.FromBoolean(leftVal >= rightVal);
else
raise ENotSupportedException.Create('Operator not supported for Double.');
end;
@@ -662,15 +595,15 @@ begin
raise ENotSupportedException.Create('Unary "-" is only supported for scalar types.');
rightScalar := rightValue.AsScalar;
case rightScalar.Kind of
skInt64: Result := TAstValue.FromScalar(TScalar.FromInt64(-rightScalar.Value.AsInt64));
skDouble: Result := TAstValue.FromScalar(TScalar.FromDouble(-rightScalar.Value.AsDouble));
skInt64: Result := TScalar.FromInt64(-rightScalar.Value.AsInt64);
skDouble: Result := TScalar.FromDouble(-rightScalar.Value.AsDouble);
else
raise ENotSupportedException.Create('Unary "-" is not supported for this scalar type.');
end;
end;
uoNot:
begin
Result := TAstValue.FromScalar(TScalar.FromBoolean(not IsTruthy(rightValue)));
Result := TScalar.FromBoolean(not IsTruthy(rightValue));
end;
else
raise ENotSupportedException.Create('Unary operator not supported');
@@ -731,7 +664,7 @@ begin
raise EArgumentException.CreateFmt('Cannot get length of type %s.', [GetEnumName(TypeInfo(TAstValueKind), Ord(seriesValue.Kind))]);
end;
Result := TAstValue.FromScalar(TScalar.FromInt64(len));
Result := TScalar.FromInt64(len);
end;
{ TDebugEvaluatorVisitor }
+8 -11
View File
@@ -80,9 +80,9 @@ type
public
class operator Initialize(out Dest: TAstValue);
class function Void: TAstValue; inline; static;
class function FromScalar(const AValue: TScalar): TAstValue; inline; static;
class function FromClosure(const AValue: TAstValue.IClosure): TAstValue; inline; static;
class function FromText(const AValue: String): TAstValue; inline; static;
class operator Implicit(const AValue: TScalar): TAstValue; overload; inline;
class operator Implicit(const AValue: TAstValue.IClosure): TAstValue; overload; inline;
class operator Implicit(const AValue: String): TAstValue; overload; inline;
class function FromSeries(const [ref] AValue: TScalarSeries): TAstValue; static; inline;
class function FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TAstValue; static; inline;
class function FromRecord(const [ref] AValue: TScalarRecord): TAstValue; static; inline;
@@ -116,8 +116,7 @@ type
Kind: TAddressKind;
ScopeDepth: Integer;
SlotIndex: Integer;
Name: String;
constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer; const AName: String);
constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
class operator Initialize(out Dest: TResolvedAddress);
end;
@@ -402,7 +401,7 @@ begin
Result := (FInterface as TVal<String>).Value;
end;
class function TAstValue.FromClosure(const AValue: TAstValue.IClosure): TAstValue;
class operator TAstValue.Implicit(const AValue: TAstValue.IClosure): TAstValue;
begin
Result.FKind := avkClosure;
Result.FInterface := AValue;
@@ -430,7 +429,7 @@ begin
Result.FScalar := Default(TScalar);
end;
class function TAstValue.FromScalar(const AValue: TScalar): TAstValue;
class operator TAstValue.Implicit(const AValue: TScalar): TAstValue;
begin
Result.FKind := avkScalar;
Result.FScalar := AValue;
@@ -444,7 +443,7 @@ begin
Result.FScalar := Default(TScalar);
end;
class function TAstValue.FromText(const AValue: String): TAstValue;
class operator TAstValue.Implicit(const AValue: String): TAstValue;
begin
Result.FKind := avkText;
Result.FInterface := TVal<String>.Create(AValue);
@@ -484,12 +483,11 @@ end;
{ TResolvedAddress }
constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer; const AName: String);
constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
begin
Kind := AKind;
ScopeDepth := AScopeDepth;
SlotIndex := ASlotIndex;
Name := AName;
end;
class operator TResolvedAddress.Initialize(out Dest: TResolvedAddress);
@@ -497,7 +495,6 @@ begin
Dest.Kind := akUnresolved;
Dest.ScopeDepth := -1;
Dest.SlotIndex := -1;
Dest.Name := 'unresolved';
end;
{ TBinaryOperatorHelper }
+1 -1
View File
@@ -299,7 +299,7 @@ var
begin
// Get the string representation of the series identifier by visiting the node.
seriesStr := Node.Series.Accept(Self).ToString;
Result := TAstValue.FromText(Format('length(%s)', [seriesStr]));
Result := Format('length(%s)', [seriesStr]);
end;
end.
+12 -12
View File
@@ -86,7 +86,7 @@ type
constructor Create(AParent: IScopeDescriptor);
destructor Destroy; override;
function Define(const Name: string): Integer;
function FindSymbol(const Name: string; out Index: Integer; out Depth: Integer): Boolean;
function FindSymbol(const Name: string; out Depth, Index: Integer): Boolean;
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
procedure PopulateFromScope(const AScope: IExecutionScope);
property Symbols: TDictionary<string, Integer> read FSymbols;
@@ -365,7 +365,7 @@ begin
FSymbols.Add(Name, Result);
end;
function TScopeDescriptor.FindSymbol(const Name: string; out Index: Integer; out Depth: Integer): Boolean;
function TScopeDescriptor.FindSymbol(const Name: string; out Depth, Index: Integer): Boolean;
var
currentDescriptor: IScopeDescriptor;
begin
@@ -579,7 +579,6 @@ begin
FBody := ABody;
FParameters := AParameters;
FScopeDescriptor := nil;
FUpvalues := []; // Initialize new field
end;
function TLambdaExpressionNode.GetUpvalues: TArray<TResolvedAddress>;
@@ -866,7 +865,7 @@ end;
function TBinder.VisitIdentifier(const Node: IIdentifierNode): TAstValue;
var
originalDepth, originalIndex: Integer;
depth, idx: Integer;
identNode: TIdentifierNode;
upvalueMap: TDictionary<TResolvedAddress, Integer>;
upvalueNodes: TList<IIdentifierNode>;
@@ -877,14 +876,17 @@ begin
if identNode.IsResolved then
Exit;
if (FCurrentDescriptor as TScopeDescriptor).FindSymbol(identNode.Name, originalIndex, originalDepth) then
if (FCurrentDescriptor as TScopeDescriptor).FindSymbol(identNode.Name, depth, idx) then
begin
if (originalDepth > 0) and (FUpvalueMapStack.Count > 0) then
if (depth > 0) and (FUpvalueMapStack.Count > 0) then
begin
upvalueMap := FUpvalueMapStack.Peek;
upvalueNodes := FUpvalueNodesStack.Peek;
originalAddress.Create(akLocalOrParent, originalDepth, originalIndex, identNode.Name);
// Imortant: we are now in the lambda's inner scope, so decrease depth by one to point to the outer scope.
dec(depth);
originalAddress.Create(akLocalOrParent, depth, idx);
if not upvalueMap.TryGetValue(originalAddress, upvalueIndex) then
begin
@@ -893,12 +895,10 @@ begin
upvalueNodes.Add(identNode);
end;
identNode.FResolvedAddress.Create(akUpvalue, 0, upvalueIndex, identNode.Name);
identNode.FResolvedAddress.Create(akUpvalue, 0, upvalueIndex);
end
else
begin
identNode.FResolvedAddress.Create(akLocalOrParent, originalDepth, originalIndex, identNode.Name);
end;
identNode.FResolvedAddress.Create(akLocalOrParent, depth, idx);
end
else
raise Exception.CreateFmt('Undefined identifier: "%s"', [identNode.Name]);
@@ -963,7 +963,7 @@ begin
Node.Initializer.Accept(Self);
slotIndex := (FCurrentDescriptor as TScopeDescriptor).Define(Node.Identifier.Name);
identNode.FResolvedAddress.Create(akLocalOrParent, 0, slotIndex, Node.Identifier.Name);
identNode.FResolvedAddress.Create(akLocalOrParent, 0, slotIndex);
end;
{ TAst }
+60
View File
@@ -90,9 +90,16 @@ type
class function FromBytes(const AValue: TScalarBytes): TScalar; static; inline;
class function FromDecimal(const AValue: TDecimal): TScalar; static; inline;
class function StringToKind(const AName: string): TScalarKind; static;
function ToString: String;
end;
TScalarKindHelper = record helper for TScalarKind
public
function ToString: string;
end;
// Basic data structures using the scalar type (these are not POD of course)
// An array of scalar values of the same kind.
@@ -383,6 +390,38 @@ begin
Result.Value := TScalarValue.FromUInt64(AValue);
end;
class function TScalar.StringToKind(const AName: string): TScalarKind;
begin
if SameText(AName, 'integer') then
Result := skInteger
else if SameText(AName, 'int64') then
Result := skInt64
else if SameText(AName, 'uint64') then
Result := skUInt64
else if SameText(AName, 'single') then
Result := skSingle
else if SameText(AName, 'double') then
Result := skDouble
else if SameText(AName, 'datetime') then
Result := skDateTime
else if SameText(AName, 'timestamp') then
Result := skTimestamp
else if SameText(AName, 'boolean') then
Result := skBoolean
else if SameText(AName, 'char') then
Result := skChar
else if SameText(AName, 'pchar') then
Result := skPChar
else if SameText(AName, 'string') then
Result := skString
else if SameText(AName, 'bytes') then
Result := skBytes
else if SameText(AName, 'decimal') then
Result := skDecimal
else
raise EArgumentException.CreateFmt('Unknown scalar type name: "%s"', [AName]);
end;
function TScalar.ToString: String;
begin
case Kind of
@@ -645,6 +684,27 @@ begin
Result.Create(FDef, values);
end;
function TScalarKindHelper.ToString: string;
begin
case Self of
skInteger: Result := 'integer';
skInt64: Result := 'int64';
skUInt64: Result := 'uint64';
skSingle: Result := 'single';
skDouble: Result := 'double';
skDateTime: Result := 'datetime';
skTimestamp: Result := 'timestamp';
skBoolean: Result := 'boolean';
skChar: Result := 'char';
skPChar: Result := 'pchar';
skString: Result := 'string';
skBytes: Result := 'bytes';
skDecimal: Result := 'decimal';
else
Result := 'unknown';
end;
end;
initialization
Assert(sizeof(TScalarValue) = 8);