Node immutability improved
This commit is contained in:
@@ -111,7 +111,7 @@ begin
|
||||
|
||||
// Get the type from the descriptor (which was populated by Binder/RTL)
|
||||
symbol := FCurrentDescriptor.FindSymbol(Node.Name);
|
||||
adr := Node.AsIdentifier.Address;
|
||||
adr := Node.Address;
|
||||
|
||||
// Create a new node, copying the address and assigning the inferred type
|
||||
Result := TAst.Identifier(Node.Name, adr, symbol.StaticType);
|
||||
@@ -135,9 +135,7 @@ function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationN
|
||||
var
|
||||
initType: IStaticType;
|
||||
newInitializer, newIdent: IAstNode;
|
||||
boundIdent: IIdentifierNode;
|
||||
adr: TResolvedAddress;
|
||||
N: TVariableDeclarationNode;
|
||||
begin
|
||||
// 1. Visit Initializer first (if it exists)
|
||||
if Assigned(Node.Initializer) then
|
||||
@@ -151,23 +149,24 @@ begin
|
||||
else
|
||||
initType := TTypes.Unknown; // (def fib)
|
||||
|
||||
// 3. Get the address from the bound identifier (SAFE CAST)
|
||||
boundIdent := Node.Identifier;
|
||||
adr := boundIdent.AsIdentifier.Address;
|
||||
// 3. Get the address from the bound identifier
|
||||
adr := Node.Identifier.Address;
|
||||
|
||||
// 4. Update the type in the scope descriptor (which was set to Unknown by the binder).
|
||||
if initType.Kind <> stUnknown then
|
||||
FCurrentDescriptor.UpdateType(adr.SlotIndex, initType);
|
||||
|
||||
// 5. Create the new (typed) identifier node
|
||||
newIdent := TAst.Identifier(boundIdent.Name, adr, initType);
|
||||
newIdent := TAst.Identifier(Node.Identifier.Name, adr, initType);
|
||||
|
||||
// 6. Create the new VariableDeclaration node
|
||||
Result := TVariableDeclarationNode.Create(newIdent.AsIdentifier, newInitializer, initType);
|
||||
|
||||
// 7. Copy runtime flags (IsBoxed)
|
||||
N := (Result as TVariableDeclarationNode);
|
||||
N.IsBoxed := (Node as TVariableDeclarationNode).IsBoxed;
|
||||
// 6. Create the new VariableDeclaration node using the factory
|
||||
Result :=
|
||||
TAst.VarDecl(
|
||||
newIdent.AsIdentifier,
|
||||
newInitializer,
|
||||
initType,
|
||||
Node.IsBoxed // 7. Copy runtime flags (IsBoxed) via interface
|
||||
);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitAssignment(const Node: IAssignmentNode): IAstNode;
|
||||
@@ -206,7 +205,6 @@ end;
|
||||
|
||||
function TTypeChecker.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
|
||||
var
|
||||
boundNode: TLambdaExpressionNode;
|
||||
newParams: TArray<IIdentifierNode>;
|
||||
newBody: IAstNode;
|
||||
bodyType, methodType: IStaticType;
|
||||
@@ -214,22 +212,20 @@ var
|
||||
i: Integer;
|
||||
savedDescriptor: IScopeDescriptor;
|
||||
begin
|
||||
boundNode := (Node as TLambdaExpressionNode);
|
||||
|
||||
// 1. Enter the lambda's scope (which Binder already created)
|
||||
savedDescriptor := FCurrentDescriptor;
|
||||
FCurrentDescriptor := boundNode.ScopeDescriptor;
|
||||
FCurrentDescriptor := Node.ScopeDescriptor;
|
||||
try
|
||||
// 2. Visit parameters (they are already bound, just need typing)
|
||||
SetLength(newParams, Length(boundNode.Parameters));
|
||||
SetLength(paramTypes, Length(boundNode.Parameters));
|
||||
SetLength(newParams, Length(Node.Parameters));
|
||||
SetLength(paramTypes, Length(Node.Parameters));
|
||||
|
||||
for i := 0 to High(boundNode.Parameters) do
|
||||
for i := 0 to High(Node.Parameters) do
|
||||
begin
|
||||
// Parameters are leaves, but we must *replace* them with typed versions
|
||||
// (even if they are just TTypes.Unknown for now, for type inference placeholders)
|
||||
var paramIdent := boundNode.Parameters[i];
|
||||
var paramAdr := paramIdent.AsIdentifier.Address;
|
||||
var paramIdent := Node.Parameters[i];
|
||||
var paramAdr := paramIdent.Address;
|
||||
var newParam := TAst.Identifier(paramIdent.Name, paramAdr);
|
||||
|
||||
newParams[i] := newParam;
|
||||
@@ -237,7 +233,7 @@ begin
|
||||
end;
|
||||
|
||||
// 3. Visit the body to infer its return type
|
||||
newBody := Accept(boundNode.Body);
|
||||
newBody := Accept(Node.Body);
|
||||
bodyType := newBody.AsTypedNode.StaticType;
|
||||
|
||||
// 4. Create the final method type
|
||||
@@ -251,14 +247,8 @@ begin
|
||||
FCurrentDescriptor := savedDescriptor;
|
||||
end;
|
||||
|
||||
// 7. Create the new (typed) lambda node
|
||||
Result := TLambdaExpressionNode.Create(newParams, newBody, methodType);
|
||||
|
||||
// 8. Copy runtime properties
|
||||
var newLambda := (Result as TLambdaExpressionNode);
|
||||
newLambda.ScopeDescriptor := boundNode.ScopeDescriptor;
|
||||
newLambda.Upvalues := boundNode.Upvalues;
|
||||
newLambda.HasNestedLambdas := boundNode.HasNestedLambdas;
|
||||
// 7. Create the new (typed) lambda node using the factory
|
||||
Result := TAst.LambdaExpr(newParams, newBody, Node.ScopeDescriptor, Node.Upvalues, Node.HasNestedLambdas, methodType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
|
||||
@@ -300,11 +290,14 @@ begin
|
||||
else if calleeType.Kind <> TStaticTypeKind.stUnknown then
|
||||
raise ETypeException.CreateFmt('Cannot invoke type %s as a function.', [calleeType.ToString]);
|
||||
|
||||
// 4. Create the new (typed) call node
|
||||
Result := TFunctionCallNode.Create(newCallee, newArgs, retType);
|
||||
|
||||
// 5. Copy runtime properties
|
||||
(Result as TFunctionCallNode).IsTailCall := (Node as TFunctionCallNode).IsTailCall;
|
||||
// 4. Create the new (typed) call node using the factory
|
||||
Result :=
|
||||
TAst.FunctionCall(
|
||||
newCallee,
|
||||
newArgs,
|
||||
retType,
|
||||
Node.IsTailCall // 5. Copy runtime properties
|
||||
);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
|
||||
@@ -508,17 +501,14 @@ var
|
||||
valType: IStaticType;
|
||||
scalarKind: TScalar.TKind;
|
||||
allScalar: Boolean;
|
||||
oldNode: TGenericRecordLiteralNode; // Parser creates this type
|
||||
newFields: TArray<TRecordFieldLiteral>;
|
||||
begin
|
||||
oldNode := (Node as TGenericRecordLiteralNode);
|
||||
|
||||
// 1. Visit all child nodes first to infer their types
|
||||
SetLength(newFields, Length(oldNode.Fields));
|
||||
for i := 0 to High(oldNode.Fields) do
|
||||
SetLength(newFields, Length(Node.Fields));
|
||||
for i := 0 to High(Node.Fields) do
|
||||
begin
|
||||
newFields[i].Key := Accept(oldNode.Fields[i].Key).AsKeyword;
|
||||
newFields[i].Value := Accept(oldNode.Fields[i].Value);
|
||||
newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword;
|
||||
newFields[i].Value := Accept(Node.Fields[i].Value);
|
||||
end;
|
||||
|
||||
SetLength(scalarDefFields, Length(newFields));
|
||||
|
||||
Reference in New Issue
Block a user