MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
axm.h
Go to the documentation of this file.
1#pragma once
2
3#include <fe/term.h>
4
5#include "mim/plugin.h"
6
7namespace mim {
8
9class Axm : public Def, public Setters<Axm> {
10private:
11 Axm(NormalizeFn, u8 curry, u8 trip, const Def* type, plugin_t, tag_t, sub_t);
12
13public:
14 using Setters<Axm>::set;
15
16 /// @name Normalization
17 /// @anchor curry_trip
18 /// For a curried App of an Axm, you only want to trigger normalization at specific spots.
19 /// For this reason, MimIR maintains a Def::curry_ counter that each App decrements.
20 /// The Axm::normalizer() will be triggered when Axm::curry() becomes `0`.
21 /// These are also the spots that you can mim::test / mim::force / mim::IsA.
22 /// After that, the counter will be set to Axm::trip().
23 /// E.g., let's say an Axm has this type:
24 /// ```
25 /// A -> B -> C -> D -> E
26 /// ^ |
27 /// | |
28 /// +---------+
29 /// ```
30 /// Using an initial value as `5` for Axm::curry and `3` as Axm::trip has the effect that here
31 /// ```
32 /// x a b c1 d1 e1 c2 d2 e2 c3 d3 e3
33 /// ```
34 /// the Axm::normalizer will be triggered after App'ing `e1`, `e2`, and `e3`.
35 ///@{
36 NormalizeFn normalizer() const { return normalizer_; }
37 u8 curry() const { return curry_; }
38 u8 trip() const { return trip_; }
39 ///@}
40
41 /// @name Normalization - Helpers
42 ///@{
43
44 /// Yields currying counter of @p def.
45 /// @returns `{nullptr, 0, 0}` if no Axm is present.
46 static std::tuple<const Axm*, u8, u8> get(const Def* def);
47
48 /// Like Axm::get, but advances the counter as one more App is about to be built on top of @p callee.
49 /// @returns `{nullptr, 0, 0}` if no Axm is present.
50 static std::tuple<const Axm*, u8, u8> next(const Def* callee);
51
52 static std::pair<u8, u8> infer_curry_and_trip(const Def* type);
53 ///@}
54
55 /// @name Annex Name
56 /// @anchor anatomy
57 /// @see annex_name "Annex Name"
58 ///@{
60 tag_t tag() const { return Annex::flags2tag(flags()); }
61 sub_t sub() const { return Annex::flags2sub(flags()); }
62 flags_t base() const { return Annex::flags2base(flags()); }
63 ///@}
64
65 /// @name IsA
66 ///@{
67 /// Type of IsA::def_.
68 template<class T>
69 struct IsANode {
70 using type = App;
71 };
72
73 template<class Id, class D>
74 class IsA {
75 static_assert(Annex::num<Id>() != size_t(-1), "invalid number of sub tags");
76 static_assert(Annex::base<Id>() != flags_t(-1), "invalid axm base");
77
78 public:
79 IsA() = default;
80 IsA(const Axm* axm, const D* def)
81 : axm_(axm)
82 , def_(def) {}
83
84 /// @name Getters
85 ///@{
86 const Axm* axm() const { return axm_; }
87 const D* operator->() const { return def_; }
88 operator const D*() const { return def_; }
89 explicit operator bool() const { return axm_ != nullptr; }
90 ///@}
91
92 /// @name Axm Name
93 /// @see annex_name "Annex Name"
94 ///@{
95 auto plugin() const { return axm()->plugin(); } ///< @see Axm::plugin.
96 auto tag() const { return axm()->tag(); } ///< @see Axm::tag.
97 auto sub() const { return axm()->sub(); } ///< @see Axm::sub.
98 auto base() const { return axm()->base(); } ///< @see Axm::base.
99 auto id() const { return Id(axm()->flags()); } ///< Axm::flags cast to @p Id.
100 ///@}
101
102 private:
103 const Axm* axm_ = nullptr;
104 const D* def_ = nullptr;
105 };
106 ///@}
107
108 /// @name Matching
109 ///@{
110 /// @see @ref cast_axm
111 template<class Id, u8 Curry = 0, bool DynCast = true>
112 static auto isa(const Def* def) {
113 using D = std::conditional_t<Curry == 0, typename Axm::IsANode<Id>::type, Def>;
114 auto [axm, curry, _] = Axm::get(def);
115 bool cond = axm && curry == Curry && axm->base() == Annex::base<Id>();
116
117 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
118 assert(cond && "assumed to be correct axm");
119 return IsA<Id, D>(axm, def->as<D>());
120 }
121
122 template<class Id, u8 Curry = 0, bool DynCast = true>
123 static auto isa(Id id, const Def* def) {
124 using D = std::conditional_t<Curry == 0, typename Axm::IsANode<Id>::type, Def>;
125 auto [axm, curry, _] = Axm::get(def);
126 bool cond = axm && curry == Curry && axm->flags() == (flags_t)id;
127
128 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
129 assert(cond && "assumed to be correct axm");
130 return IsA<Id, D>(axm, def->as<D>());
131 }
132
133 // clang-format off
134 template<class Id, u8 Curry=0> static auto as( const Def* def) { return isa<Id, Curry, false>( def); }
135 template<class Id, u8 Curry=0> static auto as(Id id, const Def* def) { return isa<Id, Curry, false>(id, def); }
136 // clang-format on
137
138 /// Like Axm::as but - instead of merely asserting in `Debug` builds - bails via Def::bail_expected when
139 /// @p def is not the expected axm.
140 /// @p fmt / @p args describe what was expected; a plain string works, as does a fe::cite_string plus arguments.
141 template<class Id, u8 Curry = 0, class... Args>
142 static auto expect(const Def* def, fe::cite_string<Args...> fmt, Args&&... args) {
143 if (auto res = isa<Id, Curry>(def)) return res;
144 def->bail_expected(fe::format_cite(fmt, std::forward<Args>(args)...));
145 }
146
147 /// Peel off all @p Id Axm%s from @p def.
148 template<class Id>
149 static const Def* peel(const Def* def) {
150 while (auto anno = isa<Id>(def))
151 def = anno->arg();
152 return def;
153 }
154 ///@}
155
156 static constexpr u8 Trip_End = u8(-1);
157 static constexpr auto Node = mim::Node::Axm;
158 static constexpr size_t Num_Ops = 0;
159
160private:
161 friend class World;
162};
163
164// clang-format off
165template<class Id> concept annex_without_subs = Annex::num<Id>() == 0;
166// clang-format on
167
168/// @name is_commutative/is_associative
169///@{
170template<class Id>
171constexpr bool is_commutative(Id) {
172 return false;
173}
174/// @warning By default we assume that any commutative operation is also associative.
175/// Please provide a proper specialization if this is not the case.
176template<class Id>
177constexpr bool is_associative(Id id) {
178 return is_commutative(id);
179}
180///@}
181
182} // namespace mim
183
184#ifndef DOXYGEN
185template<class Id, class D>
186struct std::formatter<mim::Axm::IsA<Id, D>> : fe::ostream_formatter {};
187#endif
auto base() const
Definition axm.h:98
auto sub() const
Definition axm.h:97
auto id() const
Axm::flags cast to Id.
Definition axm.h:99
const D * operator->() const
Definition axm.h:87
const Axm * axm() const
Definition axm.h:86
IsA(const Axm *axm, const D *def)
Definition axm.h:80
auto tag() const
Definition axm.h:96
auto plugin() const
Definition axm.h:95
IsA()=default
static auto as(Id id, const Def *def)
Definition axm.h:135
static const Def * peel(const Def *def)
Peel off all Id Axms from def.
Definition axm.h:149
tag_t tag() const
Definition axm.h:60
u8 trip() const
Definition axm.h:38
static std::tuple< const Axm *, u8, u8 > next(const Def *callee)
Like Axm::get, but advances the counter as one more App is about to be built on top of callee.
Definition axm.cpp:44
static auto isa(const Def *def)
Definition axm.h:112
static auto isa(Id id, const Def *def)
Definition axm.h:123
friend class World
Definition axm.h:161
flags_t base() const
Definition axm.h:62
static constexpr size_t Num_Ops
Definition axm.h:158
NormalizeFn normalizer() const
Definition axm.h:36
sub_t sub() const
Definition axm.h:61
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axm.cpp:14
static auto as(const Def *def)
Definition axm.h:134
plugin_t plugin() const
Definition axm.h:59
static auto expect(const Def *def, fe::cite_string< Args... > fmt, Args &&... args)
Like Axm::as but - instead of merely asserting in Debug builds - bails via Def::bail_expected when de...
Definition axm.h:142
static constexpr u8 Trip_End
Definition axm.h:156
static constexpr auto Node
Definition axm.h:157
u8 curry() const
Definition axm.h:37
static std::tuple< const Axm *, u8, u8 > get(const Def *def)
Yields currying counter of def.
Definition axm.cpp:38
Base class for all Defs.
Definition def.h:289
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:188
u8 trip_
Definition def.h:805
constexpr flags_t flags() const noexcept
Definition def.h:311
u8 curry_
Definition def.h:804
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
void bail_expected(fe::Cite what) const
Blames this for not being what and bails; where Def::expect and friends funnel their diagnostic.
Definition def.cpp:413
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:220
Definition ast.h:16
u8 sub_t
Definition types.h:42
u64 flags_t
Definition types.h:39
constexpr bool is_commutative(Id)
Definition axm.h:171
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:118
u64 plugin_t
Definition types.h:40
constexpr bool is_associative(Id id)
Definition axm.h:177
u8 tag_t
Definition types.h:41
uint8_t u8
Definition types.h:27
@ Axm
Definition def.h:125
static constexpr tag_t flags2tag(flags_t f)
Yields the tag part of the name as integer.
Definition plugin.h:257
static constexpr sub_t flags2sub(flags_t f)
Yields the sub part of the name as integer.
Definition plugin.h:260
static constexpr plugin_t flags2plugin(flags_t f)
Definition plugin.h:254
static consteval size_t num()
Definition plugin.h:275
static consteval flags_t base()
Definition plugin.h:276
static constexpr flags_t flags2base(flags_t f)
Includes Axm::plugin() and Axm::tag() but not Axm::sub.
Definition plugin.h:263