Comment in AST script

This commit is contained in:
Michael Schimmel
2025-10-03 11:53:02 +02:00
parent ecbe39abac
commit d47c1417f5
3 changed files with 39 additions and 13 deletions
+11 -2
View File
@@ -177,21 +177,26 @@ begin
// Cast to the bound node to access binder-specific information.
boundNode := Node as TBoundLambdaExpressionNode;
// Create the closure by capturing the value cells of all upvalues from the current scope.
sourceAddresses := boundNode.Upvalues;
SetLength(capturedCells, Length(sourceAddresses));
for i := 0 to High(sourceAddresses) do
capturedCells[i] := FScope.Capture(sourceAddresses[i]);
// Memory optimization: a lambda's scope does not need to be kept alive as a parent
// if it contains no nested lambdas that might need to capture from it later.
if boundNode.HasNestedLambdas then
closureScope := FScope
else
closureScope := nil;
// Get a factory to create the correct visitor (e.g., debug or production) for the lambda body.
visitorFactory := CreateVisitorFactory();
var scopeDescriptor := boundNode.ScopeDescriptor;
var params := boundNode.Parameters;
// [weak] prevents a reference cycle since the closure captures itself for 'recur'.
var [weak] closure: TDataValue.TFunc;
var cNode: ILambdaExpressionNode := Node;
@@ -207,6 +212,7 @@ begin
if (Length(ArgValues) <> Length(params)) then
raise EArgumentException.CreateFmt('Argument count mismatch: expected %d, got %d', [Length(params), Length(ArgValues)]);
// Create the new execution scope for this function call.
lambdaScope := TScope.CreateScope(closureScope, scopeDescriptor, capturedCells);
adr.Kind := akLocalOrParent;
@@ -216,7 +222,7 @@ begin
adr.SlotIndex := 0;
lambdaScope[adr] := TDataValue(closure);
// Populate the actual parameters.
// Populate the scope with the actual parameters passed to the function.
for i := 0 to High(ArgValues) do
begin
// Parameters in a bound lambda must be bound identifiers.
@@ -224,11 +230,13 @@ begin
lambdaScope[adr] := ArgValues[i];
end;
// Create a visitor with the new scope and execute the lambda's body.
bodyVisitor := visitorFactory(lambdaScope);
Result := cNode.Body.Accept(bodyVisitor);
end
);
// The result of visiting a lambda node is the callable closure itself.
Result := closure;
end;
@@ -427,7 +435,8 @@ begin
if boundNode.IsBoxed then
begin
// This is a captured variable. Use the clean scope method to create the box.
FScope.DefineBoxed(address, Result);
Assert(address.ScopeDepth = 0);
FScope.DefineBoxed(address.SlotIndex, Result);
end
else
begin
+8 -8
View File
@@ -29,8 +29,10 @@ type
{$endregion}
procedure Define(const Name: string; const Value: TDataValue);
// Defines a variable at a given address and stores it directly in a shared cell (boxing).
procedure DefineBoxed(const Address: TResolvedAddress; const Value: TDataValue);
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
function Dump: string;
procedure Clear;
function Capture(const Address: TResolvedAddress): IValueCell;
@@ -114,7 +116,7 @@ type
function GetNameID(const Name: String): Integer;
function Dump: string;
procedure Define(const Name: string; const Value: TDataValue);
procedure DefineBoxed(const Address: TResolvedAddress; const Value: TDataValue);
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
function Capture(const Address: TResolvedAddress): IValueCell;
function CreateDescriptor: IScopeDescriptor;
property Names: TDictionary<string, Integer> read FNames;
@@ -280,14 +282,12 @@ begin
FNameToIndex.Add(id, index);
end;
procedure TExecutionScope.DefineBoxed(const Address: TResolvedAddress; const Value: TDataValue);
procedure TExecutionScope.DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
begin
// This method is only for local variables (ScopeDepth=0).
Assert(Address.ScopeDepth = 0, 'DefineBoxed can only be used on the current scope.');
Assert((Address.SlotIndex >= 0) and (Address.SlotIndex < Length(FValues)), 'Invalid slot index during DefineBoxed.');
Assert((SlotIndex >= 0) and (SlotIndex < Length(FValues)), 'Invalid slot index during DefineBoxed.');
FValues[Address.SlotIndex].Value := TDataValue.FromIntf<IValueCell>(TValueCell.Create(Value));
FValues[Address.SlotIndex].IsBoxed := True;
FValues[SlotIndex].Value := TDataValue.FromIntf<IValueCell>(TValueCell.Create(Value));
FValues[SlotIndex].IsBoxed := True;
end;
procedure TExecutionScope.DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
+20 -3
View File
@@ -178,8 +178,26 @@ end;
function TLexer.GetNextToken: TToken;
begin
while (FCurrentPos <= Length(FSource)) and FSource[FCurrentPos].IsWhiteSpace do
Advance;
// Skip whitespace and comments
while FCurrentPos <= Length(FSource) do
begin
if FSource[FCurrentPos].IsWhiteSpace then
begin
Advance;
continue;
end;
if FSource[FCurrentPos] = ';' then
begin
// Comment found, skip to the end of the line
while (FCurrentPos <= Length(FSource)) and (not CharInSet(FSource[FCurrentPos], [#10, #13])) do
Advance;
continue;
end;
// No whitespace or comment, so break out and process the token
break;
end;
if FCurrentPos > Length(FSource) then
begin
@@ -445,7 +463,6 @@ begin
end;
{ TPrettyPrintVisitor }
// ... (Implementation of TPrettyPrintVisitor is unchanged and correct) ...
constructor TPrettyPrintVisitor.Create;
begin
inherited Create;