Thorin 1.9.0
The Higher ORder 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 "thorin/plugin.h"
6
7namespace thorin {
8
9class Axiom : public Def {
10private:
12
13public:
14 /// @name Normalization
15 /// @anchor normalization
16 ///@{
17 /// For a curried App of an Axiom, you only want to trigger normalization at specific spots.
18 /// For this reason, Thorin maintains a Def::curry_ counter that each App decrements.
19 /// The Axiom::normalizer() will be triggered when Axiom::curry() becomes `0`.
20 /// These are also the spots that you can thorin::match/thorin::force/Match.
21 /// After that, the counter will be set to Axiom::trip().
22 /// E.g., let's say an Axiom has this type:
23 /// ```
24 /// A -> B -> C -> D -> E
25 /// ^ |
26 /// | |
27 /// +---------+
28 /// ```
29 /// Using an initial value as `5` for Axiom::curry and `3` as Axiom::trip has the effect that here
30 /// ```
31 /// x a b c1 d1 e1 c2 d2 e2 c3 d3 e3
32 /// ```
33 /// the Axiom::normalizer will be triggered after App'ing `e1`, `e2`, and `e3`.
34 NormalizeFn normalizer() const { return normalizer_; }
35 u8 curry() const { return curry_; }
36 u8 trip() const { return trip_; }
37
38 /// Yields currying counter of @p def.
39 /// @returns `{nullptr, 0, 0}` if no Axiom is present.
40 static std::tuple<const Axiom*, u8, u8> get(const Def* def);
41
42 static std::pair<u8, u8> infer_curry_and_trip(const Def* type);
43 static constexpr u8 Trip_End = u8(-1);
44 ///@}
45
46 /// @name Annex Name
47 /// @anchor anatomy
48 ///@{
49 /// @see annex_name "Annex Name"
51 tag_t tag() const { return Annex::flags2tag(flags()); }
52 sub_t sub() const { return Annex::flags2sub(flags()); }
53 flags_t base() const { return Annex::flags2base(flags()); }
54 ///@}
55
56 /// Type of Match::def_.
57 template<class T> struct Match {
58 using type = App;
59 };
60
62};
63
64// clang-format off
65template<class Id> concept annex_with_subs = Annex::Num<Id> != 0;
66template<class Id> concept annex_without_subs = Annex::Num<Id> == 0;
67// clang-format on
68
69template<class Id, class D> class Match {
70 static_assert(Annex::Num<Id> != size_t(-1), "invalid number of sub tags");
71 static_assert(Annex::Base<Id> != flags_t(-1), "invalid axiom base");
72
73public:
74 Match() = default;
75 Match(const Axiom* axiom, const D* def)
76 : axiom_(axiom)
77 , def_(def) {}
78
79 /// @name Getters
80 ///@{
81 const Axiom* axiom() const { return axiom_; }
82 const D* operator->() const { return def_; }
83 operator const D*() const { return def_; }
84 explicit operator bool() { return axiom_ != nullptr; }
85 ///@}
86
87 /// @name Axiom Name
88 ///@{
89 /// @see annex_name "Annex Name"
90 auto plugin() const { return axiom()->plugin(); } ///< @see Axiom::plugin.
91 auto tag() const { return axiom()->tag(); } ///< @see Axiom::tag.
92 auto sub() const { return axiom()->sub(); } ///< @see Axiom::sub.
93 auto base() const { return axiom()->sub(); } ///< @see exiom::base.
94 auto id() const { return Id(axiom()->flags()); } ///< Axiom::flags cast to @p Id.
95 ///@}
96
97private:
98 const Axiom* axiom_ = nullptr;
99 const D* def_ = nullptr;
100};
101
102/// @name match/force
103///@{
104/// @see @ref cast_axiom
105template<class Id, bool DynCast = true> auto match(Ref def) {
106 using D = typename Axiom::Match<Id>::type;
107 auto [axiom, curry, _] = Axiom::get(def);
108 bool cond = axiom && curry == 0 && axiom->base() == Annex::Base<Id>;
109
110 if constexpr (DynCast) return cond ? Match<Id, D>(axiom, def->as<D>()) : Match<Id, D>();
111 assert(cond && "assumed to be correct axiom");
112 return Match<Id, D>(axiom, def->as<D>());
113}
114
115template<class Id, bool DynCast = true> auto match(Id id, Ref def) {
116 using D = typename Axiom::Match<Id>::type;
117 auto [axiom, curry, _] = Axiom::get(def);
118 bool cond = axiom && curry == 0 && axiom->flags() == (flags_t)id;
119
120 if constexpr (DynCast) return cond ? Match<Id, D>(axiom, def->as<D>()) : Match<Id, D>();
121 assert(cond && "assumed to be correct axiom");
122 return Match<Id, D>(axiom, def->as<D>());
123}
124
125// clang-format off
126template<class Id> auto force( Ref def) { return match<Id, false>( def); }
127template<class Id> auto force(Id id, Ref def) { return match<Id, false>(id, def); }
128///@}
129
130/// @name is_commutative/is_associative
131///@{
132template<class Id> constexpr bool is_commutative(Id) { return false; }
133/// @warning By default we assume that any commutative operation is also associative.
134/// Please provide a proper specialization if this is not the case.
135template<class Id> constexpr bool is_associative(Id id) { return is_commutative(id); }
136///@}
137// clang-format on
138
139} // namespace thorin
NormalizeFn normalizer() const
Definition axiom.h:34
u8 trip() const
Definition axiom.h:36
static constexpr u8 Trip_End
Definition axiom.h:43
u8 curry() const
Definition axiom.h:35
static std::tuple< const Axiom *, u8, u8 > get(const Def *def)
Yields currying counter of def.
Definition axiom.cpp:38
tag_t tag() const
Definition axiom.h:51
flags_t base() const
Definition axiom.h:53
sub_t sub() const
Definition axiom.h:52
plugin_t plugin() const
Definition axiom.h:50
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axiom.cpp:14
Type of Match::def_.
Definition axiom.h:57
Base class for all Defs.
Definition def.h:222
u8 curry_
Definition def.h:578
const Def * type() const
Yields the raw type of this Def, i.e. maybe nullptr.
Definition def.h:248
u8 trip_
Definition def.h:579
flags_t flags() const
Definition def.h:237
Match(const Axiom *axiom, const D *def)
Definition axiom.h:75
const D * operator->() const
Definition axiom.h:82
Match()=default
auto base() const
Definition axiom.h:93
auto plugin() const
Definition axiom.h:90
auto sub() const
Definition axiom.h:92
const Axiom * axiom() const
Definition axiom.h:81
auto id() const
Axiom::flags cast to Id.
Definition axiom.h:94
auto tag() const
Definition axiom.h:91
Helper class to retrieve Infer::arg if present.
Definition def.h:87
#define THORIN_DEF_MIXIN(T)
Definition def.h:198
Definition cfg.h:11
Ref(*)(Ref, Ref, Ref) NormalizeFn
Definition def.h:103
u8 sub_t
Definition types.h:49
auto match(Ref def)
Definition axiom.h:105
constexpr bool is_associative(Id id)
Definition axiom.h:135
auto force(Ref def)
Definition axiom.h:126
constexpr bool is_commutative(Id)
Definition axiom.h:132
uint8_t u8
Definition types.h:35
u8 tag_t
Definition types.h:48
u64 plugin_t
Definition types.h:47
u64 flags_t
Definition types.h:46
static tag_t flags2tag(flags_t f)
Yields the tag part of the name as integer.
Definition plugin.h:114
static sub_t flags2sub(flags_t f)
Yields the sub part of the name as integer.
Definition plugin.h:117
static plugin_t flags2plugin(flags_t f)
Yields the plugin part of the name as integer.
Definition plugin.h:111
static flags_t flags2base(flags_t f)
Includes Axiom::plugin() and Axiom::tag() but not Axiom::sub.
Definition plugin.h:120
static constexpr flags_t Base
Definition plugin.h:131