unit Myc.Ast.Compiler.Lowering;

interface

uses
    System.SysUtils,
    System.Classes,
    System.Generics.Collections,
    Myc.Data.Scalar,
    Myc.Data.Value,
    Myc.Ast.Nodes, // Provides EAstException
    Myc.Ast.Visitor,
    Myc.Ast.Scope,
    Myc.Ast.Types,
    Myc.Ast;

type
    // Exception specific to AST lowering/rewriting errors
    ELoweringException = class(EAstException);

    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<string, TScalar.TBinaryOp>;
        FUnaryOperators: TDictionary<string, TScalar.TUnaryOp>;
    protected
    // Implement Visit methods here when specific lowering logic is added
    // (e.g. converting operator function calls to specific node types if added in future)
    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;
begin
    inherited Create;

    // Operator folding maps (Reserved for future static optimization)
    FBinaryOperators := TDictionary<string, TScalar.TBinaryOp>.Create;

    FBinaryOperators.Add('+', TScalar.TBinaryOp.Add);
    FBinaryOperators.Add('-', TScalar.TBinaryOp.Subtract);
    FBinaryOperators.Add('*', TScalar.TBinaryOp.Multiply);
    FBinaryOperators.Add('/', TScalar.TBinaryOp.Divide);
    FBinaryOperators.Add('=', TScalar.TBinaryOp.Equal);
    FBinaryOperators.Add('<>', TScalar.TBinaryOp.NotEqual);
    FBinaryOperators.Add('<', TScalar.TBinaryOp.Less);
    FBinaryOperators.Add('<=', TScalar.TBinaryOp.LessOrEqual);
    FBinaryOperators.Add('>', TScalar.TBinaryOp.Greater);
    FBinaryOperators.Add('>=', TScalar.TBinaryOp.GreaterOrEqual);

    FUnaryOperators := TDictionary<string, TScalar.TUnaryOp>.Create;

    FUnaryOperators.Add('not', TScalar.TUnaryOp.Not);
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;
    try
        Result := lowerer.Execute(RootNode);
    except
        on E: Exception do
            raise ELoweringException.Create('Internal Error during AST Lowering: ' + E.Message);
    end;
end;

function TAstLowerer.Execute(const RootNode: IAstNode): IAstNode;
begin
    if not Assigned(RootNode) then
        exit(nil);

    Result := Accept(RootNode);
    if not Assigned(Result) then
        Result := TAst.Block([]);
end;

end.
