diff --git a/Src/AST/Myc.Ast.Binding.pas b/Src/AST/Myc.Ast.Binding.pas index 57fad27..047e306 100644 --- a/Src/AST/Myc.Ast.Binding.pas +++ b/Src/AST/Myc.Ast.Binding.pas @@ -646,7 +646,7 @@ begin var isTailCall := FIsTailStack.Peek; FNextIsTail := False; callee := Accept(Node.Callee).AsIntf; - args := TransformNodes(Node.Arguments); + args := AcceptNodes(Node.Arguments); var retType: IStaticType := TTypes.Unknown; calleeType := (callee as TAstNode).StaticType; @@ -680,7 +680,7 @@ var newMacroNode: IMacroExpansionNode; begin boundCallee := Accept(Node.Callee).AsIntf; - boundArgs := TransformNodes(Node.Arguments); + boundArgs := AcceptNodes(Node.Arguments); boundExpandedBody := Accept(Node.ExpandedBody).AsIntf; boundOriginalCall := TAst.FunctionCall(boundCallee, boundArgs); newMacroNode := TMacroExpansionNode.Create(boundOriginalCall, boundExpandedBody); @@ -1130,7 +1130,7 @@ begin // 'recur' itself doesn't evaluate to a value, it jumps. // We set its type to Void. - var boundNode := TAst.Recur(TransformNodes(Node.Arguments)); + var boundNode := TAst.Recur(AcceptNodes(Node.Arguments)); Result := SetType(TDataValue.FromIntf(boundNode), TTypes.Void); end; diff --git a/Src/AST/Myc.Ast.Types.pas b/Src/AST/Myc.Ast.Types.pas index 9cefd92..190bcac 100644 --- a/Src/AST/Myc.Ast.Types.pas +++ b/Src/AST/Myc.Ast.Types.pas @@ -555,6 +555,7 @@ end; class function TTypeRules.CanAssign(const Target, Source: IStaticType): Boolean; begin + // Basic nil-check for safety. if (not Assigned(Target)) or (not Assigned(Source)) then exit(False); @@ -562,6 +563,7 @@ begin if (Target.Kind = stUnknown) or (Source.Kind = stUnknown) then exit(True); + // Types are always assignable to themselves (identity). if Target.IsEqual(Source) then exit(True); @@ -569,17 +571,18 @@ begin if (Target.Kind = stFloat) and (Source.Kind = stOrdinal) then exit(True); + // Allow discarding the return value of a method (e.g., in a 'do' block). if (Target.Kind = stVoid) and (Source.Kind = stMethod) then exit(True); + // Allow implicit conversion from Keyword (internally an index) to Ordinal. if (Target.Kind = stOrdinal) and (Source.Kind = stKeyword) then exit(True); - // TODO: Implement full assignment compatibility rules (e.g., for records/series) - // Allow assigning a scalar record to a generic record? (Maybe later) // Allow assigning a generic record to a scalar record? (If fields match) + // Default: Assignment is not allowed if no specific rule matches. Result := False; end; diff --git a/Src/AST/Myc.Ast.Visitor.pas b/Src/AST/Myc.Ast.Visitor.pas index 4ee26c5..fd65c11 100644 --- a/Src/AST/Myc.Ast.Visitor.pas +++ b/Src/AST/Myc.Ast.Visitor.pas @@ -76,10 +76,9 @@ type function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override; function VisitRecurNode(const Node: IRecurNode): TDataValue; override; - // Helper to transform an array of nodes. - function TransformNodes(const Nodes: TArray): TArray; - function Accept(const Node: IAstNode): TDataValue; virtual; + // Helper to transform an array of nodes. + function AcceptNodes(const Nodes: TArray): TArray; property Done: Boolean read FDone write FDone; public @@ -114,6 +113,23 @@ begin Result := Node.Accept(Self); end; +function TAstTransformer.AcceptNodes(const Nodes: TArray): TArray; +var + i: Integer; + hasChanged: boolean; +begin + hasChanged := False; + SetLength(Result, Length(Nodes)); + for i := 0 to High(Nodes) do + begin + Result[i] := Accept(Nodes[i]).AsIntf; + if Result[i] <> Nodes[i] then + hasChanged := True; + end; + if not hasChanged then + Result := Nodes; +end; + function TAstTransformer.Execute(const RootNode: IAstNode): IAstNode; begin Result := Accept(RootNode).AsIntf; @@ -183,7 +199,7 @@ end; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; begin - var parameters := TransformNodes(Node.Parameters); + var parameters := AcceptNodes(Node.Parameters); var body := Accept(Node.Body).AsIntf; if (parameters = Node.Parameters) and (body = Node.Body) then Result := TDataValue.FromIntf(Node) @@ -194,7 +210,7 @@ end; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; begin var callee := Accept(Node.Callee).AsIntf; - var args := TransformNodes(Node.Arguments); + var args := AcceptNodes(Node.Arguments); if (callee = Node.Callee) and (args = Node.Arguments) then Result := TDataValue.FromIntf(Node) else @@ -209,7 +225,7 @@ var begin // Transform all children of the node callee := Accept(Node.Callee).AsIntf; - args := TransformNodes(Node.Arguments); + args := AcceptNodes(Node.Arguments); expandedBody := Accept(Node.ExpandedBody).AsIntf; if (callee = Node.Callee) and (args = Node.Arguments) and (expandedBody = Node.ExpandedBody) then @@ -271,7 +287,7 @@ end; function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; begin var name := Accept(Node.Name).AsIntf; - var parameters := TransformNodes(Node.Parameters); + var parameters := AcceptNodes(Node.Parameters); var body := Accept(Node.Body).AsIntf; if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then Result := TDataValue.FromIntf(Node) @@ -381,30 +397,13 @@ end; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): TDataValue; begin - var args := TransformNodes(Node.Arguments); + var args := AcceptNodes(Node.Arguments); if args = Node.Arguments then Result := TDataValue.FromIntf(Node) else Result := TDataValue.FromIntf(TAst.Recur(args)); end; -function TAstTransformer.TransformNodes(const Nodes: TArray): TArray; -var - i: Integer; - hasChanged: boolean; -begin - hasChanged := False; - SetLength(Result, Length(Nodes)); - for i := 0 to High(Nodes) do - begin - Result[i] := Accept(Nodes[i]).AsIntf; - if Result[i] <> Nodes[i] then - hasChanged := True; - end; - if not hasChanged then - Result := Nodes; -end; - { TAstTraverser } constructor TAstTraverser.Create;