Files
paddlepaddle--paddle/paddle/ap/include/axpr/anf_expr_util.h
T
2026-07-13 12:40:42 +08:00

761 lines
28 KiB
C++

// 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 <atomic>
#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<CoreExpr>& atomic) -> AnfExpr {
return ConvertAtomic(atomic);
},
[&](const ComposedCall<Atomic<CoreExpr>>& composed_call) -> AnfExpr {
return ConvertComposedCall(composed_call);
});
}
private:
Atomic<AnfExpr> ConvertAtomic(const Atomic<CoreExpr>& atomic) {
return atomic.Match(
[&](const Lambda<CoreExpr>& lambda) -> Atomic<AnfExpr> {
return ConvertLambda(lambda);
},
[&](const Symbol& symbol) -> Atomic<AnfExpr> {
return symbol.Match(
[&](const tVar<std::string>& var) -> Atomic<AnfExpr> {
return Atomic<AnfExpr>{var};
},
[&](const builtin_symbol::Symbol& symbol) -> Atomic<AnfExpr> {
tVar<std::string> var{symbol.Name()};
return Atomic<AnfExpr>{var};
});
},
[&](adt::Nothing) -> Atomic<AnfExpr> {
return Atomic<AnfExpr>{adt::Nothing{}};
},
[&](bool c) -> Atomic<AnfExpr> { return Atomic<AnfExpr>{c}; },
[&](int64_t c) -> Atomic<AnfExpr> { return Atomic<AnfExpr>{c}; },
[&](double c) -> Atomic<AnfExpr> { return Atomic<AnfExpr>{c}; },
[&](const std::string& val) -> Atomic<AnfExpr> {
return Atomic<AnfExpr>{val};
});
}
Atomic<AnfExpr> ConvertLambda(const Lambda<CoreExpr>& lambda) {
return Lambda<AnfExpr>{lambda->args,
ConvertCoreExprToAnfExpr(lambda->body)};
}
AnfExpr ConvertComposedCall(
const ComposedCall<Atomic<CoreExpr>>& composed_call) {
const auto& outer_func = composed_call->outer_func;
return outer_func.Match(
[&](const Lambda<CoreExpr>& lambda) -> AnfExpr {
std::vector<Bind<AnfExpr>> bindings;
return ConvertComposedCallToLet(composed_call, &bindings);
},
[&](const Symbol& symbol) -> AnfExpr {
return symbol.Match(
[&](const tVar<std::string>& 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<AnfExpr>{""};
});
},
[&](const auto& c) -> AnfExpr {
LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn();
return Atomic<AnfExpr>(c);
});
}
Combined<AnfExpr> ConvertComposedCallToCombined(
const ComposedCall<Atomic<CoreExpr>>& composed_call) {
const auto& f = ConvertAtomic(composed_call->inner_func);
std::vector<Atomic<AnfExpr>> args;
args.reserve(composed_call->args.size());
for (const auto& arg : composed_call->args) {
args.push_back(ConvertAtomic(arg));
}
return Combined<AnfExpr>{Call<AnfExpr>{f, std::move(args)}};
}
AnfExpr ConvertComposedCallToLet(
const ComposedCall<Atomic<CoreExpr>>& composed_call,
std::vector<Bind<AnfExpr>>* bindings) {
const auto& outer_func = composed_call->outer_func;
return outer_func.Match(
[&](const Lambda<CoreExpr>& lambda) -> AnfExpr {
CHECK_EQ(lambda->args.size(), 1U);
const auto& val = ConvertComposedCallToCombined(composed_call);
Bind<AnfExpr> binding{lambda->args.at(0), val};
bindings->emplace_back(std::move(binding));
const auto& body = lambda->body;
return body.Match(
[&](const Atomic<CoreExpr>& atomic_body) -> AnfExpr {
return Let<AnfExpr>{*bindings, ConvertAtomic(atomic_body)};
},
[&](const ComposedCall<Atomic<CoreExpr>>& composed_call_body)
-> AnfExpr {
return ConvertComposedCallToLet(composed_call_body, bindings);
});
},
[&](const Symbol& symbol) -> AnfExpr {
return symbol.Match(
[&](const tVar<std::string>& var) -> AnfExpr {
CHECK_EQ(var.value(), kBuiltinReturn());
const auto& body = ConvertComposedCallToCombined(composed_call);
return Let<AnfExpr>{*bindings, body};
},
[&](const builtin_symbol::Symbol& symbol) -> AnfExpr {
LOG(FATAL) << "outer_func should be a lambda or "
<< kBuiltinReturn();
return Atomic<AnfExpr>{""};
});
},
[&](const auto& c) -> AnfExpr {
LOG(FATAL) << "outer_func should be a lambda or " << kBuiltinReturn();
return Atomic<AnfExpr>(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<ComposedCallAtomic<CoreExpr>(
const Atomic<CoreExpr>& continuation)>;
using MaybeLazyCoreExprBase = std::variant<CoreExpr, LazyCoreExpr>;
struct MaybeLazyCoreExpr : public MaybeLazyCoreExprBase {
using MaybeLazyCoreExprBase::MaybeLazyCoreExprBase;
DEFINE_MATCH_METHOD();
const MaybeLazyCoreExprBase& variant() const {
return reinterpret_cast<const MaybeLazyCoreExprBase&>(*this);
}
template <typename T>
bool Has() const {
return std::holds_alternative<T>(variant());
}
template <typename T>
const T& Get() const {
return std::get<T>(variant());
}
};
template <typename T>
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>&) -> CoreExpr { return ret; },
[&](const ComposedCallAtomic<CoreExpr>& composed_call) -> CoreExpr {
Atomic<CoreExpr> return_id{tVar<std::string>{kBuiltinReturn()}};
Atomic<CoreExpr> 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<AnfExpr>& atomic_expr) {
return ConvertAtomic(atomic_expr);
},
[&](const Combined<AnfExpr>& combined_expr) {
return ConvertCombined(combined_expr);
},
[&](const Let<AnfExpr>& 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<Atomic<CoreExpr>>(),
true,
common::errors::InvalidArgument(
"core_expr should return a Atomic<CoreExpr> instance"));
const Atomic<CoreExpr> val = core_expr.Get<Atomic<CoreExpr>>();
return LazyCoreExpr([val](const Atomic<CoreExpr>& continuation) {
CoreExprBuilder core{};
return core.ComposedCallAtomic(
continuation, Symbol{builtin_symbol::Id{}}, {val});
});
});
}
value_type ConvertAtomic(const Atomic<AnfExpr>& atomic_expr) {
return atomic_expr.Match(
[&](const tVar<std::string>& 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<AnfExpr>& lambda) { return ConvertLambda(lambda); });
}
value_type ConvertCombined(const Combined<AnfExpr>& combined_expr) {
return combined_expr.Match(
[&](const Call<AnfExpr>& call_expr) { return ConvertCall(call_expr); },
[&](const If<AnfExpr>& if_expr) { return ConvertIf(if_expr); });
}
value_type ConvertVar(const tVar<std::string>& 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<AnfExpr>& 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<AnfExpr>& anf_expr) {
const auto& inner_func = ConvertAtomicToAtomic(anf_expr->func);
std::vector<Atomic<CoreExpr>> 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<CoreExpr>& continuation) {
CoreExprBuilder core{};
return core.ComposedCallAtomic(continuation, inner_func, core_args);
});
}
value_type ConvertIf(const If<AnfExpr>& anf_expr) {
const Atomic<CoreExpr>& core_cond = ConvertAtomicToAtomic(anf_expr->cond);
const auto& MakeZeroArgLambda = [](const auto& expr_ptr) {
return AnfExprBuilder().Lambda({}, expr_ptr);
};
const Atomic<CoreExpr>& core_true_expr =
ConvertAtomicToAtomic(MakeZeroArgLambda(anf_expr->true_expr));
const Atomic<CoreExpr>& core_false_expr =
ConvertAtomicToAtomic(MakeZeroArgLambda(anf_expr->false_expr));
return LazyCoreVal([=](const Atomic<CoreExpr>& continuation) {
CoreExprBuilder core{};
return core.ComposedCallAtomic(
continuation,
core.Var("if"),
{core_cond, core_true_expr, core_false_expr});
});
}
value_type ConvertLet(const Let<AnfExpr>& anf_expr) {
std::vector<std::string> symbol_names;
std::vector<LazyCoreExpr> 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<CoreExpr> 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<std::string>{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<CoreExpr>(),
true,
common::errors::InvalidArgument(
"ConvertAtomic should return a CoreExpr instance"));
const auto& core_expr = maybe_lazy_core_expr.Get<CoreExpr>();
PADDLE_ENFORCE_EQ(
core_expr.Has<Atomic<CoreExpr>>(),
true,
common::errors::InvalidArgument(
"ConvertAtomic should return a Atomic<CoreExpr> instance"));
}
Atomic<CoreExpr> GetAtomic(const value_type& val) {
return val.Get<CoreExpr>().Get<Atomic<CoreExpr>>();
}
Atomic<CoreExpr> ConvertAtomicToAtomic(const Atomic<AnfExpr>& 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<LazyCoreExpr>(),
true,
common::errors::InvalidArgument(
"ConvertCombined should return a LazyCoreExpr instance"));
}
LazyCoreExpr GetLazyCoreExpr(const value_type& val) {
return val.Get<LazyCoreExpr>();
}
LazyCoreExpr ConvertCombinedToLazyCoreExpr(
const Combined<AnfExpr>& 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<AnfExpr> (*JsonParseFuncType)(const Json& j_obj);
Result<AnfExpr> ConvertJsonToAnfExpr(const Json& j_obj);
struct ParseJsonToAnfExprHelperVar {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_string()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<tVar<std::string>>: json "
"objects should be strings");
}
std::string str = j_obj.get<std::string>();
return AnfExpr{AnfExprBuilder().Var(str)};
}
};
struct ParseJsonToAnfExprHelperNull {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_null()) {
return JsonParseMismatch(
j_obj, "ParseJsonToAnfExpr<bool>: json object should be null.");
}
return AnfExpr{AnfExprBuilder().None()};
}
};
struct ParseJsonToAnfExprHelperBool {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_boolean()) {
return JsonParseMismatch(
j_obj, "ParseJsonToAnfExpr<bool>: json object should be a boolean.");
}
bool c = j_obj.get<bool>();
return AnfExpr{AnfExprBuilder().Bool(c)};
}
};
struct ParseJsonToAnfExprHelperInt64 {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_number_integer()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<int64_t>: json object "
"should be a integral number.");
}
auto c = j_obj.get<Json::number_integer_t>();
return AnfExpr{AnfExprBuilder().Int64(c)};
}
};
struct ParseJsonToAnfExprHelperDouble {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_number_float()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<double>: json object should "
"be a floating point number.");
}
auto c = j_obj.template get<double>();
return AnfExpr{AnfExprBuilder().Double(c)};
}
};
struct ParseJsonToAnfExprHelperString {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_object()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<std::string>: an string "
"AnfExpr should be a json object.");
}
if (!j_obj.contains(AnfExpr::kString())) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<std::string>: an string "
"AnfExpr should contain a string.");
}
if (j_obj.size() != 1) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<std::string>: length of json "
"object should equal to 1.");
}
if (!j_obj[AnfExpr::kString()].is_string()) {
return JsonParseFailed(
j_obj,
"ParseJsonToAnfExpr<std::string>: an string AnfExpr "
"should contain a string.");
}
auto c = j_obj[AnfExpr::kString()].get<std::string>();
return AnfExpr{AnfExprBuilder().String(c)};
}
};
struct ParseJsonToAnfExprHelperLambdaAnfExpr {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_array()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: json "
"objects should be arrays.");
}
if (j_obj.size() != 3) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: length of "
"json array should equal to 3.");
}
if (j_obj.at(0) != AnfExpr::kLambda()) {
return JsonParseMismatch(
j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: the first "
"element of json array should equal to 'lambda'.");
}
if (!j_obj.at(1).is_array()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: the second "
"element of json array should be a list.");
}
std::vector<tVar<std::string>> args;
for (const auto& arg : j_obj.at(1)) {
if (!arg.is_string()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: lambda "
"arguments should be var names.");
}
args.emplace_back(arg.get<std::string>());
}
const auto& body = ConvertJsonToAnfExpr(j_obj.at(2));
if (!body.HasOkValue()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Lambda<AnfExpr>>: the lambda "
"body should be a valid AnfExpr.");
}
return AnfExpr{AnfExprBuilder().Lambda(args, body.GetOkValue())};
}
};
struct ParseJsonToAnfExprHelperCallAnfExpr {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_array()) {
return JsonParseMismatch(
j_obj,
"ParseJsonToAnfExpr<Call<AnfExpr>>: json objects should be arrays.");
}
if (j_obj.empty()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Call<AnfExpr>>: json arrays "
"should be not empty.");
}
const auto& func = ConvertJsonToAnfExpr(j_obj.at(0));
if (!func.HasOkValue()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Call<AnfExpr>>: the function "
"should a valid AnfExpr.");
}
if (!func.GetOkValue().Has<Atomic<AnfExpr>>()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Call<AnfExpr>>: the function "
"should a valid atomic AnfExpr.");
}
std::vector<Atomic<AnfExpr>> 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<Call<AnfExpr>>: the args "
"should be valid AnfExprs.");
}
if (!arg_expr.GetOkValue().Has<Atomic<AnfExpr>>()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<Call<AnfExpr>>: the args "
"should be valid atomic AnfExprs.");
}
args.push_back(arg_expr.GetOkValue().Get<Atomic<AnfExpr>>());
}
return AnfExpr{
AnfExprBuilder().Call(func.GetOkValue().Get<Atomic<AnfExpr>>(), args)};
}
};
struct ParseJsonToAnfExprHelperIfAnfExpr {
static Result<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_array()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<If<AnfExpr>>: json objects "
"should be valid atomic AnfExprs.");
}
if (j_obj.size() != 4) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<If<AnfExpr>>: the length of "
"json array should equal to 4.");
}
if (j_obj.at(0) != AnfExpr::kIf()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<If<AnfExpr>>: 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<If<AnfExpr>>: the second "
"argument of json array should a valid AnfExpr.");
}
if (!cond.GetOkValue().Has<Atomic<AnfExpr>>()) {
return JsonParseFailed(
j_obj,
"ParseJsonToAnfExpr<If<AnfExpr>>: the second argument of json array "
"should a valid atomic AnfExpr.");
}
const auto& cond_expr = cond.GetOkValue().Get<Atomic<AnfExpr>>();
const auto& true_expr = ConvertJsonToAnfExpr(j_obj.at(2));
if (!true_expr.HasOkValue()) {
return JsonParseFailed(j_obj,
"ParseJsonToAnfExpr<If<AnfExpr>>: 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<If<AnfExpr>>: 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<AnfExpr> Call(const Json& j_obj) {
if (!j_obj.is_array()) {
return JsonParseMismatch(
j_obj,
"ParseJsonToAnfExpr<Let<AnfExpr>>: json objects should be arrays.");
}
if (j_obj.size() != 3) {
return JsonParseMismatch(
j_obj,
"ParseJsonToAnfExpr<Let<AnfExpr>>: the length of "
"json array should equal to 3.");
}
if (j_obj.at(0) != AnfExpr::kLet()) {
return JsonParseMismatch(j_obj,
"ParseJsonToAnfExpr<Let<AnfExpr>>: the first "
"argument of json array should be 'let'.");
}
std::vector<Bind<AnfExpr>> 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<Let<AnfExpr>>: bindings "
"should be json arrays.");
}
if (binding.size() != 2) {
return JsonParseFailed(binding,
"ParseJsonToAnfExpr<Let<AnfExpr>>: the size of "
"one binding should equal to 2.");
}
if (!binding.at(0).is_string()) {
return JsonParseFailed(binding.at(0),
"ParseJsonToAnfExpr<Let<AnfExpr>>: the first "
"element of a binding should be var name.");
}
std::string var = binding.at(0).get<std::string>();
const auto& val = ConvertJsonToAnfExpr(binding.at(1));
if (!val.HasOkValue()) {
return JsonParseFailed(
binding.at(1),
"ParseJsonToAnfExpr<Let<AnfExpr>>: the second "
"element of a binding should be a valid AnfExpr.");
}
if (!val.GetOkValue().Has<Combined<AnfExpr>>()) {
return JsonParseFailed(
binding.at(1),
"ParseJsonToAnfExpr<Let<AnfExpr>>: the second element of a binding "
"should be a valid combined AnfExpr.");
}
bindings.push_back(AnfExprBuilder().Bind(
var, val.GetOkValue().Get<Combined<AnfExpr>>()));
}
const auto& body = ConvertJsonToAnfExpr(j_obj.at(2));
if (!body.HasOkValue()) {
return JsonParseFailed(
j_obj.at(2),
"ParseJsonToAnfExpr<Let<AnfExpr>>: the body of Let "
"AnfExpr should be a valid AnfExpr.");
}
return AnfExpr{AnfExprBuilder().Let(bindings, body.GetOkValue())};
}
};
inline const std::vector<JsonParseFuncType>& GetJsonParseFuncs() {
static const std::vector<JsonParseFuncType> 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<AnfExpr> 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<adt::errors::MismatchError>()) {
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<AnfExpr> 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<AnfExpr> MakeAnfExprFromJsonString(
const std::string& json_str) {
return detail::MakeAnfExprFromJsonString(json_str);
}
} // namespace ap::axpr