// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/tint/transform/utils/hoist_to_decl_before.h"

#include <unordered_map>

#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/sem/block_statement.h"
#include "src/tint/sem/for_loop_statement.h"
#include "src/tint/sem/if_statement.h"
#include "src/tint/sem/reference.h"
#include "src/tint/sem/variable.h"
#include "src/tint/sem/while_statement.h"
#include "src/tint/utils/reverse.h"

namespace tint::transform {

/// Private implementation of HoistToDeclBefore transform
class HoistToDeclBefore::State {
    CloneContext& ctx;
    ProgramBuilder& b;

    /// Holds information about a for-loop that needs to be decomposed into a
    /// loop, so that declaration statements can be inserted before the
    /// condition expression or continuing statement.
    struct LoopInfo {
        ast::StatementList cond_decls;
        ast::StatementList cont_decls;
    };

    /// Info for each else-if that needs decomposing
    struct ElseIfInfo {
        /// Decls to insert before condition
        ast::StatementList cond_decls;
    };

    /// For-loops that need to be decomposed to loops.
    std::unordered_map<const sem::ForLoopStatement*, LoopInfo> for_loops;

    /// Whiles that need to be decomposed to loops.
    std::unordered_map<const sem::WhileStatement*, LoopInfo> while_loops;

    /// 'else if' statements that need to be decomposed to 'else {if}'
    std::unordered_map<const ast::IfStatement*, ElseIfInfo> else_ifs;

    // Converts any for-loops marked for conversion to loops, inserting
    // registered declaration statements before the condition or continuing
    // statement.
    void ForLoopsToLoops() {
        if (for_loops.empty()) {
            return;
        }

        // At least one for-loop needs to be transformed into a loop.
        ctx.ReplaceAll([&](const ast::ForLoopStatement* stmt) -> const ast::Statement* {
            auto& sem = ctx.src->Sem();

            if (auto* fl = sem.Get(stmt)) {
                if (auto it = for_loops.find(fl); it != for_loops.end()) {
                    auto& info = it->second;
                    auto* for_loop = fl->Declaration();
                    // For-loop needs to be decomposed to a loop.
                    // Build the loop body's statements.
                    // Start with any let declarations for the conditional
                    // expression.
                    auto body_stmts = info.cond_decls;
                    // If the for-loop has a condition, emit this next as:
                    //   if (!cond) { break; }
                    if (auto* cond = for_loop->condition) {
                        // !condition
                        auto* not_cond =
                            b.create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
                        // { break; }
                        auto* break_body = b.Block(b.create<ast::BreakStatement>());
                        // if (!condition) { break; }
                        body_stmts.emplace_back(b.If(not_cond, break_body));
                    }
                    // Next emit the for-loop body
                    body_stmts.emplace_back(ctx.Clone(for_loop->body));

                    // Finally create the continuing block if there was one.
                    const ast::BlockStatement* continuing = nullptr;
                    if (auto* cont = for_loop->continuing) {
                        // Continuing block starts with any let declarations used by
                        // the continuing.
                        auto cont_stmts = info.cont_decls;
                        cont_stmts.emplace_back(ctx.Clone(cont));
                        continuing = b.Block(cont_stmts);
                    }

                    auto* body = b.Block(body_stmts);
                    auto* loop = b.Loop(body, continuing);
                    if (auto* init = for_loop->initializer) {
                        return b.Block(ctx.Clone(init), loop);
                    }
                    return loop;
                }
            }
            return nullptr;
        });
    }

