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
+8 -27
View File
@@ -219,34 +219,19 @@ end;
function TAstBinder.VisitConstant(const Node: IConstantNode): IAstNode;
begin
// Set type (Phase 3)
case Node.Value.Kind of
TDataValueKind.vkScalar: (Node as TAstNode).StaticType := TTypes.FromScalarKind(Node.Value.AsScalar.Kind);
TDataValueKind.vkText: (Node as TAstNode).StaticType := TTypes.Text;
TDataValueKind.vkVoid: (Node as TAstNode).StaticType := TTypes.Void;
else
(Node as TAstNode).StaticType := TTypes.Unknown;
end;
// Binding pass does not assign types.
Result := Node;
end;
function TAstBinder.VisitKeyword(const Node: IKeywordNode): IAstNode;
begin
(Node as TAstNode).StaticType := TTypes.Keyword;
// Binding pass does not assign types.
Result := Node;
end;
function TAstBinder.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode;
var
elemType: IStaticType;
begin
try
elemType := TTypes.FromScalarKind(TScalar.StringToKind(Node.Definition));
except
on E: Exception do
elemType := TTypes.Unknown;
end;
(Node as TAstNode).StaticType := TTypes.CreateSeries(elemType);
// Binding pass does not assign types.
Result := Node;
end;
@@ -254,14 +239,14 @@ function TAstBinder.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode
begin
// Visit children
Result := inherited VisitAddSeriesItem(Node);
(Node as TAstNode).StaticType := TTypes.Void;
// Binding pass does not assign types.
end;
function TAstBinder.VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode;
begin
// Visit children
Result := inherited VisitSeriesLength(Node);
(Node as TAstNode).StaticType := TTypes.Ordinal;
// Binding pass does not assign types.
end;
function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
@@ -291,8 +276,6 @@ begin
// --- Replace Node ---
// Create a new TBoundIdentifierNode (implementation is in Myc.Ast)
var boundParamNode := TBoundIdentifierNode.Create(paramNode.Name, adr);
// Set its type
(boundParamNode as TAstNode).StaticType := TTypes.Unknown;
// Replace it in the parameter array
N.Parameters[i] := boundParamNode;
end;
@@ -338,7 +321,7 @@ function TAstBinder.VisitRecurNode(const Node: IRecurNode): IAstNode;
begin
// Visit children
Result := inherited VisitRecurNode(Node);
(Node as TAstNode).StaticType := TTypes.Void; // Recur never returns a value
// Binding pass does not assign types.
end;
function TAstBinder.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
@@ -382,8 +365,7 @@ begin
// --- Replace Node ---
// Create the new TBoundIdentifierNode (implementation is in Myc.Ast)
Result := TBoundIdentifierNode.Create(Node.Name, adr);
// Copy static type from scope to the new node
(Result as TAstNode).StaticType := symbol.StaticType;
// StaticType remains TTypes.Unknown (default)
end
else
begin
@@ -414,8 +396,7 @@ begin
// 3. --- Replace Node ---
// Replace the TIdentifierNode with a new TBoundIdentifierNode
N.Identifier := TBoundIdentifierNode.Create(N.Identifier.Name, address);
// Set static type (Unknown) on the *new* node
(N.Identifier as TAstNode).StaticType := TTypes.Unknown; // TypeChecker will set this
// StaticType remains TTypes.Unknown (default)
// 4. Mutate this declaration node
N.IsBoxed := (FBoxedDeclarations <> nil) and FBoxedDeclarations.Contains(Node);
+54 -7
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,13 +169,15 @@ 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).
// 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.
@@ -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;
+11 -12
View File
@@ -324,18 +324,6 @@ type
property IsTailCall: Boolean read FIsTailCall write FIsTailCall;
end;
TMacroExpansionNode = class(TFunctionCallNode, IMacroExpansionNode)
private
FExpandedBody: IAstNode;
function GetExpandedBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroExpansion: IMacroExpansionNode; override;
property ExpandedBody: IAstNode read FExpandedBody write FExpandedBody; // Writeable
end;
TRecurNode = class(TAstNode, IRecurNode)
private
FArguments: TArray<IAstNode>;
@@ -348,6 +336,17 @@ type
property Arguments: TArray<IAstNode> read FArguments write FArguments; // Writeable
end;
TMacroExpansionNode = class(TFunctionCallNode, IMacroExpansionNode)
private
FExpandedBody: IAstNode;
function GetExpandedBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroExpansion: IMacroExpansionNode; override;
property ExpandedBody: IAstNode read FExpandedBody write FExpandedBody; // Writeable
end;
TBlockExpressionNode = class(TAstNode, IBlockExpressionNode)
private
FExpressions: TArray<IAstNode>;