/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * 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 "condition.h"

#include <compiler/core/pandagen.h>
#include <ir/expressions/binaryExpression.h>
#include <ir/expressions/unaryExpression.h>

namespace panda::es2panda::compiler {

void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel)
{
    if (expr->IsBinaryExpression()) {
        const auto *binExpr = expr->AsBinaryExpression();

        switch (binExpr->OperatorType()) {
            case lexer::TokenType::PUNCTUATOR_EQUAL:
            case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
            case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
            case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
            case lexer::TokenType::PUNCTUATOR_LESS_THAN:
            case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
            case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
            case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
                // This is a special case
                // These operators are expressed via cmp instructions and the following
                // if-else branches. Condition also expressed via cmp instruction and
                // the following if-else.
                // the goal of this method is to merge these two sequences of instructions.
                RegScope rs(pg);
                VReg lhs = pg->AllocReg();

                binExpr->Left()->Compile(pg);
                pg->StoreAccumulator(binExpr, lhs);
                binExpr->Right()->Compile(pg);
                pg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel);
                return;
            }
            case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
                binExpr->Left()->Compile(pg);
                pg->BranchIfFalse(binExpr, falseLabel);

                binExpr->Right()->Compile(pg);
                pg->BranchIfFalse(binExpr, falseLabel);
                return;
            }
            case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
                auto *endLabel = pg->AllocLabel();

                binExpr->Left()->Compile(pg);
                pg->BranchIfTrue(binExpr, endLabel);

                binExpr->Right()->Compile(pg);
                pg->BranchIfFalse(binExpr, falseLabel);
                pg->SetLabel(binExpr, endLabel);
                return;
            }
            default: {
                break;
            }
        }
    } else if (expr->IsUnaryExpression() &&
               expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) {
        expr->AsUnaryExpression()->Argument()->Compile(pg);

        pg->Negate(expr);
        pg->BranchIfFalse(expr, falseLabel);
        return;
    }

    // General case including some binExpr i.E.(a+b)
    expr->Compile(pg);
    pg->BranchIfFalse(expr, falseLabel);
}

}  // namespace panda::es2panda::compiler