/*
 * Copyright (c) 2024-2025 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.
 */

// Autogenerated file -- DO NOT EDIT!
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-non-const-parameter)
// NOLINTBEGIN(readability-function-size, readability-magic-numbers)

% Enums::enums&.each do |name, enum|
% if enum.flags&.length > 0
extern "C" __attribute__((unused)) <%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %> E2pToIr<%= name %>(Es2panda<%= name %> e2pFlags)
{
% if enum.type == 'unsigned'
% if enum.flags.length <= 32 || enum.type == "int"
    auto irFlags = (<%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>)0U;
% enum.flags&.each do |flag|
    irFlags |= (e2pFlags & Es2panda<%= name %>::<%= enum.name_to_upper_snake %>_<%= flag %>) != 0 ? <%= enum.namespace %><%=
    if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>::<%= flag %> : (<%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>)0U;
% end
% else
    auto irFlags = (<%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>)0U;
% enum.flags&.each_with_index do |flag, index|
    irFlags |= (e2pFlags & <%= if index > 0 then "(uint64_t)1U << " +
    (index - 1).to_s + "U" else "(uint64_t)0U" end %>) != 0 ? <%=
    enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>::<%= flag %> : (<%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>)0U;
% end
% end
    return irFlags;
% else
    switch(e2pFlags)
    {
% enum.flags&.each do |flag|
    case Es2panda<%= name %>::<%= enum.name_to_upper_snake %>_<%= flag %>:
        return <%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>::<%= flag %>;
% end
    default:
        ES2PANDA_UNREACHABLE();
    }
%end
}
% end

%end

% Enums::enums&.each do |name, enum|
% if enum.flags&.length > 0
extern "C" __attribute__((unused)) Es2panda<%= name %> IrToE2p<%= name %>(<%=
enum.namespace %><%= if enum.parent_class_name then
"::" + enum.parent_class_name end %>::<%= name %> irFlags)
{
% if enum.type == 'unsigned'
    Es2panda<%= name %> e2pFlags {(Es2panda<%= name %>)0U};
% if enum.flags.length <= 32 || enum.type == "int"
% enum.flags&.each do |flag|
    e2pFlags = static_cast<Es2panda<%= name %>>((irFlags & <%= enum.namespace %><%= if enum.parent_class_name then
    "::" + enum.parent_class_name end %>::<%= name %>::<%= flag
    %>) != 0 ? e2pFlags | Es2panda<%= name %>::<%= enum.name_to_upper_snake %>_<%= flag %> : e2pFlags);
% end
% else
% enum.flags&.each_with_index do |flag, index|
    e2pFlags = static_cast<Es2panda<%= name %>>((irFlags & <%= enum.namespace %><%= if enum.parent_class_name then
    "::" + enum.parent_class_name end %>::<%= name %>::<%= flag
    %>) != 0 ? e2pFlags | <%= if index > 0 then "(uint64_t)1U << " + (index - 1).to_s + "U"
    else "(uint64_t)0U" end %> : e2pFlags);
% end
% end
    return e2pFlags;
% else
    switch(irFlags)
    {
% enum.flags&.each do |flag|
    case <%= enum.namespace %><%= if enum.parent_class_name then "::" + enum.parent_class_name
end %>::<%= name %>::<%= flag %>:
        return Es2panda<%= name %>::<%= enum.name_to_upper_snake %>_<%= flag %>;
% end
    default:
        ES2PANDA_UNREACHABLE();
    }
% end
}
%end

% end

// NOLINTEND(readability-function-size, readability-magic-numbers)

// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define IS(public_name, e2p_name)                                               \
    extern "C" bool Is##public_name(es2panda_AstNode *ast)                      \
    {                                                                           \
        auto *node = reinterpret_cast<ir::AstNode *>(ast);                      \
        return node->Is##e2p_name();                                            \
    }

% Es2pandaLibApi::ast_nodes&.each do |ast_node|
% if ast_node != "AstNode" && ast_node != "TypeNode"
IS(<%= ast_node %>, <%= ast_node %>)
% end
% end

#undef IS

// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define IS(public_name, e2p_name)                                               \
    extern "C" bool ScopeIs##public_name(es2panda_Scope *scope)                 \
    {                                                                           \
        auto *e2p_scope = reinterpret_cast<varbinder::Scope *>(scope);          \
        return e2p_scope->Is##e2p_name();                                       \
    }

