unit Myc.Ast.Compiler.Lowering; interface uses System.SysUtils, System.Classes, System.Generics.Collections, Myc.Data.Scalar, Myc.Data.Value, Myc.Ast.Nodes, Myc.Ast.Visitor, Myc.Ast.Scope, Myc.Ast.Types, Myc.Ast; type IAstLowerer = interface(IAstVisitor) function Execute(const RootNode: IAstNode): IAstNode; end; // This transformer runs *after* TypeChecker (Phase 3). // It "lowers" the AST by rewriting complex nodes into simpler ones // that the evaluator can understand (e.g., operator folding). TAstLowerer = class(TAstTransformer, IAstLowerer) private FBinaryOperators: TDictionary; FUnaryOperators: TDictionary; protected // Override to find nodes to lower function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override; public constructor Create; destructor Destroy; override; function Execute(const RootNode: IAstNode): IAstNode; class function Lower(const RootNode: IAstNode): IAstNode; static; end; implementation uses System.Generics.Defaults, Myc.Data.Keyword; { TAstLowerer } constructor TAstLowerer.Create; var op: TScalar.TBinaryOp; uOp: TScalar.TUnaryOp; // Added for unary begin inherited Create; // Operator folding maps FBinaryOperators := TDictionary.Create; for op := Low(TScalar.TBinaryOp) to High(TScalar.TBinaryOp) do FBinaryOperators.Add(op.ToString, op); FUnaryOperators := TDictionary.Create; for uOp := Low(TScalar.TUnaryOp) to High(TScalar.TUnaryOp) do // Changed FUnaryOperators.Add(uOp.ToString, uOp); // Note: '-' is handled as a special case in VisitFunctionCall end; destructor TAstLowerer.Destroy; begin FUnaryOperators.Free; FBinaryOperators.Free; inherited; end; class function TAstLowerer.Lower(const RootNode: IAstNode): IAstNode; begin var lowerer := TAstLowerer.Create as IAstLowerer; Result := lowerer.Execute(RootNode); end; function TAstLowerer.Execute(const RootNode: IAstNode): IAstNode; begin Result := Accept(RootNode); // Use IAstNode-returning Accept if not Assigned(Result) then Result := TAst.Block([]); end; function TAstLowerer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var calleeIdentifier: IIdentifierNode; binaryOp: TScalar.TBinaryOp; unaryOp: TScalar.TUnaryOp; left, right: IAstNode; nodeType: IStaticType; begin // --- Optimization: Operator Folding --- if Node.Callee.Kind = akIdentifier then begin calleeIdentifier := Node.Callee.AsIdentifier; nodeType := Node.StaticType; if (Length(Node.Arguments) = 2) then begin if FBinaryOperators.TryGetValue(calleeIdentifier.Name, binaryOp) then begin // Note: We MUST visit children *before* creating the new node left := Accept(Node.Arguments[0]); right := Accept(Node.Arguments[1]); // Call constructor directly, passing the inferred type Result := TAst.BinaryExpr(left, binaryOp, right, nodeType); exit; end; end; if (Length(Node.Arguments) = 1) then begin if FUnaryOperators.TryGetValue(calleeIdentifier.Name, unaryOp) then begin right := Accept(Node.Arguments[0]); // Call constructor directly, passing the inferred type Result := TAst.UnaryExpr(unaryOp, right, nodeType); exit; end; if (calleeIdentifier.Name = '-') then begin right := Accept(Node.Arguments[0]); // Call constructor directly, passing the inferred type Result := TAst.UnaryExpr(TScalar.TUnaryOp.Negate, right, nodeType); exit; end; end; end; // If no rewrite matched, continue traversal using the base implementation Result := inherited VisitFunctionCall(Node); end; end.