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> struct IsANode {
64 using type = App;
65 };
66
67 template<class Id, class D> class IsA {
68 static_assert(Annex::Num<Id> != size_t(-1), "invalid number of sub tags");
69 static_assert(Annex::Base<Id> != flags_t(-1), "invalid axm base");
70
71 public:
72 IsA() = default;
73 IsA(const Axm* axm, const D* def)
74 : axm_(axm)
75 , def_(def) {}
76
77 /// @name Getters
78 ///@{
79 const Axm* axm() const { return axm_; }
80 const D* operator->() const { return def_; }
81 operator const D*() const { return def_; }
82 explicit operator bool() { return axm_ != nullptr; }
83 ///@}
84
85 /// @name Axm Name
86 /// @see annex_name "Annex Name"
87 ///@{
88 auto plugin() const { return axm()->plugin(); } ///< @see Axm::plugin.
89 auto tag() const { return axm()->tag(); } ///< @see Axm::tag.
90 auto sub() const { return axm()->sub(); } ///< @see Axm::sub.
91 auto base() const { return axm()->sub(); } ///< @see exiom::base.
92 auto id() const { return Id(axm()->flags()); } ///< Axm::flags cast to @p Id.
93 ///@}
94
95 private:
96 const Axm* axm_ = nullptr;
97 const D* def_ = nullptr;
98 };
99 ///@}
100
101 /// @name isa/as
102 ///@{
103 /// @see @ref cast_axm
104 template<class Id, bool DynCast = true> static auto isa(const Def* def) {
105 using D = typename Axm::IsANode<Id>::type;
106 auto [axm, curry, _] = Axm::get(def);
107 bool cond = axm && curry == 0 && axm->base() == Annex::Base<Id>;
108
109 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
110 assert(cond && "assumed to be correct axm");
111 return IsA<Id, D>(axm, def->as<D>());
112 }
113
114 template<class Id, bool DynCast = true> static auto isa(Id id, const Def* def) {
115 using D = typename Axm::IsANode<Id>::type;
116 auto [axm, curry, _] = Axm::get(def);
117 bool cond = axm && curry == 0 && axm->flags() == (flags_t)id;
118
119 if constexpr (DynCast) return cond ? IsA<Id, D>(axm, def->as<D>()) : IsA<Id, D>();
120 assert(cond && "assumed to be correct axm");
121 return IsA<Id, D>(axm, def->as<D>());
122 }
123
124 // clang-format off
125 template<class Id> static auto as( const Def* def) { return isa<Id, false>( def); }
126 template<class Id> static auto as(Id id, const Def* def) { return isa<Id, false>(id, def); }
127 // clang-format on
128 ///@}
129
130 static constexpr u8 Trip_End = u8(-1);
131 static constexpr auto Node = mim::Node::Axm;
132
133private:
134 const Def* rebuild_(World&, const Def*, Defs) const override;
135
136 friend class World;
137};
138
139// clang-format off
140template<class Id> concept annex_with_subs = Annex::Num<Id> != 0;
141template<class Id> concept annex_without_subs = Annex::Num<Id> == 0;
142// clang-format on
143
144/// @name is_commutative/is_associative
145///@{
146template<class Id> constexpr bool is_commutative(Id) { return false; }
147/// @warning By default we assume that any commutative operation is also associative.
148/// Please provide a proper specialization if this is not the case.
149template<class Id> constexpr bool is_associative(Id id) { return is_commutative(id); }
150///@}
151
152} // namespace mim
auto base() const
Definition axm.h:91
auto sub() const
Definition axm.h:90
auto id() const
Axm::flags cast to Id.
Definition axm.h:92
const D * operator->() const
Definition axm.h:80
const Axm * axm() const
Definition axm.h:79
IsA(const Axm *axm, const D *def)
Definition axm.h:73
auto tag() const
Definition axm.h:89
auto plugin() const
Definition axm.h:88
IsA()=default
tag_t tag() const
Definition axm.h:55
u8 trip() const
Definition axm.h:38
friend class World
Definition axm.h:136
static auto as(Id id, const Def *def)
Definition axm.h:126
flags_t base() const
Definition axm.h:57
NormalizeFn normalizer() const
Definition axm.h:36
static auto isa(const Def *def)
Definition axm.h:104
sub_t sub() const
Definition axm.h:56
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axm.cpp:14
plugin_t plugin() const
Definition axm.h:54
static auto isa(Id id, const Def *def)
Definition axm.h:114
static constexpr u8 Trip_End
Definition axm.h:130
static constexpr auto Node
Definition axm.h:131
static auto as(const Def *def)
Definition axm.h:125
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
const Def * rebuild_(World &, const Def *, Defs) const override
Definition def.cpp:136
Base class for all Defs.
Definition def.h:197
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:240
u8 trip_
Definition def.h:574
constexpr flags_t flags() const noexcept
Definition def.h:215
u8 curry_
Definition def.h:573
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:241
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:142
Definition ast.h:14
View< const Def * > Defs
Definition def.h:48
u8 sub_t
Definition types.h:48
u64 flags_t
Definition types.h:45
constexpr bool is_commutative(Id)
Definition axm.h:146
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:70
u64 plugin_t
Definition types.h:46
constexpr bool is_associative(Id id)
Definition axm.h:149
u8 tag_t
Definition types.h:47
uint8_t u8
Definition types.h:34
@ Axm
Definition def.h:84
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