28 auto& world = type->world();
36 return world.call(
quant::star, optional_app->arg());
41 if (
auto quant_app =
Axm::isa<quant>(arg))
return world.app(callee, quant_app->arg());
53template<
class ConjOrDisj>
55 assert(!args.empty());
56 auto& world = args.front()->world();
57 return std::accumulate(args.begin() + 1, args.end(), args.front(), [&world](
const Def* lhs,
const Def* rhs) {
58 return world.call<ConjOrDisj, false>(Defs{lhs, rhs});
63 auto& world = type->world();
64 world.DLOG(
"conj {}:{} ({})", type, callee, arg);
68 case 0:
return world.lit_tt();
71 if (
auto args = detail::flatten_in_arg<conj>(arg); !args.empty())
74 return world.annex<
empty>();
85 if (lhs_range && rhs_range)
return Lit::as(lhs_range->arg()->proj(0)) <
Lit::as(rhs_range->arg()->proj(0));
87 if (lhs_range)
return false;
88 if (rhs_range)
return true;
90 return lhs->
gid() < rhs->
gid();
94 std::stable_sort(args.begin(), args.end(), &
compare_re);
96 auto new_end = std::unique(args.begin(), args.end());
97 args.erase(new_end, args.end());
114 auto ranges_begin = args.begin();
117 if (ranges_begin == args.end())
return;
119 std::set<const Def*> to_remove;
121 auto& world = (*ranges_begin)->world();
123 std::transform(ranges_begin, args.end(), std::back_inserter(old_ranges),
get_range);
126 old_ranges, [&world](
auto&&... args) { world.DLOG(std::forward<
decltype(args)>(args)...); });
129 args.erase(ranges_begin, args.end());
130 std::transform(new_ranges.begin(), new_ranges.end(), std::back_inserter(args),
app_range{world});
135template<cls A, cls B>
141 auto check_arg_equiv = [](
const Def* lhs,
const Def* rhs) {
144 if (
auto rng_rhs =
Axm::isa<range>(not_rhs->arg()))
return rng_lhs == rng_rhs;
149 return check_arg_equiv(lhs, rhs) || check_arg_equiv(rhs, lhs);
153 Ranges lhs_ranges, rhs_ranges;
154 auto only_ranges = std::ranges::views::filter([](
auto d) {
return Axm::isa<range>(
d); });
155 std::ranges::transform(lhs | only_ranges, std::back_inserter(lhs_ranges),
get_range);
156 std::ranges::transform(negated_rhs | only_ranges, std::back_inserter(rhs_ranges),
get_range);
157 if (rhs_ranges.size() != negated_rhs.size())
return false;
159 return std::ranges::includes(lhs_ranges, rhs_ranges);
163 auto& world = type->world();
166 case 0:
return world.lit_ff();
169 auto new_args = detail::flatten_in_arg<disj>(arg);
171 const bool contains_any
172 = std::ranges::find_if(new_args, [](
const Def* ax) ->
bool {
return Axm::isa<any>(ax); })
174 const bool contains_empty
175 = std::ranges::find_if(new_args, [](
const Def* ax) ->
bool {
return Axm::isa<empty>(ax); })
178 auto make_any = [&world, contains_empty]() {
182 return world.call<
disj,
false>(
Defs{world.annex<
any>(), world.annex<
empty>()});
184 return world.annex<
any>();
187 if (contains_any)
return make_any();
191 const Def* to_remove =
nullptr;
192 for (
const auto* cls0 : new_args) {
193 for (
const auto* cls1 : new_args)
194 if (
equals_any(cls0, cls1))
return make_any();
198 auto rngs = detail::flatten_in_arg<disj>(disj_rhs->arg());
200 if (
equals_any(new_args, rngs))
return make_any();
205 erase(new_args, to_remove);
206 world.DLOG(
"final ranges {, }", new_args);
209 if (new_args.size() > 1)
return world.call<
disj,
false>(new_args);
210 return new_args.back();
217 auto& world = type->world();
218 auto [lhs, rhs] = arg->
projs<2>();
220 if (!lhs->isa<
Var>() && !rhs->isa<
Var>())
221 if (lhs->as<
Lit>()->
get() > rhs->as<
Lit>()->
get())
return world.raw_app(type, callee, {rhs, lhs});
231 for (
const auto* disj_arg :
disj->args())
242 "regex.not_ must only be used with regex.disj, regex.range, regex.any and regex.not_: {} {}", callee,
244 .
error(unwanted->loc(),
"found unwanted: {}", unwanted);
static auto isa(const Def *def)
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
virtual const Def * arity() const
Error & error(Loc loc, const char *s, Args &&... args)
static std::optional< T > isa(const Def *def)
static T as(const Def *def)
A variable introduced by a binder (mutable).
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
The World represents the whole program and manages creation of MimIR nodes (Defs).
std::pair< std::uint64_t, std::uint64_t > Range
std::optional< Range > merge_ranges(Range a, Range b) noexcept
void merge_ranges(DefVec &args)
void make_vector_unique(DefVec &args)
auto get_range(const Def *rng) -> Range
bool is_in_range(Range range, nat_t needle)
const Def * normalize_conj(const Def *type, const Def *callee, const Def *arg)
const Def * normalize_range(const Def *type, const Def *callee, const Def *arg)
const Def * normalize_disj(const Def *type, const Def *, const Def *arg)
const Def * normalize_quant(const Def *type, const Def *callee, const Def *arg)
const Def * normalize_not(const Def *, const Def *callee, const Def *arg)
bool compare_re(const Def *lhs, const Def *rhs)
const Def * make_binary_tree(Defs args)
const Def * any_unwanted_for_not(const Def *arg)
bool equals_any(const Def *cls0, const Def *cls1)
Vector< const Def * > DefVec
Vector< T, N, A >::size_type erase(Vector< T, N, A > &c, const U &value) noexcept
#define MIM_regex_NORMALIZER_IMPL
const Def * operator()(Range rng)