diff --git a/Src/AST/Myc.Ast.Binding.pas b/Src/AST/Myc.Ast.Binding.pas index 1291619..91fdbd2 100644 --- a/Src/AST/Myc.Ast.Binding.pas +++ b/Src/AST/Myc.Ast.Binding.pas @@ -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); diff --git a/Src/AST/Myc.Ast.TypeChecker.pas b/Src/AST/Myc.Ast.TypeChecker.pas index edb1fd8..b98f25f 100644 --- a/Src/AST/Myc.Ast.TypeChecker.pas +++ b/Src/AST/Myc.Ast.TypeChecker.pas @@ -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; diff --git a/Src/AST/Myc.Ast.pas b/Src/AST/Myc.Ast.pas index 8383b7e..3980c07 100644 --- a/Src/AST/Myc.Ast.pas +++ b/Src/AST/Myc.Ast.pas @@ -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; @@ -348,6 +336,17 @@ type property Arguments: TArray 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;