MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
axiom.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 Axiom : public Def, public Setters<Axiom> {
10private:
12
13public:
14 using Setters<Axiom>::set;
15
16 /// @name Normalization
17 /// @anchor normalization
18 /// For a curried App of an Axiom, 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 Axiom::normalizer() will be triggered when Axiom::curry() becomes `0`.
21 /// These are also the spots that you can mim::match / mim::force / mim::Match.
22 /// After that, the counter will be set to Axiom::trip().
23 /// E.g., let's say an Axiom has this type:
24 /// ```
25 /// A -> B -> C -> D -> E
26 /// ^ |
27 /// | |
28 /// +---------+
29 /// ```
30 /// Using an initial value as `5` for Axiom::curry and `3` as Axiom::trip has the effect that here
31 /// ```
32 /// x a b c1 d1 e1 c2 d2 e2 c3 d3 e3
33 /// ```
34 /// the Axiom::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 /// Yields currying counter of @p def.
41 /// @returns `{nullptr, 0, 0}` if no Axiom is present.
42 static std::tuple<const Axiom*, u8, u8> get(const Def* def);
43
44 static std::pair<u8, u8> infer_curry_and_trip(const Def* type);
45 static constexpr u8 Trip_End = u8(-1);
46 ///@}
47
48 /// @name Annex Name
49 /// @anchor anatomy
50 /// @see annex_name "Annex Name"
51 ///@{
53 tag_t tag() const { return Annex::flags2tag(flags()); }
54 sub_t sub() const { return Annex::flags2sub(flags()); }
55 flags_t base() const { return Annex::flags2base(flags()); }
56 ///@}
57
58 /// Type of Match::def_.
59 template<class T> struct Match {
60 using type = App;
61 };
62
63 static constexpr auto Node = Node::Axiom;
64
65private:
66 Ref rebuild_(World&, Ref, Defs) const override;
67
68 friend class World;
69};
70
71// clang-format off
72template<class Id> concept annex_with_subs = Annex::Num<Id> != 0;
73template<class Id> concept annex_without_subs = Annex::Num<Id> == 0;
74// clang-format on
75
76template<class Id, class D> class Match {
77 static_assert(Annex::Num<Id> != size_t(-1), "invalid number of sub tags");
78 static_assert(Annex::Base<Id> != flags_t(-1), "invalid axiom base");
79
80public:
81 Match() = default;
82 Match(const Axiom* axiom, const D* def)
83 : axiom_(axiom)
84 , def_(def) {}
85
86 /// @name Getters
87 ///@{
88 const Axiom* axiom() const { return axiom_; }
89 const D* operator->() const { return def_; }
90 operator const D*() const { return def_; }
91 explicit operator bool() { return axiom_ != nullptr; }
92 ///@}
93
94 /// @name Axiom Name
95 /// @see annex_name "Annex Name"
96 ///@{
97 auto plugin() const { return axiom()->plugin(); } ///< @see Axiom::plugin.
98 auto tag() const { return axiom()->tag(); } ///< @see Axiom::tag.
99 auto sub() const { return axiom()->sub(); } ///< @see Axiom::sub.
100 auto base() const { return axiom()->sub(); } ///< @see exiom::base.
101 auto id() const { return Id(axiom()->flags()); } ///< Axiom::flags cast to @p Id.
102 ///@}
103
104private:
105 const Axiom* axiom_ = nullptr;
106 const D* def_ = nullptr;
107};
108
109/// @name match/force
110///@{
111/// @see @ref cast_axiom
112template<class Id, bool DynCast = true> auto match(Ref def) {
113 using D = typename Axiom::Match<Id>::type;
114 auto [axiom, curry, _] = Axiom::get(def);
115 bool cond = axiom && curry == 0 && axiom->base() == Annex::Base<Id>;
116
117 if constexpr (DynCast) return cond ? Match<Id, D>(axiom, def->as<D>()) : Match<Id, D>();
118 assert(cond && "assumed to be correct axiom");
119 return Match<Id, D>(axiom, def->as<D>());
120}
121
122template<class Id, bool DynCast = true> auto match(Id id, Ref def) {
123 using D = typename Axiom::Match<Id>::type;
124 auto [axiom, curry, _] = Axiom::get(def);
125 bool cond = axiom && curry == 0 && axiom->flags() == (flags_t)id;
126
127 if constexpr (DynCast) return cond ? Match<Id, D>(axiom, def->as<D>()) : Match<Id, D>();
128 assert(cond && "assumed to be correct axiom");
129 return Match<Id, D>(axiom, def->as<D>());
130}
131
132// clang-format off
133template<class Id> auto force( Ref def) { return match<Id, false>( def); }
134template<class Id> auto force(Id id, Ref def) { return match<Id, false>(id, def); }
135///@}
136
137/// @name is_commutative/is_associative
138///@{
139template<class Id> constexpr bool is_commutative(Id) { return false; }
140/// @warning By default we assume that any commutative operation is also associative.
141/// Please provide a proper specialization if this is not the case.
142template<class Id> constexpr bool is_associative(Id id) { return is_commutative(id); }
143///@}
144// clang-format on
145
146} // namespace mim
NormalizeFn normalizer() const
Definition axiom.h:36
u8 curry() const
Definition axiom.h:37
sub_t sub() const
Definition axiom.h:54
tag_t tag() const
Definition axiom.h:53
flags_t base() const
Definition axiom.h:55
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axiom.cpp:14
plugin_t plugin() const
Definition axiom.h:52
u8 trip() const
Definition axiom.h:38
static std::tuple< const Axiom *, u8, u8 > get(const Def *def)
Yields currying counter of def.
Definition axiom.cpp:38
Ref rebuild_(World &, Ref, Defs) const override
Definition def.cpp:115
static constexpr auto Node
Definition axiom.h:63
static constexpr u8 Trip_End
Definition axiom.h:45
Type of Match::def_.
Definition axiom.h:59
Base class for all Defs.
Definition def.h:223
Def * set(size_t i, const Def *def)
Successively set from left to right.
Definition def.cpp:246
u8 trip_
Definition def.h:590
u8 curry_
Definition def.h:589
const Def * type() const
Definition def.h:248
flags_t flags() const
Definition def.h:238
const Axiom * axiom() const
Definition axiom.h:88
auto sub() const
Definition axiom.h:99
auto id() const
Axiom::flags cast to Id.
Definition axiom.h:101
auto tag() const
Definition axiom.h:98
const D * operator->() const
Definition axiom.h:89
Match(const Axiom *axiom, const D *def)
Definition axiom.h:82
auto plugin() const
Definition axiom.h:97
auto base() const
Definition axiom.h:100
Match()=default
Helper class to retrieve Infer::arg if present.
Definition def.h:86
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:186
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
@ Axiom
Definition def.h:40
Definition cfg.h:11
u8 sub_t
Definition types.h:48
u64 flags_t
Definition types.h:45
auto match(Ref def)
Definition axiom.h:112
constexpr bool is_commutative(Id)
Definition axiom.h:139
auto force(Ref def)
Definition axiom.h:133
u64 plugin_t
Definition types.h:46
constexpr bool is_associative(Id id)
Definition axiom.h:142
u8 tag_t
Definition types.h:47
uint8_t u8
Definition types.h:34
Ref(*)(Ref, Ref, Ref) NormalizeFn
Definition def.h:102
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 Axiom::plugin() and Axiom::tag() but not Axiom::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