% Es2pandaLibApi::scopes&.each do |scope|
% if scope != "Scope"
IS(<%= scope %>, <%= scope %>)
% end
% end

#undef IS

// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define IS(public_name, e2p_name)                                               \
    extern "C" bool TypeIs##public_name(es2panda_Type *type)                    \
    {                                                                           \
        auto *e2p_type = reinterpret_cast<checker::Type *>(type);               \
        return e2p_type->Is##e2p_name();                                        \
    }

% Es2pandaLibApi::ast_types&.each do |type|
% if type != "Type"
IS(<%= type %>, <%= type %>)
% end
% end

#undef IS

// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define IS(public_name, e2p_name)                                               \
    extern "C" bool VariableIs##public_name(es2panda_Variable *variable)        \
    {                                                                           \
        auto *e2p_variable = reinterpret_cast<varbinder::Variable *>(variable); \
        return e2p_variable->Is##e2p_name();                                    \
    }

% Es2pandaLibApi::ast_variables&.each do |variable|
% if variable[1] != "Variable"
IS(<%= variable[1] %>, <%= variable[1] %>)
% end
% end

#undef IS

// NOLINTNEXTLINE(readability-function-size)
char const *AstNodeName(es2panda_AstNode *ast)
{
% Es2pandaLibApi::ast_nodes&.each do |ast_node|
% unless ["AstNode", "Expression", "Statement", "TypeNode"].include?(ast_node)
    if(Is<%= ast_node %>(ast)) {
        return "<%= ast_node %>";
    }
% end
% end
    if(IsExpression(ast)) {
        return "Expression";
    }
    if(IsStatement(ast)) {
        return "Statement";
    }
    return "Unknown AstNode";
}

// NOLINTBEGIN(performance-for-range-copy, readability-identifier-naming)
% Es2pandaLibApi::classes&.each do |namespaceName, namespaceClasses|
% namespaceClasses&.each do |className, classData|

% classData.class_constructors&.each_with_index do |constructor, index|
/* <%= constructor["raw_decl"] %> */
extern "C" <%= classData.constructor_type().lib_type_to_str()
%>Create<%= className + constructor["overload"]
%>([[maybe_unused]] es2panda_Context *context
<%= constructor["args"]&.map { |arg|  if arg.lib_args_to_str.strip() != "" then
", " + "[[maybe_unused]] " + arg.lib_args_to_str end }&.join("") %>)
{
% constructor["args"]&.each do |arg|
    <%= arg.lib_cast["expression"] %>
% end
    auto *ctx = reinterpret_cast<Context *>(context);
    auto *ctxAllocator = ctx->allocator;
% if classData.constructor_type().lib_type_to_str() == "es2panda_AstNode *"
    auto *astNode = (<%= classData.constructor_cast["start"]
    %><%= constructor["args"]&.map { |arg| arg.lib_cast["var_name"] }&.join(", ") %>)<%=
        classData.constructor_cast["end"] %>;
    astNode->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP);
    return reinterpret_cast<<%= classData.constructor_type().lib_type_to_str()
               %>>(astNode);
% elsif
    return reinterpret_cast<<%= classData.constructor_type().lib_type_to_str()
    %>>(<%= classData.constructor_cast["start"]
    %><%= constructor["args"]&.map { |arg| arg.lib_cast["var_name"] }&.join(", ") %>)<%=
        classData.constructor_cast["end"] %>;
% end
}

% if classData.updater_allowed()

/* Updater */
extern "C" <%= classData.constructor_type().lib_type_to_str()
%>Update<%= className + constructor["overload"]
%>([[maybe_unused]] es2panda_Context *context, es2panda_AstNode *original
<%= constructor["args"]&.map { |arg|  if arg.lib_args_to_str.strip() != "" then
", " + "[[maybe_unused]] " + arg.lib_args_to_str end }&.join("") %>)
{
{
    auto *prog = const_cast<parser::Program *>(reinterpret_cast<ir::AstNode *>(original)->Program());
    if(prog != nullptr) {
        prog->SetProgramModified(true);
    }
}
% constructor["args"]&.each do |arg|
    <%= arg.lib_cast["expression"] %>
% end
    auto *ctx = reinterpret_cast<Context *>(context);
    auto *ctxAllocator = ctx->allocator;
    auto newE2pNode =  <%= classData.constructor_cast["start"]
    %><%= constructor["args"]&.map { |arg| arg.lib_cast["var_name"] }&.join(", ") %><%=
        classData.constructor_cast["end"] %>;
    auto *e2pOriginal = reinterpret_cast<ir::AstNode *>(original);
    newE2pNode->SetOriginalNode(e2pOriginal);
    newE2pNode->SetParent(e2pOriginal->Parent());
    newE2pNode->SetRange(e2pOriginal->Range());
% if classData.constructor_type().lib_type_to_str() == "es2panda_AstNode *"
    newE2pNode->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP);
