summaryrefslogtreecommitdiff
path: root/tiger-compiler/lib/misc
diff options
context:
space:
mode:
Diffstat (limited to 'tiger-compiler/lib/misc')
-rw-r--r--tiger-compiler/lib/misc/algorithm.hh48
-rw-r--r--tiger-compiler/lib/misc/algorithm.hxx84
-rw-r--r--tiger-compiler/lib/misc/concepts.hh79
-rw-r--r--tiger-compiler/lib/misc/contract.cc31
-rw-r--r--tiger-compiler/lib/misc/contract.hh72
-rw-r--r--tiger-compiler/lib/misc/contract.hxx11
-rw-r--r--tiger-compiler/lib/misc/deref.cc14
-rw-r--r--tiger-compiler/lib/misc/deref.hh41
-rw-r--r--tiger-compiler/lib/misc/deref.hxx40
-rw-r--r--tiger-compiler/lib/misc/endomap.hh64
-rw-r--r--tiger-compiler/lib/misc/endomap.hxx44
-rw-r--r--tiger-compiler/lib/misc/error.cc107
-rw-r--r--tiger-compiler/lib/misc/error.hh141
-rw-r--r--tiger-compiler/lib/misc/error.hxx32
-rw-r--r--tiger-compiler/lib/misc/escape.cc60
-rw-r--r--tiger-compiler/lib/misc/escape.hh36
-rw-r--r--tiger-compiler/lib/misc/escape.hxx27
-rw-r--r--tiger-compiler/lib/misc/file-library.cc152
-rw-r--r--tiger-compiler/lib/misc/file-library.hh95
-rw-r--r--tiger-compiler/lib/misc/file-library.hxx17
-rw-r--r--tiger-compiler/lib/misc/fwd.hh34
-rw-r--r--tiger-compiler/lib/misc/graph.hh213
-rw-r--r--tiger-compiler/lib/misc/graph.hxx171
-rw-r--r--tiger-compiler/lib/misc/indent.cc57
-rw-r--r--tiger-compiler/lib/misc/indent.hh30
-rw-r--r--tiger-compiler/lib/misc/lambda-visitor.hh89
-rw-r--r--tiger-compiler/lib/misc/libmisc.hh10
-rw-r--r--tiger-compiler/lib/misc/list.hh25
-rw-r--r--tiger-compiler/lib/misc/list.hxx43
-rw-r--r--tiger-compiler/lib/misc/local.am58
-rw-r--r--tiger-compiler/lib/misc/map.hh141
-rw-r--r--tiger-compiler/lib/misc/map.hxx176
-rw-r--r--tiger-compiler/lib/misc/ref.hh91
-rw-r--r--tiger-compiler/lib/misc/ref.hxx71
-rw-r--r--tiger-compiler/lib/misc/scoped-map.hh51
-rw-r--r--tiger-compiler/lib/misc/scoped-map.hxx86
-rw-r--r--tiger-compiler/lib/misc/select-const.hh42
-rw-r--r--tiger-compiler/lib/misc/separator.hh43
-rw-r--r--tiger-compiler/lib/misc/separator.hxx55
-rw-r--r--tiger-compiler/lib/misc/set.hh146
-rw-r--r--tiger-compiler/lib/misc/set.hxx208
-rw-r--r--tiger-compiler/lib/misc/singleton.hh28
-rw-r--r--tiger-compiler/lib/misc/symbol.cc32
-rw-r--r--tiger-compiler/lib/misc/symbol.hh77
-rw-r--r--tiger-compiler/lib/misc/symbol.hxx39
-rw-r--r--tiger-compiler/lib/misc/timer.cc208
-rw-r--r--tiger-compiler/lib/misc/timer.hh139
-rw-r--r--tiger-compiler/lib/misc/timer.hxx50
-rw-r--r--tiger-compiler/lib/misc/unique.hh85
-rw-r--r--tiger-compiler/lib/misc/unique.hxx95
-rw-r--r--tiger-compiler/lib/misc/variant.hh111
-rw-r--r--tiger-compiler/lib/misc/variant.hxx77
-rw-r--r--tiger-compiler/lib/misc/vector.hh105
-rw-r--r--tiger-compiler/lib/misc/vector.hxx193
-rw-r--r--tiger-compiler/lib/misc/xalloc.hh135
-rw-r--r--tiger-compiler/lib/misc/xalloc.hxx135
56 files changed, 4544 insertions, 0 deletions
diff --git a/tiger-compiler/lib/misc/algorithm.hh b/tiger-compiler/lib/misc/algorithm.hh
new file mode 100644
index 0000000..14250bc
--- /dev/null
+++ b/tiger-compiler/lib/misc/algorithm.hh
@@ -0,0 +1,48 @@
+/**
+ ** \file misc/algorithm.hh
+ ** \brief Some syntactic sugar to look for things in STL containers.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <misc/concepts.hh>
+
+namespace misc
+{
+ /// Invoke delete on all the members of \a c, and clear it.
+ template <typename Container>
+ requires Iterable<Container>
+ void deep_clear(Container& c);
+
+ /// Find \a v in the whole \a c.
+ template <typename Container>
+ requires ConstIterable<Container>
+ inline typename Container::const_iterator
+ find(const Container& c, const typename Container::value_type& v);
+
+ /// Find \a v in the whole \a c.
+ template <typename Container>
+ requires Iterable<Container>
+ inline typename Container::iterator
+ find(Container& c, const typename Container::value_type& v);
+
+ /// Apply \a f to all the members of \a c, and return it.
+ template <typename Container, typename Functor>
+ requires ConstIterable<Container>
+ inline Functor& for_each(Container& c, Functor& v);
+
+ /// Is \a v member of \a c?
+ template <typename Container>
+ requires ConstIterable<Container>
+ inline bool has(const Container& c, const typename Container::value_type& v);
+
+ /// Insert or update \a key -> \a value in \a map, return iterator to it.
+ template <Map Map>
+ typename Map::iterator put(Map& map,
+ const typename Map::key_type& key,
+ const typename Map::mapped_type& value);
+
+} // namespace misc
+
+#include <misc/algorithm.hxx>
diff --git a/tiger-compiler/lib/misc/algorithm.hxx b/tiger-compiler/lib/misc/algorithm.hxx
new file mode 100644
index 0000000..00ca8ad
--- /dev/null
+++ b/tiger-compiler/lib/misc/algorithm.hxx
@@ -0,0 +1,84 @@
+/**
+ ** \file misc/algorithm.hxx
+ ** \brief Some syntactic sugar to look for things in STL containers.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <ostream>
+
+#include <misc/algorithm.hh>
+
+namespace misc
+{
+ template <typename Container>
+ requires Iterable<Container>
+ void deep_clear(Container& c)
+ {
+ for (typename Container::value_type& x : c)
+ delete x;
+ c.clear();
+ }
+
+ // Find \a v in the whole \a c.
+ template <typename Container>
+ requires ConstIterable<Container>
+ inline typename Container::const_iterator
+ find(const Container& c, const typename Container::value_type& v)
+ {
+ return std::find(c.begin(), c.end(), v);
+ }
+
+ // Find \a v in the whole \a c.
+ template <typename Container>
+ requires Iterable<Container>
+ inline typename Container::iterator
+ find(Container& c, const typename Container::value_type& v)
+ {
+ return std::find(c.begin(), c.end(), v);
+ }
+
+ // Apply \a f to all the members of \a c, and return it.
+ template <typename Container, typename Functor>
+ requires ConstIterable<Container>
+ inline Functor& for_each(Container& c, Functor& f)
+ {
+ std::ranges::for_each(c, std::ref(f));
+ return f;
+ }
+
+ // Is \a v member of \a c?
+ template <typename Container>
+ requires ConstIterable<Container>
+ inline bool has(const Container& c, const typename Container::value_type& v)
+ {
+ // We specify the instance to solve a conflict between the
+ // two finds above, that compete against each other because
+ // the parameter Container can embed a "const".
+ return std::ranges::find(c, v) != c.end();
+ }
+
+ template <Map Map>
+ typename Map::iterator put(Map& map,
+ const typename Map::key_type& key,
+ const typename Map::mapped_type& value)
+ {
+ // See ``Efficient STL''.
+ auto i = map.lower_bound(key);
+
+ if (i != map.end() && !(map.key_comp()(key, i->first)))
+ {
+ // Update.
+ i->second = value;
+ return i;
+ }
+ else
+ {
+ // First insertion.
+ return map.emplace(key, value).first;
+ }
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/concepts.hh b/tiger-compiler/lib/misc/concepts.hh
new file mode 100644
index 0000000..a4a5926
--- /dev/null
+++ b/tiger-compiler/lib/misc/concepts.hh
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <concepts>
+#include <iterator>
+
+namespace misc
+{
+ // Concept describing a const Container through which you can iterate
+ // Needs methods begin() and end().
+ template <typename Container>
+ concept ConstIterable =
+ requires(Container c) {
+ {
+ c.begin() != c.end()
+ } -> std::same_as<bool>;
+ {
+ c.begin()
+ } -> std::convertible_to<typename Container::const_iterator>;
+ {
+ *c.begin()
+ } -> std::convertible_to<const typename Container::value_type&>;
+ };
+
+ // Concept describing a Container through which you can iterate
+ // Needs methods begin() and end().
+ template <typename Container>
+ concept Iterable = ConstIterable<Container>
+ && requires(Container c) {
+ {
+ c.begin()
+ } -> std::same_as<typename Container::iterator>;
+ {
+ *c.begin()
+ } -> std::same_as<typename Container::value_type&>;
+ };
+
+ // Concept discribing a map.
+ // Needs methods lower_bound() and emplace(key, value).
+ template <typename M>
+ concept Map =
+ requires(M map,
+ const typename M::key_type key,
+ const typename M::mapped_type value,
+ const typename M::iterator i) {
+ {
+ map.lower_bound(key)
+ } -> std::same_as<typename M::iterator>;
+
+ {
+ map.key_comp()
+ };
+
+ {
+ map.emplace(key, value)
+ } -> std::same_as<std::pair<typename M::iterator, bool>>;
+
+ requires std::same_as<
+ std::remove_cvref_t<decltype(*i)>,
+ std::pair<typename M::key_type const, typename M::mapped_type>>;
+ };
+
+ // Concept describing a ConstIterable but adds a constraint on the value_type
+ // the held type should be convertible into T
+ template <typename Container, typename T>
+ concept ConstIterableType = ConstIterable<Container>
+ && std::convertible_to<typename Container::value_type, T>;
+
+ // Concept describing an Iterable but adds a constraint on the value_type
+ // the held type should be convertible into T
+ template <typename Container, typename T>
+ concept IterableType = Iterable<Container>
+ && std::convertible_to<typename Container::value_type, T>;
+
+ // Concept describing an iterator on a type T
+ template <typename Iter, typename T>
+ concept Iterator =
+ std::forward_iterator<Iter> && std::same_as<typename Iter::value_type, T>;
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/contract.cc b/tiger-compiler/lib/misc/contract.cc
new file mode 100644
index 0000000..3dc70be
--- /dev/null
+++ b/tiger-compiler/lib/misc/contract.cc
@@ -0,0 +1,31 @@
+/** \file misc/contract.cc
+ ** \brief Implementation for contract.hh
+ */
+
+#include <cstdlib>
+#include <iostream>
+
+#include <misc/contract.hh>
+
+Contract::Contract(const char* condType,
+ const char* condText,
+ const char* fileName,
+ int fileLine)
+ : condType(condType)
+ , condText(condText)
+ , fileName(fileName)
+ , fileLine(fileLine)
+{}
+
+Contract::~Contract()
+{
+ const std::string message = std::string(condType) + ' ' + condText + " was false";
+ __Terminate(fileName, fileLine, message.c_str());
+}
+
+void __Terminate(const char* fileName, int fileLine, const char* reason)
+{
+ std::cerr << fileName << ":" << fileLine << ": Program abortion (" << reason
+ << ")\n";
+ abort();
+}
diff --git a/tiger-compiler/lib/misc/contract.hh b/tiger-compiler/lib/misc/contract.hh
new file mode 100644
index 0000000..39942a6
--- /dev/null
+++ b/tiger-compiler/lib/misc/contract.hh
@@ -0,0 +1,72 @@
+/**
+ ** \file misc/contract.hh
+ ** \brief Replacement for cassert.
+ **/
+
+#pragma once
+
+// Use GCC magic bits to specify we cannot return from these functions
+
+#ifndef __attribute__
+# if !defined __GNUC__
+# define __attribute__(Spec) /* empty */
+# endif
+#endif
+
+[[noreturn]] void __Terminate(const char*, int, const char*);
+
+#define die(Reason) __Terminate(__FILE__, __LINE__, Reason)
+#define unreachable() die("unreachable code reached")
+
+#ifdef NDEBUG
+
+// This a trick use to disable assertion and co in the project. We need a stream
+// in a 'else' to keep the code syntactically correct. However we do not want
+// to print anything. So the 'if' is always true and does nothing.
+// 'std::cerr' << "" is here to avoid warnings.
+# define __TestCondition \
+ if (true) \
+ { \
+ ; \
+ } \
+ else \
+ std::cerr << ""
+
+# define assertion(Expr) __TestCondition
+# define invariant(Expr) __TestCondition
+# define precondition(Expr) __TestCondition
+# define postcondition(Expr) __TestCondition
+
+#else // NDEBUG
+
+# define __TestCondition(CondType, Expr) \
+ if (Expr) \
+ { \
+ ; \
+ } \
+ else \
+ Contract(#CondType, #Expr, __FILE__, __LINE__)
+
+# define assertion(Expr) __TestCondition(Assertion, Expr)
+# define invariant(Expr) __TestCondition(Invariant, Expr)
+# define precondition(Expr) __TestCondition(Precondition, Expr)
+# define postcondition(Expr) __TestCondition(Postcondition, Expr)
+
+#endif // ! NDEBUG
+
+class Contract
+{
+public:
+ Contract(const char* condType,
+ const char* condText,
+ const char* fileName,
+ int fileLine);
+ [[noreturn]] ~Contract();
+
+ const char* condType;
+ const char* condText;
+ const char* fileName;
+ int fileLine;
+};
+
+#include <misc/contract.hxx>
diff --git a/tiger-compiler/lib/misc/contract.hxx b/tiger-compiler/lib/misc/contract.hxx
new file mode 100644
index 0000000..6b00b59
--- /dev/null
+++ b/tiger-compiler/lib/misc/contract.hxx
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <iostream>
+
+template <typename T> std::ostream& operator<<(Contract contract, T& t)
+{
+ return std::cerr << contract.fileName << ':' << contract.fileLine << ": "
+ << contract.condType << " `" << contract.condText
+ << "' failed.\n"
+ << t;
+}
diff --git a/tiger-compiler/lib/misc/deref.cc b/tiger-compiler/lib/misc/deref.cc
new file mode 100644
index 0000000..fb5a086
--- /dev/null
+++ b/tiger-compiler/lib/misc/deref.cc
@@ -0,0 +1,14 @@
+/**
+ ** \file misc/deref.cc
+ ** \brief Implementation for misc/deref.hh
+ */
+
+#include <misc/deref.hh>
+
+namespace misc
+{
+ Deref::Deref(std::ostream& o)
+ : ostr_(o)
+ {}
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/deref.hh b/tiger-compiler/lib/misc/deref.hh
new file mode 100644
index 0000000..3d4598c
--- /dev/null
+++ b/tiger-compiler/lib/misc/deref.hh
@@ -0,0 +1,41 @@
+/**
+ ** \file misc/deref.hh
+ ** \brief Automatically derefencing pointers on ostreams.
+ **/
+
+#pragma once
+
+#include <iosfwd>
+
+#include <misc/ref.hh>
+
+namespace misc
+{
+ enum deref_e
+ {
+ deref
+ };
+
+ class Deref
+ {
+ protected:
+ Deref(std::ostream&);
+
+ public:
+ template <typename T> std::ostream& operator<<(const T* t) const;
+ template <typename T> std::ostream& operator<<(T* t) const;
+ template <typename T> std::ostream& operator<<(const ref<T>& t) const;
+ template <typename T> std::ostream& operator<<(const T& t) const;
+ template <typename T> std::ostream& operator<<(T& t) const;
+
+ protected:
+ friend Deref operator<<(std::ostream&, deref_e);
+
+ std::ostream& ostr_;
+ };
+
+ Deref operator<<(std::ostream& ostr, deref_e);
+
+} // namespace misc
+
+#include <misc/deref.hxx>
diff --git a/tiger-compiler/lib/misc/deref.hxx b/tiger-compiler/lib/misc/deref.hxx
new file mode 100644
index 0000000..159b9fa
--- /dev/null
+++ b/tiger-compiler/lib/misc/deref.hxx
@@ -0,0 +1,40 @@
+/**
+ ** \file misc/deref.hxx
+ ** \brief Inline methods for misc/deref.hh.
+ **/
+
+#pragma once
+
+#include <misc/contract.hh>
+#include <misc/deref.hh>
+
+namespace misc
+{
+ template <typename T> std::ostream& Deref::operator<<(const T* t) const
+ {
+ return this->ostr_ << *t;
+ }
+
+ template <typename T> std::ostream& Deref::operator<<(T* t) const
+ {
+ return this->ostr_ << *t;
+ }
+
+ template <typename T> std::ostream& Deref::operator<<(const ref<T>& t) const
+ {
+ return this->ostr_ << *t;
+ }
+
+ template <typename T> std::ostream& Deref::operator<<(const T& t) const
+ {
+ return this->ostr_ << t;
+ }
+
+ template <typename T> std::ostream& Deref::operator<<(T& t) const
+ {
+ return this->ostr_ << t;
+ }
+
+ inline Deref operator<<(std::ostream& ostr, deref_e) { return Deref(ostr); }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/endomap.hh b/tiger-compiler/lib/misc/endomap.hh
new file mode 100644
index 0000000..4a69e87
--- /dev/null
+++ b/tiger-compiler/lib/misc/endomap.hh
@@ -0,0 +1,64 @@
+/**
+ ** \file misc/endomap.hh
+ ** \brief Declaration of misc::endomap.
+ */
+
+#pragma once
+
+#include <list>
+#include <map>
+
+#include <misc/map.hh>
+
+namespace misc
+{
+ /** \brief A renaming mapping defaulting to identity:
+ Mapping a class with itself (endomorphism).
+ Unless a value is already mapped onto another, map it to itself
+ if nonstrict. This is a special case of std::map. */
+ template <class T> class endomap : public map<T, T>
+ {
+ public:
+ /// Super class type.
+ using super_type = map<T, T>;
+
+ // Import overloaded virtual functions.
+ using super_type::operator[];
+ using super_type::operator();
+
+ enum class strictness_type
+ {
+ /// Querying about an unknown identifier returns itself.
+ nonstrict,
+ /// Querying about an unknown identifier is an error.
+ strict
+ };
+
+ /// \name Constructors and destructor.
+ /// \{
+ endomap();
+ /// \}
+
+ /// Return a duplicate of \a this.
+ endomap* clone() const override;
+
+ /// Return a reference to the value associated to \a t.
+ ///
+ /// If \a t was not inserted before, then, contrary to std::map,
+ /// we insert t -> t into the map, instead of `t -> T()'. This
+ /// spares the construction of a new T, which may have nasty
+ /// effects if this constructor has side effects (e.g.,
+ /// incrementing a counter).
+ virtual T& operator[](const T& t);
+
+ /// Lookup for \a t, returning it if unknown.
+ T operator()(const T& t) const override;
+
+ protected:
+ /// If strict, queries for an unknown (unmapped) Identifier is an error.
+ strictness_type strictness_;
+ };
+
+} // namespace misc
+
+#include <misc/endomap.hxx>
diff --git a/tiger-compiler/lib/misc/endomap.hxx b/tiger-compiler/lib/misc/endomap.hxx
new file mode 100644
index 0000000..58c1912
--- /dev/null
+++ b/tiger-compiler/lib/misc/endomap.hxx
@@ -0,0 +1,44 @@
+/** -*- C++ -*-
+ ** \file misc/endomap.hxx
+ ** \brief Implementation of misc::endomap.
+ */
+
+#pragma once
+
+#include <misc/endomap.hh>
+
+namespace misc
+{
+ template <class T>
+ endomap<T>::endomap()
+ : map<T, T>()
+ , strictness_(strictness_type::nonstrict)
+ {}
+
+ template <class T> endomap<T>* endomap<T>::clone() const
+ {
+ return new endomap<T>(*this);
+ }
+
+ template <class T> T endomap<T>::operator()(const T& t) const
+ {
+ if (const auto&& ires = this->find(t); ires != this->map_.end())
+ return ires->second;
+ else if (this->strictness_ == strictness_type::nonstrict)
+ return t;
+ std::ostringstream err;
+ err << "map: no mapping for " << t;
+ throw std::range_error(err.str());
+ }
+
+ template <class T> T& endomap<T>::operator[](const T& t)
+ {
+ // Inspired by ``Efficient STL'' on efficient insert_or_update
+ // for maps. See also misc::put.
+ auto i = this->map_.lower_bound(t);
+ if (i == this->map_.end() || this->map_.key_comp()(t, i->first))
+ i = this->map_.emplace(t, t).first;
+ return i->second;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/error.cc b/tiger-compiler/lib/misc/error.cc
new file mode 100644
index 0000000..565760b
--- /dev/null
+++ b/tiger-compiler/lib/misc/error.cc
@@ -0,0 +1,107 @@
+/**
+ ** \file misc/error.cc
+ ** \brief Implement error.
+ */
+
+#include <iostream>
+#include <stdexcept>
+
+#include <misc/contract.hh>
+#include <misc/error.hh>
+
+namespace misc
+{
+ /*--------.
+ | error. |
+ `--------*/
+
+ error::error()
+ : status_(error_type::success)
+ {}
+
+ error::error(const error& e) { *this = e; }
+
+ error& error::operator=(const error& rhs)
+ {
+ status_ = rhs.status_get();
+ stream_.str(rhs.stream_get().str());
+ return *this;
+ }
+
+ /*----------------------------.
+ | Filling the error handler. |
+ `----------------------------*/
+
+ error& error::operator<<(error_type e)
+ {
+ auto status_value = static_cast<unsigned>(status_);
+ auto e_value = static_cast<unsigned>(e);
+ if ((e_value && e_value < status_value) || (!status_value))
+ status_ = e;
+ return *this;
+ }
+
+ // Import errors.
+ error& error::operator<<(const error& rhs)
+ {
+ *this << rhs.status_get() << rhs.stream_get().str();
+ return *this;
+ }
+
+ error& error::operator<<(std::ostream& (*f)(std::ostream&))
+ {
+ stream_ << f;
+ return *this;
+ }
+
+ /*---------------.
+ | Manipulators. |
+ `---------------*/
+
+ void error::exit() const { throw *this; }
+
+ void error::exit_on_error() const
+ {
+ if (static_cast<unsigned>(status_))
+ exit();
+ }
+
+ void error::ice(const char* file, int line) const
+ {
+ std::cerr << stream_.str();
+ __Terminate(file, line, "Internal Compiler error");
+ }
+
+ void error::ice_on_error(const char* file, int line) const
+ {
+ if (static_cast<unsigned>(status_))
+ ice(file, line);
+ }
+
+ void error::clear()
+ {
+ status_ = error_type::success;
+ stream_.clear();
+ }
+
+ /*------------.
+ | Accessors. |
+ `------------*/
+
+ error::operator bool() const { return status_ != error_type::success; }
+
+ error::error_type error::status_get() const { return status_; }
+
+ unsigned error::status_get_value() const
+ {
+ return static_cast<unsigned>(status_);
+ }
+
+ const std::ostringstream& error::stream_get() const { return stream_; }
+
+ std::ostream& operator<<(std::ostream& o, const error& e)
+ {
+ return o << e.stream_get().str();
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/error.hh b/tiger-compiler/lib/misc/error.hh
new file mode 100644
index 0000000..cd0cc3a
--- /dev/null
+++ b/tiger-compiler/lib/misc/error.hh
@@ -0,0 +1,141 @@
+/**
+ ** \file misc/error.hh
+ ** \brief Declare error.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <sstream>
+
+/// Shortcuts.
+/// \{
+#define ice_here() ice(__FILE__, __LINE__)
+#define ice_on_error_here() ice_on_error(__FILE__, __LINE__)
+/// \}
+
+#ifndef TC_NORETURN
+# ifdef SWIG
+# define TC_NORETURN
+# else
+# define TC_NORETURN [[noreturn]]
+# endif
+#endif
+
+namespace misc
+{
+ /** \brief Handle errors in the whole project.
+ **
+ ** Each task has an error status depending on its exit code
+ ** described in the enum below.
+ **
+ ** Several versions of operator<< are used to fill the handler.
+ **
+ ** A global variable is defined to centralize all the error uses.
+ */
+
+ class error
+ {
+ public:
+ error();
+ error(const error& e);
+
+ /// Copy an error.
+ error& operator=(const error& e);
+
+ /// \name Filling the error handler.
+ /// \{
+
+ /// With what exit status should we end?
+ enum class error_type : unsigned
+ {
+ /// Job successfully done.
+ success = 0,
+ /// Some unspecified error happened.
+ failure = 1,
+ /// Lexical error.
+ scan = 2,
+ /// Syntactic error.
+ parse = 3,
+ /// Binding error: undefined name.
+ bind = 4,
+ /// Type checking error.
+ type = 5
+ };
+
+ /// General method: put the parameter in stream_.
+ template <typename T> error& operator<<(const T& t);
+
+ /// Set the status if \a e is lower than the current status.
+ error& operator<<(error_type e);
+
+ /// Accept std::endl etc.
+ error& operator<<(std::ostream& (*f)(std::ostream&));
+
+ /// Import errors.
+ error& operator<<(const error& rhs);
+
+ /// Member manipulator signature.
+ using member_manip_type = void (error::*)();
+ /// Const member manipulator signature.
+ using const_member_manip_type = void (error::*)() const;
+
+ /// Hook for member manipulators.
+ error& operator<<(member_manip_type f);
+ /// Hooks for const member manipulators.
+ error& operator<<(const_member_manip_type f);
+
+ /// \}
+
+ /// \name Member manipulators.
+ /// \{
+
+ /// Throw an exception to exit.
+ TC_NORETURN void exit() const;
+
+ /// If the error status is set, throw an exception to exit.
+ void exit_on_error() const;
+
+ /// Throw an Internal Compiler Error.
+ void ice(const char* file, int line) const;
+
+ /// If the error status is set, consider that an Internal Compiler
+ /// Error has happened and abort.
+ void ice_on_error(const char* file, int line) const;
+
+ /// Reset to no error.
+ void clear();
+
+ /// \}
+
+ /// \name Accessors.
+ /// \{
+
+ /// True if an error is recorded.
+ operator bool() const;
+
+ /// Get the current status.
+ error_type status_get() const;
+
+ /// Get the current status value.
+ unsigned status_get_value() const;
+
+ /// Get the stream associated with the class.
+ const std::ostringstream& stream_get() const;
+
+ /// \}
+
+ private:
+ /// The current exit status.
+ error_type status_;
+
+ /// The current error message.
+ std::ostringstream stream_;
+ };
+
+ /// Display the error message on the given ostream.
+ std::ostream& operator<<(std::ostream& o, const error& e);
+
+} // namespace misc
+
+#include <misc/error.hxx>
diff --git a/tiger-compiler/lib/misc/error.hxx b/tiger-compiler/lib/misc/error.hxx
new file mode 100644
index 0000000..ecc021f
--- /dev/null
+++ b/tiger-compiler/lib/misc/error.hxx
@@ -0,0 +1,32 @@
+/**
+ ** \file misc/error.hxx
+ ** \brief Implement template parts of misc/error.hh.
+ */
+
+#pragma once
+
+#include <misc/error.hh>
+
+namespace misc
+{
+ template <class T> error& error::operator<<(const T& t)
+ {
+ stream_ << t;
+ return *this;
+ }
+
+ // Member manipulators.
+ inline error& error::operator<<(member_manip_type f)
+ {
+ (this->*f)();
+ return *this;
+ }
+
+ // Const member manipulators.
+ inline error& error::operator<<(const_member_manip_type f)
+ {
+ (this->*f)();
+ return *this;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/escape.cc b/tiger-compiler/lib/misc/escape.cc
new file mode 100644
index 0000000..7585afb
--- /dev/null
+++ b/tiger-compiler/lib/misc/escape.cc
@@ -0,0 +1,60 @@
+/**
+ ** \file misc/escape.cc
+ ** \brief Implementation for misc/escape.hh.
+ **/
+
+#include <cctype>
+#include <iomanip>
+#include <ios>
+#include <unordered_map>
+
+#include <misc/escape.hh>
+
+namespace misc
+{
+ std::ostream& escaped::print(std::ostream& ostr) const
+ {
+ return escape_(ostr, pobj_str_);
+ }
+
+ std::ostream& escaped::escape_(std::ostream& o, const std::string& es) const
+ {
+ // For some reason yet to be found, when we use the locale for
+ // std::isprint, Valgrind goes berzerk. So we no longer do the
+ // following:
+ //
+ // static std::locale locale("");
+ //
+ // if (std::isprint(*p, locale))
+ std::ios_base::fmtflags flags = o.flags(std::ios_base::oct);
+ char fill = o.fill('0');
+
+ /* The GNU Assembler does not recognize `\a' as a valid
+ escape sequence, hence this explicit conversion to the
+ 007 octal character. For more information, see
+ http://sourceware.org/binutils/docs/as/Strings.html. */
+ static const std::unordered_map<char, std::string> escapes = {
+ {'\a', R"(\007)"}, {'\b', R"(\b)"}, {'\f', R"(\f)"},
+ {'\n', R"(\n)"}, {'\r', R"(\r)"}, {'\t', R"(\t)"},
+ {'\v', R"(\v)"}, {'\\', R"(\\)"}, {'\"', R"(\")"}};
+
+ for (const auto& p : es)
+ {
+ if (const auto&& it = escapes.find(p); it != escapes.end())
+ o << it->second;
+ else
+ {
+ if (std::isprint(p))
+ o << p;
+ else
+ o << "\\" << std::setw(3)
+ << static_cast<int>(static_cast<unsigned char>(p));
+ }
+ }
+
+ o.fill(fill);
+ o.flags(flags);
+ return o;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/escape.hh b/tiger-compiler/lib/misc/escape.hh
new file mode 100644
index 0000000..199c8b2
--- /dev/null
+++ b/tiger-compiler/lib/misc/escape.hh
@@ -0,0 +1,36 @@
+/**
+ ** \file misc/escape.hh
+ ** \brief Escape: escaping special characters for output.
+ **/
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+
+namespace misc
+{
+ class escaped
+ {
+ public:
+ std::ostream& print(std::ostream& ostr) const;
+
+ protected:
+ template <class T> escaped(const T&);
+
+ template <class T> friend escaped escape(const T&);
+
+ protected:
+ std::string pobj_str_;
+
+ private:
+ std::ostream& escape_(std::ostream& o, const std::string& es) const;
+ };
+
+ template <class T> escaped escape(const T&);
+
+ std::ostream& operator<<(std::ostream& o, const escaped&);
+
+} // namespace misc
+
+#include <misc/escape.hxx>
diff --git a/tiger-compiler/lib/misc/escape.hxx b/tiger-compiler/lib/misc/escape.hxx
new file mode 100644
index 0000000..6e08163
--- /dev/null
+++ b/tiger-compiler/lib/misc/escape.hxx
@@ -0,0 +1,27 @@
+/**
+ ** \file misc/escape.hxx
+ ** \brief Inline methods for misc/escape.hh.
+ **/
+
+#pragma once
+
+#include <misc/contract.hh>
+#include <misc/escape.hh>
+
+#include <boost/lexical_cast.hpp>
+
+namespace misc
+{
+ template <class T> escaped escape(const T& obj) { return escaped(obj); }
+
+ inline std::ostream& operator<<(std::ostream& o, const escaped& rhs)
+ {
+ return rhs.print(o);
+ }
+
+ template <class T> escaped::escaped(const T& obj)
+ {
+ pobj_str_ = boost::lexical_cast<std::string>(obj);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/file-library.cc b/tiger-compiler/lib/misc/file-library.cc
new file mode 100644
index 0000000..fe344d0
--- /dev/null
+++ b/tiger-compiler/lib/misc/file-library.cc
@@ -0,0 +1,152 @@
+/**
+ ** \file misc/file-library.cc
+ ** \brief Implements misc::file_library.
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <misc/contract.hh>
+#include <misc/file-library.hh>
+
+namespace misc
+{
+ void file_library::push_cwd()
+ {
+ // Store the working directory
+ char cwd[MAXPATHLEN + 1];
+
+ if (nullptr == getcwd(cwd, MAXPATHLEN + 1))
+ throw std::runtime_error("working directory name too long");
+
+ push_current_directory(path(std::string(cwd)));
+ }
+
+ file_library::file_library() { push_cwd(); }
+
+ file_library::file_library(path p)
+ {
+ push_cwd();
+ // Then only process given path.
+ search_path_.emplace_back(p);
+ }
+
+ void file_library::append_dir_list(std::string path_list)
+ {
+ std::string::size_type pos;
+
+ while ((pos = path_list.find(':')) != std::string::npos)
+ {
+ append_dir(path_list.substr(0, pos));
+ path_list.erase(0, pos + 1);
+ }
+ append_dir(path_list);
+ }
+
+ path file_library::ensure_absolute_path(path p) const
+ {
+ if (p.is_absolute())
+ return p;
+ else
+ return current_directory_get() / p;
+ }
+
+ void file_library::append_dir(path p)
+ {
+ search_path_.emplace_back(ensure_absolute_path(p));
+ }
+
+ void file_library::prepend_dir(path p)
+ {
+ search_path_.insert(search_path_.begin(), ensure_absolute_path(p));
+ }
+
+ void file_library::push_current_directory(path p)
+ {
+ // Ensure that path is absolute.
+ if (!p.is_absolute())
+ p = current_directory_get() / p;
+
+ current_directory_.insert(current_directory_.begin(), p);
+ }
+
+ void file_library::pop_current_directory()
+ {
+ precondition(!current_directory_.empty());
+
+ current_directory_.erase(current_directory_.begin());
+ }
+
+ path file_library::current_directory_get() const
+ {
+ precondition(!current_directory_.empty());
+
+ return current_directory_.front();
+ }
+
+ path file_library::find_file(const std::string& file)
+ {
+ // Split file in two components, basename and basedir.
+ path p = path(file);
+ path directory = p.filename();
+
+ if (directory.is_absolute())
+ {
+ // If file is absolute, just check that it exists.
+ if (!std::filesystem::exists(path(file)))
+ return path();
+ }
+ else
+ {
+ // Does the file can be found in current directory?
+ if (find_in_directory(current_directory_get(), file))
+ return (current_directory_get() / file).parent_path();
+
+ directory = find_in_search_path(directory, p.filename().string());
+ }
+
+ return directory;
+ }
+
+ bool file_library::find_in_directory(const path& dir,
+ const std::string& file) const
+ {
+ return std::filesystem::exists(path(dir / file));
+ }
+
+ path file_library::find_in_search_path(const path& relative_path,
+ const std::string& filename) const
+ {
+ path checked_dir;
+
+ // Otherwise start scanning the search path.
+ for (const path& p : search_path_)
+ {
+ if (p.is_absolute())
+ checked_dir = p;
+ else
+ checked_dir = current_directory_get() / p;
+
+ checked_dir /= relative_path;
+
+ if (find_in_directory(checked_dir, filename))
+ return checked_dir;
+ }
+
+ // File not found in search path.
+ return path();
+ }
+
+ std::ostream& file_library::dump(std::ostream& ostr) const
+ {
+ ostr << ".";
+ for (const path& p : search_path_)
+ ostr << ":" << p;
+ return ostr;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/file-library.hh b/tiger-compiler/lib/misc/file-library.hh
new file mode 100644
index 0000000..f59757f
--- /dev/null
+++ b/tiger-compiler/lib/misc/file-library.hh
@@ -0,0 +1,95 @@
+/**
+ ** \file misc/file-library.hh
+ ** \brief Manage sets of inclusion paths.
+ */
+
+#pragma once
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+namespace misc
+{
+ using path = std::filesystem::path;
+
+ /** \brief Manage search path.
+
+ Store search path and all informations used for handling
+ paths when processing import directives. */
+
+ class file_library
+ {
+ public:
+ /// \name Constructor.
+ /// \{
+ /// An empty library.
+ file_library();
+ /// Init the library with one path.
+ file_library(path p);
+ /// \}
+
+ /// \name Managing inclusion paths.
+ /// \{
+ void append_dir(path p);
+ void prepend_dir(path p);
+ /// \}
+
+ /// \name current directory.
+ /// \{
+ void push_current_directory(path p);
+ void pop_current_directory();
+ path current_directory_get() const;
+ /// \}
+
+ /// \name Findind file
+ /// \{
+ /** \brief Search a file.
+
+ Determine real path of \a file, by looking in search path if
+ necessary.
+
+ \return Directory containing \a file, or "" if not found. */
+ path find_file(const std::string& file);
+
+ /// \brief Check if \a file exists in directory \a dir.
+ bool find_in_directory(const path& dir, const std::string& file) const;
+ /// \}
+
+ /// \name Printing.
+ /// \{
+ std::ostream& dump(std::ostream& ostr) const;
+ /// \}
+
+ private:
+ /// Push the working directory on the stack.
+ void push_cwd();
+
+ /** \brief Find file "\a relative_path / \a filename" using include path.
+ \return Absolute path where the file lies or empty path
+ if the file does not exist. */
+ path find_in_search_path(const path& relative_path,
+ const std::string& filename) const;
+
+ /** \brief Split the string with character ':', and insert each
+ resultant string as a new search path. */
+ void append_dir_list(std::string path_list);
+
+ /** \brief Ensure that path is absolute by prepending current
+ directory if necessary */
+ path ensure_absolute_path(path p) const;
+
+ using path_list_type = std::vector<path>;
+
+ /// Inclusion path list.
+ path_list_type search_path_;
+
+ /// Current directory stack.
+ path_list_type current_directory_;
+ };
+
+ std::ostream& operator<<(std::ostream& ostr, const file_library& l);
+
+} // namespace misc
+
+#include <misc/file-library.hxx>
diff --git a/tiger-compiler/lib/misc/file-library.hxx b/tiger-compiler/lib/misc/file-library.hxx
new file mode 100644
index 0000000..37aead3
--- /dev/null
+++ b/tiger-compiler/lib/misc/file-library.hxx
@@ -0,0 +1,17 @@
+/**
+ ** \file misc/file-library.hxx
+ ** \brief implements inline function of misc/file-library.hh
+ */
+
+#pragma once
+
+#include <misc/file-library.hh>
+
+namespace misc
+{
+ inline std::ostream& operator<<(std::ostream& ostr, const file_library& l)
+ {
+ return l.dump(ostr);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/fwd.hh b/tiger-compiler/lib/misc/fwd.hh
new file mode 100644
index 0000000..33f0cc1
--- /dev/null
+++ b/tiger-compiler/lib/misc/fwd.hh
@@ -0,0 +1,34 @@
+/**
+ ** \file misc/fwd.hh
+ ** \brief Forward declarations for misc:: items.
+ */
+
+#pragma once
+
+namespace misc
+{
+ // From file-library.hh.
+ class file_library;
+
+ // From map.hh.
+ template <typename T, typename N> class map;
+ // From endomap.hh.
+ template <typename T> class endomap;
+
+ // From ref.hh.
+ template <typename T> class ref;
+
+ // From select-const.hh.
+ template <typename T> struct constify_traits;
+ template <typename T> struct id_traits;
+
+ // From symbol.hh.
+ class symbol;
+
+ // From xalloc.hh.
+ template <class StoredType> class xalloc;
+
+ // From timer.hh
+ class timer;
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/graph.hh b/tiger-compiler/lib/misc/graph.hh
new file mode 100644
index 0000000..c21aa99
--- /dev/null
+++ b/tiger-compiler/lib/misc/graph.hh
@@ -0,0 +1,213 @@
+/**
+ ** \file misc/graph.hh
+ ** \brief Undirected/oriented graph definition.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <boost/functional/hash.hpp> // Required by boost/graph/detail/edge.hpp.
+/* Forward declarations to help the compiler not to mix up the
+ namespace `target' with `boost::target'. This happens in the
+ instantiation of graph concepts in boost/graph/graph_concepts.hpp
+ if this forward declaration is omitted. */
+#include <boost/graph/detail/edge.hpp>
+
+namespace boost
+{
+ template <class OutEdgeListS,
+ class VertexListS,
+ class DirectedS,
+ class VertexProperty,
+ class EdgeProperty,
+ class GraphProperty,
+ class EdgeListS>
+ class adjacency_list;
+
+ template <class Directed,
+ class Vertex,
+ class OutEdgeListS,
+ class VertexListS,
+ class DirectedS,
+ class VertexProperty,
+ class EdgeProperty,
+ class GraphProperty,
+ class EdgeListS>
+ inline Vertex target(const detail::edge_base<Directed, Vertex>& e,
+ const adjacency_list<OutEdgeListS,
+ VertexListS,
+ DirectedS,
+ VertexProperty,
+ EdgeProperty,
+ GraphProperty,
+ EdgeListS>&);
+
+} // namespace boost
+
+#include <boost/graph/adjacency_list.hpp>
+
+#include <misc/set.hh>
+
+/// Handling of generic, oriented or undirected, graph.
+namespace misc
+{
+ /*--------.
+ | Graph. |
+ `--------*/
+
+ /// Graph property: name.
+ using name_prop_type = boost::property<boost::graph_name_t, std::string>;
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ class graph
+ : public boost::adjacency_list<boost::setS,
+ boost::vecS,
+ Orientation,
+ VertexLabel,
+ EdgeLabel,
+ name_prop_type>
+ {
+ public:
+ virtual ~graph() = default;
+
+ public:
+ using self_type = graph<Orientation, VertexLabel, EdgeLabel>;
+ using super_type = boost::adjacency_list<boost::setS,
+ boost::vecS,
+ Orientation,
+ VertexLabel,
+ EdgeLabel,
+ name_prop_type>;
+ using vertex_descriptor = typename super_type::vertex_descriptor;
+
+ /// Iterators.
+ public:
+ /// \{
+ /// Iterator on the vertices of a graph.
+ using vertex_iter_type =
+ typename boost::graph_traits<self_type>::vertex_iterator;
+ /// Iterator on the edges of a graph.
+ using edge_iter_type =
+ typename boost::graph_traits<self_type>::edge_iterator;
+ /// \}
+
+ /// Graph manipulation.
+ /// \{
+ public:
+ /// \brief Add a vertex to the graph.
+ ///
+ /// Just a wrapper around boost::add_vertex.
+ vertex_descriptor vertex_add(const VertexLabel& l);
+ /// Add an edge between two vertices.
+ virtual void edge_add(const vertex_descriptor& v1,
+ const vertex_descriptor& v2) = 0;
+ /// \}
+
+ /// Graph pretty printing.
+ /// \{
+ public:
+ virtual std::ostream& print(std::ostream& ostr) const;
+ virtual std::ostream& epilogue_print(std::ostream& ostr) const;
+ virtual void print(std::string file) const;
+
+ private:
+ /// Print the label of vertex of a graph.
+ virtual std::ostream& vertex_print(vertex_descriptor v,
+ std::ostream& ostr) const = 0;
+ /// \}
+
+ /// Graph name.
+ /// \{
+ public:
+ const std::string& name_get() const;
+ void name_set(const std::string& name);
+ /// \}
+ };
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ std::ostream& operator<<(std::ostream& ostr,
+ const graph<Orientation, VertexLabel, EdgeLabel>& g);
+
+ // An helper class when we do not want any data attached to vertex
+ // or an edge.
+ struct empty
+ {};
+ inline std::ostream& operator<<(std::ostream& ostr, empty);
+
+ /*----------------------------------------------------.
+ | Specialization for directed (bidirectional) graph. |
+ `----------------------------------------------------*/
+
+ /* Note that boost::bidirectionalS is like boost::directedS, except
+ that it provides access to both in-edges and out-edges, whereas
+ boost::directedS gives us only out-edges. The consequence is
+ that a bidirectional graph is twice as large as its directed
+ version. */
+ template <typename VertexLabel = empty, typename EdgeLabel = empty>
+ class directed_graph
+ : public graph<boost::bidirectionalS, VertexLabel, EdgeLabel>
+ {
+ public:
+ using self_type = directed_graph<VertexLabel, EdgeLabel>;
+ using super_type = graph<boost::bidirectionalS, VertexLabel, EdgeLabel>;
+ using vertex_descriptor = typename super_type::vertex_descriptor;
+
+ public:
+ /// Iterator on the vertices of a directed_graph.
+ using vertex_iter_type =
+ typename boost::graph_traits<self_type>::vertex_iterator;
+ /// Iterator on the neighbors of the vertex of a directed_graph.
+ using neighb_iter_type =
+ typename boost::graph_traits<self_type>::adjacency_iterator;
+
+ /// Iterators.
+ /// \{
+ public:
+ /// \brief Add an edge between two vertices.
+ ///
+ /// This is just a wrapper around boost::add_edge.
+ void edge_add(const vertex_descriptor& v1,
+ const vertex_descriptor& v2) override;
+ /// \}
+
+ /// \brief Topological sort.
+ ///
+ /// This version (algorithm 17.5 in Modern Compiler Implementation
+ /// in ML, p. 390) is not the same as boost::topological_sort since
+ /// the former works on directed acyclic graphs (DAGs) and the latter
+ /// doesn't.
+ ///
+ /// \{
+ public:
+ std::vector<vertex_descriptor> topological_sort() const;
+ /// \}
+ };
+
+ /*--------------------------------------.
+ | Specialization for undirected graph. |
+ `--------------------------------------*/
+
+ template <typename VertexLabel = empty, typename EdgeLabel = empty>
+ class undirected_graph
+ : public graph<boost::undirectedS, VertexLabel, EdgeLabel>
+ {
+ public:
+ using super_type = graph<boost::undirectedS, VertexLabel, EdgeLabel>;
+ using vertex_descriptor = typename super_type::vertex_descriptor;
+
+ public:
+ /// \brief Add an edge between two vertices.
+ ///
+ /// Use this method instead of boost::add_edge directly to keep
+ /// the order between the ends of an edge.
+ void edge_add(const vertex_descriptor& v1,
+ const vertex_descriptor& v2) override;
+ };
+
+} // namespace misc
+
+#include <misc/graph.hxx>
diff --git a/tiger-compiler/lib/misc/graph.hxx b/tiger-compiler/lib/misc/graph.hxx
new file mode 100644
index 0000000..fe97cf7
--- /dev/null
+++ b/tiger-compiler/lib/misc/graph.hxx
@@ -0,0 +1,171 @@
+/**
+ ** \file misc/graph.hxx
+ ** \brief Undirected/oriented graph implementation.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <tuple>
+
+#include <misc/algorithm.hh>
+#include <misc/contract.hh>
+#include <misc/deref.hh>
+
+namespace misc
+{
+ /*--------.
+ | Graph. |
+ `--------*/
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ typename graph<Orientation, VertexLabel, EdgeLabel>::vertex_descriptor
+ graph<Orientation, VertexLabel, EdgeLabel>::vertex_add(const VertexLabel& l)
+ {
+ return boost::add_vertex(l, *this);
+ }
+
+ /*-----------------------------------------------------------------.
+ | graph::print. |
+ | |
+ | For oriented graph, keeping edges bound to the source node looks |
+ | nicer, while an edge oriented dump is more appropriate for |
+ | unoriented graphs. In the latter case, be sure not to output |
+ | each edge twice. |
+ | |
+ | FIXME: We do lack something similar to Escape when "deref"ing, |
+ | for if there are strings in there, they should be escaped for |
+ | dotty. |
+ | |
+ | FIXME: Enforce the order by sorting before outputting. |
+ `-----------------------------------------------------------------*/
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ std::ostream&
+ graph<Orientation, VertexLabel, EdgeLabel>::print(std::ostream& ostr) const
+ {
+ using misc::deref;
+
+ std::string graphtype = boost::is_undirected(*this) ? "graph" : "digraph";
+ std::string link = boost::is_undirected(*this) ? "--" : "->";
+ ostr << "/* Graph Visualization */\n";
+
+ ostr << graphtype << " \"" << name_get() << "\" {\n"
+ << " node [shape=box];\n";
+
+ for (auto [vi, vi_end] = boost::vertices(*this); vi != vi_end; ++vi)
+ {
+ ostr << " \"" << *vi << "\" "
+ << "[label=\"";
+ vertex_print(*vi, ostr);
+ ostr << "\"]\n";
+ }
+
+ for (auto [ei, ei_end] = boost::edges(*this); ei != ei_end; ++ei)
+ {
+ std::ostringstream label;
+ label << deref << (*this)[*ei];
+ ostr << " \"" << boost::source(*ei, *this) << "\" " << link << " \""
+ << boost::target(*ei, *this) << "\"";
+ if (label.str() != "")
+ ostr << " [label=\"" << label.str() << "\"]";
+ ostr << '\n';
+ }
+
+ epilogue_print(ostr);
+
+ return ostr << "}\n";
+ }
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ std::ostream& graph<Orientation, VertexLabel, EdgeLabel>::epilogue_print(
+ std::ostream& ostr) const
+ {
+ return ostr;
+ }
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ void graph<Orientation, VertexLabel, EdgeLabel>::print(std::string file) const
+ {
+ std::ofstream ofs;
+
+ static unsigned cpt = 0;
+ if (file.empty())
+ {
+ std::stringstream sstr;
+ sstr << "graph-" << cpt << ".gv";
+ ++cpt;
+ file = sstr.str();
+ }
+
+ file += ".gv";
+ ofs.open(file.c_str());
+ print(ofs);
+ ofs.close();
+ }
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ const std::string&
+ graph<Orientation, VertexLabel, EdgeLabel>::name_get() const
+ {
+ // For some reason, the following cast is needed with Boost 1.45.
+ return boost::get_property(static_cast<const super_type&>(*this),
+ boost::graph_name);
+ }
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ void
+ graph<Orientation, VertexLabel, EdgeLabel>::name_set(const std::string& name)
+ {
+ boost::set_property(*this, boost::graph_name, name);
+ }
+
+ template <typename Orientation, typename VertexLabel, typename EdgeLabel>
+ inline std::ostream&
+ operator<<(std::ostream& ostr,
+ const graph<Orientation, VertexLabel, EdgeLabel>& g)
+ {
+ return g.print(ostr);
+ }
+
+ inline std::ostream& operator<<(std::ostream& ostr, empty) { return ostr; }
+
+ /*----------------.
+ | DirectedGraph. |
+ `----------------*/
+
+ template <typename VertexLabel, typename EdgeLabel>
+ void
+ directed_graph<VertexLabel, EdgeLabel>::edge_add(const vertex_descriptor& v1,
+ const vertex_descriptor& v2)
+ {
+ boost::add_edge(v1, v2, *this);
+ }
+
+ template <typename NodeLabel, typename EdgeLabel>
+ std::vector<typename directed_graph<NodeLabel, EdgeLabel>::vertex_descriptor>
+ directed_graph<NodeLabel, EdgeLabel>::topological_sort() const
+ {
+ std::vector<vertex_descriptor> res;
+ misc::set<vertex_descriptor> visited;
+ return res;
+ }
+
+ /*------------------.
+ | UndirectedGraph. |
+ `------------------*/
+
+ template <typename VertexLabel, typename EdgeLabel>
+ void undirected_graph<VertexLabel, EdgeLabel>::edge_add(
+ const vertex_descriptor& v1,
+ const vertex_descriptor& v2)
+ {
+ if (v1 > v2)
+ boost::add_edge(v2, v1, *this);
+ else
+ boost::add_edge(v1, v2, *this);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/indent.cc b/tiger-compiler/lib/misc/indent.cc
new file mode 100644
index 0000000..03e15cd
--- /dev/null
+++ b/tiger-compiler/lib/misc/indent.cc
@@ -0,0 +1,57 @@
+/**
+ ** \file misc/indent.cc
+ ** \brief Implementation of indentation relative functions.
+ **/
+
+#include <iomanip>
+#include <ostream>
+
+#include <misc/contract.hh>
+#include <misc/indent.hh>
+
+namespace misc
+{
+ namespace
+ {
+ /// The current indentation level for \a o.
+ inline long int& indent(std::ostream& o)
+ {
+ // The slot to store the current indentation level.
+ static const long int indent_index = std::ios::xalloc();
+ return o.iword(indent_index);
+ }
+
+ } // namespace
+
+ std::ostream& incindent(std::ostream& o)
+ {
+ indent(o) += 2;
+ return o;
+ }
+
+ std::ostream& decindent(std::ostream& o)
+ {
+ precondition(indent(o));
+ indent(o) -= 2;
+ return o;
+ }
+
+ std::ostream& resetindent(std::ostream& o)
+ {
+ indent(o) = 0;
+ return o;
+ }
+
+ std::ostream& iendl(std::ostream& o)
+ {
+ o << std::endl;
+ // Be sure to be able to restore the stream flags.
+ char fill = o.fill(' ');
+ return o << std::setw(indent(o)) << "" << std::setfill(fill);
+ }
+
+ std::ostream& incendl(std::ostream& o) { return o << incindent << iendl; }
+
+ std::ostream& decendl(std::ostream& o) { return o << decindent << iendl; }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/indent.hh b/tiger-compiler/lib/misc/indent.hh
new file mode 100644
index 0000000..04cd610
--- /dev/null
+++ b/tiger-compiler/lib/misc/indent.hh
@@ -0,0 +1,30 @@
+/**
+ ** \file misc/indent.hh
+ ** \brief Indentation relative functions.
+ **/
+
+#pragma once
+
+#include <iosfwd>
+
+namespace misc
+{
+ /// Increment the indentation.
+ std::ostream& incindent(std::ostream& o);
+
+ /// Decrement the indentation.
+ std::ostream& decindent(std::ostream& o);
+
+ /// Reset the indentation.
+ std::ostream& resetindent(std::ostream& o);
+
+ /// Print an end of line, then set the indentation.
+ std::ostream& iendl(std::ostream& o);
+
+ /// Increment the indentation, print an end of line, and set the indentation.
+ std::ostream& incendl(std::ostream& o);
+
+ /// Decrement the indentation, print an end of line, and set the indentation.
+ std::ostream& decendl(std::ostream& o);
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/lambda-visitor.hh b/tiger-compiler/lib/misc/lambda-visitor.hh
new file mode 100644
index 0000000..db0b403
--- /dev/null
+++ b/tiger-compiler/lib/misc/lambda-visitor.hh
@@ -0,0 +1,89 @@
+/**
+ ** \file misc/lambda-visitor.hh
+ ** \brief Declaration of misc::LambdaVisitor.
+ **/
+
+#pragma once
+
+namespace misc
+{
+ /** \brief Allows to build a visitor from lambdas to use with std::visit.
+ **
+ ** This allows to use a syntax such as
+ ** std::visit(
+ ** LambdaVisitor{
+ ** Lambda1,
+ ** Lambda2,
+ ** ...
+ ** }, variant);
+ ** to a call specific lambdas depending on the static type of the variant.
+ **
+ ** For instance, the following code:
+ **
+ ** std::visit(
+ ** LambdaVisitor{
+ ** [](int) { std::cout << "It's an int!\n"; },
+ ** [](std::string) { std::cout << "It's a string!\n"; },
+ ** [](auto) { std::cout << "It's anything else!\n"; },
+ ** }, var);
+ **
+ ** would have the following results for these variants:
+ ** std::variant<int, std::string, char> v1 = 1; // It's an int!
+ ** std::variant<int, std::string, char> v2 = "Tigrou"; // It's a string!
+ ** std::variant<int, std::string, char> v3 = 'a'; // It's anything else!
+ **
+ ** This allows to perform quick and efficient pattern matching on variants'
+ ** static type.
+ **
+ ** The really powerful thing here is that this can be used to match multiple
+ ** variants. For instance the following code:
+ **
+ ** std::visit(
+ ** LambdaVisitor{
+ ** [](int, std::string) { ... },
+ ** [](auto, std::string) { ... },
+ ** [](auto, auto) { ... },
+ ** }, var1, var2);
+ **
+ ** would call the first lambda if var1 is an int and var2 a string, the
+ ** second lambda if var2 is a string and var1 anything else than an int,
+ ** and the third in any other case.
+ **
+ ** Do note that you can have a return value for your lambdas, and have
+ ** something like so:
+ ** int a = std::visit(
+ ** LambdaVisitor{
+ ** ...
+ ** }, var);
+ **
+ **
+ ** Be careful , you must necessarily have a matching lambda for any possible
+ ** values of the variants used as arguments! You won't be able to compile
+ ** otherwise.
+ **/
+ template <class... Ts> struct LambdaVisitor : Ts...
+ {
+ /** C++ actually desugars lambdas to some kind of struct functors.
+ ** For instance, the following lambda could be desugared to the following
+ ** struct:
+ **
+ ** auto f = [](int a) { std::cout << a; }
+ **
+ ** struct {
+ ** auto operator()(int a) {
+ ** std::cout << a;
+ ** }
+ ** } f;
+ **
+ ** We therefore want to access the operator() of every lambda/functor used
+ ** to create the LambdaVisitor.
+ **/
+ using Ts::operator()...;
+ };
+
+ /// Class template argument deduction. This allows to implicitly deduce the
+ /// templated type of the visitor created from the types of the arguments
+ /// it is constructed with, without having to explicitly fill the template.
+ template <class... Ts> LambdaVisitor(Ts...) -> LambdaVisitor<Ts...>;
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/libmisc.hh b/tiger-compiler/lib/misc/libmisc.hh
new file mode 100644
index 0000000..9303941
--- /dev/null
+++ b/tiger-compiler/lib/misc/libmisc.hh
@@ -0,0 +1,10 @@
+/**
+ ** \file misc/libmisc.hh
+ ** \brief A library of handy C++ tools.
+ */
+
+#pragma once
+
+/// A set of handy C++ tools.
+namespace misc
+{} // namespace misc
diff --git a/tiger-compiler/lib/misc/list.hh b/tiger-compiler/lib/misc/list.hh
new file mode 100644
index 0000000..d27ab66
--- /dev/null
+++ b/tiger-compiler/lib/misc/list.hh
@@ -0,0 +1,25 @@
+/**
+ ** \file misc/list.hh
+ ** \brief Declaration of misc::list
+ */
+
+#pragma once
+
+#include <misc/vector.hh>
+
+/// Wrappers on misc::vectors to provide functional-style list manipulation.
+namespace misc::list
+{
+ /// Build a list of a \a head and a \a tail.
+ template <typename T> vector<T> cons(const T head, const vector<T>& tail);
+
+ /// Get the head and tail of the list. Invert of cons.
+ template <typename T> std::pair<T, vector<T>> snoc(const vector<T>& v);
+
+ /// Decompose the list into an array to use structured bindings.
+ template <std::size_t Size, typename T>
+ std::array<T, Size> decompose(const vector<T>& v);
+
+} // namespace misc::list
+
+#include <misc/list.hxx>
diff --git a/tiger-compiler/lib/misc/list.hxx b/tiger-compiler/lib/misc/list.hxx
new file mode 100644
index 0000000..63d7f0d
--- /dev/null
+++ b/tiger-compiler/lib/misc/list.hxx
@@ -0,0 +1,43 @@
+/**
+ ** \file misc/list.hh
+ ** \brief Implementation of misc::list
+ */
+
+#pragma once
+
+#include <misc/list.hh>
+
+namespace misc::list
+{
+ template <class T> inline vector<T> cons(const T head, const vector<T>& tail)
+ {
+ vector<T> res;
+
+ res.emplace_back(head);
+ res.append(tail);
+
+ return res;
+ }
+
+ template <class T> inline std::pair<T, vector<T>> snoc(const vector<T>& v)
+ {
+ precondition(v.size() > 0);
+
+ T head = v[0];
+ vector<T> tail(v.begin() + 1, v.end());
+
+ return {head, tail};
+ }
+
+ template <std::size_t Size_, typename T>
+ inline std::array<T, Size_> decompose(const vector<T>& v)
+ {
+ precondition(v.size() == Size_);
+
+ std::array<T, Size_> res;
+ std::copy(v.begin(), v.end(), res.begin());
+
+ return res;
+ }
+
+} // namespace misc::list
diff --git a/tiger-compiler/lib/misc/local.am b/tiger-compiler/lib/misc/local.am
new file mode 100644
index 0000000..e0e8bcb
--- /dev/null
+++ b/tiger-compiler/lib/misc/local.am
@@ -0,0 +1,58 @@
+## --------- ##
+## libmisc. ##
+## --------- ##
+
+noinst_LTLIBRARIES = %D%/libmisc.la
+%C%_libmisc_la_SOURCES = \
+ %D%/fwd.hh \
+ %D%/libmisc.hh \
+ %D%/concepts.hh \
+ %D%/algorithm.hh %D%/algorithm.hxx \
+ %D%/contract.hh %D%/contract.hxx %D%/contract.cc \
+ %D%/deref.hh %D%/deref.hxx %D%/deref.cc \
+ %D%/error.hh %D%/error.hxx %D%/error.cc \
+ %D%/escape.hh %D%/escape.hxx %D%/escape.cc \
+ %D%/file-library.hh %D%/file-library.hxx %D%/file-library.cc \
+ %D%/graph.hh %D%/graph.hxx \
+ %D%/indent.hh %D%/indent.cc \
+ %D%/map.hh %D%/map.hxx \
+ %D%/endomap.hh %D%/endomap.hxx \
+ %D%/ref.hh %D%/ref.hxx \
+ %D%/select-const.hh \
+ %D%/set.hh %D%/set.hxx \
+ %D%/separator.hh %D%/separator.hxx \
+ %D%/symbol.hh %D%/symbol.hxx %D%/symbol.cc \
+ %D%/timer.hh %D%/timer.hxx %D%/timer.cc \
+ %D%/unique.hh %D%/unique.hxx \
+ %D%/variant.hh %D%/variant.hxx %D%/vector.hh %D%/vector.hxx \
+ %D%/lambda-visitor.hh \
+ %D%/list.hh %D%/list.hxx \
+ %D%/xalloc.hh %D%/xalloc.hxx
+
+%C%_libmisc_la_SOURCES += %D%/scoped-map.hh %D%/scoped-map.hxx
+
+%C%_libmisc_la_SOURCES += %D%/singleton.hh
+
+%C%_libmisc_la_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS)
+%C%_libmisc_la_LIBADD = $(BOOST_SYSTEM_LIBS)
+
+## ------- ##
+## Tests. ##
+## ------- ##
+
+check_PROGRAMS += \
+ %D%/test-deref \
+ %D%/test-error \
+ %D%/test-escape \
+ %D%/test-graph \
+ %D%/test-indent \
+ %D%/test-separator \
+ %D%/test-scoped \
+ %D%/test-symbol \
+ %D%/test-timer \
+ %D%/test-unique \
+ %D%/test-variant \
+ %D%/test-xalloc
+%C%_test_variant_CXXFLAGS = -Wno-unused
+
+LDADD = %D%/libmisc.la
diff --git a/tiger-compiler/lib/misc/map.hh b/tiger-compiler/lib/misc/map.hh
new file mode 100644
index 0000000..952a1e2
--- /dev/null
+++ b/tiger-compiler/lib/misc/map.hh
@@ -0,0 +1,141 @@
+/**
+ ** \file misc/map.hh
+ ** \brief Declaration of misc::Map.
+ */
+
+#pragma once
+
+#include <map>
+#include <stdexcept>
+#include <vector>
+#include <misc/concepts.hh>
+
+namespace misc
+{
+ /** \brief Wrapper around std::map providing syntactic sugar
+ for any mapping of types manipulation. */
+ template <class T, class N> class map
+ {
+ protected:
+ using map_type = std::map<T, N>;
+
+ public:
+ /// The map's key type.
+ using key_type = typename map_type::key_type;
+ /// The type of object associated with the keys.
+ using mapped_type = typename map_type::mapped_type;
+ /// The type of object, std::pair<const key_type, data_type>,
+ /// stored in the map.
+ using value_type = typename map_type::value_type;
+ /// Type of the function object that compares two keys for ordering.
+ using key_compare = typename map_type::key_compare;
+ /// Iterator used to iterate through a map.
+ using iterator = typename map_type::iterator;
+ /// Const iterator used to iterate through a map.
+ using const_iterator = typename map_type::const_iterator;
+
+ public:
+ /// \name Constructors and destructor.
+ /// \{
+ map() = default;
+ /// Return a duplicate of \a this.
+ virtual ~map() = default;
+ /// \}
+
+ /// Return a duplicate of \a this.
+ virtual map* clone() const;
+
+ /// Returns the key_compare object used by the map.
+ key_compare key_comp() const;
+
+ /// Lookup for \a t.
+ /// \{
+ virtual iterator find(const T& t);
+ virtual const_iterator find(const T& t) const;
+ /// \}
+
+ /// Lookup for \a t and throw an exception if not available.
+ /// \{
+ virtual iterator xfind(const T& t);
+ virtual const_iterator xfind(const T& t) const;
+ /// \}
+
+ /// Lookup for the value associated to \a t.
+ virtual N operator[](const T& t) const;
+
+ /// \brief Return a reference to the value associated to \a t.
+ ///
+ /// This method is not virtual, so that it is not automatically
+ /// instantiated at the instantiation of misc::map. This way,
+ /// there won't be errors from the compiler about \a N not being a
+ /// model of the concept Default Constructible. This is needed
+ /// for some instantiations of misc::map, notably the ones that
+ /// uses a symbol::Symbol as mapped type, which has no default
+ /// constructor (note that in this case everything will be fine as
+ /// long as this method is not called -- compile errors will occur
+ /// otherwise).
+ ///
+ /// We might want to provide two flavors of misc::map, one that
+ /// requires that its second parameter is a model of Default
+ /// Constructible and that provides an operator[] similar to
+ /// std::map's; and another one that doesn't.
+ N& operator[](const T& t);
+
+ /// Lookup for \a t, throwing std::range_error if it is not found.
+ virtual N operator()(const T& t) const;
+
+ /// Lookup for a list \a ts of T's, throwing std::range_error if
+ /// one or several elements are not found.
+ template <typename Container>
+ requires ConstIterableType<Container, T>
+ std::vector<N> operator()(const Container& ts) const;
+
+ /// \name Iterating.
+ /// \{
+ virtual iterator begin();
+ virtual iterator end();
+ virtual const_iterator begin() const;
+ virtual const_iterator end() const;
+ /// \}
+
+ /// Finds the first element whose key is not less than \a k.
+ /// \{
+ virtual iterator lower_bound(const T& k);
+ virtual const_iterator lower_bound(const T& k) const;
+ /// \}
+
+ /// Inserts \a x into the map.
+ virtual std::pair<iterator, bool> insert(const std::pair<const T, N>& x);
+ /// Copy the contents of \a other to \a this.
+ virtual void insert(const map& other);
+
+ /// Insert a new element built in-place using \a args into the map.
+ template <class... Args> std::pair<iterator, bool> emplace(Args&&... args);
+
+ /// Is the map empty ?
+ virtual bool empty() const;
+
+ /// Number of known identifiers.
+ virtual size_t size() const;
+
+ /// Remove and return mapping for \a t from the map.
+ virtual N take(const T& t);
+
+ /// Erase all of the elements.
+ virtual void clear();
+
+ /// Description of known mappings.
+ virtual std::ostream& print(std::ostream& ostr) const;
+
+ protected:
+ /// Mapping from T to N.
+ map_type map_;
+ };
+
+ /// Output \a m onto \a ostr.
+ template <class T, class N>
+ std::ostream& operator<<(std::ostream& ostr, const map<T, N>& m);
+
+} // namespace misc
+
+#include <misc/map.hxx>
diff --git a/tiger-compiler/lib/misc/map.hxx b/tiger-compiler/lib/misc/map.hxx
new file mode 100644
index 0000000..fb429ac
--- /dev/null
+++ b/tiger-compiler/lib/misc/map.hxx
@@ -0,0 +1,176 @@
+/** -*- C++ -*-
+ ** \file misc/map.hxx
+ ** \brief Implementation of misc::map.
+ */
+
+#pragma once
+
+#include <iostream>
+#include <sstream>
+
+#include <boost/lexical_cast.hpp>
+
+#include <misc/contract.hh>
+#include <misc/indent.hh>
+#include <misc/map.hh>
+
+namespace misc
+{
+ template <class T, class N> map<T, N>* map<T, N>::clone() const
+ {
+ return new map<T, N>(*this);
+ }
+
+ template <class T, class N>
+ typename map<T, N>::const_iterator map<T, N>::find(const T& t) const
+ {
+ return map_.find(t);
+ }
+
+ template <class T, class N>
+ typename map<T, N>::iterator map<T, N>::find(const T& t)
+ {
+ return map_.find(t);
+ }
+
+ template <class T, class N>
+ typename map<T, N>::iterator map<T, N>::xfind(const T& t)
+ {
+ if (auto&& ires = find(t); ires != map_.end())
+ return ires;
+ else
+ throw std::range_error(std::string("map: no mapping for ")
+ + boost::lexical_cast<std::string>(t));
+ }
+
+ template <class T, class N>
+ typename map<T, N>::const_iterator map<T, N>::xfind(const T& t) const
+ {
+ if (const auto&& ires = find(t); ires != map_.end())
+ return ires;
+ else
+ throw std::range_error(std::string("map: no mapping for ")
+ + boost::lexical_cast<std::string>(t));
+ }
+
+ template <class T, class N>
+ typename map<T, N>::key_compare map<T, N>::key_comp() const
+ {
+ return map_.key_comp();
+ }
+
+ template <class T, class N> N map<T, N>::operator()(const T& t) const
+ {
+ return xfind(t)->second;
+ }
+
+ template <class T, class N>
+ template <typename Container>
+ requires ConstIterableType<Container, T>
+ std::vector<N> map<T, N>::operator()(const Container& ts) const
+ {
+ std::vector<N> res;
+ for (const T& t : ts)
+ res.emplace_back(operator()(t));
+ return res;
+ }
+
+ template <class T, class N>
+ std::ostream& map<T, N>::print(std::ostream& ostr) const
+ {
+ for (const value_type& p : *this)
+ ostr << p.first << " -> " << p.second << misc::iendl;
+ return ostr;
+ }
+
+ template <class T, class N> N map<T, N>::operator[](const T& t) const
+ {
+ return operator()(t);
+ }
+
+ template <class T, class N> N& map<T, N>::operator[](const T& t)
+ {
+ return map_[t];
+ }
+
+ template <class T, class N> typename map<T, N>::iterator map<T, N>::begin()
+ {
+ return map_.begin();
+ }
+
+ template <class T, class N> typename map<T, N>::iterator map<T, N>::end()
+ {
+ return map_.end();
+ }
+
+ template <class T, class N>
+ typename map<T, N>::const_iterator map<T, N>::begin() const
+ {
+ return map_.begin();
+ }
+
+ template <class T, class N>
+ typename map<T, N>::const_iterator map<T, N>::end() const
+ {
+ return map_.end();
+ }
+
+ template <class T, class N>
+ typename map<T, N>::iterator map<T, N>::lower_bound(const T& k)
+ {
+ return map_.lower_bound(k);
+ }
+
+ template <class T, class N>
+ typename map<T, N>::const_iterator map<T, N>::lower_bound(const T& k) const
+ {
+ return map_.lower_bound(k);
+ }
+
+ template <class T, class N>
+ std::pair<typename map<T, N>::iterator, bool>
+ map<T, N>::insert(const std::pair<const T, N>& x)
+ {
+ return map_.insert(x);
+ }
+
+ template <class T, class N> void map<T, N>::insert(const map& other)
+ {
+ map_.insert(other.begin(), other.end());
+ }
+
+ template <class T, class N>
+ template <class... Args>
+ std::pair<typename map<T, N>::iterator, bool>
+ map<T, N>::emplace(Args&&... args)
+ {
+ return map_.emplace(std::forward<Args>(args)...);
+ }
+
+ template <class T, class N> bool map<T, N>::empty() const
+ {
+ return map_.empty();
+ }
+
+ template <class T, class N> size_t map<T, N>::size() const
+ {
+ return map_.size();
+ }
+
+ template <class T, class N> N map<T, N>::take(const T& t)
+ {
+ auto ires = xfind(t);
+ N elt = ires->second;
+ map_.erase(ires);
+ return elt;
+ }
+
+ template <class T, class N> void map<T, N>::clear() { map_.clear(); }
+
+ template <class T, class N>
+ std::ostream& operator<<(std::ostream& ostr, const map<T, N>& m)
+ {
+ return m.print(ostr);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/ref.hh b/tiger-compiler/lib/misc/ref.hh
new file mode 100644
index 0000000..8d70a7f
--- /dev/null
+++ b/tiger-compiler/lib/misc/ref.hh
@@ -0,0 +1,91 @@
+/**
+ ** \file misc/ref.hh
+ ** \brief Declaration of misc::ref.
+ **/
+
+#pragma once
+
+#include <memory>
+
+namespace misc
+{
+ /// A std::shared_ptr wrapper.
+ ///
+ /// Compared to its super type, this implementation provides
+ /// cast operators, and implicit constructors.
+ template <typename T> class ref : public std::shared_ptr<T>
+ {
+ public:
+ /// The parent class.
+ using super_type = std::shared_ptr<T>;
+ /// The type pointed to.
+ using element_type = T;
+
+ /// \name Constructors & Destructor.
+ /// \{
+ /** \brief Construct a new reference to the value pointed to by \a other.
+ ** The new reference shares the property of the object with \a other. */
+ template <typename U> ref(const ref<U>& other);
+
+ /** \brief Copy constructor.
+ **
+ ** Although the implementation is subsumed by the previous, more
+ ** generic one, the C++ standard still mandates this specific
+ ** signature. Otherwise, the compiler will provide a default
+ ** implementation, which is of course wrong. Note that the
+ ** same applies for the assignment operator. */
+ ref(const ref<T>& other);
+
+ /** \brief Construct a counted reference to a newly allocated object.
+ ** The new reference takes the property of the object pointed to
+ ** by \a p. If \a p is null, then the reference is invalid and
+ ** must be \c reset() before use. */
+ ref(T* p = nullptr);
+
+ /// \name Equality operators.
+ /// \{
+
+ /** \brief Reference comparison.
+ ** Returns true if this points to \a p. */
+ bool operator==(const T* p) const;
+
+ /** \brief Reference comparison.
+ ** Returns false if this points to \a p. */
+ bool operator!=(const T* p) const;
+
+ /// \}
+
+ /// \name Assignment operators.
+ /// \{
+
+ /** \brief Use default copy-assignment operator. */
+ ref<T>& operator=(const ref<T>& r) = default;
+
+ /// \}
+
+ /// \name Casts.
+ /// \{
+
+ /** \brief Cast the reference.
+ ** Return a new reference, possibly throwing an exception if the
+ ** dynamic_cast is invalid.
+ **/
+ template <typename U> ref<U> cast() const;
+
+ /** \brief Cast the reference (unsafe).
+ ** Return a new reference, possibly a null reference if the
+ ** dynamic_cast is invalid.
+ **/
+ template <typename U> ref<U> unsafe_cast() const;
+ /// \}
+
+ /** \brief Test fellowship.
+ ** Return true if the reference points to an object which is
+ ** really of the specified type.
+ **/
+ template <typename U> bool is_a() const;
+ };
+
+} // namespace misc
+
+#include <misc/ref.hxx>
diff --git a/tiger-compiler/lib/misc/ref.hxx b/tiger-compiler/lib/misc/ref.hxx
new file mode 100644
index 0000000..ae740fd
--- /dev/null
+++ b/tiger-compiler/lib/misc/ref.hxx
@@ -0,0 +1,71 @@
+/**
+ ** \file misc/ref.hxx
+ ** \brief Implementation of misc::ref.
+ **/
+
+#pragma once
+
+#include <typeinfo>
+
+#include <misc/ref.hh>
+
+namespace misc
+{
+ /*-----------------.
+ | Ctors and dtor. |
+ `-----------------*/
+
+ template <typename T>
+ template <typename U>
+ ref<T>::ref(const ref<U>& other)
+ : super_type(other)
+ {}
+
+ template <typename T>
+ ref<T>::ref(const ref<T>& other)
+ : super_type(other)
+ {}
+
+ template <typename T>
+ ref<T>::ref(T* p)
+ : super_type(p)
+ {}
+
+ /*---------------------.
+ | Equality operators. |
+ `---------------------*/
+
+ template <typename T> bool ref<T>::operator==(const T* other) const
+ {
+ return this->get() == other;
+ }
+
+ template <typename T> bool ref<T>::operator!=(const T* other) const
+ {
+ return !(*this == other);
+ }
+
+ /*--------.
+ | Casts. |
+ `--------*/
+
+ template <typename T> template <typename U> ref<U> ref<T>::unsafe_cast() const
+ {
+ ref<U> res;
+ (std::dynamic_pointer_cast<U, element_type>(*this)).swap(res);
+ return res;
+ }
+
+ template <typename T> template <typename U> ref<U> ref<T>::cast() const
+ {
+ if (!this->get() || !this->is_a<U>())
+ throw std::bad_cast();
+ return unsafe_cast<U>();
+ }
+
+ template <typename T> template <typename U> bool ref<T>::is_a() const
+ {
+ return dynamic_cast<U*>(this->get());
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/scoped-map.hh b/tiger-compiler/lib/misc/scoped-map.hh
new file mode 100644
index 0000000..a193e24
--- /dev/null
+++ b/tiger-compiler/lib/misc/scoped-map.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file misc/scoped-map.hh
+ ** \brief Declaration of misc::scoped_map.
+ **
+ ** This implements a stack of dictionnaries. Each time a scope is
+ ** opened, a new dictionnary is added on the top of the stack; the
+ ** dictionary is removed when the scope is closed. Lookup of keys
+ ** is done in the last added dictionnary first (LIFO).
+ **
+ ** In particular this class is used to implement symbol tables.
+ **/
+
+#pragma once
+
+#include <map>
+#include <ostream>
+#include <stack>
+#include <vector>
+
+namespace misc
+{
+ template <typename Key, typename Data> class scoped_map
+ {
+ // FIXME DONE: Some code was deleted here.
+ public:
+ // initializes a new stack with an empty map on top as the first scope
+ scoped_map()
+ {
+ scopes_.push_back(std::map<Key,Data>());
+ }
+ void put(const Key& key, const Data& value);
+ Data get(const Key& key) const requires(!std::is_pointer_v<Data>);
+ Data get(const Key& key) const requires(std::is_pointer_v<Data>);
+ std::ostream& dump(std::ostream& ostr) const;
+ void scope_begin();
+ void scope_end();
+
+ private:
+ std::vector<std::map<Key, Data>> scopes_;
+ };
+
+ template <typename Key, typename Data>
+ std::ostream& operator<<(std::ostream& ostr,
+ const scoped_map<Key, Data>& tbl);
+
+ // FIXME DONE: Some code was deleted here.
+ // heehee
+
+} // namespace misc
+
+#include <misc/scoped-map.hxx>
diff --git a/tiger-compiler/lib/misc/scoped-map.hxx b/tiger-compiler/lib/misc/scoped-map.hxx
new file mode 100644
index 0000000..14258b9
--- /dev/null
+++ b/tiger-compiler/lib/misc/scoped-map.hxx
@@ -0,0 +1,86 @@
+/** \file misc/scoped-map.hxx
+ ** \brief Implementation of misc::scoped_map.
+ */
+
+#include <misc/scoped-map.hh>
+
+#pragma once
+
+#include <sstream>
+#include <stdexcept>
+#include <type_traits>
+
+#include <ranges>
+#include <misc/algorithm.hh>
+#include <misc/contract.hh>
+#include <misc/indent.hh>
+
+namespace misc
+{
+ // FIXME DONE: Some code was deleted here.
+
+ template <typename Key, typename Data>
+ void scoped_map<Key, Data>::put(const Key& key, const Data& value)
+ {
+ scopes_.back().insert_or_assign(key, value);
+ }
+
+ template <typename Key, typename Data>
+ Data scoped_map<Key, Data>::get(const Key& key) const
+ requires(std::is_pointer_v<Data>)
+ {
+ if (auto data = scopes_.back().find(key); data != scopes_.back().end())
+ return data->second;
+ return nullptr;
+ }
+
+ template <typename Key, typename Data>
+ Data scoped_map<Key, Data>::get(const Key& key) const
+ requires(!std::is_pointer_v<Data>)
+ {
+ if (auto data = scopes_.back().find(key); data != scopes_.back().end())
+ return data->second;
+ throw std::range_error("Key is not in scope.");
+ }
+
+ template <typename Key, typename Data>
+ std::ostream& scoped_map<Key, Data>::dump(std::ostream& ostr) const
+ {
+ ostr << "Printing\n";
+ const char* sep = "-------------------------\n";
+ int depth = 0;
+ for (auto scope : scopes_)
+ {
+ ostr << sep << "Scope " << depth++ << incendl;
+ for (auto kvp : scope)
+ {
+ ostr << kvp.first << " -> " << kvp.second << iendl;
+ }
+ ostr << decendl << sep;
+ }
+ ostr << "endprint\n";
+ return ostr;
+ }
+ template <typename Key, typename Data>
+ void scoped_map<Key, Data>::scope_begin()
+ {
+ std::map<Key, Data> new_scope;
+ for (auto kvp : scopes_.back())
+ {
+ new_scope.insert_or_assign(kvp.first, kvp.second);
+ }
+ scopes_.push_back(new_scope);
+ }
+ template <typename Key, typename Data> void scoped_map<Key, Data>::scope_end()
+ {
+ scopes_.pop_back();
+ }
+
+ template <typename Key, typename Data>
+ inline std::ostream& operator<<(std::ostream& ostr,
+ const scoped_map<Key, Data>& tbl)
+ {
+ return tbl.dump(ostr);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/select-const.hh b/tiger-compiler/lib/misc/select-const.hh
new file mode 100644
index 0000000..23ea6d0
--- /dev/null
+++ b/tiger-compiler/lib/misc/select-const.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file misc/select-const.hh
+ ** \brief Select between a non const or a const type.
+ */
+
+#pragma once
+
+namespace misc
+{
+ /*------------------.
+ | const selectors. |
+ `------------------*/
+
+ /// Return \a T constified.
+ template <typename T> struct constify_traits
+ {
+ using type = const T;
+ };
+
+ /// Return \a T as is.
+ template <typename T> struct id_traits
+ {
+ using type = T;
+ };
+
+ /*------------------.
+ | select_iterator. |
+ `------------------*/
+
+ /// The iterator over a non const structure is plain iterator.
+ template <typename T> struct select_iterator
+ {
+ using type = typename T::iterator;
+ };
+
+ /// The iterator over a const structure is a const_iterator.
+ template <typename T> struct select_iterator<const T>
+ {
+ using type = typename T::const_iterator;
+ };
+
+} //namespace misc
diff --git a/tiger-compiler/lib/misc/separator.hh b/tiger-compiler/lib/misc/separator.hh
new file mode 100644
index 0000000..228e4eb
--- /dev/null
+++ b/tiger-compiler/lib/misc/separator.hh
@@ -0,0 +1,43 @@
+/**
+ ** \file misc/separator.hh
+ ** \brief Output containers with a separator between items.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <utility>
+
+namespace misc
+{
+ template <class C, typename S> class separator
+ {
+ public:
+ separator(const C& c, const S& s);
+ std::ostream& operator()(std::ostream& o) const;
+
+ private:
+ const C& container_;
+ const S& separator_;
+ };
+
+ /// Shorthand to create separator(c, s).
+ template <class C, typename S>
+ separator<C, S> separate(const C& c, const S& s);
+
+ /// Shorthand to create separator(c, '\n').
+ template <class C> separator<C, char> separate(const C& c);
+
+ /// Output the separator object \a s on \a ostr.
+ template <class C, typename S>
+ inline std::ostream& operator<<(std::ostream& ostr, const separator<C, S>& s);
+
+ /// Output the pair \a p on \a ostr.
+ /// Usefull if you want to to use a std::pair("something", misc::iendl)
+ /// as your separator.
+ template <class A, typename B>
+ inline std::ostream& operator<<(std::ostream& ostr, const std::pair<A, B>& p);
+
+} // namespace misc
+
+#include <misc/separator.hxx>
diff --git a/tiger-compiler/lib/misc/separator.hxx b/tiger-compiler/lib/misc/separator.hxx
new file mode 100644
index 0000000..103b78d
--- /dev/null
+++ b/tiger-compiler/lib/misc/separator.hxx
@@ -0,0 +1,55 @@
+/**
+ ** \file misc/separator.hxx
+ ** \brief Output containers with a separator between items.
+ */
+
+#pragma once
+
+#include <ostream>
+
+#include <misc/deref.hh>
+#include <misc/separator.hh>
+
+namespace misc
+{
+ template <class C, class S>
+ inline separator<C, S>::separator(const C& c, const S& s)
+ : container_(c)
+ , separator_(s)
+ {}
+
+ template <class C, typename S>
+ inline std::ostream& separator<C, S>::operator()(std::ostream& o) const
+ {
+ for (auto i = container_.begin(); i != container_.end(); ++i)
+ {
+ if (i != container_.begin())
+ o << separator_;
+ o << deref << *i;
+ }
+ return o;
+ }
+
+ template <class C, typename S>
+ separator<C, S> separate(const C& c, const S& s)
+ {
+ return separator<C, S>(c, s);
+ }
+
+ template <class C> separator<C, char> separate(const C& c)
+ {
+ return separate(c, '\n');
+ }
+
+ template <class C, typename S>
+ inline std::ostream& operator<<(std::ostream& o, const separator<C, S>& s)
+ {
+ return s(o);
+ }
+
+ template <class A, typename B>
+ inline std::ostream& operator<<(std::ostream& o, const std::pair<A, B>& p)
+ {
+ return o << p.first << p.second;
+ }
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/set.hh b/tiger-compiler/lib/misc/set.hh
new file mode 100644
index 0000000..5ded61b
--- /dev/null
+++ b/tiger-compiler/lib/misc/set.hh
@@ -0,0 +1,146 @@
+/**
+ ** \file misc/set.hh
+ ** \brief misc::set: wrapper around std::set.
+ **
+ ** Set class is a std::set wrapper used to facilitate set
+ ** operations such as '+' (union) and '-' and also redefine
+ ** functions such as set_union, set_intersection etc. in
+ ** order to be more specific and more simple to handle set for our
+ ** purpose.
+ **/
+
+#pragma once
+
+#include <algorithm>
+#include <iosfwd>
+#include <set>
+#include <vector>
+#include <misc/concepts.hh>
+
+namespace misc
+{
+ template <typename Key,
+ typename Compare = std::less<Key>,
+ typename Allocator = std::allocator<Key>>
+ /**
+ ** \brief The class misc::set is wrapper around std::set.
+ **
+ ** Because Doxygen doesn't handle template
+ ** parameters names mix we keep the shorter version,
+ ** so K for Key, C for Compare and A for Allocator. */
+ class set : public std::set<Key, Compare, Allocator>
+ {
+ public:
+ /// \name typedefs
+ /// \{
+ using set_type = typename std::set<Key, Compare, Allocator>;
+
+ using iterator = typename set_type::iterator;
+ using const_iterator = typename set_type::const_iterator;
+ using reverse_iterator = typename set_type::reverse_iterator;
+ using const_reverse_iterator = typename set_type::const_reverse_iterator;
+ using size_type = typename set_type::size_type;
+ using const_reference = typename set_type::const_reference;
+ /// \}
+
+ /// \name constructor(s)/destructor.
+ /// \{
+
+ explicit set() = default;
+
+ template <typename Iter>
+ requires Iterator<Iter, Key>
+ explicit set(Iter first, Iter last);
+
+ /* Useful to convert a container (e.g. std::vector) in misc::set. */
+ template <typename Container>
+ requires ConstIterableType<Container, Key>
+ explicit set(const Container v);
+
+ /// \}
+
+ /** \name Element vs. set.
+ \{ */
+
+ /// Is \a k part of \a this set?
+ bool has(const Key& k) const;
+
+ /** \brief Return the addition of \a data into \a this.
+ \a data must not yet be part of \a this. */
+ set operator+(const Key& data) const;
+
+ /** \brief Insert \a data in \a this.
+ \a data must not yet be part of \a this. */
+ set& operator+=(const Key& data);
+
+ /** \brief Return the removal of \a data into \a this.
+ \a data must be part of \a this. */
+ set operator-(const Key& data) const;
+
+ /** \brief Remove \a data from \a this.
+ \a data must be part of \a this. */
+ set& operator-=(const Key& data);
+
+ /// \}
+
+ /** \name Set vs. set.
+ \{ */
+
+ /// Union with another set \a s.
+ // FIXME: Deprecate this use, it ought to be direct sum.
+ set operator+(const set<Key, Compare, Allocator>& s) const;
+
+ /// In place union with another set \a s.
+ set& operator+=(const set<Key, Compare, Allocator>& s);
+
+ /// Subtraction with another set \a s.
+ set operator-(const set<Key, Compare, Allocator>& s) const;
+
+ /// In place subtraction with another set \a s.
+ set& operator-=(const set<Key, Compare, Allocator>& s);
+
+ /// Union with another set \a s.
+ set operator|(const set& s) const;
+
+ /// In place union with another set \a s.
+ set& operator|=(const set& s);
+
+ /// Intersection with another set \a s.
+ set operator&(const set& s) const;
+
+ /// In place intersection with another set \a s.
+ set& operator&=(const set& s);
+
+ /// \}
+ }; // class set
+
+ template <typename Key, typename Compare, typename Allocator>
+ inline set<Key, Compare, Allocator>
+ set_difference(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2);
+
+ template <typename Key, typename Compare, typename Allocator>
+ inline set<Key, Compare, Allocator>
+ set_intersection(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2);
+
+ template <typename Key, typename Compare, typename Allocator>
+ inline set<Key, Compare, Allocator>
+ set_union(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2);
+
+ /* Print a human-dump for debugging.
+
+ Warning: this method requires that type Key overloads the operator
+ '<<'. If it is not the case do it or remove set print method
+ and << operator (see below). */
+ template <typename Key, typename Compare, typename Allocator>
+ inline std::ostream& operator<<(std::ostream& ostr,
+ const set<Key, Compare, Allocator>& s);
+
+ template <typename Key, typename Compare, typename Allocator>
+ inline bool operator%(const Key& k, const set<Key, Compare, Allocator>& s);
+
+} // namespace misc
+
+#include <misc/set.hxx>
diff --git a/tiger-compiler/lib/misc/set.hxx b/tiger-compiler/lib/misc/set.hxx
new file mode 100644
index 0000000..9645c95
--- /dev/null
+++ b/tiger-compiler/lib/misc/set.hxx
@@ -0,0 +1,208 @@
+/**
+ ** \file misc/set.hxx
+ ** \brief misc::set: wrapper around std::set.
+ **/
+
+#pragma once
+
+#include <algorithm>
+#include <ostream>
+
+#include <misc/contract.hh>
+#include <misc/set.hh>
+
+namespace misc
+{
+ template <class Key, class Compare, class Allocator>
+ template <typename Iter>
+ requires Iterator<Iter, Key>
+ inline set<Key, Compare, Allocator>::set(Iter first, Iter last)
+ {
+ this->insert(first, last);
+ }
+
+ /* Useful to convert a std::vector or other Compare in misc::set. */
+ template <class Key, class Compare, class Allocator>
+ template <typename Container>
+ requires ConstIterableType<Container, Key>
+ inline set<Key, Compare, Allocator>::set(const Container v)
+ {
+ for (const Key& x : v)
+ this->insert(x);
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline bool set<Key, Compare, Allocator>::has(const Key& k) const
+ {
+ return set_type::find(k) != this->end();
+ }
+
+ /* \brief Return the addition of \a data into \a this.
+ \a data must not yet be part of \a this. */
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>
+ set<Key, Compare, Allocator>::operator+(const Key& data) const
+ {
+ precondition(!(data % *this));
+ set<Key, Compare, Allocator> res(*this);
+ res.insert(data);
+ return res;
+ }
+
+ /* \brief Insert \a data in \a this.
+ \a data must not yet be part of \a this. */
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>&
+ set<Key, Compare, Allocator>::operator+=(const Key& data)
+ {
+ precondition(!(data % *this));
+ this->insert(data);
+ return *this;
+ }
+
+ /* \brief Return the removal of \a data into \a this.
+ \a data must be part of \a this. */
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>
+ set<Key, Compare, Allocator>::operator-(const Key& data) const
+ {
+ precondition(data % *this);
+ set<Key, Compare, Allocator> res(*this);
+ res.erase(data);
+ return res;
+ }
+
+ /* \brief Remove \a data from \a this.
+ \a data must be part of \a this. */
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>&
+ set<Key, Compare, Allocator>::operator-=(const Key& data)
+ {
+ precondition(data % *this);
+ this->erase(data);
+ return *this;
+ }
+
+ // Union with another set \a s.
+ // FIXME: Deprecate this use, it ought to be direct sum.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator> set<Key, Compare, Allocator>::operator+(
+ const set<Key, Compare, Allocator>& s) const
+ {
+ return set_union(*this, s);
+ }
+
+ // In place union with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>& set<Key, Compare, Allocator>::operator+=(
+ const set<Key, Compare, Allocator>& s)
+ {
+ return *this = *this + s;
+ }
+
+ // Subtraction with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator> set<Key, Compare, Allocator>::operator-(
+ const set<Key, Compare, Allocator>& s) const
+ {
+ return set_difference(*this, s);
+ }
+
+ // In place subtraction with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>& set<Key, Compare, Allocator>::operator-=(
+ const set<Key, Compare, Allocator>& s)
+ {
+ *this = *this - s;
+ return *this;
+ }
+
+ // Union with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator> set<Key, Compare, Allocator>::operator|(
+ const set<Key, Compare, Allocator>& s) const
+ {
+ return *this + s;
+ }
+
+ // In place union with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>& set<Key, Compare, Allocator>::operator|=(
+ const set<Key, Compare, Allocator>& s)
+ {
+ return *this += s;
+ }
+
+ // Intersection with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator> set<Key, Compare, Allocator>::operator&(
+ const set<Key, Compare, Allocator>& s) const
+ {
+ return set_intersection(*this, s);
+ }
+
+ // In place intersection with another set \a s.
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>& set<Key, Compare, Allocator>::operator&=(
+ const set<Key, Compare, Allocator>& s)
+ {
+ return *this = *this & s;
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>
+ set_difference(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2)
+ {
+ set<Key, Compare, Allocator> res;
+ // Specifying the key_comp to use is required: without it, the
+ // first set is properly ordered using its own key_comp, but
+ // neither the second set nor the resulting set are ordering
+ // using it. Even if s1, s2, and res do use the same Compare!
+ std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(),
+ inserter(res, res.begin()), s1.key_comp());
+ return res;
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>
+ set_intersection(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2)
+ {
+ set<Key, Compare, Allocator> res;
+ std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
+ inserter(res, res.begin()), s1.key_comp());
+ return res;
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline set<Key, Compare, Allocator>
+ set_union(const set<Key, Compare, Allocator>& s1,
+ const set<Key, Compare, Allocator>& s2)
+ {
+ set<Key, Compare, Allocator> res;
+ std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(),
+ inserter(res, res.begin()), s1.key_comp());
+ return res;
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline std::ostream& operator<<(std::ostream& ostr,
+ const set<Key, Compare, Allocator>& s)
+ {
+ for (auto i = s.begin(); i != s.end();)
+ {
+ ostr << *i;
+ if (++i != s.end())
+ ostr << ", ";
+ }
+ return ostr;
+ }
+
+ template <class Key, class Compare, class Allocator>
+ inline bool operator%(const Key& k, const set<Key, Compare, Allocator>& s)
+ {
+ return s.has(k);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/singleton.hh b/tiger-compiler/lib/misc/singleton.hh
new file mode 100644
index 0000000..609136f
--- /dev/null
+++ b/tiger-compiler/lib/misc/singleton.hh
@@ -0,0 +1,28 @@
+/**
+ ** \file misc/singleton.hh
+ ** \brief Generic singleton
+ */
+
+#pragma once
+
+namespace misc
+{
+ template <typename T> class Singleton
+ {
+ // FIXME DONE: Some code was deleted here.
+ protected:
+ Singleton() = default;
+
+ private:
+ Singleton(const Singleton<T>&) = delete;
+ Singleton& operator=(const Singleton<T>&) = delete;
+
+ public:
+ static T& instance()
+ {
+ static T instance_;
+ return instance_;
+ }
+ };
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/symbol.cc b/tiger-compiler/lib/misc/symbol.cc
new file mode 100644
index 0000000..edd8c86
--- /dev/null
+++ b/tiger-compiler/lib/misc/symbol.cc
@@ -0,0 +1,32 @@
+/**
+ ** \file misc/symbol.cc
+ ** \brief Implementation of misc::symbol.
+ */
+
+#include <sstream>
+#include <string>
+
+#include <misc/symbol.hh>
+
+namespace misc
+{
+ symbol::symbol(const std::string& s)
+ : unique<std::string>(s)
+ {}
+
+ symbol::symbol(const char* s)
+ : unique<std::string>(std::string(s))
+ {}
+
+ symbol symbol::fresh() { return fresh("a"); }
+
+ symbol symbol::fresh(const symbol& s)
+ {
+ /// Counter of unique symbols.
+ static unsigned counter_ = 0;
+ std::string str = s.get() + "_" + std::to_string(counter_);
+ ++counter_;
+ return symbol(str);
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/symbol.hh b/tiger-compiler/lib/misc/symbol.hh
new file mode 100644
index 0000000..6d0a1e1
--- /dev/null
+++ b/tiger-compiler/lib/misc/symbol.hh
@@ -0,0 +1,77 @@
+/**
+ ** \file misc/symbol.hh
+ ** \brief Definition of misc::symbol.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <set>
+#include <string>
+
+#include <misc/unique.hh>
+
+namespace misc
+{
+ /** \brief Define symbol class.
+ **
+ ** Map any string to a unique reference.
+ ** This allows to avoid an "strcmp()" style comparison of strings:
+ ** reference comparison is much faster.
+ */
+ class symbol : public unique<std::string>
+ {
+ using super_type = unique<std::string>;
+ /// The type "set of strings".
+ using string_set_type = super_type::object_set_type;
+ /// The type for the size of string map.
+ using string_size_type = string_set_type::size_type;
+
+ /** \name Ctor & Dtor.
+ ** \{ */
+ public:
+ /** \brief Construct a symbol.
+ ** \param s referenced string */
+ symbol(const std::string& s);
+ /** \brief Construct a symbol.
+ ** \param s referenced string */
+ symbol(const char* s = "");
+ /** \brief Construct a symbol.
+ ** \param s symbol to copy. */
+ constexpr symbol(const symbol& s) = default;
+ /** \} */
+
+ /** \name Operators.
+ ** \{ */
+ public:
+ /** \brief Assign a symbol to this symbol.
+ ** \param rhs symbol to copy. */
+ symbol& operator=(const symbol& rhs);
+
+ /** \brief Compare two symbol for equality.
+ ** \param rhs string to compare with. */
+ bool operator==(const symbol& rhs) const;
+ /** \brief Compare two symbol for inequality.
+ ** \param rhs string to compare with. *//* */
+ bool operator!=(const symbol& rhs) const;
+ /** \} */
+
+ public:
+ /** \name Factory methods.
+ ** \{ */
+ /** \brief Create a new unique symbol. */
+ static symbol fresh();
+ /** \brief Create a new unique symbol, forged from \a s. */
+ static symbol fresh(const symbol& s);
+ /** \} */
+ };
+
+ /** \brief Intercept output stream redirection.
+ ** \param ostr the destination output stream
+ ** \param the a reference to the symbol to redirect
+ */
+ std::ostream& operator<<(std::ostream& ostr, const symbol& the);
+
+} // namespace misc
+
+#include <misc/symbol.hxx>
diff --git a/tiger-compiler/lib/misc/symbol.hxx b/tiger-compiler/lib/misc/symbol.hxx
new file mode 100644
index 0000000..c31cb8c
--- /dev/null
+++ b/tiger-compiler/lib/misc/symbol.hxx
@@ -0,0 +1,39 @@
+/**
+ ** \file misc/symbol.hxx
+ ** \brief Inline implementation of misc::symbol.
+ */
+
+#pragma once
+
+#include <misc/symbol.hh>
+
+namespace misc
+{
+ inline symbol& symbol::operator=(const symbol& rhs)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (this != &rhs)
+ {
+ super_type::operator=(rhs);
+ }
+ return *this;
+ }
+
+ inline bool symbol::operator==(const symbol& rhs) const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return super_type::operator==(rhs);
+ }
+
+ inline bool symbol::operator!=(const symbol& rhs) const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return !(*this == rhs);
+ }
+
+ inline std::ostream& operator<<(std::ostream& ostr, const symbol& the)
+ {
+ // FIXME DONE: Some code was deleted here.
+ return ostr << the.get();
+ }
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/timer.cc b/tiger-compiler/lib/misc/timer.cc
new file mode 100644
index 0000000..703930f
--- /dev/null
+++ b/tiger-compiler/lib/misc/timer.cc
@@ -0,0 +1,208 @@
+/**
+ ** \file misc/timer.cc
+ ** \brief Implementation for misc/timer.hh.
+ */
+
+#include <iomanip>
+#include <sys/times.h>
+#include <unistd.h>
+
+#include <misc/contract.hh>
+#include <misc/timer.hh>
+
+namespace misc
+{
+ /*-----------------.
+ | timer::time_var. |
+ `-----------------*/
+
+ timer::time_var::time_var()
+ : initial(true)
+ {}
+
+ void timer::time_var::start()
+ {
+ struct tms tms;
+
+ begin.wall = times(&tms);
+ begin.user = tms.tms_utime;
+ begin.sys = tms.tms_stime;
+
+ if (initial)
+ {
+ initial = false;
+ first = begin;
+ }
+ }
+
+ void timer::time_var::stop()
+ {
+ struct tms tms;
+
+ last.wall = times(&tms);
+ last.user = tms.tms_utime;
+ last.sys = tms.tms_stime;
+ elapsed.wall += last.wall - begin.wall;
+ elapsed.user += last.user - begin.user;
+ elapsed.sys += last.sys - begin.sys;
+ }
+
+ bool timer::time_var::is_zero()
+ {
+ return elapsed.wall == 0 && elapsed.user == 0 && elapsed.sys == 0;
+ }
+
+ /*--------.
+ | timer. |
+ `--------*/
+
+ timer::timer()
+ : dump_stream(nullptr)
+ {}
+
+ // Duplicate a timer. No tasks should be running.
+ timer::timer(const timer& rhs)
+ : intmap(rhs.intmap)
+ , total(rhs.total)
+ , dump_stream(rhs.dump_stream)
+ {
+ precondition(rhs.tasks.empty());
+
+ for (const task_map_type::value_type& p : rhs.tasksmap)
+ if (tasksmap.find(p.first) == tasksmap.end())
+ tasksmap[p.first] = new time_var(*p.second);
+ }
+
+ timer::~timer()
+ {
+ // Print information if automatic dumping has been enabled.
+ if (dump_stream)
+ {
+ // Consider that if the tasks were not properly closed, then
+ // stop was not invoked either.
+ if (!tasks.empty())
+ {
+ do
+ pop();
+ while (!tasks.empty());
+ stop();
+ }
+ dump(*dump_stream);
+ }
+
+ // Deallocate all our time_var's.
+ for (task_map_type::value_type& p : tasksmap)
+ delete p.second;
+ }
+
+ void timer::name(int i, const std::string& task_name)
+ {
+ intmap[i] = task_name;
+ }
+
+ void timer::timeinfo(long time, long total_time, std::ostream& out)
+ {
+ out << std::setiosflags(std::ios::left) << std::setw(6)
+ << std::setprecision(6) << float(time) / clocks_per_sec
+ << std::resetiosflags(std::ios::left) << " (" << std::setw(5)
+ << std::setprecision(3)
+ << (total_time ? float(time) * 100 / total_time : float(time)) << "%) ";
+ }
+
+ void timer::dump(std::ostream& out)
+ {
+ out << "Execution times (seconds)\n";
+ for (const task_map_type::value_type& p : tasksmap)
+ {
+ if (!p.second->is_zero())
+ {
+ out << " " << p.first << std::setw(26 - p.first.length()) << ": ";
+ timeinfo(p.second->elapsed.user, total.elapsed.user, out);
+ out << " ";
+ timeinfo(p.second->elapsed.sys, total.elapsed.sys, out);
+ out << " ";
+ timeinfo(p.second->elapsed.wall, total.elapsed.wall, out);
+ out << '\n';
+ }
+ }
+ out << '\n';
+
+ out << "Cumulated times (seconds)\n";
+ for (const task_map_type::value_type& p : tasksmap)
+ {
+ if (p.second->last.wall != p.second->first.wall)
+ {
+ out << " " << p.first << std::setw(26 - p.first.length()) << ": ";
+ timeinfo(p.second->last.user - p.second->first.user,
+ total.elapsed.user, out);
+ out << " ";
+ timeinfo(p.second->last.sys - p.second->first.sys,
+ total.elapsed.sys, out);
+ out << " ";
+ timeinfo(p.second->last.wall - p.second->first.wall,
+ total.elapsed.wall, out);
+ out << '\n';
+ }
+ }
+ out << '\n';
+
+ out << " TOTAL (seconds)" << std::setw(11) << ": "
+
+ << std::setiosflags(std::ios::left) << std::setw(7)
+ << float(total.elapsed.user) / clocks_per_sec << std::setw(11)
+ << "user,"
+
+ << std::setw(7) << float(total.elapsed.sys) / clocks_per_sec
+ << std::setw(11) << "system,"
+
+ << std::setw(7) << float(total.elapsed.wall) / clocks_per_sec << "wall"
+
+ << std::resetiosflags(std::ios::left) << std::endl;
+ }
+
+ void timer::push(const std::string& task_name)
+ {
+ time_var* current;
+
+ // If the stack is not empty, set the elapsed time for the current
+ // task.
+ if (!tasks.empty())
+ tasks.top()->stop();
+
+ if (tasksmap.find(task_name) == tasksmap.end())
+ tasksmap[task_name] = new time_var;
+
+ current = tasksmap[task_name];
+ tasks.push(current);
+ current->start();
+ }
+
+ void timer::pop()
+ {
+ precondition(!tasks.empty());
+
+ // Set the elapsed time for the current task before popping it.
+ tasks.top()->stop();
+ tasks.pop();
+
+ // Set the start time of the previous task to the current time.
+ if (!tasks.empty())
+ tasks.top()->start();
+ }
+
+ timer& timer::operator<<(const timer& rhs)
+ {
+ // No task should be running when merging timers.
+ precondition(rhs.tasks.empty());
+
+ for (const task_map_type::value_type& p : rhs.tasksmap)
+ if (tasksmap.find(p.first) == tasksmap.end())
+ tasksmap[p.first] = new time_var(*p.second);
+
+ intmap.insert(rhs.intmap.begin(), rhs.intmap.end());
+ return *this;
+ }
+
+ const long timer::clocks_per_sec = sysconf(_SC_CLK_TCK);
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/timer.hh b/tiger-compiler/lib/misc/timer.hh
new file mode 100644
index 0000000..5310b58
--- /dev/null
+++ b/tiger-compiler/lib/misc/timer.hh
@@ -0,0 +1,139 @@
+/**
+ ** \file misc/timer.hh
+ ** \brief timer: Timing nested tasks.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <iostream>
+#include <map>
+#include <stack>
+#include <string>
+
+namespace misc
+{
+ /// Timing nested tasks.
+ class timer
+ {
+ public:
+ timer();
+ timer(const timer& rhs);
+ ~timer();
+
+ /// Start a sub timer for a named task.
+ /// \param name a constant string which is the task's name
+ void push(const std::string& name);
+
+ /// Start a sub timer with an integer corresponding to a task.
+ /// \see push()
+ /// \see name()
+ void push(int i);
+
+ /// Stop the current task and ensure its name matches the string
+ /// passed as argument.
+ /// \param task_name The name of the task to stop.
+ void pop(const std::string& task_name);
+
+ /// \see pop()
+ /// \see pop(const std::string name)
+ void pop(int i);
+
+ /// Stop the current task's timer(the last task pushed on the stack).
+ void pop();
+
+ /// Write results.
+ /// \param out An output stream, set to std::cerr by default.
+ void dump(std::ostream& out = std::cerr);
+
+ /// Enable automatic information dumping upon destruction of the
+ /// timer on stream \a out.
+ void dump_on_destruction(std::ostream& out);
+
+ /// Assign name \a task_name to task number \a i.
+ void name(int i, const std::string& task_name);
+
+ /// Start the timer.
+ /// \see stop()
+ void start();
+
+ /// Stop the timer.
+ /// \see start()
+ void stop();
+
+ /// \brief Import timer.
+ ///
+ /// Import tasks defined in \a rhs. The total execution time of
+ /// \a rhs is ignored.
+ ///
+ /// \pre No task should be running in \a rhs.
+ timer& operator<<(const timer& rhs);
+
+ private:
+ class time_var;
+ class time
+ {
+ friend class timer;
+ friend class timer::time_var;
+
+ public:
+ time();
+
+ time& operator+=(const time& rhs);
+
+ private:
+ long user;
+ long sys;
+ long wall;
+ };
+
+ class time_var
+ {
+ public:
+ time_var();
+
+ void start();
+ void stop();
+
+ bool is_zero();
+
+ time begin;
+ time elapsed;
+ time first;
+ time last;
+ bool initial;
+ };
+
+ /// Write formatted timing results on \a out.
+ void timeinfo(long time, long total_time, std::ostream& out);
+
+ using task_map_type = std::map<const std::string, time_var*>;
+
+ /// Time information associated to each task name.
+ task_map_type tasksmap;
+
+ /// Stack of timed tasks.
+ std::stack<time_var*> tasks;
+
+ /// Dictionnary mapping an integer to a task name.
+ /// \see push(int)
+ std::map<int, std::string> intmap;
+
+ /// Total time measured by the timer.
+ /// \see start()
+ /// \see stop()
+ time_var total;
+
+ /// A potential stream onto which results are dumped when the
+ /// timer is destroyed. If this pointer is null, no action is
+ /// taken during the destruction of the timer.
+ std::ostream* dump_stream;
+
+ /// Number of clocks ticks per second, set according to the system
+ /// timing function used.
+ static const long clocks_per_sec;
+ };
+
+} // namespace misc
+
+#include <misc/timer.hxx>
diff --git a/tiger-compiler/lib/misc/timer.hxx b/tiger-compiler/lib/misc/timer.hxx
new file mode 100644
index 0000000..6e4ceb5
--- /dev/null
+++ b/tiger-compiler/lib/misc/timer.hxx
@@ -0,0 +1,50 @@
+/**
+ ** \file misc/timer.hxx
+ ** \brief Inline methods for misc/timer.hh.
+ */
+
+#pragma once
+
+#include <misc/contract.hh>
+#include <misc/timer.hh>
+
+namespace misc
+{
+ inline void timer::push(int i)
+ {
+ precondition(this->intmap.find(i) != this->intmap.end());
+ this->push(this->intmap[i]);
+ }
+
+ inline void timer::pop([[maybe_unused]] const std::string& task_name)
+ {
+ precondition(this->tasksmap[task_name] == this->tasks.top());
+ this->pop();
+ }
+
+ inline void timer::pop(int i) { this->pop(this->intmap[i]); }
+
+ inline void timer::dump_on_destruction(std::ostream& out)
+ {
+ this->dump_stream = &out;
+ }
+
+ inline void timer::start() { this->total.start(); }
+
+ inline void timer::stop() { this->total.stop(); }
+
+ inline timer::time::time()
+ : user(0)
+ , sys(0)
+ , wall(0)
+ {}
+
+ inline timer::time& timer::time::operator+=(const time& rhs)
+ {
+ this->wall += rhs.wall;
+ this->user += rhs.user;
+ this->sys += rhs.sys;
+ return *this;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/unique.hh b/tiger-compiler/lib/misc/unique.hh
new file mode 100644
index 0000000..27cd05e
--- /dev/null
+++ b/tiger-compiler/lib/misc/unique.hh
@@ -0,0 +1,85 @@
+/**
+ ** \file misc/unique.hh
+ ** \brief Definition of misc::unique.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <set>
+
+namespace misc
+{
+ /** \brief Define \c unique class.
+ **
+ ** Implementation of the flyweight pattern.
+ ** Map identical objects to a unique reference.
+ */
+ template <typename T, class C = std::less<T>> class unique
+ {
+ protected:
+ /// The unique's object type.
+ using object_set_type = std::set<T, C>;
+ /// The type for the size of the unique set.
+ using object_size_type = typename object_set_type::size_type;
+
+ public:
+ using value_type = unique;
+ using data_type = T;
+
+ /** \name Ctor & Dtor.
+ ** \{ */
+ /** \brief Construct a \c unique.
+ ** \param s referenced object */
+ unique(const data_type& s);
+ /** \brief Construct a \c unique.
+ ** \param u \c unique to copy. */
+ constexpr unique(const unique& u) = default;
+ virtual ~unique() = default;
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ /// The object referenced by \c this.
+ const data_type& get() const;
+ operator const data_type&() const;
+
+ /// The number of referenced objects.
+ static object_size_type object_map_size();
+ /** \} */
+
+ /** \name Operators.
+ ** \{ */
+ /** \brief Assign a \c unique to this \c unique.
+ ** \param rhs \c unique to copy. */
+ value_type& operator=(const value_type& rhs);
+
+ /** \brief Compare two \c unique for equality.
+ ** \param rhs \c unique to compare with. */
+ bool operator==(const value_type& rhs) const;
+ /** \brief Compare two \c unique for inequality.
+ ** \param rhs \c unique to compare with. */
+ bool operator!=(const value_type& rhs) const;
+ /** \brief Compare two \c unique for order.
+ ** \param rhs \c unique to compare with. */
+ bool operator<(const value_type& rhs) const;
+ /** \} */
+
+ protected:
+ /// Return the set of uniques.
+ static object_set_type& object_set_instance();
+
+ /// Pointer to the unique referenced object.
+ const data_type* obj_;
+ };
+
+ /** \brief Intercept output stream redirection.
+ ** \param ostr the destination output stream
+ ** \param u a reference to the unique to redirect
+ */
+ template <typename T, class C>
+ std::ostream& operator<<(std::ostream& ostr, const unique<T, C>& u);
+
+} // namespace misc
+
+#include <misc/unique.hxx>
diff --git a/tiger-compiler/lib/misc/unique.hxx b/tiger-compiler/lib/misc/unique.hxx
new file mode 100644
index 0000000..a8560fa
--- /dev/null
+++ b/tiger-compiler/lib/misc/unique.hxx
@@ -0,0 +1,95 @@
+/**
+ ** \file misc/unique.hxx
+ ** \brief Inline implementation of misc::unique.
+ */
+
+#pragma once
+
+#include <misc/contract.hh>
+#include <misc/unique.hh>
+
+namespace misc
+{
+ template <typename T, class C> unique<T, C>::unique(const data_type& s)
+ // FIXME DONE: Some code was deleted here (Initializations).
+ /** \brief Following the Flyweight design pattern, set the attribute to a
+ unique reference of value s. You might want to check out std::set methods
+ on cppreference.com. */
+ {
+ if (object_set_instance().insert(s).second)
+ {
+ obj_ = &(*(object_set_instance().find(s)));
+ }
+ else
+ {
+ obj_ = &(*(object_set_instance().find(s)));
+ }
+ }
+
+ template <typename T, class C>
+ typename unique<T, C>::object_set_type& unique<T, C>::object_set_instance()
+ {
+ // FIXME DONE: Some code was deleted here (Classical Singleton pattern, a la Scott Meyers').
+ /** \brief Create a persistent instance of a set which would hold each value. */
+ static object_set_type res{};
+ return res;
+ }
+
+ template <typename T, class C>
+ typename unique<T, C>::object_size_type unique<T, C>::object_map_size()
+ {
+ // FIXME DONE: Some code was deleted here.
+ return object_set_instance().size();
+ }
+
+ template <typename T, class C>
+ inline const typename unique<T, C>::data_type& unique<T, C>::get() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return *obj_;
+ }
+
+ template <typename T, class C>
+ inline unique<T, C>::operator const data_type&() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return *obj_;
+ }
+
+ template <typename T, class C>
+ inline typename unique<T, C>::value_type&
+ unique<T, C>::operator=(const value_type& rhs)
+ {
+ if (this != &rhs)
+ obj_ = rhs.obj_;
+ return *this;
+ }
+
+ template <typename T, class C>
+ inline bool unique<T, C>::operator==(const value_type& rhs) const
+ {
+ return obj_ == rhs.obj_;
+ }
+
+ template <typename T, class C>
+ inline bool unique<T, C>::operator!=(const value_type& rhs) const
+ {
+ return !operator==(rhs);
+ }
+
+ template <typename T, class C>
+ inline bool unique<T, C>::operator<(const value_type& rhs) const
+ {
+ C cmp;
+ assertion(obj_);
+ assertion(rhs.obj_);
+ return cmp(*obj_, *rhs.obj_);
+ }
+
+ template <typename T, class C>
+ inline std::ostream& operator<<(std::ostream& ostr, const unique<T, C>& the)
+ {
+ return ostr << the.get();
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/variant.hh b/tiger-compiler/lib/misc/variant.hh
new file mode 100644
index 0000000..71a8c1a
--- /dev/null
+++ b/tiger-compiler/lib/misc/variant.hh
@@ -0,0 +1,111 @@
+/**
+ ** \file misc/variant.hh
+ ** \brief Interface of misc::variant.
+ **
+ ** misc::variant is a wrapper over std::variant that adds
+ ** conversion operators to the original standard variant class.
+ ** misc::variant is used just like std::variant, and you
+ ** won't be disturbed when using it.
+ **/
+
+#pragma once
+
+#include <variant>
+
+namespace misc
+{
+ // Defining some concepts sepecific to variants:
+
+ // Type T can be converted into another type in Ts,
+ // used to set the variant's value.
+ template <typename T, typename... Ts>
+ concept ContainsTypeSet =
+ std::disjunction<std::is_convertible<T, Ts>...>::value;
+
+ // A type in Ts can be converted into T, used to get the variant's value.
+ template <typename T, typename... Ts>
+ concept ContainsTypeGet =
+ std::disjunction<std::is_convertible<Ts, T>...>::value;
+
+ /// Type V is a visitor on each Ts.
+ template <typename V, typename... Ts>
+ concept Visits = std::conjunction<std::is_invocable<V, Ts>...>::value;
+
+ /// A wrapper over std::variant supporting conversion operators.
+ ///
+ /// Constraints:
+ /// - No type may be const-qualified.
+ /// - Each type must be unique.
+ /// - The first type must be default constructible.
+ ///
+ /// Proper declaration form:
+ /// misc::variant<T, T1, ..., Tn>
+
+ template <typename T, typename... Ts>
+ class variant : public std::variant<T, Ts...>
+ {
+ public:
+ /// The type of this variant.
+ using self_type = variant<T, Ts...>;
+ /// Super type.
+
+ using super_type = std::variant<T, Ts...>;
+
+ /// Constructors.
+ /// \{
+ variant() = default;
+
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ variant(const U& rhs);
+ /// \}
+
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ self_type& operator=(const U&);
+
+ /// \brief Convert this variant to a value of type \a U.
+ ///
+ /// This conversion relies on std::get. In particular, if the
+ /// conversion fails, a std::bad_variant_access exception is thrown.
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ operator U&();
+
+ /// Likewise, const version.
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ operator const U&() const;
+
+ /** \brief Visit variants of this class.
+ ** std::visit does not handle classes inheriting from std::variant, hence
+ ** these wrappers.
+ ** \{ */
+ template <typename V>
+ requires Visits<V, T, Ts...>
+ auto visit(V&& visitor) const;
+
+ template <typename V, class... Variants>
+ static auto visit(V&& visitor, Variants&&... vars);
+ /** \} */
+ };
+
+ // Here add variadic template recursion on std::get
+ template <typename T, typename... Ts>
+ std::ostream& operator<<(std::ostream& os, const variant<T, Ts...>& obj);
+
+ class PrintVisitor
+ {
+ public:
+ PrintVisitor(std::ostream& os)
+ : os_(os)
+ {}
+
+ template <typename T> std::ostream& operator()(const T& value) const;
+
+ private:
+ std::ostream& os_;
+ };
+} // namespace misc
+
+#include <misc/variant.hxx>
diff --git a/tiger-compiler/lib/misc/variant.hxx b/tiger-compiler/lib/misc/variant.hxx
new file mode 100644
index 0000000..1f7feab
--- /dev/null
+++ b/tiger-compiler/lib/misc/variant.hxx
@@ -0,0 +1,77 @@
+/**
+ ** \file misc/variant.hxx
+ ** \brief Implementation of misc::variant.
+ **/
+
+#pragma once
+
+#include <variant>
+
+#include <type_traits>
+#include <misc/variant.hh>
+
+namespace misc
+{
+ template <typename T, typename... Ts>
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ variant<T, Ts...>::variant(const U& rhs)
+ : super_type(rhs)
+ {}
+
+ template <typename T, typename... Ts>
+ template <typename U>
+ requires ContainsTypeSet<U, T, Ts...>
+ variant<T, Ts...>& variant<T, Ts...>::operator=(const U& rhs)
+ {
+ // Don't assign to oneself.
+ if (static_cast<const void*>(&rhs) != static_cast<const void*>(this))
+ super_type::operator=(rhs);
+ return *this;
+ }
+
+ template <typename T, typename... Ts>
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ variant<T, Ts...>::operator U&()
+ {
+ return std::get<U>(*this);
+ }
+
+ template <typename T, typename... Ts>
+ template <typename U>
+ requires ContainsTypeGet<U, T, Ts...>
+ variant<T, Ts...>::operator const U&() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return std::get<U>(*this);
+ }
+
+ template <typename T, typename... Ts>
+ template <typename V>
+ requires Visits<V, T, Ts...>
+ auto variant<T, Ts...>::visit(V&& visitor) const
+ {
+ return std::visit(visitor, static_cast<super_type>(*this));
+ }
+
+ template <typename T, typename... Ts>
+ template <typename V, class... Variants>
+ auto variant<T, Ts...>::visit(V&& visitor, Variants&&... vars)
+ {
+ return std::visit(visitor, static_cast<super_type>(vars)...);
+ }
+
+ template <typename T, typename... Ts>
+ std::ostream& operator<<(std::ostream& os, const variant<T, Ts...>& obj)
+ {
+ PrintVisitor pv(os);
+ return std::visit(pv, static_cast<const std::variant<T, Ts...>>(obj));
+ }
+
+ template <typename T>
+ std::ostream& PrintVisitor::operator()(const T& value) const
+ {
+ return os_ << value;
+ }
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/vector.hh b/tiger-compiler/lib/misc/vector.hh
new file mode 100644
index 0000000..2207552
--- /dev/null
+++ b/tiger-compiler/lib/misc/vector.hh
@@ -0,0 +1,105 @@
+/**
+ ** \file misc/vector.hh
+ ** \brief Declaration of misc::vector
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <iosfwd>
+#include <vector>
+
+namespace misc
+{
+ template <class Ident_> class vector : public std::vector<Ident_>
+ {
+ public:
+ /// Super class type.
+ using super_type = std::vector<Ident_>;
+
+ /// \name Constructors and destructor.
+ /// \{
+ /// Build an empty vector.
+ vector();
+
+ /// Build a one-element vector.
+ vector(const Ident_& t);
+
+ /// Build a two-element vector.
+ vector(const Ident_& t1, const Ident_& t2);
+
+ /// Concat an element and a vector.
+ vector(const Ident_& t, const vector& v);
+
+ // Build a vector from an initializer list.
+ vector(std::initializer_list<Ident_> l);
+
+ /// Build a vector from 2 iterators.
+ template <class InputIterator> vector(InputIterator b, InputIterator e);
+
+ /// Build a vector fro, another container.
+ template <class C> vector(const C& c);
+ /// \}
+
+ /// \name Content management.
+ /// \{
+ /// Is \a data part of \a this vector?
+ bool has(const Ident_& data) const;
+
+ /// Prepend \a v into \a this and return the new iterator.
+ typename super_type::iterator prepend(const vector<Ident_>& v);
+ typename super_type::iterator prepend(const vector<Ident_>&& v);
+
+ /// Append \a v into \a this and return the new iterator.
+ typename super_type::iterator append(const vector<Ident_>& v);
+ typename super_type::iterator append(const vector<Ident_>&& v);
+
+ /// Append \a v into \a this.
+ vector operator+(const vector& v) const;
+ /// Append \a v into \a this.
+ vector& operator+=(const vector& v);
+
+ /// Append \a v into \a this from it and return the new iterator.
+ template <typename Iterator>
+ typename super_type::iterator position_append(const vector& v, Iterator it);
+ template <typename Iterator>
+ typename super_type::iterator position_append(const vector&& v,
+ Iterator it);
+
+ /** \brief Remove \a data from \a this.
+ \a data must be part of \a this. */
+ vector& remove(const Ident_& data);
+ /// \}
+
+ virtual std::ostream& dump(std::ostream& ostr) const;
+ };
+
+ /// Output \a v onto \a ostr.
+ template <class Ident_>
+ std::ostream& operator<<(std::ostream& ostr, const vector<Ident_>& v);
+
+ template <typename T>
+ auto append_and_move(std::vector<T>& res, std::vector<T>&& to_append);
+
+ template <typename T>
+ auto append_and_move(std::vector<T>& res, std::vector<T>& to_append);
+
+ template <typename T>
+ auto prepend_and_move(std::vector<T>& res, std::vector<T>&& to_prepend);
+
+ template <typename T>
+ auto prepend_and_move(std::vector<T>& res, std::vector<T>& to_prepend);
+
+ template <typename T, typename Iterator>
+ auto position_append_and_move(std::vector<T>& res,
+ Iterator res_iterator,
+ std::vector<T>&& to_append);
+
+ template <typename T, typename Iterator>
+ auto position_append_and_move(std::vector<T>& res,
+ Iterator res_iterator,
+ std::vector<T>& to_append);
+
+} // namespace misc
+
+#include <misc/vector.hxx>
diff --git a/tiger-compiler/lib/misc/vector.hxx b/tiger-compiler/lib/misc/vector.hxx
new file mode 100644
index 0000000..5c516cb
--- /dev/null
+++ b/tiger-compiler/lib/misc/vector.hxx
@@ -0,0 +1,193 @@
+/** -*- C++ -*-
+ ** \file misc/vector.hxx
+ ** \brief Implementation of misc::vector.
+ */
+
+#pragma once
+
+#include <ostream>
+
+#include <misc/contract.hh>
+
+namespace misc
+{
+ template <class T> vector<T>::vector() {}
+
+ template <class T> vector<T>::vector(const T& t) { this->push_back(t); }
+
+ template <class T> vector<T>::vector(const T& t1, const T& t2)
+ {
+ this->push_back(t1);
+ this->push_back(t2);
+ }
+
+ template <class T> vector<T>::vector(const T& t, const vector<T>& v)
+ {
+ this->push_back(t);
+ this->insert(this->end(), v.begin(), v.end());
+ }
+
+ template <class T> vector<T>::vector(std::initializer_list<T> l)
+ {
+ this->insert(this->begin(), l.begin(), l.end());
+ }
+
+ template <class T>
+ template <class InputIterator>
+ vector<T>::vector(InputIterator b, InputIterator e)
+ : super_type(b, e)
+ {}
+
+ template <class T>
+ template <class C>
+ vector<T>::vector(const C& c)
+ : super_type(c.begin(), c.end())
+ {}
+
+ template <class T> bool vector<T>::has(const T& data) const
+ {
+ return std::ranges::find(*this, data) != this->end();
+ }
+
+ template <class T>
+ inline typename std::vector<T>::iterator
+ vector<T>::prepend(const vector<T>& v)
+ {
+ auto it = this->insert(this->begin(), v.begin(), v.end());
+ return it;
+ }
+
+ template <class T>
+ inline typename std::vector<T>::iterator
+ vector<T>::prepend(const vector<T>&& v)
+ {
+ auto it = this->insert(this->begin(), v.begin(), v.end());
+ return it;
+ }
+
+ template <class T>
+ inline typename std::vector<T>::iterator vector<T>::append(const vector<T>& v)
+ {
+ auto it = this->insert(this->end(), v.begin(), v.end());
+ return it;
+ }
+
+ template <class T>
+ inline typename std::vector<T>::iterator
+ vector<T>::append(const vector<T>&& v)
+ {
+ auto it = this->insert(this->end(), v.begin(), v.end());
+ return it;
+ }
+
+ template <class T>
+ inline vector<T> vector<T>::operator+(const vector<T>& v) const
+ {
+ vector<T> res = *this;
+ return res += v;
+ }
+
+ template <class T> inline vector<T>& vector<T>::operator+=(const vector<T>& v)
+ {
+ this->insert(this->end(), v.begin(), v.end());
+ return *this;
+ }
+
+ template <class T>
+ template <typename Iterator>
+ inline typename std::vector<T>::iterator
+ vector<T>::position_append(const vector<T>& v, Iterator it)
+ {
+ auto new_it = this->insert(it, v.begin(), v.end());
+ return new_it;
+ }
+
+ template <class T>
+ template <typename Iterator>
+ inline typename std::vector<T>::iterator
+ vector<T>::position_append(const vector<T>&& v, Iterator it)
+ {
+ auto new_it = this->insert(it, v.begin(), v.end());
+ return new_it;
+ }
+
+ template <class T> inline vector<T>& vector<T>::remove(const T& data)
+ {
+ precondition(has(data));
+ this->erase(std::ranges::find(*this, data));
+ return *this;
+ }
+
+ template <class T> std::ostream& vector<T>::dump(std::ostream& ostr) const
+ {
+ for (typename super_type::const_iterator i = this->begin();
+ i != this->end(); ++i)
+ ostr << (i == this->begin() ? "" : ", ") << *i;
+ return ostr;
+ }
+
+ template <class T>
+ std::ostream& operator<<(std::ostream& ostr, const vector<T>& v)
+ {
+ return v.dump(ostr);
+ }
+
+ template <typename T>
+ auto append_and_move(std::vector<T>& v1, std::vector<T>&& v2)
+ {
+ auto it = v1.insert(v1.end(), make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+ template <typename T>
+ auto append_and_move(std::vector<T>& v1, std::vector<T>& v2)
+ {
+ auto it = v1.insert(v1.end(), make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+ template <typename T>
+ auto prepend_and_move(std::vector<T>& v1, std::vector<T>&& v2)
+ {
+ auto it = v1.insert(v1.begin(), make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+ template <typename T>
+ auto prepend_and_move(std::vector<T>& v1, std::vector<T>& v2)
+ {
+ auto it = v1.insert(v1.begin(), make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+ template <typename T, typename Iterator>
+ auto position_append_and_move(std::vector<T>& v1,
+ Iterator v1_iterator,
+ std::vector<T>&& v2)
+ {
+ auto it = v1.insert(v1_iterator, make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+ template <typename T, typename Iterator>
+ auto position_append_and_move(std::vector<T>& v1,
+ Iterator v1_iterator,
+ std::vector<T>& v2)
+ {
+ auto it = v1.insert(v1_iterator, make_move_iterator(v2.begin()),
+ make_move_iterator(v2.end()));
+ v2.clear();
+ return it;
+ }
+
+} // namespace misc
diff --git a/tiger-compiler/lib/misc/xalloc.hh b/tiger-compiler/lib/misc/xalloc.hh
new file mode 100644
index 0000000..1d819ef
--- /dev/null
+++ b/tiger-compiler/lib/misc/xalloc.hh
@@ -0,0 +1,135 @@
+/**
+ ** \file misc/xalloc.hh
+ ** \brief Declaration of misc::xalloc.
+ **/
+
+#pragma once
+
+#include <functional>
+#include <iostream>
+
+namespace misc
+{
+ /// Defines the operator() for the classes get_type, set_type and swap_type.
+ struct iomanipulator
+ {
+ virtual ~iomanipulator() = default;
+ virtual void operator()(std::ostream& o) const = 0;
+ };
+
+ /** \brief Launch the iomanipulator action on o.
+ **
+ ** Call the operator() of g (so set, get or swap the
+ ** xalloced data with data_).
+ */
+ std::ostream& operator<<(std::ostream& o, const iomanipulator& g);
+
+ /** \brief Allocate slots in std::ostreams.
+ **
+ ** Used to store flags in streams so that calling print
+ ** with additional parameters is no longer required (for
+ ** example in ast/libast.hh).
+ **
+ ** Set, get or swap data.
+ ** The idea is to build the right inner class with set, get or
+ ** swap methods, then use this class as a parameter of operator<<.
+ **
+ ** `StoredType` must be `CopyConstructible`. If it's not
+ ** `DefaultConstructible`, then arguments for its constructor are
+ ** to be passed to the `xalloc` constructor.
+ */
+ template <class StoredType> class xalloc
+ {
+ private:
+ /** \brief Handle the data to put in the xalloced place.
+ **
+ ** This inner class is used only with the set method.
+ */
+ class set_type : public iomanipulator
+ {
+ public:
+ /// Set data_ to data.
+ set_type(const xalloc& slot, StoredType& data);
+ /// Set the data in the xalloced place.
+ void operator()(std::ostream& ostr) const override;
+
+ private:
+ /// The xalloced data.
+ const xalloc& slot_;
+ /// Data to put in the stream.
+ StoredType& data_;
+ };
+
+ /** \brief Handle the data to get from the xalloced place.
+ **
+ ** This inner class is used only with the get method.
+ */
+ class get_type : public iomanipulator
+ {
+ public:
+ /// Set data_ to data.
+ get_type(const xalloc& slot, StoredType& data);
+
+ /// Get the data from the xalloced place.
+ void operator()(std::ostream& ostr) const override;
+
+ private:
+ /// The xalloced data.
+ const xalloc& slot_;
+ /// Variable in which we return the xalloc data.
+ StoredType& data_;
+ };
+
+ /** \brief Swap the data stored in the stream for a given one.
+ **
+ ** This inner class is used only with the swap method.
+ */
+ class swap_type : public iomanipulator
+ {
+ public:
+ /// Set data_ to data.
+ swap_type(const xalloc& slot, StoredType& data);
+
+ /// Swap the data from the xalloced place for a given one.
+ void operator()(std::ostream& ostr) const override;
+
+ private:
+ /// The xalloced data.
+ const xalloc& slot_;
+ /// Variable in which we store the data to be swapped.
+ StoredType& data_;
+ };
+
+ /// The index of the slot.
+ const long int index_;
+ // The model that is used to create new instances.
+ const StoredType model_;
+
+ public:
+ /// Allocates the slot.
+ template <typename... Args> xalloc(Args&&... args);
+
+ static void
+ deallocate(std::ios_base::event type, std::ios_base& ios, int index);
+
+ /// The xalloc index.
+ long int index() const;
+ /// The stored data as an lvalue.
+ StoredType& operator()(std::ostream& ostr) const;
+
+ /// A setter.
+ /// \param data where to find the value when the setter is executed.
+ set_type set(StoredType& data) const;
+
+ /// A getter.
+ /// \param data where to store the value when the getter is executed.
+ get_type get(StoredType& data) const;
+
+ /// A swapper.
+ /// \param data value to exchange when the swapper is executed.
+ swap_type swap(StoredType& data) const;
+ };
+
+} // namespace misc
+
+#include <misc/xalloc.hxx>
diff --git a/tiger-compiler/lib/misc/xalloc.hxx b/tiger-compiler/lib/misc/xalloc.hxx
new file mode 100644
index 0000000..8ae692a
--- /dev/null
+++ b/tiger-compiler/lib/misc/xalloc.hxx
@@ -0,0 +1,135 @@
+/**
+ ** \file misc/xalloc.hxx
+ ** \brief Implementation for misc/xalloc.hh.
+ */
+
+#pragma once
+
+#include <utility>
+
+#include <misc/xalloc.hh>
+
+namespace misc
+{
+ /*----------------.
+ | iomanipulator. |
+ `----------------*/
+
+ inline std::ostream& operator<<(std::ostream& o, const iomanipulator& g)
+ {
+ g(o);
+ return o;
+ }
+
+ /*---------------------.
+ | xalloc<StoredType>. |
+ `---------------------*/
+
+ template <class StoredType>
+ template <typename... Args>
+ xalloc<StoredType>::xalloc(Args&&... args)
+ : index_(std::ios::xalloc())
+ , model_{std::forward<Args>(args)...}
+ {}
+
+ template <class StoredType> long int xalloc<StoredType>::index() const
+ {
+ return index_;
+ }
+
+ template <class StoredType>
+ StoredType& xalloc<StoredType>::operator()(std::ostream& ostr) const
+ {
+ void*& storage_ptr = ostr.pword(index_);
+
+ if (!storage_ptr)
+ {
+ storage_ptr = new StoredType{model_};
+ ostr.register_callback(xalloc::deallocate, index_);
+ }
+
+ return *static_cast<StoredType*>(storage_ptr);
+ }
+
+ template <class StoredType>
+ void xalloc<StoredType>::deallocate(std::ios_base::event type,
+ std::ios_base& ios,
+ int index)
+ {
+ if (type == std::ios_base::erase_event)
+ {
+ StoredType* ptr = static_cast<StoredType*>(ios.pword(index));
+ delete ptr;
+ }
+ }
+
+ /*-----------.
+ | set_type. |
+ `-----------*/
+
+ template <class StoredType>
+ xalloc<StoredType>::set_type::set_type(const xalloc& slot, StoredType& data)
+ : slot_(slot)
+ , data_(data)
+ {}
+
+ template <class StoredType>
+ void xalloc<StoredType>::set_type::operator()(std::ostream& ostr) const
+ {
+ slot_(ostr) = data_;
+ }
+
+ template <class StoredType>
+ typename xalloc<StoredType>::set_type
+ xalloc<StoredType>::set(StoredType& data) const
+ {
+ return set_type(*this, data);
+ }
+
+ /*-----------.
+ | get_type. |
+ `-----------*/
+
+ template <class StoredType>
+ xalloc<StoredType>::get_type::get_type(const xalloc& slot, StoredType& data)
+ : slot_(slot)
+ , data_(data)
+ {}
+
+ template <class StoredType>
+ void xalloc<StoredType>::get_type::operator()(std::ostream& ostr) const
+ {
+ data_ = slot_(ostr);
+ }
+
+ template <class StoredType>
+ typename xalloc<StoredType>::get_type
+ xalloc<StoredType>::get(StoredType& data) const
+ {
+ return get_type(*this, data);
+ }
+
+ /*------------.
+ | swap_type. |
+ `------------*/
+
+ template <class StoredType>
+ xalloc<StoredType>::swap_type::swap_type(const xalloc& slot, StoredType& data)
+ : slot_(slot)
+ , data_(data)
+ {}
+
+ template <class StoredType>
+ void xalloc<StoredType>::swap_type::operator()(std::ostream& ostr) const
+ {
+ std::swap(slot_(ostr), data_);
+ }
+
+ template <class StoredType>
+ typename xalloc<StoredType>::swap_type
+ xalloc<StoredType>::swap(StoredType& data) const
+ {
+ return swap_type(*this, data);
+ }
+
+} // namespace misc