MimIR 0.1
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/assert.h>
4
5#include "mim/plugin.h"
6
7namespace mim {
8
9class Axm : public Def, public Setters<Axm> {
10private:
12
13public:
14 using Setters<Axm>::set;
15
16 /// @name Normalization
17 /// @anchor normalization
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 static std::pair<u8, u8> infer_curry_and_trip(const Def* type);
48 ///@}
49
50 /// @name Annex Name
51 /// @anchor anatomy
52 /// @see annex_name "Annex Name"
53 ///@{
55 tag_t tag() const { return Annex::flags2tag(flags()); }
56 sub_t sub() const { return Annex::flags2sub(flags()); }
57 flags_t base() const { return Annex::flags2base(flags()); }
58 ///@}
59
60 /// @name IsA
61 ///@{
62 /// Type of IsA::def_.
63 template<class T>
64 struct IsANode {
65 using type = App;
66 };
67
68 template<class Id, class D>
69 class IsA {
70 static_assert(Annex::Num<Id> != size_t(-1), "invalid number of sub tags");
71 static_assert(Annex::Base<Id> != flags_t(-1), "invalid axm base");
72
73 public:
74 IsA() = default;
75 IsA(const Axm* axm, const D* def)
76 : axm_(axm)
77 , def_(def) {}
78
79 /// @name Getters
80 ///@{
81 const Axm* axm() const { return axm_; }
82 const D* operator->() const { return def_; }
83 operator const D*() const { return def_; }
84 explicit operator bool() { return axm_ != nullptr; }
85 ///@}
86
87 /// @name Axm Name
88 /// @see annex_name "Annex Name"
89 ///@{
90 auto plugin() const { return axm()->plugin(); } ///< @see Axm::plugin.
91 auto tag() const { return axm()->tag(); } ///< @see Axm::tag.
92 auto sub() const { return axm()->sub(); } ///< @see Axm::sub.
93 auto base() const { return axm()->sub(); } ///< @see exiom::base.
94 auto id() const { return Id(axm()->flags()); } ///< Axm::flags cast to @p Id.
95 ///@}
96
97 private:
98 const Axm* axm_ = nullptr;
99 const D* def_ = nullptr;
100 };
101 ///@}
102
103 /// @name isa/as
104 ///@{
105 /// @see @ref cast_axm
106 template<class Id, bool DynCast = true>
107 static auto isa(const Def* def) {
108 using D = typename Axm::IsANode<Id>::type;
109 auto [axm, curry, _] = Axm::get(def);
110 bool cond = axm && curry == 0 && axm->base() == Annex::Base<Id>;
111
112 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
113 assert(cond && "assumed to be correct axm");
114 return IsA<Id, D>(axm, def->as<D>());
115 }
116
117 template<class Id, bool DynCast = true>
118 static auto isa(Id id, const Def* def) {
119 using D = typename Axm::IsANode<Id>::type;
120 auto [axm, curry, _] = Axm::get(def);
121 bool cond = axm && curry == 0 && axm->flags() == (flags_t)id;
122
123 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
124 assert(cond && "assumed to be correct axm");
125 return IsA<Id, D>(axm, def->as<D>());
126 }
127
128 // clang-format off
129 template<class Id> static auto as( const Def* def) { return isa<Id, false>( def); }
130 template<class Id> static auto as(Id id, const Def* def) { return isa<Id, false>(id, def); }
131 // clang-format on
132 ///@}
133
134 static constexpr u8 Trip_End = u8(-1);
135 static constexpr auto Node = mim::Node::Axm;
136 static constexpr size_t Num_Ops = 0;
137
138private:
139 const Def* rebuild_(World&, const Def*, Defs) const final;
140
141 friend class World;
142};
143
144// clang-format off
145template<class Id> concept annex_with_subs = Annex::Num<Id> != 0;
146template<class Id> concept annex_without_subs = Annex::Num<Id> == 0;
147// clang-format on
148
149/// @name is_commutative/is_associative
150///@{
151template<class Id>
152constexpr bool is_commutative(Id) {
153 return false;
154}
155/// @warning By default we assume that any commutative operation is also associative.
156/// Please provide a proper specialization if this is not the case.
157template<class Id>
158constexpr bool is_associative(Id id) {
159 return is_commutative(id);
160}
161///@}
162
163} // namespace mim
auto base() const
Definition axm.h:93
auto sub() const
Definition axm.h:92
auto id() const
Axm::flags cast to Id.
Definition axm.h:94
const D * operator->() const
Definition axm.h:82
const Axm * axm() const
Definition axm.h:81
IsA(const Axm *axm, const D *def)
Definition axm.h:75
auto tag() const
Definition axm.h:91
auto plugin() const
Definition axm.h:90
IsA()=default
tag_t tag() const
Definition axm.h:55
u8 trip() const
Definition axm.h:38
friend class World
Definition axm.h:141
static auto as(Id id, const Def *def)
Definition axm.h:130
flags_t base() const
Definition axm.h:57
static constexpr size_t Num_Ops
Definition axm.h:136
NormalizeFn normalizer() const
Definition axm.h:36
static auto isa(const Def *def)
Definition axm.h:107
sub_t sub() const
Definition axm.h:56
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axm.cpp:14
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:135
plugin_t plugin() const
Definition axm.h:54
static auto isa(Id id, const Def *def)
Definition axm.h:118
static constexpr u8 Trip_End
Definition axm.h:134
static constexpr auto Node
Definition axm.h:135
static auto as(const Def *def)
Definition axm.h:129
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:216
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:244
u8 trip_
Definition def.h:625
constexpr flags_t flags() const noexcept
Definition def.h:234
u8 curry_
Definition def.h:624
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:260
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:161
Definition ast.h:14
View< const Def * > Defs
Definition def.h:51
u8 sub_t
Definition types.h:48
u64 flags_t
Definition types.h:45
constexpr bool is_commutative(Id)
Definition axm.h:152
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:75
u64 plugin_t
Definition types.h:46
constexpr bool is_associative(Id id)
Definition axm.h:158
u8 tag_t
Definition types.h:47
uint8_t u8
Definition types.h:34
@ Axm
Definition def.h:89
static sub_t flags2sub(flags_t f)
Yields the sub part of the name as integer.
Definition plugin.h:105
static plugin_t flags2plugin(flags_t f)
Definition plugin.h:99
static flags_t flags2base(flags_t f)
Includes Axm::plugin() and Axm::tag() but not Axm::sub.
Definition plugin.h:108
static constexpr size_t Num
Definition plugin.h:115
static constexpr flags_t Base
Definition plugin.h:118
static tag_t flags2tag(flags_t f)
Yields the tag part of the name as integer.
Definition plugin.h:102