AST type infer SoC

This commit is contained in:
Michael Schimmel
2025-11-04 20:35:34 +01:00
parent d82a75aba6
commit f73c0c67b8
3 changed files with 74 additions and 47 deletions
+55 -8
View File
@@ -47,7 +47,7 @@ type
function VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode; override;
function VisitRecurNode(const Node: IRecurNode): IAstNode; override;
// Base cases (types are already set by Binder)
// Base cases (types are now set here)
function VisitConstant(const Node: IConstantNode): IAstNode; override;
function VisitKeyword(const Node: IKeywordNode): IAstNode; override;
@@ -100,27 +100,49 @@ begin
end;
function TTypeChecker.VisitConstant(const Node: IConstantNode): IAstNode;
var
constType: IStaticType;
begin
// Type was set by Binder, just propagate it up.
// This is a leaf node, call inherited (does nothing)
Result := inherited VisitConstant(Node);
// Assign the type based on the literal value
case Node.Value.Kind of
TDataValueKind.vkScalar: constType := TTypes.FromScalarKind(Node.Value.AsScalar.Kind);
TDataValueKind.vkText: constType := TTypes.Text;
TDataValueKind.vkVoid: constType := TTypes.Void;
else
constType := TTypes.Unknown;
end;
Result := SetType(Result, constType);
end;
function TTypeChecker.VisitKeyword(const Node: IKeywordNode): IAstNode;
begin
// Type was set by Binder, just propagate it up.
// This is a leaf node
Result := inherited VisitKeyword(Node);
Result := SetType(Result, TTypes.Keyword);
end;
function TTypeChecker.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
var
symbol: TResolvedSymbol;
begin
// Type was set by Binder (read from scope), just propagate it up.
// This is a leaf node (guaranteed to be IBoundIdentifierNode)
Result := inherited VisitIdentifier(Node);
// Get the type from the descriptor (which was populated by Binder/RTL)
symbol := FCurrentDescriptor.FindSymbol(Node.Name);
Result := SetType(Result, symbol.StaticType);
end;
function TTypeChecker.VisitRecurNode(const Node: IRecurNode): IAstNode;
begin
// Type was set by Binder (TTypes.Void), just propagate it up.
// Visit children first
Result := inherited VisitRecurNode(Node);
// Recur always results in Void (it never returns)
Result := SetType(Result, TTypes.Void);
end;
function TTypeChecker.VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode;
@@ -147,14 +169,16 @@ begin
if Assigned(Node.Initializer) then
initType := (Node.Initializer as TAstNode).StaticType
else
initType := TTypes.Void;
initType := TTypes.Unknown; // <-- This was TTypes.Void
// 3. Get the address from the bound identifier (SAFE CAST)
boundIdent := Node.Identifier;
adr := boundIdent.AsBoundIdentifierNode.Address;
// 4. Update the type in the scope descriptor (which was set to Unknown by the binder).
FCurrentDescriptor.UpdateType(adr.SlotIndex, initType);
// Only update if we have a concrete type (not the default Unknown).
if initType.Kind <> stUnknown then
FCurrentDescriptor.UpdateType(adr.SlotIndex, initType);
// 5. Update the static types of the nodes themselves.
(boundIdent as TAstNode).StaticType := initType;
@@ -164,6 +188,7 @@ end;
function TTypeChecker.VisitAssignment(const Node: IAssignmentNode): IAstNode;
var
targetType, sourceType: IStaticType;
adr: TResolvedAddress;
begin
// 1. Visit children first (Identifier, Value)
inherited;
@@ -176,6 +201,17 @@ begin
if not TTypeRules.CanAssign(targetType, sourceType) then
raise ETypeException.CreateFmt('Cannot assign type %s to %s', [sourceType.ToString, targetType.ToString]);
// 4. If the target was 'Unknown' (from 'def'), update the descriptor
// with the new, inferred type. This enables recursion.
if (targetType.Kind = stUnknown) and (sourceType.Kind <> stUnknown) then
begin
adr := Node.Identifier.AsBoundIdentifierNode.Address;
FCurrentDescriptor.UpdateType(adr.SlotIndex, sourceType);
// Re-set the identifier's node type (it was visited *before* this)
(Node.Identifier as TAstNode).StaticType := sourceType;
targetType := sourceType;
end;
Result := SetType(Node, targetType);
end;
@@ -489,9 +525,20 @@ begin
end;
function TTypeChecker.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode;
var
elemType: IStaticType;
begin
// Type was set by Binder, just propagate it up.
// This is a leaf node
Result := inherited VisitCreateSeries(Node);
// Assign the type
try
elemType := TTypes.FromScalarKind(TScalar.StringToKind(Node.Definition));
except
on E: Exception do
elemType := TTypes.Unknown;
end;
Result := SetType(Result, TTypes.CreateSeries(elemType));
end;
function TTypeChecker.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode;