* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "ast_nodes.h"
#include <utility>
namespace ge {
namespace {
template <typename T>
ArrayRef<T> CopyArray(AstContext &ctx, const std::vector<T> &items) {
auto copied = ctx.AllocateMutableArray<T>(items.size());
GE_ASSERT_TRUE(copied.Data() != nullptr || items.empty());
for (size_t i = 0; i < items.size(); ++i) {
copied[i] = items[i];
}
return ArrayRef<T>(copied.Data(), copied.Size());
}
template <typename NodeT, typename... Args>
NodeT *AllocateNode(AstContext &ctx, Args &&...args) {
void *mem = ctx.Allocate(sizeof(NodeT));
GE_ASSERT_NOTNULL(mem);
return new (mem) NodeT(std::forward<Args>(args)...);
}
template <typename NodeT>
NodeT *CreateNamedContainer(AstContext &ctx, const std::string &name, const std::vector<DeclNode *> &items) {
return AllocateNode<NodeT>(ctx, ctx.CopyString(name.c_str()), CopyArray(ctx, items));
}
}
ParamDecl *ParamDecl::Create(AstContext &ctx, const std::string &type_spec, const std::string &name) {
return AllocateNode<ParamDecl>(ctx, ctx.CopyString(type_spec.c_str()), ctx.CopyString(name.c_str()));
}
Status ParamDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
TranslationUnit *TranslationUnit::Create(AstContext &ctx, const std::vector<DeclNode *> &items) {
return AllocateNode<TranslationUnit>(ctx, CopyArray(ctx, items));
}
Status TranslationUnit::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
StablePartDecl *StablePartDecl::Create(AstContext &ctx, StablePartId id, StablePartRole role,
StablePartPlacement placement) {
return AllocateNode<StablePartDecl>(ctx, id, role, placement);
}
Status StablePartDecl::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
IncludeDecl *IncludeDecl::Create(AstContext &ctx, const std::string &path, Kind kind) {
return AllocateNode<IncludeDecl>(ctx, ctx.CopyString(path.c_str()), kind);
}
Status IncludeDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
SpaceDecl *SpaceDecl::Create(AstContext &ctx) { return AllocateNode<SpaceDecl>(ctx); }
Status SpaceDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
TypeAliasDecl *TypeAliasDecl::Create(AstContext &ctx, const std::string &type_spec, const std::string &name) {
return AllocateNode<TypeAliasDecl>(ctx, ctx.CopyString(type_spec.c_str()), ctx.CopyString(name.c_str()));
}
Status TypeAliasDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
NamespaceDecl *NamespaceDecl::Create(AstContext &ctx, const std::string &name, const std::vector<DeclNode *> &items) {
return CreateNamedContainer<NamespaceDecl>(ctx, name, items);
}
Status NamespaceDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
ExternBlockDecl *ExternBlockDecl::Create(AstContext &ctx, const std::string &language,
const std::vector<DeclNode *> &items) {
return CreateNamedContainer<ExternBlockDecl>(ctx, language, items);
}
Status ExternBlockDecl::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
ClassDecl *ClassDecl::Create(AstContext &ctx, const std::string &name, const std::vector<DeclNode *> &items) {
return CreateNamedContainer<ClassDecl>(ctx, name, items);
}
Status ClassDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
StructDecl *StructDecl::Create(AstContext &ctx, const std::string &name, const std::vector<DeclNode *> &items) {
return CreateNamedContainer<StructDecl>(ctx, name, items);
}
Status StructDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
AccessSectionDecl *AccessSectionDecl::Create(AstContext &ctx, Kind kind) {
return AllocateNode<AccessSectionDecl>(ctx, kind);
}
Status AccessSectionDecl::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
FieldDecl *FieldDecl::Create(AstContext &ctx, const std::string &type_spec, const std::string &name, Expr *init) {
return AllocateNode<FieldDecl>(ctx, ctx.CopyString(type_spec.c_str()), ctx.CopyString(name.c_str()), init);
}
Status FieldDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
MethodDecl *MethodDecl::Create(AstContext &ctx, const std::string &name, const std::vector<ParamDecl *> ¶ms,
const std::string &return_type, const std::string &trailing_spec) {
return AllocateNode<MethodDecl>(ctx, ctx.CopyString(name.c_str()), CopyArray(ctx, params),
ctx.CopyString(return_type.c_str()), ctx.CopyString(trailing_spec.c_str()));
}
Status MethodDecl::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
FunctionDecl *FunctionDecl::Create(AstContext &ctx, const std::string &name, const std::vector<ParamDecl *> ¶ms,
const std::string &return_type) {
return AllocateNode<FunctionDecl>(ctx, ctx.CopyString(name.c_str()), CopyArray(ctx, params),
ctx.CopyString(return_type.c_str()));
}
Status FunctionDecl::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
FunctionDef *FunctionDef::Create(AstContext &ctx, const std::string &name, const std::vector<ParamDecl *> ¶ms,
const std::string &return_type, BlockStmt *body) {
GE_ASSERT_NOTNULL(body);
return AllocateNode<FunctionDef>(ctx, ctx.CopyString(name.c_str()), CopyArray(ctx, params),
ctx.CopyString(return_type.c_str()), body);
}
Status FunctionDef::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
MethodDef *MethodDef::Create(AstContext &ctx, const std::string &owner, const std::string &name,
const std::vector<ParamDecl *> ¶ms, const std::string &return_type,
const std::vector<std::string> &member_init_names, const std::vector<Expr *> &member_init_exprs,
BlockStmt *body) {
GE_ASSERT_NOTNULL(body);
GE_ASSERT_TRUE(member_init_names.size() == member_init_exprs.size());
std::vector<StringRef> copied_member_init_names;
copied_member_init_names.reserve(member_init_names.size());
for (const auto &member_init_name : member_init_names) {
copied_member_init_names.push_back(ctx.CopyString(member_init_name.c_str()));
}
return AllocateNode<MethodDef>(ctx, ctx.CopyString(owner.c_str()), ctx.CopyString(name.c_str()), CopyArray(ctx, params),
ctx.CopyString(return_type.c_str()), CopyArray(ctx, copied_member_init_names),
CopyArray(ctx, member_init_exprs), body);
}
Status MethodDef::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
IdentifierExpr *IdentifierExpr::Create(AstContext &ctx, const std::string &name) {
return AllocateNode<IdentifierExpr>(ctx, ctx.CopyString(name.c_str()));
}
Status IdentifierExpr::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
LiteralExpr *LiteralExpr::CreateInt(AstContext &ctx, int64_t value, IntSuffix suffix) {
return AllocateNode<LiteralExpr>(ctx, Kind::kInt, value, suffix, false, StringRef());
}
LiteralExpr *LiteralExpr::CreateBool(AstContext &ctx, bool value) {
return AllocateNode<LiteralExpr>(ctx, Kind::kBool, 0, IntSuffix::kNone, value, StringRef());
}
LiteralExpr *LiteralExpr::CreateString(AstContext &ctx, const std::string &value) {
return AllocateNode<LiteralExpr>(ctx, Kind::kString, 0, IntSuffix::kNone, false, ctx.CopyString(value.c_str()));
}
LiteralExpr *LiteralExpr::CreateNullptr(AstContext &ctx) {
return AllocateNode<LiteralExpr>(ctx, Kind::kNullptr, 0, IntSuffix::kNone, false, StringRef());
}
Status LiteralExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
AssignExpr *AssignExpr::Create(AstContext &ctx, Expr *lhs, Expr *rhs) {
GE_ASSERT_NOTNULL(lhs);
GE_ASSERT_NOTNULL(rhs);
return AllocateNode<AssignExpr>(ctx, lhs, rhs);
}
Status AssignExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
BinaryExpr *BinaryExpr::Create(AstContext &ctx, Op op, Expr *lhs, Expr *rhs) {
GE_ASSERT_NOTNULL(lhs);
GE_ASSERT_NOTNULL(rhs);
return AllocateNode<BinaryExpr>(ctx, op, lhs, rhs);
}
Status BinaryExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
UnaryExpr *UnaryExpr::Create(AstContext &ctx, Op op, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<UnaryExpr>(ctx, op, expr);
}
Status UnaryExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
CallExpr *CallExpr::Create(AstContext &ctx, Expr *callee, const std::vector<Expr *> &args) {
GE_ASSERT_NOTNULL(callee);
return AllocateNode<CallExpr>(ctx, callee, CopyArray(ctx, args));
}
Status CallExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
MakeUniqueArrayExpr *MakeUniqueArrayExpr::Create(AstContext &ctx, const TypeName &elem_type, Expr *count) {
GE_ASSERT_NOTNULL(count);
return AllocateNode<MakeUniqueArrayExpr>(ctx, elem_type, count);
}
Status MakeUniqueArrayExpr::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
ToStrExpr *ToStrExpr::Create(AstContext &ctx, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<ToStrExpr>(ctx, expr);
}
Status ToStrExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
MemcpyExpr *MemcpyExpr::Create(AstContext &ctx, Expr *dst, Expr *src, Expr *size) {
GE_ASSERT_NOTNULL(dst);
GE_ASSERT_NOTNULL(src);
GE_ASSERT_NOTNULL(size);
return AllocateNode<MemcpyExpr>(ctx, dst, src, size);
}
Status MemcpyExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
SizeofExpr *SizeofExpr::Create(AstContext &ctx, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<SizeofExpr>(ctx, expr);
}
Status SizeofExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
RemoveFileExpr *RemoveFileExpr::Create(AstContext &ctx, Expr *path) {
GE_ASSERT_NOTNULL(path);
return AllocateNode<RemoveFileExpr>(ctx, path);
}
Status RemoveFileExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
IgnoreOutputExpr *IgnoreOutputExpr::Create(AstContext &ctx, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<IgnoreOutputExpr>(ctx, expr);
}
Status IgnoreOutputExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
ContainerMethodExpr *ContainerMethodExpr::Create(AstContext &ctx, Method method, Expr *container,
const std::vector<Expr *> &args) {
GE_ASSERT_NOTNULL(container);
return AllocateNode<ContainerMethodExpr>(ctx, method, container, CopyArray(ctx, args));
}
Status ContainerMethodExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
AddrOfExpr *AddrOfExpr::Create(AstContext &ctx, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<AddrOfExpr>(ctx, expr);
}
Status AddrOfExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
SubscriptExpr *SubscriptExpr::Create(AstContext &ctx, Expr *base, Expr *index) {
GE_ASSERT_NOTNULL(base);
GE_ASSERT_NOTNULL(index);
return AllocateNode<SubscriptExpr>(ctx, base, index);
}
Status SubscriptExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
MemberExpr *MemberExpr::Create(AstContext &ctx, Expr *object, const std::string &field) {
GE_ASSERT_NOTNULL(object);
return AllocateNode<MemberExpr>(ctx, object, ctx.CopyString(field.c_str()));
}
Status MemberExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
CppArrowMemberExpr *CppArrowMemberExpr::Create(AstContext &ctx, Expr *object, const std::string &field) {
GE_ASSERT_NOTNULL(object);
return AllocateNode<CppArrowMemberExpr>(ctx, object, ctx.CopyString(field.c_str()));
}
Status CppArrowMemberExpr::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
CppCastExpr *CppCastExpr::Create(AstContext &ctx, Kind kind, const std::string &target_type, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<CppCastExpr>(ctx, kind, ctx.CopyString(target_type.c_str()), expr);
}
Status CppCastExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
LambdaExpr *LambdaExpr::Create(AstContext &ctx, const std::vector<std::string> &captures, BlockStmt *body) {
GE_ASSERT_NOTNULL(body);
std::vector<StringRef> copied;
copied.reserve(captures.size());
for (const auto &capture : captures) {
copied.push_back(ctx.CopyString(capture.c_str()));
}
return AllocateNode<LambdaExpr>(ctx, CopyArray(ctx, copied), body);
}
Status LambdaExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
InitListExpr *InitListExpr::Create(AstContext &ctx, const std::vector<Expr *> &elements) {
return AllocateNode<InitListExpr>(ctx, CopyArray(ctx, elements));
}
Status InitListExpr::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
CommentStmt *CommentStmt::Create(AstContext &ctx, const std::string &text) {
return AllocateNode<CommentStmt>(ctx, ctx.CopyString(text.c_str()));
}
Status CommentStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
BlankLineStmt *BlankLineStmt::Create(AstContext &ctx) { return AllocateNode<BlankLineStmt>(ctx); }
Status BlankLineStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
VarDeclStmt *VarDeclStmt::Create(AstContext &ctx, const std::string &type_spec, const std::string &name, Expr *init) {
return AllocateNode<VarDeclStmt>(ctx, ctx.CopyString(type_spec.c_str()), ctx.CopyString(name.c_str()), init);
}
Status VarDeclStmt::Accept(CodeEmitter &emitter, std::string &output) const {
return emitter.Emit(*this, output);
}
ExprStmt *ExprStmt::Create(AstContext &ctx, Expr *expr) {
GE_ASSERT_NOTNULL(expr);
return AllocateNode<ExprStmt>(ctx, expr);
}
Status ExprStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
ReturnStmt *ReturnStmt::Create(AstContext &ctx, Expr *value) { return AllocateNode<ReturnStmt>(ctx, value); }
Status ReturnStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
BlockStmt *BlockStmt::Create(AstContext &ctx, const std::vector<Stmt *> &statements) {
return AllocateNode<BlockStmt>(ctx, CopyArray(ctx, statements));
}
Status BlockStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
IfStmt *IfStmt::Create(AstContext &ctx, Expr *cond, BlockStmt *then_block, BlockStmt *else_block) {
GE_ASSERT_NOTNULL(cond);
GE_ASSERT_NOTNULL(then_block);
return AllocateNode<IfStmt>(ctx, cond, then_block, else_block);
}
Status IfStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
ForStmt *ForStmt::Create(AstContext &ctx, Stmt *init, Expr *cond, Expr *step, BlockStmt *body) {
GE_ASSERT_NOTNULL(init);
GE_ASSERT_NOTNULL(cond);
GE_ASSERT_NOTNULL(step);
GE_ASSERT_NOTNULL(body);
return AllocateNode<ForStmt>(ctx, init, cond, step, body);
}
Status ForStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
RangeForStmt *RangeForStmt::Create(AstContext &ctx, const std::string &type_spec, const std::string &name, Expr *range,
BlockStmt *body) {
GE_ASSERT_NOTNULL(range);
GE_ASSERT_NOTNULL(body);
return AllocateNode<RangeForStmt>(ctx, ctx.CopyString(type_spec.c_str()), ctx.CopyString(name.c_str()), range, body);
}
Status RangeForStmt::Accept(CodeEmitter &emitter, std::string &output) const { return emitter.Emit(*this, output); }
}