// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved. // // 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. #pragma once #include #include #include "paddle/ap/include/axpr/anf_expr.h" namespace ap::axpr { struct AnfExprHelper { adt::Result FunctionToString( const Lambda& lambda) const { return FunctionToString("unnamed", lambda); } private: adt::Result FunctionToString( const std::string& func_name, const Lambda& lambda) const { std::ostringstream ss; auto Generate = [&](const std::string& str) { ss << str << "\n"; }; ADT_RETURN_IF_ERR(SerializeFunction(Generate, func_name, lambda)); return ss.str(); } adt::Result SerializeFunction( const std::function& Generate, const std::string& func_name, const Lambda& lambda) const { { std::ostringstream ss; ss << "def " << func_name << "("; int i = 0; for (const auto& arg : lambda->args) { if (i++ > 0) { ss << ", "; } ss << arg.value(); } ss << "):"; Generate(ss.str()); } { auto BodyGenerate = [&](const std::string& str) { Generate(std::string(" ") + str); }; ADT_RETURN_IF_ERR(SerializeLastExprInLambda(BodyGenerate, lambda->body)); } return adt::Ok{}; } struct LambdaBodySerializeCtx { std::function Generate; std::size_t auto_id_in_body = 0; std::size_t GetAutoIdInBody() { return auto_id_in_body++; } }; adt::Result SerializeLastExprInLambda( const std::function& Generate, const AnfExpr& lambda_body) const { LambdaBodySerializeCtx ctx{Generate}; return SerializeLastExprInLambda(&ctx, lambda_body); } adt::Result SerializeLastExprInLambda( LambdaBodySerializeCtx* ctx, const AnfExpr& lambda_body) const { return lambda_body.Match([&](const auto& impl) -> adt::Result { return SerializeLastExprInLambdaImpl(ctx, impl); }); } adt::Result SerializeLastExprInLambdaImpl( LambdaBodySerializeCtx* ctx, const Atomic& atomic) const { ADT_LET_CONST_REF( atomic_str, atomic.Match([&](const auto& impl) -> adt::Result { return AtomicToStringImpl(ctx, impl); })); ctx->Generate(std::string() + "return " + atomic_str); return adt::Ok{}; } adt::Result AtomicToString(LambdaBodySerializeCtx* ctx, const Atomic& atomic) const { return atomic.Match([&](const auto& impl) -> adt::Result { return AtomicToStringImpl(ctx, impl); }); } adt::Result SerializeLastExprInLambdaImpl( LambdaBodySerializeCtx* ctx, const Combined& combined) const { ADT_LET_CONST_REF( combined_str, combined.Match([&](const auto& impl) -> adt::Result { return CombinedToStringImpl(ctx, impl); })); ctx->Generate(std::string() + "return " + combined_str); return adt::Ok{}; } adt::Result CombinedToString( LambdaBodySerializeCtx* ctx, const Combined& combined) const { return combined.Match([&](const auto& impl) -> adt::Result { return CombinedToStringImpl(ctx, impl); }); } adt::Result SerializeLastExprInLambdaImpl( LambdaBodySerializeCtx* ctx, const Let& let) const { for (const auto& [var, combined] : let->bindings) { ADT_LET_CONST_REF(combined_str, CombinedToString(ctx, combined)); ctx->Generate(var.value() + " = " + combined_str); } return SerializeLastExprInLambda(ctx, let->body); } adt::Result CombinedToStringImpl( LambdaBodySerializeCtx* ctx, const Call& call) const { std::ostringstream ss; ADT_LET_CONST_REF(func_name, AtomicToString(ctx, call->func)); ss << func_name << "("; int i = 0; for (const auto& arg : call->args) { if (i++ > 0) { ss << ", "; } ADT_LET_CONST_REF(arg_str, AtomicToString(ctx, arg)); ss << arg_str; } ss << ")"; return ss.str(); } adt::Result CombinedToStringImpl( LambdaBodySerializeCtx* ctx, const If& if_expr) const { std::ostringstream ss; ADT_LET_CONST_REF(cond, AtomicToString(ctx, if_expr->cond)); ADT_LET_CONST_REF(true_expr, AnfExprToString(ctx, if_expr->true_expr)); ADT_LET_CONST_REF(false_expr, AnfExprToString(ctx, if_expr->false_expr)); ss << true_expr << " if " << cond << " else " << false_expr; return ss.str(); } adt::Result AnfExprToString(LambdaBodySerializeCtx* ctx, const AnfExpr& anf_expr) const { return anf_expr.Match( [&](const Atomic& atomic) -> adt::Result { return AtomicToString(ctx, atomic); }, [&](const Combined& combined) -> adt::Result { return CombinedToString(ctx, combined); }, [&](const Let&) -> adt::Result { return adt::errors::TypeError{ "Let is not supported in AnfExprToString()."}; }); } adt::Result AtomicToStringImpl(LambdaBodySerializeCtx* ctx, const adt::Nothing&) const { return std::string("None"); } adt::Result AtomicToStringImpl(LambdaBodySerializeCtx* ctx, bool c) const { return std::string(c ? "True" : "False"); } adt::Result AtomicToStringImpl(LambdaBodySerializeCtx* ctx, int64_t c) const { return std::to_string(c); } adt::Result AtomicToStringImpl(LambdaBodySerializeCtx* ctx, double c) const { return std::to_string(c); } adt::Result AtomicToStringImpl(LambdaBodySerializeCtx* ctx, const std::string& str) const { std::ostringstream ss; ss << std::quoted(str); return ss.str(); } adt::Result AtomicToStringImpl( LambdaBodySerializeCtx* ctx, const tVar& var) const { return var.value(); } adt::Result AtomicToStringImpl( LambdaBodySerializeCtx* ctx, const Lambda& lambda) const { const auto& func_name = std::string("tmp_func_") + std::to_string(ctx->GetAutoIdInBody()); ADT_RETURN_IF_ERR(SerializeFunction(ctx->Generate, func_name, lambda)); return func_name; } }; } // namespace ap::axpr