% end
% if className + constructor["overload"] == "MethodDefinition"
    for (auto overload : e2pOriginal->AsMethodDefinition()->Overloads()) {
        overload->SetBaseOverloadMethod(newE2pNode);
    }
    newE2pNode->AsMethodDefinition()->SetBaseOverloadMethod(e2pOriginal->AsMethodDefinition()->BaseOverloadMethod());
    if (e2pOriginal->AsMethodDefinition()->BaseOverloadMethod() != nullptr) {
        auto originalOverloads = e2pOriginal->AsMethodDefinition()->BaseOverloadMethod()->Overloads();
        for (auto &overload : originalOverloads) {
            if (overload == e2pOriginal) {
                overload = newE2pNode;
            }
        }
        e2pOriginal->AsMethodDefinition()->BaseOverloadMethod()->SetOverloads(std::move(originalOverloads));
    }
    auto oriOverloads = e2pOriginal->AsMethodDefinition()->Overloads();
    newE2pNode->AsMethodDefinition()->SetOverloads(std::move(oriOverloads));

% end
% if className == "AssignmentExpression"
    if (e2pOriginal->AsAssignmentExpression()->IsIgnoreConstAssign()) {
        newE2pNode->SetIgnoreConstAssign();
    }
% end
% if className == "AssignmentExpression"
    if (e2pOriginal->AsAssignmentExpression()->IsIgnoreConstAssign()) {
        newE2pNode->SetIgnoreConstAssign();
    }
% end
    return reinterpret_cast<<%= classData.constructor_type().lib_type_to_str()
    %>>(newE2pNode);
}

%end    # updater end

% end   # constructors end

% classData.class_methods&.each_with_index do |method_info, index|
/* <%= method_info["raw_decl"] %> */
extern "C" <%= method_info["return_type"].lib_type_to_str %><%= className + method_info["overload_name"]
%>([[maybe_unused]] es2panda_Context *context<%= if classData.call_cast["call_var_str"]
then ", " + classData.call_cast["call_var_str"] end %><%=
method_info["args"]&.map { |arg| if arg.lib_args_to_str.strip() != "" then
", " + "[[maybe_unused]] " + arg.lib_args_to_str end}&.join("") %>/*return_args:*/<%= method_info["return_arg_to_str"] %>)
{
% if method_info['get_modifier'] == 'set' && classData.updater_allowed()
{
    auto *prog = const_cast<parser::Program *>(reinterpret_cast<ir::AstNode *>(<%= classData.call_cast['call_var']['name'] %>)->Program());
    if (prog != nullptr) {
        prog->SetProgramModified(true);
    }
}
% end
% method_info["args"]&.each do |arg|
    <%= arg.lib_cast["expression"] %>
% end
    <%= method_info["return_expr"] %>
}

% end   # methods end

% end
% end   # classes end

% Es2pandaLibApi::structs&.each do |structName, structData|

% structData.struct_getters&.each_with_index do |method_info, index|
extern "C" <%= method_info["return_type"].lib_type_to_str %><%= structName + method_info["name"]
%>([[maybe_unused]] es2panda_Context *context<%= if structData.call_cast["call_var_str"]
then structData.call_cast["call_var_str"] end %>/*return_args:*/<%= method_info["return_arg_to_str"] %>)
{
% method_info["args"]&.each do |arg|
    <%= arg.lib_cast["expression"] %>
% end
    <%= method_info["return_expr"] %>
}

% end   # getters end

% end   # structs end


% Es2pandaLibApi::print_stats
// NOLINTEND(performance-for-range-copy, readability-identifier-naming)
 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-non-const-parameter)