// 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 "glog/logging.h" #include "nlohmann/json.hpp" #include "paddle/ap/include/axpr/anf_expr.h" #include "paddle/ap/include/axpr/anf_expr_builder.h" #include "paddle/ap/include/axpr/core_expr.h" #include "paddle/ap/include/axpr/core_expr_builder.h" #include "paddle/common/enforce.h" namespace ap::axpr { AnfExpr ConvertCoreExprToAnfExpr(const CoreExpr& core_expr); namespace detail { struct CoreExprToAnfExprConverter { AnfExpr ConvertCoreExprToAnfExpr(const CoreExpr& core_expr) { return core_expr.Match( [&](const Atomic& atomic) -> AnfExpr { return ConvertAtomic(atomic); }, [&](const ComposedCall>& composed_call) -> AnfExpr { return ConvertComposedCall(composed_call); }); } private: Atomic ConvertAtomic(const Atomic& atomic) { return atomic.Match( [&](const Lambda& lambda) -> Atomic { return ConvertLambda(lambda); }, [&](const Symbol& symbol) -> Atomic { return symbol.Match( [&](const tVar& var) -> Atomic { return Atomic{var}; }, [&](const builtin_symbol::Symbol& symbol) -> Atomic { tVar var{symbol.Name()}; return Atomic{var}; }); }, [&](adt::Nothing) -> Atomic { return Atomic{adt::Nothing{}}; }, [&](bool c) -> Atomic { return Atomic{c}; }, [&](int64_t c) -> Atomic { return Atomic{c}; }, [&](double c) -> Atomic { return Atomic{c}; }, [&](const std::string& val) -> Atomic { return Atomic{val}; }); } Atomic ConvertLambda(const Lambda& lambda) { return Lambda{lambda->args, ConvertCoreExprToAnfExpr(lambda->body)}; } AnfExpr ConvertComposedCall( const ComposedCall>& composed_call) { const auto& outer_func = composed_call->outer_func; return outer_func.Match( [&](const Lambda& lambda) -> AnfExpr { std::vector> bindings; return ConvertComposedCallToLet(composed_call, &bindings); }, [&](const Symbol& symbol) -> AnfExpr { return symbol.Match( [&](const tVar& var) -> AnfExpr { CHECK_EQ(var.value(), kBuiltinReturn()); return ConvertComposedCallToCombined(composed_call); }, [&](const builtin_symbol::Symbol& symbol) -> AnfExpr { LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn(); return Atomic{""}; }); }, [&](const auto& c) -> AnfExpr { LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn(); return Atomic(c); }); } Combined ConvertComposedCallToCombined( const ComposedCall>& composed_call) { const auto& f = ConvertAtomic(composed_call->inner_func); std::vector> args; args.reserve(composed_call->args.size()); for (const auto& arg : composed_call->args) { args.push_back(ConvertAtomic(arg)); } return Combined{Call{f, std::move(args)}}; } AnfExpr ConvertComposedCallToLet( const ComposedCall>& composed_call, std::vector>* bindings) { const auto& outer_func = composed_call->outer_func; return outer_func.Match( [&](const Lambda& lambda) -> AnfExpr { CHECK_EQ(lambda->args.size(), 1U); const auto& val = ConvertComposedCallToCombined(composed_call); Bind binding{lambda->args.at(0), val}; bindings->emplace_back(std::move(binding)); const auto& body = lambda->body; return body.Match( [&](const Atomic& atomic_body) -> AnfExpr { return Let{*bindings, ConvertAtomic(atomic_body)}; }, [&](const ComposedCall>& composed_call_body) -> AnfExpr { return ConvertComposedCallToLet(composed_call_body, bindings); }); }, [&](const Symbol& symbol) -> AnfExpr { return symbol.Match( [&](const tVar& var) -> AnfExpr { CHECK_EQ(var.value(), kBuiltinReturn()); const auto& body = ConvertComposedCallToCombined(composed_call); return Let{*bindings, body}; }, [&](const builtin_symbol::Symbol& symbol) -> AnfExpr { LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn(); return Atomic{""}; }); }, [&](const auto& c) -> AnfExpr { LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn(); return Atomic(c); }); } }; } // namespace detail inline AnfExpr ConvertCoreExprToAnfExpr(const CoreExpr& core_expr) { return detail::CoreExprToAnfExprConverter().ConvertCoreExprToAnfExpr( core_expr); } namespace detail { // Convert anf expr to core expr without duplicate var name. struct AnfExprToCoreExprConverter { AnfExprToCoreExprConverter() : core_() {} using LazyCoreExpr = std::function( const Atomic& continuation)>; using MaybeLazyCoreExprBase = std::variant; struct MaybeLazyCoreExpr : public MaybeLazyCoreExprBase { using MaybeLazyCoreExprBase::MaybeLazyCoreExprBase; DEFINE_MATCH_METHOD(); const MaybeLazyCoreExprBase& variant() const { return reinterpret_cast(*this); } template bool Has() const { return std::holds_alternative(variant()); } template const T& Get() const { return std::get(variant()); } }; template MaybeLazyCoreExpr CoreVal(const T& val) { return MaybeLazyCoreExpr{CoreExpr{val}}; } MaybeLazyCoreExpr LazyCoreVal(const LazyCoreExpr& lazy) { return MaybeLazyCoreExpr{lazy}; } using value_type = MaybeLazyCoreExpr; CoreExpr ConvertAnfExprToCoreExpr(const AnfExpr& anf_expr) { MaybeLazyCoreExpr ret_val = Convert(anf_expr); const auto& lazy_core_expr = TryWrapperToLazyCoreExpr(ret_val); CoreExpr ret = lazy_core_expr(CoreExprBuilder().Var(kBuiltinReturn())); return ret.Match( [&](const Atomic&) -> CoreExpr { return ret; }, [&](const ComposedCallAtomic& composed_call) -> CoreExpr { Atomic return_id{tVar{kBuiltinReturn()}}; Atomic identity{Symbol{builtin_symbol::Id{}}}; if (composed_call->outer_func != return_id) { return composed_call; } if (composed_call->inner_func != identity) { return composed_call; } if (composed_call->args.size() != 1) { return composed_call; } return composed_call->args.at(0); }); } value_type Convert(const AnfExpr& anf_expr) { return anf_expr.Match( [&](const Atomic& atomic_expr) { return ConvertAtomic(atomic_expr); }, [&](const Combined& combined_expr) { return ConvertCombined(combined_expr); }, [&](const Let& let_expr) { return ConvertLet(let_expr); }); } LazyCoreExpr TryWrapperToLazyCoreExpr( const MaybeLazyCoreExpr& maybe_lazy_core_expr) { return maybe_lazy_core_expr.Match( [&](const LazyCoreExpr& lazy) { return lazy; }, [&](const CoreExpr& core_expr) { PADDLE_ENFORCE_EQ( core_expr.Has>(), true, common::errors::InvalidArgument( "core_expr should return a Atomic instance")); const Atomic val = core_expr.Get>(); return LazyCoreExpr([val](const Atomic& continuation) { CoreExprBuilder core{}; return core.ComposedCallAtomic( continuation, Symbol{builtin_symbol::Id{}}, {val}); }); }); } value_type ConvertAtomic(const Atomic& atomic_expr) { return atomic_expr.Match( [&](const tVar& var) { return ConvertVar(var); }, [&](const adt::Nothing) { return ConvertNothing(); }, [&](bool c) { return ConvertBool(c); }, [&](int64_t c) { return ConvertInt64(c); }, [&](double c) { return ConvertDouble(c); }, [&](const std::string& c) { return ConvertString(c); }, [&](const Lambda& lambda) { return ConvertLambda(lambda); }); } value_type ConvertCombined(const Combined& combined_expr) { return combined_expr.Match( [&](const Call& call_expr) { return ConvertCall(call_expr); }, [&](const If& if_expr) { return ConvertIf(if_expr); }); } value_type ConvertVar(const tVar& var) { const auto& opt_symbol = builtin_symbol::GetSymbolFromString(var.value()); return CoreVal(opt_symbol.Match( [&](const builtin_symbol::Symbol& symbol) -> Symbol { return symbol; }, [&](const adt::Nothing&) -> Symbol { return var; })); } value_type ConvertNothing() { return CoreVal(core_.None()); } value_type ConvertBool(const bool c) { return CoreVal(core_.Bool(c)); } value_type ConvertInt64(const int64_t c) { return CoreVal(core_.Int64(c)); } value_type ConvertDouble(const double c) { return CoreVal(core_.Double(c)); } value_type ConvertString(const std::string& c) { return CoreVal(core_.String(c)); } value_type ConvertLambda(const Lambda& anf_expr) { const auto& core_body_val = Convert(anf_expr->body); LazyCoreExpr lazy_core_expr = TryWrapperToLazyCoreExpr(core_body_val); CoreExpr core_body = lazy_core_expr(core_.Var(kBuiltinReturn())); return CoreVal(core_.Lambda(anf_expr->args, core_body)); } value_type ConvertCall(const Call& anf_expr) { const auto& inner_func = ConvertAtomicToAtomic(anf_expr->func); std::vector> core_args{}; core_args.reserve(anf_expr->args.size()); for (const auto& arg : anf_expr->args) { core_args.push_back(ConvertAtomicToAtomic(arg)); } return LazyCoreVal( [inner_func, core_args](const Atomic& continuation) { CoreExprBuilder core{}; return core.ComposedCallAtomic(continuation, inner_func, core_args); }); } value_type ConvertIf(const If& anf_expr) { const Atomic& core_cond = ConvertAtomicToAtomic(anf_expr->cond); const auto& MakeZeroArgLambda = [](const auto& expr_ptr) { return AnfExprBuilder().Lambda({}, expr_ptr); }; const Atomic& core_true_expr = ConvertAtomicToAtomic(MakeZeroArgLambda(anf_expr->true_expr)); const Atomic& core_false_expr = ConvertAtomicToAtomic(MakeZeroArgLambda(anf_expr->false_expr)); return LazyCoreVal([=](const Atomic& continuation) { CoreExprBuilder core{}; return core.ComposedCallAtomic( continuation, core.Var("if"), {core_cond, core_true_expr, core_false_expr}); }); } value_type ConvertLet(const Let& anf_expr) { std::vector symbol_names; std::vector lazy_core_exprs; lazy_core_exprs.reserve(anf_expr->bindings.size()); for (const auto& binding : anf_expr->bindings) { symbol_names.push_back(binding.var.value()); lazy_core_exprs.push_back(ConvertCombinedToLazyCoreExpr(binding.val)); } value_type body_val = Convert(anf_expr->body); LazyCoreExpr body_lazy_core_expr = TryWrapperToLazyCoreExpr(body_val); lazy_core_exprs.push_back(body_lazy_core_expr); PADDLE_ENFORCE_EQ( lazy_core_exprs.size(), symbol_names.size() + 1, common::errors::InvalidArgument( "lazy_core_exprs.size() should equal to symbol_names.size() + 1")); return LazyCoreVal( [symbol_names, lazy_core_exprs](Atomic continuation) { CoreExprBuilder core{}; LazyCoreExpr first_body_lazy_core_expr = lazy_core_exprs.at(0); for (int i = lazy_core_exprs.size() - 1; i > 0; i--) { const auto& var = symbol_names.at(i - 1); LazyCoreExpr lazy_core_expr = lazy_core_exprs.at(i); CoreExpr body = lazy_core_expr(continuation); continuation = core.Lambda({tVar{var}}, body); } return first_body_lazy_core_expr(continuation); }); } private: void CheckIsAtomic(const value_type& maybe_lazy_core_expr) { PADDLE_ENFORCE_EQ(maybe_lazy_core_expr.Has(), true, common::errors::InvalidArgument( "ConvertAtomic should return a CoreExpr instance")); const auto& core_expr = maybe_lazy_core_expr.Get(); PADDLE_ENFORCE_EQ( core_expr.Has>(), true, common::errors::InvalidArgument( "ConvertAtomic should return a Atomic instance")); } Atomic GetAtomic(const value_type& val) { return val.Get().Get>(); } Atomic ConvertAtomicToAtomic(const Atomic& atomic_anf) { value_type val = ConvertAtomic(atomic_anf); CheckIsAtomic(val); return GetAtomic(val); } void CheckIsLazyCoreExpr(const value_type& maybe_lazy_core_expr) { PADDLE_ENFORCE_EQ( maybe_lazy_core_expr.Has(), true, common::errors::InvalidArgument( "ConvertCombined should return a LazyCoreExpr instance")); } LazyCoreExpr GetLazyCoreExpr(const value_type& val) { return val.Get(); } LazyCoreExpr ConvertCombinedToLazyCoreExpr( const Combined& combined_anf) { value_type val = ConvertCombined(combined_anf); CheckIsLazyCoreExpr(val); return GetLazyCoreExpr(val); } CoreExprBuilder core_; }; } // namespace detail inline CoreExpr ConvertAnfExprToCoreExpr(const AnfExpr& anf_expr) { return detail::AnfExprToCoreExprConverter().ConvertAnfExprToCoreExpr( anf_expr); } namespace detail { using adt::Result; using Json = nlohmann::json; inline adt::errors::Error JsonParseFailed(const Json& j_obj, const std::string& msg) { return adt::errors::TypeError{msg + " json: " + j_obj.dump()}; } inline adt::errors::Error JsonParseMismatch(const Json& j_obj, const std::string& msg) { return adt::errors::MismatchError{msg}; } typedef Result (*JsonParseFuncType)(const Json& j_obj); Result ConvertJsonToAnfExpr(const Json& j_obj); struct ParseJsonToAnfExprHelperVar { static Result Call(const Json& j_obj) { if (!j_obj.is_string()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: json " "objects should be strings"); } std::string str = j_obj.get(); return AnfExpr{AnfExprBuilder().Var(str)}; } }; struct ParseJsonToAnfExprHelperNull { static Result Call(const Json& j_obj) { if (!j_obj.is_null()) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr: json object should be null."); } return AnfExpr{AnfExprBuilder().None()}; } }; struct ParseJsonToAnfExprHelperBool { static Result Call(const Json& j_obj) { if (!j_obj.is_boolean()) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr: json object should be a boolean."); } bool c = j_obj.get(); return AnfExpr{AnfExprBuilder().Bool(c)}; } }; struct ParseJsonToAnfExprHelperInt64 { static Result Call(const Json& j_obj) { if (!j_obj.is_number_integer()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr: json object " "should be a integral number."); } auto c = j_obj.get(); return AnfExpr{AnfExprBuilder().Int64(c)}; } }; struct ParseJsonToAnfExprHelperDouble { static Result Call(const Json& j_obj) { if (!j_obj.is_number_float()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr: json object should " "be a floating point number."); } auto c = j_obj.template get(); return AnfExpr{AnfExprBuilder().Double(c)}; } }; struct ParseJsonToAnfExprHelperString { static Result Call(const Json& j_obj) { if (!j_obj.is_object()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr: an string " "AnfExpr should be a json object."); } if (!j_obj.contains(AnfExpr::kString())) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr: an string " "AnfExpr should contain a string."); } if (j_obj.size() != 1) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr: length of json " "object should equal to 1."); } if (!j_obj[AnfExpr::kString()].is_string()) { return JsonParseFailed( j_obj, "ParseJsonToAnfExpr: an string AnfExpr " "should contain a string."); } auto c = j_obj[AnfExpr::kString()].get(); return AnfExpr{AnfExprBuilder().String(c)}; } }; struct ParseJsonToAnfExprHelperLambdaAnfExpr { static Result Call(const Json& j_obj) { if (!j_obj.is_array()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: json " "objects should be arrays."); } if (j_obj.size() != 3) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: length of " "json array should equal to 3."); } if (j_obj.at(0) != AnfExpr::kLambda()) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr>: the first " "element of json array should equal to 'lambda'."); } if (!j_obj.at(1).is_array()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the second " "element of json array should be a list."); } std::vector> args; for (const auto& arg : j_obj.at(1)) { if (!arg.is_string()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: lambda " "arguments should be var names."); } args.emplace_back(arg.get()); } const auto& body = ConvertJsonToAnfExpr(j_obj.at(2)); if (!body.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the lambda " "body should be a valid AnfExpr."); } return AnfExpr{AnfExprBuilder().Lambda(args, body.GetOkValue())}; } }; struct ParseJsonToAnfExprHelperCallAnfExpr { static Result Call(const Json& j_obj) { if (!j_obj.is_array()) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr>: json objects should be arrays."); } if (j_obj.empty()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: json arrays " "should be not empty."); } const auto& func = ConvertJsonToAnfExpr(j_obj.at(0)); if (!func.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the function " "should a valid AnfExpr."); } if (!func.GetOkValue().Has>()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the function " "should a valid atomic AnfExpr."); } std::vector> args; for (size_t i = 1; i < j_obj.size(); ++i) { const auto& arg = j_obj.at(i); const auto& arg_expr = ConvertJsonToAnfExpr(arg); if (!arg_expr.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the args " "should be valid AnfExprs."); } if (!arg_expr.GetOkValue().Has>()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the args " "should be valid atomic AnfExprs."); } args.push_back(arg_expr.GetOkValue().Get>()); } return AnfExpr{ AnfExprBuilder().Call(func.GetOkValue().Get>(), args)}; } }; struct ParseJsonToAnfExprHelperIfAnfExpr { static Result Call(const Json& j_obj) { if (!j_obj.is_array()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: json objects " "should be valid atomic AnfExprs."); } if (j_obj.size() != 4) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: the length of " "json array should equal to 4."); } if (j_obj.at(0) != AnfExpr::kIf()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: the first " "argument of json array should equal to 'if'."); } const auto& cond = ConvertJsonToAnfExpr(j_obj.at(1)); if (!cond.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the second " "argument of json array should a valid AnfExpr."); } if (!cond.GetOkValue().Has>()) { return JsonParseFailed( j_obj, "ParseJsonToAnfExpr>: the second argument of json array " "should a valid atomic AnfExpr."); } const auto& cond_expr = cond.GetOkValue().Get>(); const auto& true_expr = ConvertJsonToAnfExpr(j_obj.at(2)); if (!true_expr.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the third " "argument of json array should a valid AnfExpr."); } const auto& false_expr = ConvertJsonToAnfExpr(j_obj.at(3)); if (!false_expr.HasOkValue()) { return JsonParseFailed(j_obj, "ParseJsonToAnfExpr>: the forth " "argument of json array should a valid AnfExpr."); } return AnfExpr{AnfExprBuilder().If( cond_expr, true_expr.GetOkValue(), false_expr.GetOkValue())}; } }; struct ParseJsonToAnfExprHelperLetAnfExpr { static Result Call(const Json& j_obj) { if (!j_obj.is_array()) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr>: json objects should be arrays."); } if (j_obj.size() != 3) { return JsonParseMismatch( j_obj, "ParseJsonToAnfExpr>: the length of " "json array should equal to 3."); } if (j_obj.at(0) != AnfExpr::kLet()) { return JsonParseMismatch(j_obj, "ParseJsonToAnfExpr>: the first " "argument of json array should be 'let'."); } std::vector> bindings; const auto& j_bindings = j_obj.at(1); for (size_t i = 0; i < j_bindings.size(); ++i) { const auto& binding = j_bindings.at(i); if (!binding.is_array()) { return JsonParseFailed(binding, "ParseJsonToAnfExpr>: bindings " "should be json arrays."); } if (binding.size() != 2) { return JsonParseFailed(binding, "ParseJsonToAnfExpr>: the size of " "one binding should equal to 2."); } if (!binding.at(0).is_string()) { return JsonParseFailed(binding.at(0), "ParseJsonToAnfExpr>: the first " "element of a binding should be var name."); } std::string var = binding.at(0).get(); const auto& val = ConvertJsonToAnfExpr(binding.at(1)); if (!val.HasOkValue()) { return JsonParseFailed( binding.at(1), "ParseJsonToAnfExpr>: the second " "element of a binding should be a valid AnfExpr."); } if (!val.GetOkValue().Has>()) { return JsonParseFailed( binding.at(1), "ParseJsonToAnfExpr>: the second element of a binding " "should be a valid combined AnfExpr."); } bindings.push_back(AnfExprBuilder().Bind( var, val.GetOkValue().Get>())); } const auto& body = ConvertJsonToAnfExpr(j_obj.at(2)); if (!body.HasOkValue()) { return JsonParseFailed( j_obj.at(2), "ParseJsonToAnfExpr>: the body of Let " "AnfExpr should be a valid AnfExpr."); } return AnfExpr{AnfExprBuilder().Let(bindings, body.GetOkValue())}; } }; inline const std::vector& GetJsonParseFuncs() { static const std::vector vec{ &ParseJsonToAnfExprHelperLambdaAnfExpr::Call, &ParseJsonToAnfExprHelperIfAnfExpr::Call, &ParseJsonToAnfExprHelperLetAnfExpr::Call, &ParseJsonToAnfExprHelperCallAnfExpr::Call, &ParseJsonToAnfExprHelperVar::Call, &ParseJsonToAnfExprHelperNull::Call, &ParseJsonToAnfExprHelperBool::Call, &ParseJsonToAnfExprHelperInt64::Call, &ParseJsonToAnfExprHelperDouble::Call, &ParseJsonToAnfExprHelperString::Call, }; return vec; } inline Result ConvertJsonToAnfExpr(const Json& j_obj) { try { for (const auto& parse_func : GetJsonParseFuncs()) { const auto& ret = parse_func(j_obj); if (ret.HasOkValue()) { return ret.GetOkValue(); } if (!ret.GetError().Has()) { LOG(ERROR) << "\nTraceback (most recent call last):\n" << ret.GetError().CallStackToString() << "\n" << ret.GetError().class_name() << ": ConvertJsonToAnfExpr: " << ret.GetError().msg(); return ret.GetError(); } } } catch (std::exception& e) { return JsonParseFailed(j_obj, "ConvertJsonToAnfExpr: throw error when parsing."); } return JsonParseFailed(j_obj, "ConvertJsonToAnfExpr: failed to convert."); } inline Result MakeAnfExprFromJsonString(const std::string& json_str) { try { return detail::ConvertJsonToAnfExpr(Json::parse(json_str)); } catch (std::exception& e) { return adt::errors::InvalidArgumentError{ std::string() + "json parse failed. exception::what():" + e.what()}; } } } // namespace detail inline adt::Result MakeAnfExprFromJsonString( const std::string& json_str) { return detail::MakeAnfExprFromJsonString(json_str); } } // namespace ap::axpr