Comment in AST script
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user