AST Identities
This commit is contained in:
@@ -12,6 +12,7 @@ uses
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Types,
|
||||
Myc.Ast.Identities, // Wichtig für Casts (AsNamed etc.)
|
||||
Myc.Ast;
|
||||
|
||||
type
|
||||
@@ -107,7 +108,6 @@ begin
|
||||
begin
|
||||
if not Assigned(ctx.FParent) then
|
||||
begin
|
||||
// Should technically not happen if Binder did its job, but safe guard it.
|
||||
Result := TTypes.Unknown;
|
||||
Exit;
|
||||
end;
|
||||
@@ -180,7 +180,7 @@ function TTypeChecker.Execute(const RootNode: IAstNode; const Layout: IScopeLayo
|
||||
begin
|
||||
Result := Accept(RootNode);
|
||||
if not Assigned(Result) then
|
||||
Result := TAst.Block([]);
|
||||
Result := TAst.Block([], nil);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitConstant(const Node: IConstantNode): IAstNode;
|
||||
@@ -197,18 +197,21 @@ function TTypeChecker.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
|
||||
var
|
||||
typ: IStaticType;
|
||||
adr: TResolvedAddress;
|
||||
identity: INamedIdentity;
|
||||
begin
|
||||
adr := Node.Address;
|
||||
identity := Node.Identity.AsNamed; // Extract specific identity
|
||||
|
||||
// If binder failed to resolve, we propagate Unknown type to prevent cascading errors.
|
||||
if adr.Kind = akUnresolved then
|
||||
begin
|
||||
Result := TAst.Identifier(Node.Name, adr, TTypes.Unknown);
|
||||
// Propagate identity, set type to Unknown
|
||||
Result := TAst.Identifier(identity, adr, TTypes.Unknown);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
typ := FCurrentContext.LookupType(adr);
|
||||
Result := TAst.Identifier(Node.Name, adr, typ);
|
||||
// CoW: Reuse Identity
|
||||
Result := TAst.Identifier(identity, adr, typ);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitRecurNode(const Node: IRecurNode): IAstNode;
|
||||
@@ -220,7 +223,8 @@ begin
|
||||
for i := 0 to High(Node.Arguments) do
|
||||
newArgs[i] := Accept(Node.Arguments[i]);
|
||||
|
||||
Result := TAst.Recur(newArgs, TTypes.Void);
|
||||
// CoW: Reuse Identity
|
||||
Result := TAst.Recur(Node.Identity, newArgs, TTypes.Void);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode;
|
||||
@@ -231,11 +235,14 @@ var
|
||||
lambdaNode: ILambdaExpressionNode;
|
||||
placeholderType: IStaticType;
|
||||
i: Integer;
|
||||
identNode: IIdentifierNode;
|
||||
identIdentity: INamedIdentity;
|
||||
begin
|
||||
adr := Node.Target.AsIdentifier.Address;
|
||||
identNode := Node.Target.AsIdentifier;
|
||||
identIdentity := identNode.Identity.AsNamed;
|
||||
adr := identNode.Address;
|
||||
initType := TTypes.Unknown;
|
||||
|
||||
// If address is unresolved (binder error), we just process the initializer and return.
|
||||
if adr.Kind = akUnresolved then
|
||||
begin
|
||||
if Assigned(Node.Initializer) then
|
||||
@@ -271,8 +278,11 @@ begin
|
||||
if initType.Kind <> stUnknown then
|
||||
FCurrentContext.SetType(adr.SlotIndex, initType);
|
||||
|
||||
newIdent := TAst.Identifier(Node.Target.AsIdentifier.Name, adr, initType);
|
||||
Result := TAst.VarDecl(newIdent.AsIdentifier, newInitializer, initType, Node.IsBoxed);
|
||||
// Reuse Identity for Identifier
|
||||
newIdent := TAst.Identifier(identIdentity, adr, initType);
|
||||
|
||||
// Reuse Identity for VarDecl
|
||||
Result := TAst.VarDecl(Node.Identity, newIdent, newInitializer, initType, Node.IsBoxed);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitAssignment(const Node: IAssignmentNode): IAstNode;
|
||||
@@ -283,12 +293,17 @@ var
|
||||
lambdaNode: ILambdaExpressionNode;
|
||||
placeholderType: IStaticType;
|
||||
i: Integer;
|
||||
identNode: IIdentifierNode;
|
||||
identIdentity: INamedIdentity;
|
||||
begin
|
||||
newIdent := Accept(Node.Target);
|
||||
targetType := newIdent.AsTypedNode.StaticType;
|
||||
adr := newIdent.AsIdentifier.Address;
|
||||
// Rebuild Identifier with potential type info updates
|
||||
identNode := Node.Target.AsIdentifier;
|
||||
identIdentity := identNode.Identity.AsNamed;
|
||||
|
||||
newIdent := Accept(Node.Target); // This visits identifier and might update type from context
|
||||
targetType := newIdent.AsTypedNode.StaticType;
|
||||
adr := identNode.Address;
|
||||
|
||||
// If binder failed, address is unresolved. We still check the value but skip assignment logic.
|
||||
if adr.Kind = akUnresolved then
|
||||
begin
|
||||
Accept(Node.Value);
|
||||
@@ -316,26 +331,25 @@ begin
|
||||
newValue := Accept(Node.Value);
|
||||
sourceType := newValue.AsTypedNode.StaticType;
|
||||
|
||||
// Only check assignment if both types are known to avoid cascading error reports
|
||||
if (targetType.Kind <> stUnknown) and (sourceType.Kind <> stUnknown) then
|
||||
begin
|
||||
if not TTypeRules.CanAssign(targetType, sourceType) then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
FLog.AddError(Format('Cannot assign type %s to %s', [sourceType.ToString, targetType.ToString]), Node);
|
||||
// We continue, effectively ignoring the assignment type-wise (variable keeps old type).
|
||||
end;
|
||||
end;
|
||||
|
||||
// Type Inference for 'Unknown' targets
|
||||
if ((targetType.Kind = stUnknown) or Assigned(placeholderType)) and (sourceType.Kind <> stUnknown) then
|
||||
begin
|
||||
FCurrentContext.SetType(adr.SlotIndex, sourceType);
|
||||
newIdent := TAst.Identifier(newIdent.AsIdentifier.Name, adr, sourceType);
|
||||
// Recreate Identifier with new type and original identity
|
||||
newIdent := TAst.Identifier(identIdentity, adr, sourceType);
|
||||
targetType := sourceType;
|
||||
end;
|
||||
|
||||
Result := TAst.Assign(newIdent.AsIdentifier, newValue, targetType);
|
||||
// CoW: Reuse Assignment Identity
|
||||
Result := TAst.Assign(Node.Identity, newIdent, newValue, targetType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
|
||||
@@ -348,6 +362,8 @@ var
|
||||
upvalueAddrs: TArray<TResolvedAddress>;
|
||||
i: Integer;
|
||||
finalDescriptor: IScopeDescriptor;
|
||||
paramIdent: IIdentifierNode;
|
||||
paramIdentity: INamedIdentity;
|
||||
begin
|
||||
upvalueAddrs := Node.Upvalues;
|
||||
SetLength(upvalueTypes, Length(upvalueAddrs));
|
||||
@@ -361,23 +377,24 @@ begin
|
||||
|
||||
for i := 0 to High(Node.Parameters) do
|
||||
begin
|
||||
var paramIdent := Node.Parameters[i];
|
||||
paramIdent := Node.Parameters[i];
|
||||
paramIdentity := paramIdent.Identity.AsNamed;
|
||||
var paramAdr := paramIdent.Address;
|
||||
|
||||
paramTypes[i] := TTypes.Unknown;
|
||||
|
||||
if paramAdr.Kind <> akUnresolved then
|
||||
FCurrentContext.SetType(paramAdr.SlotIndex, paramTypes[i]);
|
||||
|
||||
newParams[i] := TAst.Identifier(paramIdent.Name, paramAdr, paramTypes[i]);
|
||||
// CoW: Reuse Parameter Identity
|
||||
newParams[i] := TAst.Identifier(paramIdentity, paramAdr, paramTypes[i]);
|
||||
end;
|
||||
|
||||
newBody := Accept(Node.Body);
|
||||
bodyType := newBody.AsTypedNode.StaticType;
|
||||
methodType := TTypes.CreateMethod(paramTypes, bodyType);
|
||||
|
||||
// Set self-reference type (slot 0 is <self>)
|
||||
FCurrentContext.SetType(0, methodType);
|
||||
|
||||
finalDescriptor := TScope.CreateDescriptor(Node.Layout, FCurrentContext.Types);
|
||||
finally
|
||||
var temp := FCurrentContext;
|
||||
@@ -385,8 +402,19 @@ begin
|
||||
temp.Free;
|
||||
end;
|
||||
|
||||
// CoW: Reuse Lambda Identity
|
||||
Result :=
|
||||
TAst.LambdaExpr(newParams, newBody, Node.Layout, finalDescriptor, Node.Upvalues, Node.HasNestedLambdas, Node.IsPure, methodType);
|
||||
TAst.LambdaExpr(
|
||||
Node.Identity,
|
||||
newParams,
|
||||
newBody,
|
||||
Node.Layout,
|
||||
finalDescriptor,
|
||||
Node.Upvalues,
|
||||
Node.HasNestedLambdas,
|
||||
Node.IsPure,
|
||||
methodType
|
||||
);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
|
||||
@@ -449,7 +477,6 @@ begin
|
||||
retType := bestSig.ReturnType
|
||||
else
|
||||
begin
|
||||
// Log error, but don't crash
|
||||
if Assigned(FLog) then
|
||||
begin
|
||||
argsStr := '';
|
||||
@@ -460,15 +487,8 @@ begin
|
||||
Node
|
||||
);
|
||||
end;
|
||||
retType := TTypes.Unknown; // Poison result
|
||||
retType := TTypes.Unknown;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// We have unknown arguments (probably due to upstream errors).
|
||||
// We cannot resolve the signature, so the result is Unknown.
|
||||
// We do NOT log an error here to avoid spam.
|
||||
retType := TTypes.Unknown;
|
||||
end;
|
||||
end
|
||||
else if calleeType.Kind <> TStaticTypeKind.stUnknown then
|
||||
@@ -478,7 +498,17 @@ begin
|
||||
retType := TTypes.Unknown;
|
||||
end;
|
||||
|
||||
Result := TAst.FunctionCall(newCallee, newArgs, retType, Node.IsTailCall);
|
||||
// CoW: Reuse Call Identity
|
||||
Result :=
|
||||
TAst.FunctionCall(
|
||||
Node.Identity,
|
||||
newCallee,
|
||||
newArgs,
|
||||
retType,
|
||||
Node.IsTailCall,
|
||||
nil, // StaticTarget set by Specializer
|
||||
False // IsTargetPure set by Specializer
|
||||
);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
|
||||
@@ -496,7 +526,8 @@ begin
|
||||
else
|
||||
blockType := TTypes.Void;
|
||||
|
||||
Result := TAst.Block(newExprs, blockType);
|
||||
// CoW: Reuse Block Identity
|
||||
Result := TAst.Block(Node.Identity, newExprs, blockType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
|
||||
@@ -509,7 +540,6 @@ begin
|
||||
newElse := Accept(Node.ElseBranch);
|
||||
|
||||
conditionType := newCond.AsTypedNode.StaticType;
|
||||
|
||||
if (conditionType.Kind <> stUnknown)
|
||||
and not TTypeRules.CanAssign(TTypes.Ordinal, conditionType)
|
||||
and not TTypeRules.CanAssign(TTypes.Boolean, conditionType) then
|
||||
@@ -531,7 +561,8 @@ begin
|
||||
resultType := TTypes.Unknown;
|
||||
end;
|
||||
|
||||
Result := TAst.IfExpr(newCond, newThen, newElse, resultType);
|
||||
// CoW: Reuse If Identity
|
||||
Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, resultType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode;
|
||||
@@ -563,7 +594,8 @@ begin
|
||||
resultType := TTypes.Unknown;
|
||||
end;
|
||||
|
||||
Result := TAst.TernaryExpr(newCond, newThen, newElse, resultType);
|
||||
// CoW: Reuse Ternary Identity
|
||||
Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, resultType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitMemberAccess(const Node: IMemberAccessNode): IAstNode;
|
||||
@@ -616,7 +648,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := TAst.MemberAccess(newBase, newMember.AsKeyword, elemType);
|
||||
// CoW: Reuse MemberAccess Identity
|
||||
Result := TAst.MemberAccess(Node.Identity, newBase, newMember.AsKeyword, elemType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitIndexer(const Node: IIndexerNode): IAstNode;
|
||||
@@ -653,7 +686,8 @@ begin
|
||||
FLog.AddError(Format('Indexer `[]` requires an Ordinal index, but got %s', [indexType.ToString]), Node);
|
||||
end;
|
||||
|
||||
Result := TAst.Indexer(newBase, newIndex, elemType);
|
||||
// CoW: Reuse Indexer Identity
|
||||
Result := TAst.Indexer(Node.Identity, newBase, newIndex, elemType);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
|
||||
@@ -705,7 +739,7 @@ begin
|
||||
begin
|
||||
def := TScalarRecordRegistry.Intern(scalarDefFields);
|
||||
staticType := TTypes.CreateRecord(def);
|
||||
Result := TAst.RecordLiteral(newFields, def, nil, staticType);
|
||||
Result := TAst.RecordLiteral(Node.Identity, newFields, def, nil, staticType);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@@ -716,16 +750,19 @@ begin
|
||||
|
||||
var genDef := TGenericRecordRegistry.Intern(genDefFields);
|
||||
staticType := TTypes.CreateGenericRecord(genDef);
|
||||
Result := TAst.RecordLiteral(newFields, nil, genDef, staticType);
|
||||
Result := TAst.RecordLiteral(Node.Identity, newFields, nil, genDef, staticType);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode;
|
||||
var
|
||||
elemType: IStaticType;
|
||||
defIdentity: IDefinitionIdentity;
|
||||
begin
|
||||
try
|
||||
elemType := TTypes.FromScalarKind(TScalar.StringToKind(Node.Definition));
|
||||
// Use definition from Identity to ensure SSOT
|
||||
defIdentity := Node.Identity.AsDefinition;
|
||||
elemType := TTypes.FromScalarKind(TScalar.StringToKind(defIdentity.Definition));
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
@@ -735,7 +772,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := TAst.CreateSeries(Node.Definition, TTypes.CreateSeries(elemType));
|
||||
// CoW: Reuse Definition Identity
|
||||
Result := TAst.CreateSeries(defIdentity, TTypes.CreateSeries(elemType));
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode;
|
||||
@@ -759,7 +797,6 @@ begin
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Only check assignment compatibility if value type is known
|
||||
if (valueType.Kind <> stUnknown) and not TTypeRules.CanAssign(seriesType.ElementType, valueType) then
|
||||
begin
|
||||
if Assigned(FLog) then
|
||||
@@ -781,12 +818,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := TAst.AddSeriesItem(newSeries.AsIdentifier, newValue, newLookback, TTypes.Void);
|
||||
// CoW: Reuse Add Identity
|
||||
Result := TAst.AddSeriesItem(Node.Identity, newSeries.AsIdentifier, newValue, newLookback, TTypes.Void);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitNop(const Node: INopNode): IAstNode;
|
||||
begin
|
||||
Result := TAst.Nop(TTypes.Void);
|
||||
Result := TAst.Nop(Node.Identity, TTypes.Void);
|
||||
end;
|
||||
|
||||
function TTypeChecker.VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode;
|
||||
@@ -805,7 +843,8 @@ begin
|
||||
FLog.AddError(Format('"length" requires a series, but got %s', [seriesType.ToString]), Node);
|
||||
end;
|
||||
|
||||
Result := TAst.SeriesLength(newSeries.AsIdentifier, TTypes.Ordinal);
|
||||
// CoW: Reuse SeriesLength Identity
|
||||
Result := TAst.SeriesLength(Node.Identity, newSeries.AsIdentifier, TTypes.Ordinal);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user