    // Converts any while-loops marked for conversion to loops, inserting
    // registered declaration statements before the condition.
    void WhilesToLoops() {
        if (while_loops.empty()) {
            return;
        }

        // At least one while needs to be transformed into a loop.
        ctx.ReplaceAll([&](const ast::WhileStatement* stmt) -> const ast::Statement* {
            auto& sem = ctx.src->Sem();

            if (auto* w = sem.Get(stmt)) {
                if (auto it = while_loops.find(w); it != while_loops.end()) {
                    auto& info = it->second;
                    auto* while_loop = w->Declaration();
                    // While needs to be decomposed to a loop.
                    // Build the loop body's statements.
                    // Start with any let declarations for the conditional
                    // expression.
                    auto body_stmts = info.cond_decls;
                    // Emit the condition as:
                    //   if (!cond) { break; }
                    auto* cond = while_loop->condition;
                    // !condition
                    auto* not_cond =
                        b.create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
                    // { break; }
                    auto* break_body = b.Block(b.create<ast::BreakStatement>());
                    // if (!condition) { break; }
                    body_stmts.emplace_back(b.If(not_cond, break_body));

                    // Next emit the body
                    body_stmts.emplace_back(ctx.Clone(while_loop->body));

                    const ast::BlockStatement* continuing = nullptr;

                    auto* body = b.Block(body_stmts);
                    auto* loop = b.Loop(body, continuing);
                    return loop;
                }
            }
            return nullptr;
        });
    }

    void ElseIfsToElseWithNestedIfs() {
        // Decompose 'else-if' statements into 'else { if }' blocks.
        ctx.ReplaceAll([&](const ast::IfStatement* else_if) -> const ast::Statement* {
            if (!else_ifs.count(else_if)) {
                return nullptr;
            }
            auto& else_if_info = else_ifs[else_if];

            // Build the else block's body statements, starting with let decls for
            // the conditional expression.
            auto& body_stmts = else_if_info.cond_decls;

            // Move the 'else-if' into the new `else` block as a plain 'if'.
            auto* cond = ctx.Clone(else_if->condition);
            auto* body = ctx.Clone(else_if->body);
            auto* new_if = b.If(cond, body, b.Else(ctx.Clone(else_if->else_statement)));
            body_stmts.emplace_back(new_if);

            // Replace the 'else-if' with the new 'else' block.
            return b.Block(body_stmts);
        });
    }

  public:
    /// Constructor
    /// @param ctx_in the clone context
    explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst) {}

    /// Hoists `expr` to a `let` or `var` with optional `decl_name`, inserting it
    /// before `before_expr`.
    /// @param before_expr expression to insert `expr` before
    /// @param expr expression to hoist
    /// @param as_const hoist to `let` if true, otherwise to `var`
    /// @param decl_name optional name to use for the variable/constant name
    /// @return true on success
    bool Add(const sem::Expression* before_expr,
             const ast::Expression* expr,
             bool as_const,
             const char* decl_name) {
        auto name = b.Symbols().New(decl_name);

        // Construct the let/var that holds the hoisted expr
        auto* v = as_const ? b.Let(name, nullptr, ctx.Clone(expr))
                           : b.Var(name, nullptr, ctx.Clone(expr));
        auto* decl = b.Decl(v);

        if (!InsertBefore(before_expr->Stmt(), decl)) {
            return false;
        }

        // Replace the initializer expression with a reference to the let
        ctx.Replace(expr, b.Expr(name));
        return true;
    }

