MimIR
0.5-dev
MimIR is my Intermediate Representation
Toggle main menu visibility
Loading...
Searching...
No Matches
normalizers.cpp
Go to the documentation of this file.
1
#include <algorithm>
2
#include <optional>
3
4
#include <fe/assert.h>
5
6
#include <
mim/world.h
>
7
8
#include <
mim/plug/option/option.h
>
9
10
#include "
mim/plug/ord/ord.h
"
11
12
namespace
mim::plug::ord
{
13
14
namespace
{
15
16
/// Decides whether the keys @p k1 and @p k2 are equal; `std::nullopt` means "don't know".
17
/// Distinct literals are distinct keys, as the key's `lt` is assumed to be a strict total order.
18
std::optional<bool> key_eq(
const
Def
* k1,
const
Def
* k2) {
19
if
(k1 == k2)
return
true
;
20
if
(k1->isa<
Lit
>() && k2->isa<
Lit
>())
return
false
;
21
return
{};
22
}
23
24
}
// namespace
25
26
template
<init
id
>
27
const
Def
*
normalize_init
(
const
Def
* type,
const
Def
* callee,
const
Def
* arg) {
28
auto
& w = type->world();
29
if
(
auto
n =
Lit::isa
(callee->as<
App
>()->
arg
())) {
30
auto
key = [](
const
Def
* kv) {
return
id
==
init::map
? kv->proj(2, 0) : kv; };
31
auto
kvs =
DefVec
();
32
for
(
auto
kv : arg->
projs
(*n))
33
if
(
auto
i = std::ranges::find_if(kvs, [&](
const
Def
* cur) {
return
key(cur) == key(kv); }); i != kvs.end())
34
*i = kv;
35
else
36
kvs.emplace_back(kv);
37
if
(kvs.size() != *n)
return
w.app(w.app(callee->as<
App
>()->
callee
(), w.lit_nat(kvs.size())), kvs);
38
}
39
return
w.raw_app(type, callee, arg);
40
}
41
42
template
<size>
43
const
Def
*
normalize_size
(
const
Def
*,
const
Def
*,
const
Def
* arg) {
44
if
(
auto
init
=
Axm::isa<ord::init>
(arg))
return
init
->decurry()->arg();
45
return
nullptr
;
46
}
47
48
const
Def
*
normalize_get
(
const
Def
* type,
const
Def
* callee,
const
Def
* arg) {
49
auto
& w = arg->
world
();
50
auto
[map, k] = arg->
projs
<2>();
51
52
if
(
auto
init
=
Axm::isa<ord::init>
(map)) {
53
if
(
auto
n =
Lit::isa
(
init
->decurry()->arg())) {
54
auto
kvs =
init
->arg();
55
for
(
auto
kv : kvs->projs(*n))
56
if
(
auto
[key, val] = kv->projs<2>(); key == k)
return
w.inj(type,
option::Opt_ctor::Some
, val);
57
// FIXME a closed kvs doesn't rule out an open k matching at runtime.
58
if
(kvs->is_closed())
return
w.inj(type,
option::Opt_ctor::None
, w.tuple());
59
}
60
}
61
62
// get(insert(m, (k', v)), k) = Some v if k' = k
63
// = get(m, k) if k' ≠ k
64
if
(
auto
ins =
Axm::isa
(
insert::map
, map)) {
65
auto
[m, kv] = ins->args<2>();
66
auto
[k_, v] = kv->projs<2>();
67
if
(
auto
eq = key_eq(k_, k))
68
return
*eq ? w.inj(type,
option::Opt_ctor::Some
, v) : w.app(callee, w.tuple({m, k}));
69
}
70
71
return
nullptr
;
72
}
73
74
template
<contains
id
>
75
const
Def
*
normalize_contains
(
const
Def
*,
const
Def
* callee,
const
Def
* arg) {
76
auto
& w = arg->
world
();
77
auto
[c, k] = arg->
projs
<2>();
78
79
if
(
auto
init
=
Axm::isa<ord::init>
(c)) {
80
if
(
auto
n =
Lit::isa
(
init
->decurry()->arg())) {
81
auto
kvs =
init
->arg();
82
for
(
auto
kv : kvs->projs(*n)) {
83
auto
key =
id
==
contains::map
? kv->proj(2, 0) : kv;
84
if
(key == k)
return
w.lit_tt();
85
}
86
// FIXME a closed kvs doesn't rule out an open k matching at runtime.
87
return
kvs->is_closed() ? w.lit_ff() :
nullptr
;
88
}
89
90
if
(
auto
pack =
init
->arg()->isa_imm<
Pack
>()) w.log().w(
"Pack not yet implemented: {}"
, pack);
91
}
92
93
// contains(insert(m, k'), k) = tt if k' = k
94
// = contains(m, k) if k' ≠ k
95
if
(
auto
ins =
Axm::isa
(
id
==
contains::map
?
insert::map
:
insert::set
, c)) {
96
auto
[m, kv] = ins->args<2>();
97
auto
key =
id
==
contains::map
? kv->proj(2, 0) : kv;
98
if
(
auto
eq = key_eq(key, k))
return
*eq ? w.lit_tt() : w.app(callee, w.tuple({m, k}));
99
}
100
101
return
nullptr
;
102
}
103
104
template
<insert
id
>
105
const
Def
*
normalize_insert
(
const
Def
* type,
const
Def
* callee,
const
Def
* arg) {
106
auto
& w = type->world();
107
auto
[ms, kv] = arg->
projs
<2>();
108
109
if
(
auto
init
=
Axm::isa<ord::init>
(ms)) {
110
auto
[n, kvs] =
init
->uncurry_args<2>();
111
if
(
auto
l =
Lit::isa
(n)) {
112
auto
key =
id
==
ord::insert::map
? kv->proj(2, 0) : kv;
113
auto
new_ops =
DefVec
();
114
bool
updated =
false
;
115
for
(
auto
cur : kvs->projs(*l)) {
116
auto
cur_key =
id
==
ord::insert::map
? cur->proj(2, 0) : cur;
117
if
(key == cur_key) updated =
true
;
118
new_ops.emplace_back(key == cur_key ? kv : cur);
119
}
120
if
(!updated) new_ops.emplace_back(kv);
121
return
w.app(w.app(
init
->decurry()->callee(), w.lit_nat(new_ops.size())), new_ops);
122
}
123
124
if
(
auto
pack =
init
->arg()->isa_imm<
Pack
>()) w.log().w(
"Pack not yet implemented: {}"
, pack);
125
}
126
127
// insert(insert(m, k'), k) = insert(m, k) if k' = k
128
// = insert(insert(m, k), k') if k' ≠ k and k < k' (canonical order of literal keys)
129
if
(
auto
ins =
Axm::isa
(
id
, ms)) {
130
auto
[m, kv_] = ins->args<2>();
131
auto
key = [](
const
Def
* kv) {
return
id
==
ord::insert::map
? kv->proj(2, 0) : kv; };
132
if
(
auto
eq = key_eq(key(kv_), key(kv))) {
133
if
(*eq)
return
w.app(callee, w.tuple({m, kv}));
134
if
(*
Lit::isa
(key(kv)) < *
Lit::isa
(key(kv_)))
135
return
w.app(callee, w.tuple({w.app(callee, w.tuple({m, kv})), kv_}));
136
}
137
}
138
139
return
{};
140
}
141
142
MIM_ord_NORMALIZER_IMPL
143
144
}
// namespace mim::plug::ord
mim::App
Definition
lam.h:215
mim::App::callee
const Def * callee() const
Definition
lam.h:237
mim::App::arg
const Def * arg() const
Definition
lam.h:251
mim::Axm::isa
static auto isa(const Def *def)
Definition
axm.h:112
mim::Def
Base class for all Defs.
Definition
def.h:289
mim::Def::world
World & world() const noexcept
Definition
def.h:1105
mim::Def::projs
auto projs(Projector auto f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Definition
def.h:457
mim::Lit
Definition
def.h:948
mim::Lit::isa
static std::optional< T > isa(const Def *def)
Definition
def.h:976
mim::Pack
A (possibly paramterized) Tuple.
Definition
tuple.h:332
mim::plug::ord
The ord Plugin
Definition
normalizers.cpp:12
mim::plug::ord::normalize_contains
const Def * normalize_contains(const Def *, const Def *callee, const Def *arg)
Definition
normalizers.cpp:75
mim::plug::ord::normalize_size
const Def * normalize_size(const Def *, const Def *, const Def *arg)
Definition
normalizers.cpp:43
mim::plug::ord::normalize_insert
const Def * normalize_insert(const Def *type, const Def *callee, const Def *arg)
Definition
normalizers.cpp:105
mim::plug::ord::contains::map
@ map
Definition
autogen.h:100
mim::plug::ord::insert::map
@ map
Definition
autogen.h:112
mim::plug::ord::insert::set
@ set
Definition
autogen.h:111
mim::plug::ord::normalize_init
const Def * normalize_init(const Def *type, const Def *callee, const Def *arg)
Definition
normalizers.cpp:27
mim::plug::ord::normalize_get
const Def * normalize_get(const Def *type, const Def *callee, const Def *arg)
Definition
normalizers.cpp:48
mim::plug::ord::init
init
Definition
autogen.h:38
mim::plug::ord::init::map
@ map
Definition
autogen.h:40
mim::DefVec
fe::Vector< const Def * > DefVec
Definition
def.h:98
option.h
MIM_ord_NORMALIZER_IMPL
#define MIM_ord_NORMALIZER_IMPL
Definition
autogen.h:122
ord.h
mim::plug::option::Opt_ctor::None
@ None
Definition
autogen.h:18
mim::plug::option::Opt_ctor::Some
@ Some
Definition
autogen.h:18
world.h
src
mim
plug
ord
normalizers.cpp
Generated by
1.18.0