    /// Inserts `stmt` before `before_stmt`, possibly marking a for-loop to be
    /// converted to a loop, or an else-if to an else { if }. If `decl` is
    /// nullptr, for-loop and else-if conversions are marked, but no hoisting
    /// takes place.
    /// @param before_stmt statement to insert `stmt` before
    /// @param stmt statement to insert
    /// @return true on success
    bool InsertBefore(const sem::Statement* before_stmt, const ast::Statement* stmt) {
        auto* ip = before_stmt->Declaration();

        auto* else_if = before_stmt->As<sem::IfStatement>();
        if (else_if && else_if->Parent()->Is<sem::IfStatement>()) {
            // Insertion point is an 'else if' condition.
            // Need to convert 'else if' to 'else { if }'.
            auto& else_if_info = else_ifs[else_if->Declaration()];

            // Index the map to convert this else if, even if `stmt` is nullptr.
            auto& decls = else_if_info.cond_decls;
            if (stmt) {
                decls.emplace_back(stmt);
            }
            return true;
        }

        if (auto* fl = before_stmt->As<sem::ForLoopStatement>()) {
            // Insertion point is a for-loop condition.
            // For-loop needs to be decomposed to a loop.

            // Index the map to convert this for-loop, even if `stmt` is nullptr.
            auto& decls = for_loops[fl].cond_decls;
            if (stmt) {
                decls.emplace_back(stmt);
            }
            return true;
        }

        if (auto* w = before_stmt->As<sem::WhileStatement>()) {
            // Insertion point is a while condition.
            // While needs to be decomposed to a loop.

            // Index the map to convert this while, even if `stmt` is nullptr.
            auto& decls = while_loops[w].cond_decls;
            if (stmt) {
                decls.emplace_back(stmt);
            }
            return true;
        }

        auto* parent = before_stmt->Parent();  // The statement's parent
        if (auto* block = parent->As<sem::BlockStatement>()) {
            // Insert point sits in a block. Simple case.
            // Insert the stmt before the parent statement.
            if (stmt) {
                ctx.InsertBefore(block->Declaration()->statements, ip, stmt);
            }
            return true;
        }

        if (auto* fl = parent->As<sem::ForLoopStatement>()) {
            // Insertion point is a for-loop initializer or continuing statement.
            // These require special care.
            if (fl->Declaration()->initializer == ip) {
                // Insertion point is a for-loop initializer.
                // Insert the new statement above the for-loop.
                if (stmt) {
                    ctx.InsertBefore(fl->Block()->Declaration()->statements, fl->Declaration(),
                                     stmt);
                }
                return true;
            }

            if (fl->Declaration()->continuing == ip) {
                // Insertion point is a for-loop continuing statement.
                // For-loop needs to be decomposed to a loop.

                // Index the map to convert this for-loop, even if `stmt` is nullptr.
                auto& decls = for_loops[fl].cont_decls;
                if (stmt) {
                    decls.emplace_back(stmt);
                }
                return true;
            }

            TINT_ICE(Transform, b.Diagnostics()) << "unhandled use of expression in for-loop";
            return false;
        }

        TINT_ICE(Transform, b.Diagnostics())
            << "unhandled expression parent statement type: " << parent->TypeInfo().name;
        return false;
    }

    /// Use to signal that we plan on hoisting a decl before `before_expr`. This
    /// will convert 'for-loop's to 'loop's and 'else-if's to 'else {if}'s if
    /// needed.
    /// @param before_expr expression we would hoist a decl before
    /// @return true on success
    bool Prepare(const sem::Expression* before_expr) {
        return InsertBefore(before_expr->Stmt(), nullptr);
    }

    /// Applies any scheduled insertions from previous calls to Add() to
    /// CloneContext. Call this once before ctx.Clone().
    /// @return true on success
    bool Apply() {
        ForLoopsToLoops();
        WhilesToLoops();
        ElseIfsToElseWithNestedIfs();
        return true;
    }
};

HoistToDeclBefore::HoistToDeclBefore(CloneContext& ctx) : state_(std::make_unique<State>(ctx)) {}

HoistToDeclBefore::~HoistToDeclBefore() {}

bool HoistToDeclBefore::Add(const sem::Expression* before_expr,
                            const ast::Expression* expr,
                            bool as_const,
                            const char* decl_name) {
    return state_->Add(before_expr, expr, as_const, decl_name);
}

bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt,
                                     const ast::Statement* stmt) {
    return state_->InsertBefore(before_stmt, stmt);
}

bool HoistToDeclBefore::Prepare(const sem::Expression* before_expr) {
    return state_->Prepare(before_expr);
}

bool HoistToDeclBefore::Apply() {
    return state_->Apply();
}

}  // namespace tint::transform
